ocean-brain 0.8.2 → 0.11.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 +2 -0
- package/dist/mcp.js +103 -105
- package/package.json +3 -2
- package/server/client/dist/assets/{ArrowRight.es-g2YZTklZ.js → ArrowRight.es-BEhnlwfe.js} +1 -1
- package/server/client/dist/assets/AuxiliaryPanelHeader-B1k7pZpn.js +1 -0
- package/server/client/dist/assets/Calendar-D7QJsAlg.js +25 -0
- package/server/client/dist/assets/{Callout-B_IPSF_5.js → Callout-BTd1BYtV.js} +1 -1
- package/server/client/dist/assets/{Copy.es-CNxe4ujr.js → Copy.es-BoLjilxv.js} +1 -1
- package/server/client/dist/assets/File.es-Ct7fscBg.js +1 -0
- package/server/client/dist/assets/Graph-DYUb7gQb.js +46 -0
- package/server/client/dist/assets/{Graph-D9GeO71k.js → Graph-LY_IgMYy.js} +1 -1
- package/server/client/dist/assets/{Image.es-DnON8cv2.js → Image.es-OYyN3BYt.js} +1 -1
- package/server/client/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/server/client/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/server/client/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/server/client/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/server/client/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/server/client/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/server/client/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/server/client/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/server/client/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/server/client/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/server/client/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/server/client/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/server/client/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/server/client/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/server/client/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/server/client/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/server/client/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/server/client/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/server/client/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/server/client/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/server/client/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/server/client/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/server/client/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/server/client/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/server/client/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/server/client/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/server/client/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/server/client/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/server/client/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/server/client/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/server/client/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/server/client/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/server/client/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/server/client/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/server/client/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/server/client/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/server/client/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/server/client/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/server/client/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/server/client/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/server/client/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/server/client/dist/assets/Note-DsMhwrHw.js +25 -0
- package/server/client/dist/assets/NotePropertiesPanel-aCKXAe5F.js +2 -0
- package/server/client/dist/assets/PencilLine.es-0JpEgxFY.js +1 -0
- package/server/client/dist/assets/{Plus.es-CQ8wn2is.js → Plus.es-DRfLW_bI.js} +1 -1
- package/server/client/dist/assets/Reminders-COr1OHvF.js +1 -0
- package/server/client/dist/assets/Search-Ctkx0BQk.js +31 -0
- package/server/client/dist/assets/SurfaceCard-t7pdfhEe.js +1 -0
- package/server/client/dist/assets/Tag-BjxtrIQW.js +1 -0
- package/server/client/dist/assets/TagNotes-DV_fdRbg.js +1 -0
- package/server/client/dist/assets/{Trash.es-0aPpA-3S.js → Trash.es-Bo1VyK9Q.js} +1 -1
- package/server/client/dist/assets/ViewChip-DlCkL4z4.js +1 -0
- package/server/client/dist/assets/ViewNotes-wWWeFJyU.js +1 -0
- package/server/client/dist/assets/ViewSectionDialog-DhH8harC.js +102 -0
- package/server/client/dist/assets/Views-CWE99SnI.js +1 -0
- package/server/client/dist/assets/abnfDiagram-VRR7QNED-CWlV5dXw.js +1 -0
- package/server/client/dist/assets/app-B9WZRrAH.css +1 -0
- package/server/client/dist/assets/app-BpSMjzET.js +26 -0
- package/server/client/dist/assets/arc-BV-n6RUX.js +1 -0
- package/server/client/dist/assets/architectureDiagram-ZJ3FMSHR-CekzMXdu.js +36 -0
- package/server/client/dist/assets/blockDiagram-677ZJIJ3-B49yHoxq.js +132 -0
- package/server/client/dist/assets/c4Diagram-LMCZKHZV-0AfB9NBC.js +10 -0
- package/server/client/dist/assets/channel-CigOulR-.js +1 -0
- package/server/client/dist/assets/chunk-2Q5K7J3B-DaPQAU1q.js +1 -0
- package/server/client/dist/assets/chunk-32BRIVSS-CfL3kZAg.js +1 -0
- package/server/client/dist/assets/chunk-5VM5RSS4-DeOwWPE_.js +15 -0
- package/server/client/dist/assets/chunk-EX3LRPZG-C3W1oc9y.js +231 -0
- package/server/client/dist/assets/chunk-JWPE2WC7-_Oqh79OY.js +1 -0
- package/server/client/dist/assets/chunk-MOJQB5TN-DDKNNzI6.js +88 -0
- package/server/client/dist/assets/chunk-RYQCIY6F-DCHah7CC.js +1 -0
- package/server/client/dist/assets/chunk-V7JOEXUC-uUOIzgxj.js +206 -0
- package/server/client/dist/assets/chunk-VR4S4FIN-DDVw2WPs.js +1 -0
- package/server/client/dist/assets/chunk-XXDRQBXY-Coo4UFm2.js +1 -0
- package/server/client/dist/assets/classDiagram-OUVF2IWQ-D13ISIOW.js +1 -0
- package/server/client/dist/assets/classDiagram-v2-EOCWNBFH-D13ISIOW.js +1 -0
- package/server/client/dist/assets/colors-Cc3OSVma.js +1 -0
- package/server/client/dist/assets/cose-bilkent-JH36ORCC-C3pHmHpD.js +1 -0
- package/server/client/dist/assets/cynefin-VYW2F7L2-DU_G4Atc.js +166 -0
- package/server/client/dist/assets/cynefinDiagram-TSTJHNR4-DZ6iiJFo.js +62 -0
- package/server/client/dist/assets/cytoscape.esm-D3_iZ_3b.js +321 -0
- package/server/client/dist/assets/dagre-VKFMJZFB-DNELbhwC.js +4 -0
- package/server/client/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/server/client/dist/assets/diagram-FQU43EPY-CMEvZJ61.js +3 -0
- package/server/client/dist/assets/diagram-G47NLZAW-BYDtf6j9.js +24 -0
- package/server/client/dist/assets/diagram-NH7WQ7WH-CmXfcCQA.js +24 -0
- package/server/client/dist/assets/diagram-OA4YK3LP-BflTKJxU.js +30 -0
- package/server/client/dist/assets/diagram-WEI45ONY-KW3fKqna.js +41 -0
- package/server/client/dist/assets/ebnfDiagram-CCIWWBDH-CbyhY5Nj.js +1 -0
- package/server/client/dist/assets/erDiagram-Q63AITRT-CC2eZV8g.js +85 -0
- package/server/client/dist/assets/{floating-ui.react-dom-wWLZ1CdM.js → floating-ui.react-dom-BWTnA00G.js} +1 -1
- package/server/client/dist/assets/flowDiagram-23GEKE2U-unplo7Qm.js +156 -0
- package/server/client/dist/assets/ganttDiagram-NO4QXBWP-BcBK5HcZ.js +292 -0
- package/server/client/dist/assets/gitGraphDiagram-IHSO6WYX-DgVbbb5k.js +106 -0
- package/server/client/dist/assets/graph-C5DFNLrC.js +1 -0
- package/server/client/dist/assets/image-delete-confirmation-D7xrODQV.js +1 -0
- package/server/client/dist/assets/image.api-CyQisInP.js +17 -0
- package/server/client/dist/assets/index-B-E1Ilh9.js +1 -0
- package/server/client/dist/assets/infoDiagram-FWYZ7A6U-N_D9RdfG.js +2 -0
- package/server/client/dist/assets/init-Gi6I4Gst.js +1 -0
- package/server/client/dist/assets/isObject-U9U2HXiq.js +1 -0
- package/server/client/dist/assets/ishikawaDiagram-FXEZZL3T-BBKrzmB2.js +70 -0
- package/server/client/dist/assets/journeyDiagram-5HDEW3XC-NdCxLmQB.js +139 -0
- package/server/client/dist/assets/kanban-definition-HUTT4EX6-Ck7t4-tt.js +89 -0
- package/server/client/dist/assets/katex-DywYRkvg.css +1 -0
- package/server/client/dist/assets/katex-HP8lGamR.js +257 -0
- package/server/client/dist/assets/katex-x288kqHd.js +257 -0
- package/server/client/dist/assets/layout-Cz0MDlGi.js +1 -0
- package/server/client/dist/assets/linear-D6yRgDLq.js +1 -0
- package/server/client/dist/assets/manage-image-azmo5iVw.js +1 -0
- package/server/client/dist/assets/manage-image-detail-BF-uSqb_.js +1 -0
- package/server/client/dist/assets/map-Mm1V-_Na.js +1 -0
- package/server/client/dist/assets/{mcp-CT_9IV2c.js → mcp-CCaFd0zm.js} +4 -4
- package/server/client/dist/assets/{mcp-admin-adapter-xAuyZc_M.js → mcp-admin-adapter-PMmgPupc.js} +1 -1
- package/server/client/dist/assets/mermaid.core-B14ZAmWA.js +308 -0
- package/server/client/dist/assets/min-tv6RD-6E.js +1 -0
- package/server/client/dist/assets/mindmap-definition-LN4V7U3C-BTUqSdcP.js +96 -0
- package/server/client/dist/assets/{note-core-Buwzyxi7.js → note-core-DUTqUh5N.js} +2 -2
- package/server/client/dist/assets/{note-runtime-CPDVOFEo.js → note-runtime-zN5ddTba.js} +1 -1
- package/server/client/dist/assets/{note-ui-CHI-tzj-.js → note-ui-CtijppHK.js} +1 -1
- package/server/client/dist/assets/{note.api-D_00ZzJC.js → note.api-D3oJmG3q.js} +6 -6
- package/server/client/dist/assets/ordinal-Cboi1Yqb.js +1 -0
- package/server/client/dist/assets/pegDiagram-2B236MQR-Cjcu3mVz.js +1 -0
- package/server/client/dist/assets/pieDiagram-ENE6RG2P-BxI_c22Z.js +39 -0
- package/server/client/dist/assets/{placeholder-DbdGiYGL.js → placeholder-AusSo8p9.js} +4 -4
- package/server/client/dist/assets/properties-BrNJLkxR.js +1 -0
- package/server/client/dist/assets/quadrantDiagram-ABIIQ3AL-DGm0a-yR.js +7 -0
- package/server/client/dist/assets/railroadDiagram-RFXS5EU6-DmCDu89O.js +1 -0
- package/server/client/dist/assets/requirementDiagram-TGXJPOKE-CBpUt7Ig.js +84 -0
- package/server/client/dist/assets/route-preload.js +2 -2
- package/server/client/dist/assets/sankeyDiagram-HTMAVEWB-BjGnDZlp.js +40 -0
- package/server/client/dist/assets/search-D-xKTPdO.js +1 -0
- package/server/client/dist/assets/search-admin-adapter-CJnJmL6w.js +1 -0
- package/server/client/dist/assets/sequenceDiagram-DBY2YBRQ-B7rpCfS6.js +162 -0
- package/server/client/dist/assets/sizeCapture-X5ZJPWSS-CUJhD0uW.js +1 -0
- package/server/client/dist/assets/stateDiagram-2N3HPSRC-Y9-3XqRX.js +1 -0
- package/server/client/dist/assets/stateDiagram-v2-6OUMAXLB-DbHXhT02.js +1 -0
- package/server/client/dist/assets/swimlanes-5IMT3BWC-Cs1NO9ng.js +2 -0
- package/server/client/dist/assets/swimlanesDiagram-G3AALYLV-DQnrq2ZC.js +8 -0
- package/server/client/dist/assets/{tag.api-CX0SE06J.js → tag.api-DNSQpqwk.js} +3 -3
- package/server/client/dist/assets/time-D5LRMumI.js +9 -0
- package/server/client/dist/assets/timeline-definition-FHXFAJF6-8fqD4WNL.js +120 -0
- package/server/client/dist/assets/toNumber-DE3J3kMD.js +1 -0
- package/server/client/dist/assets/transform-BUB79_za.js +1 -0
- package/server/client/dist/assets/trash-D4-9sv8q.js +1 -0
- package/server/client/dist/assets/url-9nrbQs7Z.js +1 -0
- package/server/client/dist/assets/{useReminderMutate-CLK1tHvT.js → useReminderMutate-BrGO9M0o.js} +4 -4
- package/server/client/dist/assets/vennDiagram-L72KCM5P-BPqKkd5a.js +34 -0
- package/server/client/dist/assets/wardleyDiagram-EHGQE667-Cq11kU2M.js +78 -0
- package/server/client/dist/assets/xychartDiagram-FW5EYKEG-DJ6UzFj-.js +7 -0
- package/server/client/dist/index.html +7 -7
- package/server/dist/features/image/services/delete.js +25 -1
- package/server/dist/features/note/graphql/note.field.resolver.js +2 -0
- package/server/dist/features/note/graphql/note.mutation.resolver.js +54 -23
- package/server/dist/features/note/graphql/note.query.resolver.js +15 -5
- package/server/dist/features/note/graphql/note.type-defs.js +2 -1
- package/server/dist/features/note/http/mcp.js +1 -60
- package/server/dist/features/note/services/authoring.js +17 -80
- package/server/dist/features/note/services/markdown-patch.js +80 -8
- package/server/dist/features/note/services/note-reference-index.js +98 -0
- package/server/dist/features/note/services/properties.js +21 -1
- package/server/dist/features/note/services/property-restore.js +26 -0
- package/server/dist/features/note/services/search.js +5 -0
- package/server/dist/features/note/services/snapshot.js +82 -58
- package/server/dist/features/note/services/trash.js +18 -31
- package/server/dist/features/note/services/write.js +10 -3
- package/server/dist/features/search/embedding-api-key-store.js +57 -0
- package/server/dist/features/search/embedding-client.js +179 -0
- package/server/dist/features/search/graphql/index.js +6 -0
- package/server/dist/features/search/graphql/resolver.js +32 -0
- package/server/dist/features/search/graphql/type-defs.js +37 -0
- package/server/dist/features/search/http/handlers.js +108 -0
- package/server/dist/features/search/hybrid-ranking.js +57 -0
- package/server/dist/features/search/hybrid-search.js +176 -0
- package/server/dist/features/search/note-change.js +16 -0
- package/server/dist/features/search/note-chunking.js +75 -0
- package/server/dist/features/search/related-notes.js +186 -0
- package/server/dist/features/search/search-config.js +150 -0
- package/server/dist/features/search/search-manager.js +431 -0
- package/server/dist/features/search/semantic-indexer.js +138 -0
- package/server/dist/features/search/sqlite-vector-index.js +636 -0
- package/server/dist/features/search/url-normalization.js +10 -0
- package/server/dist/features/tag/services/organization.js +3 -0
- package/server/dist/features/view/services/workspace.js +1 -1
- package/server/dist/main.js +12 -3
- package/server/dist/modules/blocknote.js +4 -5
- package/server/dist/paths.js +7 -2
- package/server/dist/routes/api.js +37 -0
- package/server/dist/routes/mcp.js +0 -5
- package/server/dist/schema/index.js +3 -0
- package/server/prisma/migrations/20260728090000_0019_note_reference_index/migration.sql +15 -0
- package/server/prisma/schema.prisma +16 -0
- package/server/client/dist/assets/Calendar-BP6HTuSn.js +0 -25
- package/server/client/dist/assets/Graph-Xha3fwhp.js +0 -46
- package/server/client/dist/assets/Image-BLEjLUqd.js +0 -1
- package/server/client/dist/assets/Note-DjrCYtat.js +0 -24
- package/server/client/dist/assets/NotePropertiesPanel-2DgXEM4B.js +0 -2
- package/server/client/dist/assets/Reminders-B4l3KdlK.js +0 -1
- package/server/client/dist/assets/Search-BN5sf7bE.js +0 -1
- package/server/client/dist/assets/SurfaceCard-BZm73nyS.js +0 -1
- package/server/client/dist/assets/Tag-oSnmViVp.js +0 -1
- package/server/client/dist/assets/TagNotes-BDTCcJcL.js +0 -1
- package/server/client/dist/assets/ViewNotes-CiZtGJNE.js +0 -1
- package/server/client/dist/assets/ViewSectionDialog-Ctl_694Y.js +0 -102
- package/server/client/dist/assets/Views-D-zlatYD.js +0 -1
- package/server/client/dist/assets/app-DmqIOMWF.css +0 -1
- package/server/client/dist/assets/app-cTRcKMGc.js +0 -26
- package/server/client/dist/assets/image.api-CVuuvTBk.js +0 -17
- package/server/client/dist/assets/index-DKJChPr4.js +0 -1
- package/server/client/dist/assets/manage-image-BZjaxp-f.js +0 -1
- package/server/client/dist/assets/manage-image-detail-DPv0FQ2m.js +0 -1
- package/server/client/dist/assets/properties-D447wsWk.js +0 -1
- package/server/client/dist/assets/time-B3pt8vt4.js +0 -9
- package/server/client/dist/assets/trash-8sH7EZgc.js +0 -1
- package/server/client/dist/assets/url-BSnWpmJx.js +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import models from "../../../models.js";
|
|
2
2
|
import { extractTagIdsFromContentJson, markdownToBlocksJson } from "../../../modules/blocknote.js";
|
|
3
|
+
import { replaceNoteReferences } from "./note-reference-index.js";
|
|
3
4
|
import { buildNoteSearchProjection } from "./search.js";
|
|
4
|
-
import { captureNoteBaseline } from "./snapshot.js";
|
|
5
5
|
class InvalidNoteAuthoringInputError extends Error {
|
|
6
6
|
constructor(message) {
|
|
7
7
|
super(message);
|
|
@@ -60,59 +60,28 @@ const createNoteAuthoringService = (deps) => {
|
|
|
60
60
|
...input.layout ? { layout: input.layout } : {}
|
|
61
61
|
});
|
|
62
62
|
return serializeNote(note);
|
|
63
|
-
},
|
|
64
|
-
updateNote: async (input) => {
|
|
65
|
-
if (input.title === void 0 && input.markdown === void 0 && input.layout === void 0) {
|
|
66
|
-
throw new InvalidNoteAuthoringInputError("At least one note field must be provided for update.");
|
|
67
|
-
}
|
|
68
|
-
const existingNote = await deps.findNoteById(input.id);
|
|
69
|
-
if (!existingNote) {
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
|
-
const nextData = {};
|
|
73
|
-
if (input.title !== void 0) {
|
|
74
|
-
const title = input.title.trim();
|
|
75
|
-
if (!title) {
|
|
76
|
-
throw new InvalidNoteAuthoringInputError("A note title is required.");
|
|
77
|
-
}
|
|
78
|
-
nextData.title = await replacePlaceholders(title);
|
|
79
|
-
}
|
|
80
|
-
if (input.markdown !== void 0) {
|
|
81
|
-
const replacedMarkdown = await replacePlaceholders(input.markdown);
|
|
82
|
-
nextData.content = await deps.parseMarkdownToContentJson(replacedMarkdown);
|
|
83
|
-
nextData.tagIds = deps.extractTagIds(nextData.content);
|
|
84
|
-
}
|
|
85
|
-
if (input.layout !== void 0) {
|
|
86
|
-
nextData.layout = input.layout;
|
|
87
|
-
}
|
|
88
|
-
await deps.captureBaseline({
|
|
89
|
-
noteId: input.id,
|
|
90
|
-
...input.editSessionId ? { editSessionId: input.editSessionId } : {},
|
|
91
|
-
...input.snapshotMeta ? { meta: input.snapshotMeta } : {}
|
|
92
|
-
});
|
|
93
|
-
const updatedNote = await deps.updateNote(input.id, nextData);
|
|
94
|
-
return serializeNote(updatedNote);
|
|
95
63
|
}
|
|
96
64
|
};
|
|
97
65
|
};
|
|
98
66
|
const defaultNoteAuthoringService = createNoteAuthoringService({
|
|
99
67
|
createNote: async (input) => {
|
|
100
|
-
return models
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
content: input.content,
|
|
104
|
-
...buildNoteSearchProjection({
|
|
68
|
+
return models.$transaction(async (tx) => {
|
|
69
|
+
const note = await tx.note.create({
|
|
70
|
+
data: {
|
|
105
71
|
title: input.title,
|
|
106
|
-
content: input.content
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
72
|
+
content: input.content,
|
|
73
|
+
...buildNoteSearchProjection({
|
|
74
|
+
title: input.title,
|
|
75
|
+
content: input.content
|
|
76
|
+
}),
|
|
77
|
+
...input.layout ? { layout: input.layout } : {},
|
|
78
|
+
...input.tagIds ? { tags: { connect: input.tagIds.map((id) => ({ id: Number(id) })) } } : {}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
await replaceNoteReferences(tx, note.id, input.content);
|
|
82
|
+
return note;
|
|
111
83
|
});
|
|
112
84
|
},
|
|
113
|
-
findNoteById: async (id) => {
|
|
114
|
-
return models.note.findUnique({ where: { id } });
|
|
115
|
-
},
|
|
116
85
|
findPlaceholders: async (templates) => {
|
|
117
86
|
if (templates.length === 0) {
|
|
118
87
|
return [];
|
|
@@ -126,45 +95,13 @@ const defaultNoteAuthoringService = createNoteAuthoringService({
|
|
|
126
95
|
});
|
|
127
96
|
},
|
|
128
97
|
parseMarkdownToContentJson: markdownToBlocksJson,
|
|
129
|
-
extractTagIds: extractTagIdsFromContentJson
|
|
130
|
-
captureBaseline: captureNoteBaseline,
|
|
131
|
-
updateNote: async (id, input) => {
|
|
132
|
-
const existingNote = await models.note.findUnique({
|
|
133
|
-
where: { id },
|
|
134
|
-
select: {
|
|
135
|
-
title: true,
|
|
136
|
-
content: true
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
if (!existingNote) {
|
|
140
|
-
throw new Error("NOTE_NOT_FOUND");
|
|
141
|
-
}
|
|
142
|
-
const nextTitle = input.title ?? existingNote.title;
|
|
143
|
-
const nextContent = input.content ?? existingNote.content;
|
|
144
|
-
return models.note.update({
|
|
145
|
-
where: { id },
|
|
146
|
-
data: {
|
|
147
|
-
title: input.title,
|
|
148
|
-
content: input.content,
|
|
149
|
-
layout: input.layout,
|
|
150
|
-
...buildNoteSearchProjection({
|
|
151
|
-
title: nextTitle,
|
|
152
|
-
content: nextContent
|
|
153
|
-
}),
|
|
154
|
-
...input.tagIds ? { tags: { set: input.tagIds.map((tagId) => ({ id: Number(tagId) })) } } : {}
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
}
|
|
98
|
+
extractTagIds: extractTagIdsFromContentJson
|
|
158
99
|
});
|
|
159
100
|
const createNoteFromMarkdown = async (input) => {
|
|
160
101
|
return defaultNoteAuthoringService.createNote(input);
|
|
161
102
|
};
|
|
162
|
-
const updateNoteFromMarkdown = async (input) => {
|
|
163
|
-
return defaultNoteAuthoringService.updateNote(input);
|
|
164
|
-
};
|
|
165
103
|
export {
|
|
166
104
|
InvalidNoteAuthoringInputError,
|
|
167
105
|
createNoteAuthoringService,
|
|
168
|
-
createNoteFromMarkdown
|
|
169
|
-
updateNoteFromMarkdown
|
|
106
|
+
createNoteFromMarkdown
|
|
170
107
|
};
|
|
@@ -21,6 +21,66 @@ const getLineRange = (markdown, match) => {
|
|
|
21
21
|
lineEnd
|
|
22
22
|
};
|
|
23
23
|
};
|
|
24
|
+
const MARKDOWN_PATCH_WHITESPACE_PATTERN = /\p{Zs}| |&#(?:x[0-9a-f]+|\d+);/giu;
|
|
25
|
+
const SPACE_SEPARATOR_PATTERN = /^\p{Zs}$/u;
|
|
26
|
+
const normalizePatchWhitespaceToken = (value) => {
|
|
27
|
+
if (!value.startsWith("&")) {
|
|
28
|
+
return " ";
|
|
29
|
+
}
|
|
30
|
+
if (/^ $/i.test(value)) {
|
|
31
|
+
return " ";
|
|
32
|
+
}
|
|
33
|
+
const numericValue = value.slice(2, -1);
|
|
34
|
+
const isHexadecimal = numericValue.toLowerCase().startsWith("x");
|
|
35
|
+
const codePoint = Number.parseInt(isHexadecimal ? numericValue.slice(1) : numericValue, isHexadecimal ? 16 : 10);
|
|
36
|
+
if (!Number.isSafeInteger(codePoint) || codePoint < 0 || codePoint > 1114111) {
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
return SPACE_SEPARATOR_PATTERN.test(String.fromCodePoint(codePoint)) ? " " : value;
|
|
40
|
+
};
|
|
41
|
+
const normalizeMarkdownPatchText = (value) => {
|
|
42
|
+
let text = "";
|
|
43
|
+
const rawStarts = [];
|
|
44
|
+
const rawEnds = [];
|
|
45
|
+
const appendText = (appendValue, rawStart, rawEnd) => {
|
|
46
|
+
text += appendValue;
|
|
47
|
+
for (let index = 0; index < appendValue.length; index += 1) {
|
|
48
|
+
rawStarts.push(rawStart);
|
|
49
|
+
rawEnds.push(rawEnd);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const appendRawRange = (start, end) => {
|
|
53
|
+
for (let index = start; index < end; ) {
|
|
54
|
+
const codePoint = value.codePointAt(index);
|
|
55
|
+
if (codePoint === void 0) {
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
const character = String.fromCodePoint(codePoint);
|
|
59
|
+
appendText(character, index, index + character.length);
|
|
60
|
+
index += character.length;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
let sourceCursor = 0;
|
|
64
|
+
for (const match of value.matchAll(MARKDOWN_PATCH_WHITESPACE_PATTERN)) {
|
|
65
|
+
const start = match.index;
|
|
66
|
+
const token = match[0];
|
|
67
|
+
const end = start + token.length;
|
|
68
|
+
appendRawRange(sourceCursor, start);
|
|
69
|
+
const normalizedToken = normalizePatchWhitespaceToken(token);
|
|
70
|
+
if (normalizedToken === token) {
|
|
71
|
+
appendRawRange(start, end);
|
|
72
|
+
} else {
|
|
73
|
+
appendText(normalizedToken, start, end);
|
|
74
|
+
}
|
|
75
|
+
sourceCursor = end;
|
|
76
|
+
}
|
|
77
|
+
appendRawRange(sourceCursor, value.length);
|
|
78
|
+
return {
|
|
79
|
+
text,
|
|
80
|
+
rawStarts,
|
|
81
|
+
rawEnds
|
|
82
|
+
};
|
|
83
|
+
};
|
|
24
84
|
const buildExcerpt = (markdown, start, end) => {
|
|
25
85
|
const excerpt = markdown.slice(start, end).trim();
|
|
26
86
|
return excerpt.length > 0 ? excerpt : void 0;
|
|
@@ -46,19 +106,27 @@ const toPatchMatch = (markdown, match, totalMatches) => {
|
|
|
46
106
|
};
|
|
47
107
|
const findExactTextMatches = (markdown, text) => {
|
|
48
108
|
const matches = [];
|
|
109
|
+
const normalizedMarkdown = normalizeMarkdownPatchText(markdown);
|
|
110
|
+
const normalizedText = normalizeMarkdownPatchText(text).text;
|
|
49
111
|
let searchStart = 0;
|
|
50
|
-
while (searchStart <=
|
|
51
|
-
const start =
|
|
112
|
+
while (searchStart <= normalizedMarkdown.text.length) {
|
|
113
|
+
const start = normalizedMarkdown.text.indexOf(normalizedText, searchStart);
|
|
52
114
|
if (start === -1) {
|
|
53
115
|
break;
|
|
54
116
|
}
|
|
117
|
+
const end = start + normalizedText.length;
|
|
118
|
+
const rawStart = normalizedMarkdown.rawStarts[start];
|
|
119
|
+
const rawEnd = normalizedMarkdown.rawEnds[end - 1];
|
|
120
|
+
if (rawStart === void 0 || rawEnd === void 0) {
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
55
123
|
matches.push({
|
|
56
124
|
matchIndex: matches.length,
|
|
57
|
-
start,
|
|
58
|
-
end:
|
|
59
|
-
text
|
|
125
|
+
start: rawStart,
|
|
126
|
+
end: rawEnd,
|
|
127
|
+
text: markdown.slice(rawStart, rawEnd)
|
|
60
128
|
});
|
|
61
|
-
searchStart =
|
|
129
|
+
searchStart = end;
|
|
62
130
|
}
|
|
63
131
|
return matches;
|
|
64
132
|
};
|
|
@@ -238,10 +306,14 @@ const createChangePlan = ({
|
|
|
238
306
|
};
|
|
239
307
|
};
|
|
240
308
|
const matchHasAnchors = (markdown, match, selector) => {
|
|
241
|
-
if (selector.before !== void 0 && !markdown.slice(0, match.start).endsWith(
|
|
309
|
+
if (selector.before !== void 0 && !normalizeMarkdownPatchText(markdown.slice(0, match.start)).text.endsWith(
|
|
310
|
+
normalizeMarkdownPatchText(selector.before).text
|
|
311
|
+
)) {
|
|
242
312
|
return false;
|
|
243
313
|
}
|
|
244
|
-
if (selector.after !== void 0 && !markdown.slice(match.end).startsWith(
|
|
314
|
+
if (selector.after !== void 0 && !normalizeMarkdownPatchText(markdown.slice(match.end)).text.startsWith(
|
|
315
|
+
normalizeMarkdownPatchText(selector.after).text
|
|
316
|
+
)) {
|
|
245
317
|
return false;
|
|
246
318
|
}
|
|
247
319
|
return true;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import models from "../../../models.js";
|
|
2
|
+
import { extractReferenceBlocksFromContent, normalizeReferenceId } from "./content-blocks.js";
|
|
3
|
+
const NOTE_REFERENCE_INDEX_VERSION = 1;
|
|
4
|
+
const NOTE_REFERENCE_INDEX_STATE_ID = 1;
|
|
5
|
+
const SQLITE_MAX_INT_ID = 2147483647;
|
|
6
|
+
const REFERENCE_INDEX_REBUILD_BATCH_SIZE = 250;
|
|
7
|
+
const toNoteId = (value) => {
|
|
8
|
+
const normalized = normalizeReferenceId(value);
|
|
9
|
+
if (!normalized || !/^[1-9]\d*$/.test(normalized)) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const id = Number(normalized);
|
|
13
|
+
return Number.isSafeInteger(id) && id <= SQLITE_MAX_INT_ID ? id : null;
|
|
14
|
+
};
|
|
15
|
+
const extractNoteReferenceIds = (content) => {
|
|
16
|
+
return Array.from(
|
|
17
|
+
new Set(
|
|
18
|
+
extractReferenceBlocksFromContent(content).map((block) => toNoteId(block.props?.id)).filter((id) => id !== null)
|
|
19
|
+
)
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
const replaceNoteReferences = async (db, sourceNoteId, content) => {
|
|
23
|
+
const targetIds = extractNoteReferenceIds(content).filter((targetNoteId) => targetNoteId !== sourceNoteId);
|
|
24
|
+
await db.noteReference.deleteMany({ where: { sourceNoteId } });
|
|
25
|
+
if (targetIds.length === 0) {
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
const references = targetIds.map((targetNoteId) => ({ sourceNoteId, targetNoteId }));
|
|
29
|
+
if (references.length > 0) {
|
|
30
|
+
await db.noteReference.createMany({ data: references });
|
|
31
|
+
}
|
|
32
|
+
return references.length;
|
|
33
|
+
};
|
|
34
|
+
const rebuildNoteReferenceIndex = async () => {
|
|
35
|
+
await models.noteReference.deleteMany();
|
|
36
|
+
let cursor = 0;
|
|
37
|
+
let processedCount = 0;
|
|
38
|
+
while (true) {
|
|
39
|
+
const notes = await models.note.findMany({
|
|
40
|
+
where: { id: { gt: cursor } },
|
|
41
|
+
orderBy: { id: "asc" },
|
|
42
|
+
take: REFERENCE_INDEX_REBUILD_BATCH_SIZE,
|
|
43
|
+
select: {
|
|
44
|
+
id: true,
|
|
45
|
+
content: true
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
if (notes.length === 0) {
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
const references = notes.flatMap(
|
|
52
|
+
(note) => extractNoteReferenceIds(note.content).filter((targetNoteId) => targetNoteId !== note.id).map((targetNoteId) => ({
|
|
53
|
+
sourceNoteId: note.id,
|
|
54
|
+
targetNoteId
|
|
55
|
+
}))
|
|
56
|
+
);
|
|
57
|
+
if (references.length > 0) {
|
|
58
|
+
await models.noteReference.createMany({ data: references });
|
|
59
|
+
processedCount += references.length;
|
|
60
|
+
}
|
|
61
|
+
cursor = notes[notes.length - 1].id;
|
|
62
|
+
}
|
|
63
|
+
await models.noteReferenceIndexState.upsert({
|
|
64
|
+
where: { id: NOTE_REFERENCE_INDEX_STATE_ID },
|
|
65
|
+
create: {
|
|
66
|
+
id: NOTE_REFERENCE_INDEX_STATE_ID,
|
|
67
|
+
version: NOTE_REFERENCE_INDEX_VERSION,
|
|
68
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
69
|
+
},
|
|
70
|
+
update: {
|
|
71
|
+
version: NOTE_REFERENCE_INDEX_VERSION
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return processedCount;
|
|
75
|
+
};
|
|
76
|
+
let activeRebuild = null;
|
|
77
|
+
const ensureNoteReferenceIndex = async () => {
|
|
78
|
+
const state = await models.noteReferenceIndexState.findUnique({
|
|
79
|
+
where: { id: NOTE_REFERENCE_INDEX_STATE_ID },
|
|
80
|
+
select: { version: true }
|
|
81
|
+
});
|
|
82
|
+
if (state?.version === NOTE_REFERENCE_INDEX_VERSION) {
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
if (!activeRebuild) {
|
|
86
|
+
activeRebuild = rebuildNoteReferenceIndex().finally(() => {
|
|
87
|
+
activeRebuild = null;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return activeRebuild;
|
|
91
|
+
};
|
|
92
|
+
export {
|
|
93
|
+
NOTE_REFERENCE_INDEX_STATE_ID,
|
|
94
|
+
NOTE_REFERENCE_INDEX_VERSION,
|
|
95
|
+
ensureNoteReferenceIndex,
|
|
96
|
+
extractNoteReferenceIds,
|
|
97
|
+
replaceNoteReferences
|
|
98
|
+
};
|
|
@@ -329,6 +329,13 @@ const findReferencedRemovedPropertyOptionValue = ({
|
|
|
329
329
|
}
|
|
330
330
|
return null;
|
|
331
331
|
};
|
|
332
|
+
const viewQueryReferencesProperty = ({ query, key }) => {
|
|
333
|
+
const parsed = parseViewQueryRecord(query);
|
|
334
|
+
if (!parsed || !Array.isArray(parsed.propertyFilters)) {
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
return parsed.propertyFilters.some((filter) => isRecord(filter) && getNormalizedViewFilterKey(filter) === key);
|
|
338
|
+
};
|
|
332
339
|
const buildTypedValueData = async (input, definitionId, tx = models) => {
|
|
333
340
|
const resetValues = {
|
|
334
341
|
textValue: null,
|
|
@@ -695,6 +702,18 @@ const deleteNotePropertyDefinition = async ({
|
|
|
695
702
|
if (!definition) {
|
|
696
703
|
return null;
|
|
697
704
|
}
|
|
705
|
+
const referencingViewSections = await tx.viewSection.findMany({
|
|
706
|
+
where: { query: { contains: definition.key } },
|
|
707
|
+
select: { title: true, query: true }
|
|
708
|
+
});
|
|
709
|
+
const referencingView = referencingViewSections.find(
|
|
710
|
+
(section) => viewQueryReferencesProperty({ query: section.query, key: definition.key })
|
|
711
|
+
);
|
|
712
|
+
if (referencingView) {
|
|
713
|
+
throw new InvalidNotePropertyInputError(
|
|
714
|
+
`Property ${definition.key} is used by view ${referencingView.title} and cannot be deleted.`
|
|
715
|
+
);
|
|
716
|
+
}
|
|
698
717
|
const affectedNoteCount = definition._count.properties;
|
|
699
718
|
if (affectedNoteCount > 0 && !confirmImpact) {
|
|
700
719
|
throw new NotePropertyDeleteConfirmationRequiredError(normalizedKey, affectedNoteCount);
|
|
@@ -869,5 +888,6 @@ export {
|
|
|
869
888
|
updateNotePropertiesWithVersionGuard,
|
|
870
889
|
updateNotePropertiesWithVersionGuardAndSnapshot,
|
|
871
890
|
updateNotePropertyDefinition,
|
|
872
|
-
validateNotePropertiesPatchValues
|
|
891
|
+
validateNotePropertiesPatchValues,
|
|
892
|
+
viewQueryReferencesProperty
|
|
873
893
|
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const resolveRestoredPropertyTarget = async (property, deps) => {
|
|
2
|
+
const definition = await deps.findDefinitionByKey(property.key);
|
|
3
|
+
if (!definition || definition.valueType !== property.valueType) {
|
|
4
|
+
return null;
|
|
5
|
+
}
|
|
6
|
+
if (property.valueType !== "select") {
|
|
7
|
+
return {
|
|
8
|
+
propertyDefinitionId: definition.id,
|
|
9
|
+
optionId: null
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
if (!property.optionValue) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const option = await deps.findOptionByValue(definition.id, property.optionValue);
|
|
16
|
+
if (!option) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
propertyDefinitionId: definition.id,
|
|
21
|
+
optionId: option.id
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export {
|
|
25
|
+
resolveRestoredPropertyTarget
|
|
26
|
+
};
|
|
@@ -140,6 +140,10 @@ const extractVisibleSearchTextFromContent = (content) => {
|
|
|
140
140
|
return "";
|
|
141
141
|
}
|
|
142
142
|
};
|
|
143
|
+
const NOTE_CONTENT_PREVIEW_MAX_LENGTH = 100;
|
|
144
|
+
const buildNoteContentPreview = (content) => {
|
|
145
|
+
return extractVisibleSearchTextFromContent(content).slice(0, NOTE_CONTENT_PREVIEW_MAX_LENGTH);
|
|
146
|
+
};
|
|
143
147
|
const matchesNoteSearchQuery = (note, query) => {
|
|
144
148
|
const parsedQuery = typeof query === "string" ? parseNoteSearchQuery(query) : query;
|
|
145
149
|
if (!parsedQuery.hasFilters) {
|
|
@@ -166,6 +170,7 @@ export {
|
|
|
166
170
|
NOTE_SEARCH_IGNORED_NODE_TYPES,
|
|
167
171
|
NOTE_SEARCH_PASS_THROUGH_NODE_TYPES,
|
|
168
172
|
NOTE_SEARCH_TEXT_SCHEMA_VERSION,
|
|
173
|
+
buildNoteContentPreview,
|
|
169
174
|
buildNoteSearchProjection,
|
|
170
175
|
buildNoteSearchText,
|
|
171
176
|
extractVisibleSearchTextFromContent,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FILE_HEADERS_ONLY, formatPatch, structuredPatch } from "diff";
|
|
2
2
|
import { ensureTagByName } from "../../../features/tag/services/organization.js";
|
|
3
|
-
import models from "../../../models.js";
|
|
3
|
+
import models, { Prisma } from "../../../models.js";
|
|
4
4
|
import { blocksToMarkdown, extractTagIdsFromContentJson } from "../../../modules/blocknote.js";
|
|
5
5
|
import { parseBlockNoteContent, walkBlockNoteTree } from "../../../modules/blocknote-tree.js";
|
|
6
6
|
import {
|
|
@@ -10,7 +10,10 @@ import {
|
|
|
10
10
|
SNAPSHOT_RETENTION_DAYS
|
|
11
11
|
} from "../../../modules/recovery-retention.js";
|
|
12
12
|
import { calculateMarkdownSha256 } from "./markdown-patch.js";
|
|
13
|
+
import { replaceNoteReferences } from "./note-reference-index.js";
|
|
14
|
+
import { resolveRestoredPropertyTarget } from "./property-restore.js";
|
|
13
15
|
import { buildNoteSearchProjection, extractVisibleSearchTextFromContent } from "./search.js";
|
|
16
|
+
import { createNoteVersionConflictError, MissingNoteVersionError, parseNoteVersion } from "./write-conflict.js";
|
|
14
17
|
const SNAPSHOT_CONTENT_PREVIEW_MAX_LENGTH = 240;
|
|
15
18
|
const parseMeta = (value) => {
|
|
16
19
|
if (!value) {
|
|
@@ -384,6 +387,19 @@ const createNoteSnapshotService = (deps) => ({
|
|
|
384
387
|
if (!note) {
|
|
385
388
|
return null;
|
|
386
389
|
}
|
|
390
|
+
if (!note.updatedAt) {
|
|
391
|
+
throw new Error("Note update time is required to restore a snapshot.");
|
|
392
|
+
}
|
|
393
|
+
const expectedTimestamp = parseNoteVersion(options.expectedUpdatedAt);
|
|
394
|
+
if (expectedTimestamp === null) {
|
|
395
|
+
throw new MissingNoteVersionError();
|
|
396
|
+
}
|
|
397
|
+
if (note.updatedAt.getTime() !== expectedTimestamp) {
|
|
398
|
+
throw createNoteVersionConflictError({
|
|
399
|
+
expectedUpdatedAt: expectedTimestamp,
|
|
400
|
+
currentUpdatedAt: note.updatedAt.getTime()
|
|
401
|
+
});
|
|
402
|
+
}
|
|
387
403
|
const payload = parsePayload(snapshot.payload);
|
|
388
404
|
const resolvedTags = deps.resolveRestoredTags ? await deps.resolveRestoredTags(payload.content) : extractRestoredTagIds(payload.content);
|
|
389
405
|
const restoredPayload = resolvedTags && !Array.isArray(resolvedTags) ? {
|
|
@@ -403,7 +419,8 @@ const createNoteSnapshotService = (deps) => ({
|
|
|
403
419
|
}
|
|
404
420
|
const restoredNote = await deps.updateNote(snapshot.noteId, {
|
|
405
421
|
...restoredPayload,
|
|
406
|
-
...restoredTagIds !== void 0 ? { tagIds: restoredTagIds } : {}
|
|
422
|
+
...restoredTagIds !== void 0 ? { tagIds: restoredTagIds } : {},
|
|
423
|
+
expectedUpdatedAt: options.expectedUpdatedAt
|
|
407
424
|
});
|
|
408
425
|
await deps.trimOverflowSnapshots(note.id, SNAPSHOT_MAX_PER_NOTE, RECOVERY_CLEANUP_BATCH_LIMIT);
|
|
409
426
|
return restoredNote;
|
|
@@ -527,68 +544,75 @@ const defaultNoteSnapshotService = createNoteSnapshotService({
|
|
|
527
544
|
});
|
|
528
545
|
},
|
|
529
546
|
updateNote: async (id, input) => {
|
|
530
|
-
const { tagIds, properties, ...noteInput } = input;
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
547
|
+
const { tagIds, properties, expectedUpdatedAt, ...noteInput } = input;
|
|
548
|
+
const expectedTimestamp = parseNoteVersion(expectedUpdatedAt);
|
|
549
|
+
if (expectedTimestamp === null) {
|
|
550
|
+
throw new MissingNoteVersionError();
|
|
551
|
+
}
|
|
552
|
+
try {
|
|
553
|
+
return await models.$transaction(async (tx) => {
|
|
554
|
+
const note = await tx.note.update({
|
|
555
|
+
where: { id, updatedAt: new Date(expectedTimestamp) },
|
|
556
|
+
data: {
|
|
557
|
+
...noteInput,
|
|
558
|
+
...buildNoteSearchProjection({
|
|
559
|
+
title: noteInput.title,
|
|
560
|
+
content: noteInput.content
|
|
561
|
+
}),
|
|
562
|
+
...tagIds !== void 0 ? { tags: { set: tagIds.map((tagId) => ({ id: tagId })) } } : {}
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
if (noteInput.content !== void 0) {
|
|
566
|
+
await replaceNoteReferences(tx, note.id, noteInput.content);
|
|
541
567
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
568
|
+
if (properties !== void 0) {
|
|
569
|
+
await tx.noteProperty.deleteMany({ where: { noteId: id } });
|
|
570
|
+
for (const property of properties) {
|
|
571
|
+
const target = await resolveRestoredPropertyTarget(property, {
|
|
572
|
+
findDefinitionByKey: (key) => tx.propertyDefinition.findUnique({ where: { key } }),
|
|
573
|
+
findOptionByValue: (propertyDefinitionId, value) => tx.propertyOption.findUnique({
|
|
574
|
+
where: {
|
|
575
|
+
propertyDefinitionId_value: {
|
|
576
|
+
propertyDefinitionId,
|
|
577
|
+
value
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
})
|
|
581
|
+
});
|
|
582
|
+
if (!target) {
|
|
583
|
+
continue;
|
|
556
584
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
585
|
+
await tx.noteProperty.create({
|
|
586
|
+
data: {
|
|
587
|
+
noteId: id,
|
|
588
|
+
propertyDefinitionId: target.propertyDefinitionId,
|
|
589
|
+
optionId: target.optionId,
|
|
590
|
+
textValue: property.textValue ?? null,
|
|
591
|
+
textValueNormalized: property.textValueNormalized ?? null,
|
|
592
|
+
numberValue: property.numberValue ?? null,
|
|
593
|
+
dateValue: property.dateValue ? new Date(property.dateValue) : null,
|
|
594
|
+
boolValue: property.boolValue ?? null
|
|
563
595
|
}
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
propertyDefinitionId: definition.id,
|
|
580
|
-
optionId: option?.id ?? null,
|
|
581
|
-
textValue: property.textValue ?? null,
|
|
582
|
-
textValueNormalized: property.textValueNormalized ?? null,
|
|
583
|
-
numberValue: property.numberValue ?? null,
|
|
584
|
-
dateValue: property.dateValue ? new Date(property.dateValue) : null,
|
|
585
|
-
boolValue: property.boolValue ?? null
|
|
586
|
-
}
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
return note;
|
|
600
|
+
});
|
|
601
|
+
} catch (error) {
|
|
602
|
+
if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2025") {
|
|
603
|
+
const currentNote = await models.note.findUnique({
|
|
604
|
+
where: { id },
|
|
605
|
+
select: { updatedAt: true }
|
|
606
|
+
});
|
|
607
|
+
if (currentNote && currentNote.updatedAt.getTime() !== expectedTimestamp) {
|
|
608
|
+
throw createNoteVersionConflictError({
|
|
609
|
+
expectedUpdatedAt: expectedTimestamp,
|
|
610
|
+
currentUpdatedAt: currentNote.updatedAt.getTime()
|
|
587
611
|
});
|
|
588
612
|
}
|
|
589
613
|
}
|
|
590
|
-
|
|
591
|
-
}
|
|
614
|
+
throw error;
|
|
615
|
+
}
|
|
592
616
|
}
|
|
593
617
|
});
|
|
594
618
|
const captureNoteBaseline = async (input) => {
|