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.
- package/README.md +66 -2
- package/dist/mcp.js +439 -480
- package/package.json +2 -2
- package/server/client/dist/assets/{ArrowRight.es-BlNsZQFs.js → ArrowRight.es-nBJws3ws.js} +1 -1
- package/server/client/dist/assets/{AuxiliaryPanelHeader-HAttwVby.js → AuxiliaryPanelHeader-BN_2axQu.js} +1 -1
- package/server/client/dist/assets/{Calendar-DH3eSSRs.js → Calendar-vA4Xa4Qr.js} +1 -1
- package/server/client/dist/assets/{Callout-CcYyvHQP.js → Callout-Bo2P960P.js} +1 -1
- package/server/client/dist/assets/{CaretUp.es-C8iY5OlB.js → CaretUp.es-DDbqKn78.js} +1 -1
- package/server/client/dist/assets/{CheckCircle.es-Dqr3WImn.js → CheckCircle.es-CyY9aLBF.js} +1 -1
- package/server/client/dist/assets/{Copy.es-fMv0ETir.js → Copy.es-BwX4tEoU.js} +1 -1
- package/server/client/dist/assets/{File.es-CHtXXafR.js → File.es-DeTgvUnI.js} +1 -1
- package/server/client/dist/assets/{FileText.es-DPIwDCEe.js → FileText.es-C-bpw8dQ.js} +1 -1
- package/server/client/dist/assets/{FlowArrow.es-Dxee98ir.js → FlowArrow.es-CKcMBOmX.js} +1 -1
- package/server/client/dist/assets/{Graph-hVj6vAYJ.js → Graph-BNoSRJP3.js} +1 -1
- package/server/client/dist/assets/{Graph-CdEu8eAn.js → Graph-DYYxNAWn.js} +1 -1
- package/server/client/dist/assets/{Image.es-CjXY1JVf.js → Image.es-d4jWnijM.js} +1 -1
- package/server/client/dist/assets/{Info.es-CYxg-Vku.js → Info.es-DVzN2joA.js} +1 -1
- package/server/client/dist/assets/Integration-gDDtIJYJ.js +1 -0
- package/server/client/dist/assets/{LinkSimple.es-B-P-7Iem.js → LinkSimple.es-BD4aGTc3.js} +1 -1
- package/server/client/dist/assets/Note-FL31jb2U.js +19 -0
- package/server/client/dist/assets/{NotePropertiesPanel-6P7UfRBR.js → NotePropertiesPanel-os22Ppnu.js} +1 -1
- package/server/client/dist/assets/{Plus.es-Dy6onD-Z.js → Plus.es-Cl8zOOZa.js} +1 -1
- package/server/client/dist/assets/Reminders-Dt2JuGci.js +1 -0
- package/server/client/dist/assets/{Search-D9detGWk.js → Search-CPPTW2PO.js} +2 -2
- package/server/client/dist/assets/{SurfaceCard-D5QxOte_.js → SurfaceCard-jL2qzrzF.js} +1 -1
- package/server/client/dist/assets/{Tag-Bquqtx23.js → Tag-3DbGmuxa.js} +1 -1
- package/server/client/dist/assets/{TagNotes-CbjfxqAN.js → TagNotes-DLwRF8pT.js} +1 -1
- package/server/client/dist/assets/Trash.es-fxukjAO6.js +1 -0
- package/server/client/dist/assets/{ViewChip-BVkZAXyx.js → ViewChip-CVe_HNyd.js} +1 -1
- package/server/client/dist/assets/Views-8ghLRax7.js +1 -0
- package/server/client/dist/assets/{abnfDiagram-N423BO3Z-D44O4T7q.js → abnfDiagram-N423BO3Z-CPgGmCbn.js} +1 -1
- package/server/client/dist/assets/app-Bcl0U7r9.css +1 -0
- package/server/client/dist/assets/app-DzChh-V0.js +151 -0
- package/server/client/dist/assets/{arc-Cil9fXuW.js → arc-DqTgRpuF.js} +1 -1
- package/server/client/dist/assets/{architectureDiagram-T3A2C74G-Cjq6ayF2.js → architectureDiagram-T3A2C74G-rTYMAQ-J.js} +1 -1
- package/server/client/dist/assets/{blockDiagram-VBNYF7ZC-B2Xm5N0i.js → blockDiagram-VBNYF7ZC-BOluytVz.js} +1 -1
- package/server/client/dist/assets/{c4Diagram-5PPSVZJV-Dp0y-lCR.js → c4Diagram-5PPSVZJV-C8gbPpcb.js} +1 -1
- package/server/client/dist/assets/{calendar-data-wB0ifXdo.js → calendar-data-BQ24n348.js} +1 -1
- package/server/client/dist/assets/channel--aI9fJWX.js +1 -0
- package/server/client/dist/assets/{chunk-2GRJ4B5K-CWaaNkFx.js → chunk-2GRJ4B5K-CRER5Ka0.js} +1 -1
- package/server/client/dist/assets/{chunk-2Q5K7J3B-Ces-xz2S.js → chunk-2Q5K7J3B-hxmJWGu_.js} +1 -1
- package/server/client/dist/assets/{chunk-5RXB4S5H-B-4Chlfc.js → chunk-5RXB4S5H-Bpr5Us8Y.js} +1 -1
- package/server/client/dist/assets/{chunk-5VM5RSS4-C8_HVwuz.js → chunk-5VM5RSS4-CKUz9fAb.js} +1 -1
- package/server/client/dist/assets/{chunk-6Q2QTUOP-xZ8ofRqk.js → chunk-6Q2QTUOP-B8XEOHPN.js} +1 -1
- package/server/client/dist/assets/{chunk-GF5L2VYU-Bpa43a7s.js → chunk-GF5L2VYU-BBUD-HJi.js} +1 -1
- package/server/client/dist/assets/{chunk-JWPE2WC7-DsyTXbuq.js → chunk-JWPE2WC7-Dq6_B8-d.js} +1 -1
- package/server/client/dist/assets/{chunk-KBJHAD2P-BDhjm9-8.js → chunk-KBJHAD2P--2VZEwNJ.js} +1 -1
- package/server/client/dist/assets/{chunk-RYQCIY6F-Cn-jdp6I.js → chunk-RYQCIY6F-CKCwnKiC.js} +1 -1
- package/server/client/dist/assets/{chunk-XXDRQBXY-BKsc_0wh.js → chunk-XXDRQBXY-VDufR1Oi.js} +1 -1
- package/server/client/dist/assets/classDiagram-JCYQIIEL-BsbwE38V.js +1 -0
- package/server/client/dist/assets/classDiagram-v2-OCEON4UE-BsbwE38V.js +1 -0
- package/server/client/dist/assets/{cose-bilkent-JH36ORCC-jmn3Q4zj.js → cose-bilkent-JH36ORCC-D4nqOx8S.js} +1 -1
- package/server/client/dist/assets/{cynefinDiagram-MW4NZA55-BpLstuBJ.js → cynefinDiagram-MW4NZA55-CUuLMs-6.js} +1 -1
- package/server/client/dist/assets/{dagre-VZM6K2ZE-B5ft5Yzm.js → dagre-VZM6K2ZE-CUSkhZgS.js} +1 -1
- package/server/client/dist/assets/{diagram-7IWD3JNH-B_W9IsWZ.js → diagram-7IWD3JNH-D95eVcKx.js} +4 -4
- package/server/client/dist/assets/{diagram-B4RE2ZJO-32chS3GX.js → diagram-B4RE2ZJO-7OH_fb0K.js} +1 -1
- package/server/client/dist/assets/{diagram-LBJQPF4R-Bqupdb3-.js → diagram-LBJQPF4R-D9UwEIMd.js} +1 -1
- package/server/client/dist/assets/{diagram-Q27KOJAE-BD8jKBsv.js → diagram-Q27KOJAE-Dx7WFDuX.js} +1 -1
- package/server/client/dist/assets/{diagram-UB23O5K3-C40jAU8D.js → diagram-UB23O5K3-D2BYwAKT.js} +1 -1
- package/server/client/dist/assets/{ebnfDiagram-BXEA7PRR-BQfW9mFA.js → ebnfDiagram-BXEA7PRR-DbeA-fk4.js} +1 -1
- package/server/client/dist/assets/{erDiagram-JOGREHBK-ILZnLzz2.js → erDiagram-JOGREHBK-jWW-ICGO.js} +1 -1
- package/server/client/dist/assets/{flowDiagram-UKHOOZJN-CDmwr2dI.js → flowDiagram-UKHOOZJN-68iZdxxw.js} +1 -1
- package/server/client/dist/assets/{ganttDiagram-PKOTCBZU-DBcrUc49.js → ganttDiagram-PKOTCBZU-CxwY3VXg.js} +1 -1
- package/server/client/dist/assets/{gitGraphDiagram-DS77QQ5N-_xO6__FK.js → gitGraphDiagram-DS77QQ5N-Ci6o5MfZ.js} +1 -1
- package/server/client/dist/assets/{image.api-ChvlfuZg.js → image.api-CyIIEGkG.js} +1 -1
- package/server/client/dist/assets/index-Iy_BgP1R.js +1 -0
- package/server/client/dist/assets/{infoDiagram-6WML65LV-CuIIcu-L.js → infoDiagram-6WML65LV-DY7aMdjV.js} +1 -1
- package/server/client/dist/assets/integrations-LOdTs1T6.js +1 -0
- package/server/client/dist/assets/{ishikawaDiagram-WSZJBQD7-BVtRGTOj.js → ishikawaDiagram-WSZJBQD7-Bh5qKh1d.js} +1 -1
- package/server/client/dist/assets/{journeyDiagram-NVQOT4AX-D5-Nzb2N.js → journeyDiagram-NVQOT4AX-B_svXTTT.js} +1 -1
- package/server/client/dist/assets/{kanban-definition-27J2QSJJ-DmOhgC8H.js → kanban-definition-27J2QSJJ-CaJslHGg.js} +1 -1
- package/server/client/dist/assets/manage-image-DXedfr7U.js +1 -0
- package/server/client/dist/assets/{manage-image-detail-BIDHUR5-.js → manage-image-detail-DmifOPNU.js} +1 -1
- package/server/client/dist/assets/{mcp-admin-adapter-D0R8p9az.js → mcp-admin-adapter-CmKsg1vd.js} +1 -1
- package/server/client/dist/assets/mcp-d8IzsoRz.js +5 -0
- package/server/client/dist/assets/{mermaid.core-C2tL9tq7.js → mermaid.core-BfUQM5vF.js} +4 -4
- package/server/client/dist/assets/{mindmap-definition-FAOFIHXS-DuvsPqrh.js → mindmap-definition-FAOFIHXS-DGbkJda2.js} +1 -1
- package/server/client/dist/assets/{note-core-YhYEmI_R.js → note-core-DRBsBf9H.js} +9 -9
- package/server/client/dist/assets/{note-runtime-B3ats-dC.js → note-runtime-ztZvXRIu.js} +16 -16
- package/server/client/dist/assets/{note-ui-BtzPk8gA.js → note-ui-DRnAnwKv.js} +1 -1
- package/server/client/dist/assets/{pegDiagram-VL7TDLO6-D64crEZV.js → pegDiagram-VL7TDLO6-Bip6zQct.js} +1 -1
- package/server/client/dist/assets/{pieDiagram-7S7Q4E2Y--kl7vopC.js → pieDiagram-7S7Q4E2Y-CjfjGY8Y.js} +1 -1
- package/server/client/dist/assets/{placeholder-DKgxoe_f.js → placeholder-G6iEBbDy.js} +1 -1
- package/server/client/dist/assets/{properties-B7Fv95qY.js → properties-BPobx_Qk.js} +1 -1
- package/server/client/dist/assets/{quadrantDiagram-CIZ2JOQS-DuvJ4M2y.js → quadrantDiagram-CIZ2JOQS-B6F1yUT-.js} +1 -1
- package/server/client/dist/assets/{railroadDiagram-AXF67PYL-BMKmCOY7.js → railroadDiagram-AXF67PYL-D-0fLe0F.js} +1 -1
- package/server/client/dist/assets/{requirementDiagram-LRYGKXZP-DY1eJcy0.js → requirementDiagram-LRYGKXZP-tm4mnCyJ.js} +1 -1
- package/server/client/dist/assets/route-preload.js +2 -2
- package/server/client/dist/assets/{sankeyDiagram-W5VNT64P-C3Ka4GKM.js → sankeyDiagram-W5VNT64P-DSBWFurb.js} +1 -1
- package/server/client/dist/assets/{search-ddYl3qH-.js → search-DanMKCC8.js} +1 -1
- package/server/client/dist/assets/{search-admin-adapter-Daf7e2YQ.js → search-admin-adapter-7sTcWTmv.js} +1 -1
- package/server/client/dist/assets/{sequenceDiagram-SI44F4Z6-Bhpwtk2s.js → sequenceDiagram-SI44F4Z6-KrwjjJIV.js} +1 -1
- package/server/client/dist/assets/{sizeCapture-X5ZJPWSS-BFta71TW.js → sizeCapture-X5ZJPWSS-DL2cn_Q6.js} +1 -1
- package/server/client/dist/assets/{stateDiagram-OKZ733FA-D6GCn1io.js → stateDiagram-OKZ733FA-CKuNDH85.js} +1 -1
- package/server/client/dist/assets/{stateDiagram-v2-UEYNNEHI-g4yinGDn.js → stateDiagram-v2-UEYNNEHI-BFaj2wbM.js} +1 -1
- package/server/client/dist/assets/{swimlanes-SLNWSIFB-DLFvOjUl.js → swimlanes-SLNWSIFB-5S17nqhK.js} +2 -2
- package/server/client/dist/assets/swimlanesDiagram-ULZ7WXOC-dexsHJq2.js +8 -0
- package/server/client/dist/assets/{tag.api-DEUROVKQ.js → tag.api-kKZl04yY.js} +1 -1
- package/server/client/dist/assets/{time-PxWila4-.js → time-BwwQGbK-.js} +38 -38
- package/server/client/dist/assets/{timeline-definition-Z64GVDOM-DTSIekSM.js → timeline-definition-Z64GVDOM-CU1hp_7d.js} +3 -3
- package/server/client/dist/assets/{trash-BHida7BG.js → trash-Cepvi7G8.js} +1 -1
- package/server/client/dist/assets/url-Bp8sXMb4.js +1 -0
- package/server/client/dist/assets/{useNoteMutate-BjvZUmtX.js → useNoteMutate-D-mZKXjl.js} +3 -3
- package/server/client/dist/assets/{useReminderMutate-C5n-5LM-.js → useReminderMutate-Cexk1ydX.js} +1 -1
- package/server/client/dist/assets/{vennDiagram-T6HMQDX7-CMNqSI2X.js → vennDiagram-T6HMQDX7-MoiVLnil.js} +1 -1
- package/server/client/dist/assets/{wardleyDiagram-T6FBY63Y-DV-JOYqB.js → wardleyDiagram-T6FBY63Y-cZkfdI6C.js} +1 -1
- package/server/client/dist/assets/{xychartDiagram-ELKLHX3M-BUIniF4m.js → xychartDiagram-ELKLHX3M-B63hxD-r.js} +1 -1
- package/server/client/dist/index.html +6 -6
- package/server/dist/app.js +2 -0
- package/server/dist/features/integration/auth.js +21 -0
- package/server/dist/features/integration/manifest.js +87 -0
- package/server/dist/features/integration/schema.js +54 -0
- package/server/dist/features/integration/service.js +173 -0
- package/server/dist/features/mcp-admin/service.js +19 -83
- package/server/dist/features/note/graphql/note.field.resolver.js +1 -1
- package/server/dist/features/note/graphql/note.query.resolver.js +6 -0
- package/server/dist/features/note/graphql/note.type-defs.js +13 -1
- package/server/dist/features/note/http/authoring.js +493 -0
- package/server/dist/features/note/http/mcp.js +15 -463
- package/server/dist/features/note/services/authoring.js +17 -1
- package/server/dist/features/note/services/markdown-intent-write.js +1 -0
- package/server/dist/features/note/services/markdown-read.js +85 -0
- package/server/dist/features/note/services/properties.js +36 -30
- package/server/dist/features/note/services/search.js +17 -0
- package/server/dist/features/search/graphql/resolver.js +10 -1
- package/server/dist/features/search/graphql/type-defs.js +3 -0
- package/server/dist/features/tag/graphql/tag.query.resolver.js +10 -0
- package/server/dist/features/tag/graphql/tag.type-defs.js +1 -0
- package/server/dist/features/view/graphql/mcp.query.resolver.js +22 -0
- package/server/dist/features/view/graphql/view.query.resolver.js +2 -0
- package/server/dist/features/view/graphql/view.type-defs.js +27 -0
- package/server/dist/features/view/services/mcp-read.js +142 -0
- package/server/dist/features/view/services/workspace.js +12 -4
- package/server/dist/modules/auth-guard.js +24 -1
- package/server/dist/modules/integration-token.js +27 -0
- package/server/dist/modules/mcp-auth.js +37 -23
- package/server/dist/modules/mcp-token.js +6 -25
- package/server/dist/routes/api.js +2 -0
- package/server/dist/routes/graphql.js +2 -1
- package/server/dist/routes/integrations.js +117 -0
- package/server/dist/routes/mcp.js +29 -9
- package/server/prisma/migrations/20260917120000_0020_plugin_installations/migration.sql +39 -0
- package/server/prisma/migrations/20260917150000_0021_integration_connections/migration.sql +29 -0
- package/server/prisma/schema.prisma +34 -10
- package/server/client/dist/assets/Note-CpzLtGVM.js +0 -19
- package/server/client/dist/assets/Reminders-DnuALBL6.js +0 -1
- package/server/client/dist/assets/Trash.es-XEcWG_aq.js +0 -1
- package/server/client/dist/assets/Views-L4eC96Lx.js +0 -1
- package/server/client/dist/assets/app-BFM2V_Rx.js +0 -151
- package/server/client/dist/assets/app-DjDwGe0t.css +0 -1
- package/server/client/dist/assets/channel-DZFalh-h.js +0 -1
- package/server/client/dist/assets/classDiagram-JCYQIIEL-CkEhFvVV.js +0 -1
- package/server/client/dist/assets/classDiagram-v2-OCEON4UE-CkEhFvVV.js +0 -1
- package/server/client/dist/assets/index-CJPl3MJE.js +0 -1
- package/server/client/dist/assets/manage-image-CSJ3Flgc.js +0 -1
- package/server/client/dist/assets/mcp-D8footel.js +0 -5
- package/server/client/dist/assets/swimlanesDiagram-ULZ7WXOC-Ci4mcvmo.js +0 -8
- 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
|
+
};
|