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.
Files changed (244) hide show
  1. package/README.md +2 -0
  2. package/dist/mcp.js +103 -105
  3. package/package.json +3 -2
  4. package/server/client/dist/assets/{ArrowRight.es-g2YZTklZ.js → ArrowRight.es-BEhnlwfe.js} +1 -1
  5. package/server/client/dist/assets/AuxiliaryPanelHeader-B1k7pZpn.js +1 -0
  6. package/server/client/dist/assets/Calendar-D7QJsAlg.js +25 -0
  7. package/server/client/dist/assets/{Callout-B_IPSF_5.js → Callout-BTd1BYtV.js} +1 -1
  8. package/server/client/dist/assets/{Copy.es-CNxe4ujr.js → Copy.es-BoLjilxv.js} +1 -1
  9. package/server/client/dist/assets/File.es-Ct7fscBg.js +1 -0
  10. package/server/client/dist/assets/Graph-DYUb7gQb.js +46 -0
  11. package/server/client/dist/assets/{Graph-D9GeO71k.js → Graph-LY_IgMYy.js} +1 -1
  12. package/server/client/dist/assets/{Image.es-DnON8cv2.js → Image.es-OYyN3BYt.js} +1 -1
  13. package/server/client/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  14. package/server/client/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  15. package/server/client/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  16. package/server/client/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  17. package/server/client/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  18. package/server/client/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  19. package/server/client/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  20. package/server/client/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  21. package/server/client/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  22. package/server/client/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  23. package/server/client/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  24. package/server/client/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  25. package/server/client/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  26. package/server/client/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  27. package/server/client/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  28. package/server/client/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  29. package/server/client/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  30. package/server/client/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  31. package/server/client/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  32. package/server/client/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  33. package/server/client/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  34. package/server/client/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  35. package/server/client/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  36. package/server/client/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  37. package/server/client/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  38. package/server/client/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  39. package/server/client/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  40. package/server/client/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  41. package/server/client/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  42. package/server/client/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  43. package/server/client/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  44. package/server/client/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  45. package/server/client/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  46. package/server/client/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  47. package/server/client/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  48. package/server/client/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  49. package/server/client/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  50. package/server/client/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  51. package/server/client/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  52. package/server/client/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  53. package/server/client/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  54. package/server/client/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  55. package/server/client/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  56. package/server/client/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  57. package/server/client/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  58. package/server/client/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  59. package/server/client/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  60. package/server/client/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  61. package/server/client/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  62. package/server/client/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  63. package/server/client/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  64. package/server/client/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  65. package/server/client/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  66. package/server/client/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  67. package/server/client/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  68. package/server/client/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  69. package/server/client/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  70. package/server/client/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  71. package/server/client/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  72. package/server/client/dist/assets/Note-DsMhwrHw.js +25 -0
  73. package/server/client/dist/assets/NotePropertiesPanel-aCKXAe5F.js +2 -0
  74. package/server/client/dist/assets/PencilLine.es-0JpEgxFY.js +1 -0
  75. package/server/client/dist/assets/{Plus.es-CQ8wn2is.js → Plus.es-DRfLW_bI.js} +1 -1
  76. package/server/client/dist/assets/Reminders-COr1OHvF.js +1 -0
  77. package/server/client/dist/assets/Search-Ctkx0BQk.js +31 -0
  78. package/server/client/dist/assets/SurfaceCard-t7pdfhEe.js +1 -0
  79. package/server/client/dist/assets/Tag-BjxtrIQW.js +1 -0
  80. package/server/client/dist/assets/TagNotes-DV_fdRbg.js +1 -0
  81. package/server/client/dist/assets/{Trash.es-0aPpA-3S.js → Trash.es-Bo1VyK9Q.js} +1 -1
  82. package/server/client/dist/assets/ViewChip-DlCkL4z4.js +1 -0
  83. package/server/client/dist/assets/ViewNotes-wWWeFJyU.js +1 -0
  84. package/server/client/dist/assets/ViewSectionDialog-DhH8harC.js +102 -0
  85. package/server/client/dist/assets/Views-CWE99SnI.js +1 -0
  86. package/server/client/dist/assets/abnfDiagram-VRR7QNED-CWlV5dXw.js +1 -0
  87. package/server/client/dist/assets/app-B9WZRrAH.css +1 -0
  88. package/server/client/dist/assets/app-BpSMjzET.js +26 -0
  89. package/server/client/dist/assets/arc-BV-n6RUX.js +1 -0
  90. package/server/client/dist/assets/architectureDiagram-ZJ3FMSHR-CekzMXdu.js +36 -0
  91. package/server/client/dist/assets/blockDiagram-677ZJIJ3-B49yHoxq.js +132 -0
  92. package/server/client/dist/assets/c4Diagram-LMCZKHZV-0AfB9NBC.js +10 -0
  93. package/server/client/dist/assets/channel-CigOulR-.js +1 -0
  94. package/server/client/dist/assets/chunk-2Q5K7J3B-DaPQAU1q.js +1 -0
  95. package/server/client/dist/assets/chunk-32BRIVSS-CfL3kZAg.js +1 -0
  96. package/server/client/dist/assets/chunk-5VM5RSS4-DeOwWPE_.js +15 -0
  97. package/server/client/dist/assets/chunk-EX3LRPZG-C3W1oc9y.js +231 -0
  98. package/server/client/dist/assets/chunk-JWPE2WC7-_Oqh79OY.js +1 -0
  99. package/server/client/dist/assets/chunk-MOJQB5TN-DDKNNzI6.js +88 -0
  100. package/server/client/dist/assets/chunk-RYQCIY6F-DCHah7CC.js +1 -0
  101. package/server/client/dist/assets/chunk-V7JOEXUC-uUOIzgxj.js +206 -0
  102. package/server/client/dist/assets/chunk-VR4S4FIN-DDVw2WPs.js +1 -0
  103. package/server/client/dist/assets/chunk-XXDRQBXY-Coo4UFm2.js +1 -0
  104. package/server/client/dist/assets/classDiagram-OUVF2IWQ-D13ISIOW.js +1 -0
  105. package/server/client/dist/assets/classDiagram-v2-EOCWNBFH-D13ISIOW.js +1 -0
  106. package/server/client/dist/assets/colors-Cc3OSVma.js +1 -0
  107. package/server/client/dist/assets/cose-bilkent-JH36ORCC-C3pHmHpD.js +1 -0
  108. package/server/client/dist/assets/cynefin-VYW2F7L2-DU_G4Atc.js +166 -0
  109. package/server/client/dist/assets/cynefinDiagram-TSTJHNR4-DZ6iiJFo.js +62 -0
  110. package/server/client/dist/assets/cytoscape.esm-D3_iZ_3b.js +321 -0
  111. package/server/client/dist/assets/dagre-VKFMJZFB-DNELbhwC.js +4 -0
  112. package/server/client/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  113. package/server/client/dist/assets/diagram-FQU43EPY-CMEvZJ61.js +3 -0
  114. package/server/client/dist/assets/diagram-G47NLZAW-BYDtf6j9.js +24 -0
  115. package/server/client/dist/assets/diagram-NH7WQ7WH-CmXfcCQA.js +24 -0
  116. package/server/client/dist/assets/diagram-OA4YK3LP-BflTKJxU.js +30 -0
  117. package/server/client/dist/assets/diagram-WEI45ONY-KW3fKqna.js +41 -0
  118. package/server/client/dist/assets/ebnfDiagram-CCIWWBDH-CbyhY5Nj.js +1 -0
  119. package/server/client/dist/assets/erDiagram-Q63AITRT-CC2eZV8g.js +85 -0
  120. package/server/client/dist/assets/{floating-ui.react-dom-wWLZ1CdM.js → floating-ui.react-dom-BWTnA00G.js} +1 -1
  121. package/server/client/dist/assets/flowDiagram-23GEKE2U-unplo7Qm.js +156 -0
  122. package/server/client/dist/assets/ganttDiagram-NO4QXBWP-BcBK5HcZ.js +292 -0
  123. package/server/client/dist/assets/gitGraphDiagram-IHSO6WYX-DgVbbb5k.js +106 -0
  124. package/server/client/dist/assets/graph-C5DFNLrC.js +1 -0
  125. package/server/client/dist/assets/image-delete-confirmation-D7xrODQV.js +1 -0
  126. package/server/client/dist/assets/image.api-CyQisInP.js +17 -0
  127. package/server/client/dist/assets/index-B-E1Ilh9.js +1 -0
  128. package/server/client/dist/assets/infoDiagram-FWYZ7A6U-N_D9RdfG.js +2 -0
  129. package/server/client/dist/assets/init-Gi6I4Gst.js +1 -0
  130. package/server/client/dist/assets/isObject-U9U2HXiq.js +1 -0
  131. package/server/client/dist/assets/ishikawaDiagram-FXEZZL3T-BBKrzmB2.js +70 -0
  132. package/server/client/dist/assets/journeyDiagram-5HDEW3XC-NdCxLmQB.js +139 -0
  133. package/server/client/dist/assets/kanban-definition-HUTT4EX6-Ck7t4-tt.js +89 -0
  134. package/server/client/dist/assets/katex-DywYRkvg.css +1 -0
  135. package/server/client/dist/assets/katex-HP8lGamR.js +257 -0
  136. package/server/client/dist/assets/katex-x288kqHd.js +257 -0
  137. package/server/client/dist/assets/layout-Cz0MDlGi.js +1 -0
  138. package/server/client/dist/assets/linear-D6yRgDLq.js +1 -0
  139. package/server/client/dist/assets/manage-image-azmo5iVw.js +1 -0
  140. package/server/client/dist/assets/manage-image-detail-BF-uSqb_.js +1 -0
  141. package/server/client/dist/assets/map-Mm1V-_Na.js +1 -0
  142. package/server/client/dist/assets/{mcp-CT_9IV2c.js → mcp-CCaFd0zm.js} +4 -4
  143. package/server/client/dist/assets/{mcp-admin-adapter-xAuyZc_M.js → mcp-admin-adapter-PMmgPupc.js} +1 -1
  144. package/server/client/dist/assets/mermaid.core-B14ZAmWA.js +308 -0
  145. package/server/client/dist/assets/min-tv6RD-6E.js +1 -0
  146. package/server/client/dist/assets/mindmap-definition-LN4V7U3C-BTUqSdcP.js +96 -0
  147. package/server/client/dist/assets/{note-core-Buwzyxi7.js → note-core-DUTqUh5N.js} +2 -2
  148. package/server/client/dist/assets/{note-runtime-CPDVOFEo.js → note-runtime-zN5ddTba.js} +1 -1
  149. package/server/client/dist/assets/{note-ui-CHI-tzj-.js → note-ui-CtijppHK.js} +1 -1
  150. package/server/client/dist/assets/{note.api-D_00ZzJC.js → note.api-D3oJmG3q.js} +6 -6
  151. package/server/client/dist/assets/ordinal-Cboi1Yqb.js +1 -0
  152. package/server/client/dist/assets/pegDiagram-2B236MQR-Cjcu3mVz.js +1 -0
  153. package/server/client/dist/assets/pieDiagram-ENE6RG2P-BxI_c22Z.js +39 -0
  154. package/server/client/dist/assets/{placeholder-DbdGiYGL.js → placeholder-AusSo8p9.js} +4 -4
  155. package/server/client/dist/assets/properties-BrNJLkxR.js +1 -0
  156. package/server/client/dist/assets/quadrantDiagram-ABIIQ3AL-DGm0a-yR.js +7 -0
  157. package/server/client/dist/assets/railroadDiagram-RFXS5EU6-DmCDu89O.js +1 -0
  158. package/server/client/dist/assets/requirementDiagram-TGXJPOKE-CBpUt7Ig.js +84 -0
  159. package/server/client/dist/assets/route-preload.js +2 -2
  160. package/server/client/dist/assets/sankeyDiagram-HTMAVEWB-BjGnDZlp.js +40 -0
  161. package/server/client/dist/assets/search-D-xKTPdO.js +1 -0
  162. package/server/client/dist/assets/search-admin-adapter-CJnJmL6w.js +1 -0
  163. package/server/client/dist/assets/sequenceDiagram-DBY2YBRQ-B7rpCfS6.js +162 -0
  164. package/server/client/dist/assets/sizeCapture-X5ZJPWSS-CUJhD0uW.js +1 -0
  165. package/server/client/dist/assets/stateDiagram-2N3HPSRC-Y9-3XqRX.js +1 -0
  166. package/server/client/dist/assets/stateDiagram-v2-6OUMAXLB-DbHXhT02.js +1 -0
  167. package/server/client/dist/assets/swimlanes-5IMT3BWC-Cs1NO9ng.js +2 -0
  168. package/server/client/dist/assets/swimlanesDiagram-G3AALYLV-DQnrq2ZC.js +8 -0
  169. package/server/client/dist/assets/{tag.api-CX0SE06J.js → tag.api-DNSQpqwk.js} +3 -3
  170. package/server/client/dist/assets/time-D5LRMumI.js +9 -0
  171. package/server/client/dist/assets/timeline-definition-FHXFAJF6-8fqD4WNL.js +120 -0
  172. package/server/client/dist/assets/toNumber-DE3J3kMD.js +1 -0
  173. package/server/client/dist/assets/transform-BUB79_za.js +1 -0
  174. package/server/client/dist/assets/trash-D4-9sv8q.js +1 -0
  175. package/server/client/dist/assets/url-9nrbQs7Z.js +1 -0
  176. package/server/client/dist/assets/{useReminderMutate-CLK1tHvT.js → useReminderMutate-BrGO9M0o.js} +4 -4
  177. package/server/client/dist/assets/vennDiagram-L72KCM5P-BPqKkd5a.js +34 -0
  178. package/server/client/dist/assets/wardleyDiagram-EHGQE667-Cq11kU2M.js +78 -0
  179. package/server/client/dist/assets/xychartDiagram-FW5EYKEG-DJ6UzFj-.js +7 -0
  180. package/server/client/dist/index.html +7 -7
  181. package/server/dist/features/image/services/delete.js +25 -1
  182. package/server/dist/features/note/graphql/note.field.resolver.js +2 -0
  183. package/server/dist/features/note/graphql/note.mutation.resolver.js +54 -23
  184. package/server/dist/features/note/graphql/note.query.resolver.js +15 -5
  185. package/server/dist/features/note/graphql/note.type-defs.js +2 -1
  186. package/server/dist/features/note/http/mcp.js +1 -60
  187. package/server/dist/features/note/services/authoring.js +17 -80
  188. package/server/dist/features/note/services/markdown-patch.js +80 -8
  189. package/server/dist/features/note/services/note-reference-index.js +98 -0
  190. package/server/dist/features/note/services/properties.js +21 -1
  191. package/server/dist/features/note/services/property-restore.js +26 -0
  192. package/server/dist/features/note/services/search.js +5 -0
  193. package/server/dist/features/note/services/snapshot.js +82 -58
  194. package/server/dist/features/note/services/trash.js +18 -31
  195. package/server/dist/features/note/services/write.js +10 -3
  196. package/server/dist/features/search/embedding-api-key-store.js +57 -0
  197. package/server/dist/features/search/embedding-client.js +179 -0
  198. package/server/dist/features/search/graphql/index.js +6 -0
  199. package/server/dist/features/search/graphql/resolver.js +32 -0
  200. package/server/dist/features/search/graphql/type-defs.js +37 -0
  201. package/server/dist/features/search/http/handlers.js +108 -0
  202. package/server/dist/features/search/hybrid-ranking.js +57 -0
  203. package/server/dist/features/search/hybrid-search.js +176 -0
  204. package/server/dist/features/search/note-change.js +16 -0
  205. package/server/dist/features/search/note-chunking.js +75 -0
  206. package/server/dist/features/search/related-notes.js +186 -0
  207. package/server/dist/features/search/search-config.js +150 -0
  208. package/server/dist/features/search/search-manager.js +431 -0
  209. package/server/dist/features/search/semantic-indexer.js +138 -0
  210. package/server/dist/features/search/sqlite-vector-index.js +636 -0
  211. package/server/dist/features/search/url-normalization.js +10 -0
  212. package/server/dist/features/tag/services/organization.js +3 -0
  213. package/server/dist/features/view/services/workspace.js +1 -1
  214. package/server/dist/main.js +12 -3
  215. package/server/dist/modules/blocknote.js +4 -5
  216. package/server/dist/paths.js +7 -2
  217. package/server/dist/routes/api.js +37 -0
  218. package/server/dist/routes/mcp.js +0 -5
  219. package/server/dist/schema/index.js +3 -0
  220. package/server/prisma/migrations/20260728090000_0019_note_reference_index/migration.sql +15 -0
  221. package/server/prisma/schema.prisma +16 -0
  222. package/server/client/dist/assets/Calendar-BP6HTuSn.js +0 -25
  223. package/server/client/dist/assets/Graph-Xha3fwhp.js +0 -46
  224. package/server/client/dist/assets/Image-BLEjLUqd.js +0 -1
  225. package/server/client/dist/assets/Note-DjrCYtat.js +0 -24
  226. package/server/client/dist/assets/NotePropertiesPanel-2DgXEM4B.js +0 -2
  227. package/server/client/dist/assets/Reminders-B4l3KdlK.js +0 -1
  228. package/server/client/dist/assets/Search-BN5sf7bE.js +0 -1
  229. package/server/client/dist/assets/SurfaceCard-BZm73nyS.js +0 -1
  230. package/server/client/dist/assets/Tag-oSnmViVp.js +0 -1
  231. package/server/client/dist/assets/TagNotes-BDTCcJcL.js +0 -1
  232. package/server/client/dist/assets/ViewNotes-CiZtGJNE.js +0 -1
  233. package/server/client/dist/assets/ViewSectionDialog-Ctl_694Y.js +0 -102
  234. package/server/client/dist/assets/Views-D-zlatYD.js +0 -1
  235. package/server/client/dist/assets/app-DmqIOMWF.css +0 -1
  236. package/server/client/dist/assets/app-cTRcKMGc.js +0 -26
  237. package/server/client/dist/assets/image.api-CVuuvTBk.js +0 -17
  238. package/server/client/dist/assets/index-DKJChPr4.js +0 -1
  239. package/server/client/dist/assets/manage-image-BZjaxp-f.js +0 -1
  240. package/server/client/dist/assets/manage-image-detail-DPv0FQ2m.js +0 -1
  241. package/server/client/dist/assets/properties-D447wsWk.js +0 -1
  242. package/server/client/dist/assets/time-B3pt8vt4.js +0 -9
  243. package/server/client/dist/assets/trash-8sH7EZgc.js +0 -1
  244. 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.note.create({
101
- data: {
102
- title: input.title,
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
- ...input.layout ? { layout: input.layout } : {},
109
- ...input.tagIds ? { tags: { connect: input.tagIds.map((id) => ({ id: Number(id) })) } } : {}
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 <= markdown.length) {
51
- const start = markdown.indexOf(text, searchStart);
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: start + text.length,
59
- text
125
+ start: rawStart,
126
+ end: rawEnd,
127
+ text: markdown.slice(rawStart, rawEnd)
60
128
  });
61
- searchStart = start + text.length;
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(selector.before)) {
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(selector.after)) {
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
- return models.$transaction(async (tx) => {
532
- const note = await tx.note.update({
533
- where: { id },
534
- data: {
535
- ...noteInput,
536
- ...buildNoteSearchProjection({
537
- title: noteInput.title,
538
- content: noteInput.content
539
- }),
540
- ...tagIds !== void 0 ? { tags: { set: tagIds.map((tagId) => ({ id: tagId })) } } : {}
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
- if (properties !== void 0) {
544
- await tx.noteProperty.deleteMany({ where: { noteId: id } });
545
- for (const property of properties) {
546
- const definition = await tx.propertyDefinition.upsert({
547
- where: { key: property.key },
548
- create: {
549
- key: property.key,
550
- name: property.name,
551
- valueType: property.valueType
552
- },
553
- update: {
554
- name: property.name,
555
- valueType: property.valueType
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
- const option = property.valueType === "select" && property.optionValue ? await tx.propertyOption.upsert({
559
- where: {
560
- propertyDefinitionId_value: {
561
- propertyDefinitionId: definition.id,
562
- value: property.optionValue
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
- create: {
566
- propertyDefinitionId: definition.id,
567
- value: property.optionValue,
568
- label: property.optionLabel ?? property.optionValue,
569
- color: property.optionColor ?? null
570
- },
571
- update: {
572
- label: property.optionLabel ?? property.optionValue,
573
- color: property.optionColor ?? null
574
- }
575
- }) : null;
576
- await tx.noteProperty.create({
577
- data: {
578
- noteId: id,
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
- return note;
591
- });
614
+ throw error;
615
+ }
592
616
  }
593
617
  });
594
618
  const captureNoteBaseline = async (input) => {