ocean-brain 0.2.2 → 0.3.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 (113) hide show
  1. package/dist/index.js +73 -41
  2. package/dist/mcp.js +587 -26
  3. package/package.json +6 -1
  4. package/scripts/postinstall-prisma.mjs +41 -0
  5. package/server/client/dist/assets/Calendar-DRv2aEl8.js +28 -0
  6. package/server/client/dist/assets/Callout-B2kPcDrq.js +1 -0
  7. package/server/client/dist/assets/Graph-DotbTrZR.js +1 -0
  8. package/server/client/dist/assets/Image-B5R7gF2P.js +1 -0
  9. package/server/client/dist/assets/Image.es-Dld9r9MJ.js +1 -0
  10. package/server/client/dist/assets/ModalActionRow-CES9L_Gy.js +1 -0
  11. package/server/client/dist/assets/Note-SK4hDhEM.css +1 -0
  12. package/server/client/dist/assets/Note-cIbXJc1v.js +1 -0
  13. package/server/client/dist/assets/Reminders-4LunlZRb.js +1 -0
  14. package/server/client/dist/assets/{Search-BANPp2ZV.js → Search-Cp17DGR6.js} +1 -1
  15. package/server/client/dist/assets/SurfaceCard-yzVU4Qkx.js +1 -0
  16. package/server/client/dist/assets/Tag-CwmuMPmo.js +1 -0
  17. package/server/client/dist/assets/TagNotes-gGroWMtT.js +1 -0
  18. package/server/client/dist/assets/Trash.es-B3KWD8_C.js +1 -0
  19. package/server/client/dist/assets/color-wpu7wT_s.js +1 -0
  20. package/server/client/dist/assets/{image.api-rBH0OSWJ.js → image.api-DJgOBt8S.js} +1 -1
  21. package/server/client/dist/assets/index-40Y2UsVr.js +205 -0
  22. package/server/client/dist/assets/index-BnxpTwtL.css +1 -0
  23. package/server/client/dist/assets/index-DYUg2N-6.js +1 -0
  24. package/server/client/dist/assets/manage-image-ByY1mRZx.js +1 -0
  25. package/server/client/dist/assets/manage-image-detail-BVaDZHRu.js +1 -0
  26. package/server/client/dist/assets/mcp-Jj3061aI.js +1 -0
  27. package/server/client/dist/assets/placeholder-4P_GK7fV.js +34 -0
  28. package/server/client/dist/assets/trash-CPBwY07S.js +1 -0
  29. package/server/client/dist/assets/{useReminderMutate-CU-UinGn.js → useReminderMutate-1YVndM2T.js} +1 -1
  30. package/server/client/dist/index.html +2 -2
  31. package/server/dist/app.js +97 -9
  32. package/server/dist/app.js.map +1 -1
  33. package/server/dist/main.js +16 -2
  34. package/server/dist/main.js.map +1 -1
  35. package/server/dist/modules/auth-guard.js +73 -0
  36. package/server/dist/modules/auth-guard.js.map +1 -0
  37. package/server/dist/modules/auth-mode.js +51 -0
  38. package/server/dist/modules/auth-mode.js.map +1 -0
  39. package/server/dist/modules/auth.js +9 -0
  40. package/server/dist/modules/auth.js.map +1 -1
  41. package/server/dist/modules/blocknote.js +7 -1
  42. package/server/dist/modules/blocknote.js.map +1 -1
  43. package/server/dist/modules/error-handler.js +41 -0
  44. package/server/dist/modules/error-handler.js.map +1 -0
  45. package/server/dist/modules/image-upload.js +114 -0
  46. package/server/dist/modules/image-upload.js.map +1 -0
  47. package/server/dist/modules/mcp-admin.js +88 -0
  48. package/server/dist/modules/mcp-admin.js.map +1 -0
  49. package/server/dist/modules/mcp-auth.js +71 -0
  50. package/server/dist/modules/mcp-auth.js.map +1 -0
  51. package/server/dist/modules/mcp-token.js +28 -0
  52. package/server/dist/modules/mcp-token.js.map +1 -0
  53. package/server/dist/modules/note-authoring.js +140 -0
  54. package/server/dist/modules/note-authoring.js.map +1 -0
  55. package/server/dist/modules/note-cleanup.js +207 -0
  56. package/server/dist/modules/note-cleanup.js.map +1 -0
  57. package/server/dist/modules/note-snapshot.js +223 -0
  58. package/server/dist/modules/note-snapshot.js.map +1 -0
  59. package/server/dist/modules/note-trash.js +262 -0
  60. package/server/dist/modules/note-trash.js.map +1 -0
  61. package/server/dist/modules/prisma-runtime.js +46 -0
  62. package/server/dist/modules/prisma-runtime.js.map +1 -0
  63. package/server/dist/modules/recovery-retention.js +26 -0
  64. package/server/dist/modules/recovery-retention.js.map +1 -0
  65. package/server/dist/modules/remote-image.js +176 -0
  66. package/server/dist/modules/remote-image.js.map +1 -0
  67. package/server/dist/modules/tag-organization.js +66 -0
  68. package/server/dist/modules/tag-organization.js.map +1 -0
  69. package/server/dist/modules/use-async.js +2 -4
  70. package/server/dist/modules/use-async.js.map +1 -1
  71. package/server/dist/schema/note/index.js +150 -6
  72. package/server/dist/schema/note/index.js.map +1 -1
  73. package/server/dist/start.js +11 -0
  74. package/server/dist/start.js.map +1 -0
  75. package/server/dist/types/index.js.map +1 -1
  76. package/server/dist/urls.js +3 -2
  77. package/server/dist/urls.js.map +1 -1
  78. package/server/dist/views/auth.js +305 -0
  79. package/server/dist/views/auth.js.map +1 -0
  80. package/server/dist/views/image.js +24 -81
  81. package/server/dist/views/image.js.map +1 -1
  82. package/server/dist/views/index.js +4 -0
  83. package/server/dist/views/index.js.map +1 -1
  84. package/server/dist/views/mcp-admin.js +42 -0
  85. package/server/dist/views/mcp-admin.js.map +1 -0
  86. package/server/dist/views/note.js +124 -0
  87. package/server/dist/views/note.js.map +1 -0
  88. package/server/dist/views/tag.js +23 -0
  89. package/server/dist/views/tag.js.map +1 -0
  90. package/server/prisma/migrations/20260331183000_0010_note_snapshot/migration.sql +13 -0
  91. package/server/prisma/migrations/20260331195000_0011_note_trash_entities/migration.sql +35 -0
  92. package/server/prisma/migrations/20260331213000_0012_image_hash_unique/migration.sql +49 -0
  93. package/server/prisma/migrations/20260404000000_0013_mcp_admin_control/migration.sql +9 -0
  94. package/server/prisma/schema.prisma +66 -1
  95. package/server/client/dist/assets/Calendar-ST5q_8KT.js +0 -48
  96. package/server/client/dist/assets/Callout-CrWW3bg0.js +0 -1
  97. package/server/client/dist/assets/Graph-CzJjt6rP.js +0 -1
  98. package/server/client/dist/assets/Image-Dxg1qqZw.js +0 -1
  99. package/server/client/dist/assets/Image.es-DZ0H6wH1.js +0 -1
  100. package/server/client/dist/assets/Note-Bu7fN3B6.js +0 -6
  101. package/server/client/dist/assets/Note-CCvXqPzv.css +0 -1
  102. package/server/client/dist/assets/Plus.es-CS3WVMDq.js +0 -1
  103. package/server/client/dist/assets/PriorityLegend-D61iBwNW.js +0 -1
  104. package/server/client/dist/assets/Reminders-BjirJMOR.css +0 -1
  105. package/server/client/dist/assets/Reminders-DjWRombU.js +0 -1
  106. package/server/client/dist/assets/Tag-DbKSLTj0.js +0 -1
  107. package/server/client/dist/assets/TagNotes-B6s7jtL7.js +0 -1
  108. package/server/client/dist/assets/index-BzWwEDoL.js +0 -1
  109. package/server/client/dist/assets/index-CF5_ZCYN.js +0 -162
  110. package/server/client/dist/assets/index-DjZk2Gpg.css +0 -1
  111. package/server/client/dist/assets/manage-image-detail-DOx6QsCl.js +0 -1
  112. package/server/client/dist/assets/manage-image-g-MC6Fkc.js +0 -1
  113. package/server/client/dist/assets/placeholder-DV3u6MrA.js +0 -34
@@ -0,0 +1 @@
1
+ import{j as e}from"./note-vendor-BofYbzmZ.js";import{p as n,j as i,P as d,L as m,a6 as Z,a1 as A,a7 as h,a8 as g,a9 as x}from"./index-40Y2UsVr.js";import{a}from"./graph-vendor-CUxe67Lr.js";import{c as p,n as M}from"./Trash.es-B3KWD8_C.js";import{I as E}from"./Image.es-Dld9r9MJ.js";import"./note-core-BCgMq5QA.js";const f=new Map([["bold",a.createElement(a.Fragment,null,a.createElement("path",{d:"M236.37,139.4a12,12,0,0,0-12-3A84.07,84.07,0,0,1,119.6,31.59a12,12,0,0,0-15-15A108.86,108.86,0,0,0,49.69,55.07,108,108,0,0,0,136,228a107.09,107.09,0,0,0,64.93-21.69,108.86,108.86,0,0,0,38.44-54.94A12,12,0,0,0,236.37,139.4Zm-49.88,47.74A84,84,0,0,1,68.86,69.51,84.93,84.93,0,0,1,92.27,48.29Q92,52.13,92,56A108.12,108.12,0,0,0,200,164q3.87,0,7.71-.27A84.79,84.79,0,0,1,186.49,187.14Z"}))],["duotone",a.createElement(a.Fragment,null,a.createElement("path",{d:"M227.89,147.89A96,96,0,1,1,108.11,28.11,96.09,96.09,0,0,0,227.89,147.89Z",opacity:"0.2"}),a.createElement("path",{d:"M233.54,142.23a8,8,0,0,0-8-2,88.08,88.08,0,0,1-109.8-109.8,8,8,0,0,0-10-10,104.84,104.84,0,0,0-52.91,37A104,104,0,0,0,136,224a103.09,103.09,0,0,0,62.52-20.88,104.84,104.84,0,0,0,37-52.91A8,8,0,0,0,233.54,142.23ZM188.9,190.34A88,88,0,0,1,65.66,67.11a89,89,0,0,1,31.4-26A106,106,0,0,0,96,56,104.11,104.11,0,0,0,200,160a106,106,0,0,0,14.92-1.06A89,89,0,0,1,188.9,190.34Z"}))],["fill",a.createElement(a.Fragment,null,a.createElement("path",{d:"M235.54,150.21a104.84,104.84,0,0,1-37,52.91A104,104,0,0,1,32,120,103.09,103.09,0,0,1,52.88,57.48a104.84,104.84,0,0,1,52.91-37,8,8,0,0,1,10,10,88.08,88.08,0,0,0,109.8,109.8,8,8,0,0,1,10,10Z"}))],["light",a.createElement(a.Fragment,null,a.createElement("path",{d:"M232.13,143.64a6,6,0,0,0-6-1.49A90.07,90.07,0,0,1,113.86,29.85a6,6,0,0,0-7.49-7.48A102.88,102.88,0,0,0,54.48,58.68,102,102,0,0,0,197.32,201.52a102.88,102.88,0,0,0,36.31-51.89A6,6,0,0,0,232.13,143.64Zm-42,48.29a90,90,0,0,1-126-126A90.9,90.9,0,0,1,99.65,37.66,102.06,102.06,0,0,0,218.34,156.35,90.9,90.9,0,0,1,190.1,191.93Z"}))],["regular",a.createElement(a.Fragment,null,a.createElement("path",{d:"M233.54,142.23a8,8,0,0,0-8-2,88.08,88.08,0,0,1-109.8-109.8,8,8,0,0,0-10-10,104.84,104.84,0,0,0-52.91,37A104,104,0,0,0,136,224a103.09,103.09,0,0,0,62.52-20.88,104.84,104.84,0,0,0,37-52.91A8,8,0,0,0,233.54,142.23ZM188.9,190.34A88,88,0,0,1,65.66,67.11a89,89,0,0,1,31.4-26A106,106,0,0,0,96,56,104.11,104.11,0,0,0,200,160a106,106,0,0,0,14.92-1.06A89,89,0,0,1,188.9,190.34Z"}))],["thin",a.createElement(a.Fragment,null,a.createElement("path",{d:"M230.72,145.06a4,4,0,0,0-4-1A92.08,92.08,0,0,1,111.94,29.27a4,4,0,0,0-5-5A100.78,100.78,0,0,0,56.08,59.88a100,100,0,0,0,140,140,100.78,100.78,0,0,0,35.59-50.87A4,4,0,0,0,230.72,145.06ZM191.3,193.53A92,92,0,0,1,62.47,64.7a93,93,0,0,1,39.88-30.35,100.09,100.09,0,0,0,119.3,119.3A93,93,0,0,1,191.3,193.53Z"}))]]),u=new Map([["bold",a.createElement(a.Fragment,null,a.createElement("path",{d:"M116,36V20a12,12,0,0,1,24,0V36a12,12,0,0,1-24,0Zm80,92a68,68,0,1,1-68-68A68.07,68.07,0,0,1,196,128Zm-24,0a44,44,0,1,0-44,44A44.05,44.05,0,0,0,172,128ZM51.51,68.49a12,12,0,1,0,17-17l-12-12a12,12,0,0,0-17,17Zm0,119-12,12a12,12,0,0,0,17,17l12-12a12,12,0,1,0-17-17ZM196,72a12,12,0,0,0,8.49-3.51l12-12a12,12,0,0,0-17-17l-12,12A12,12,0,0,0,196,72Zm8.49,115.51a12,12,0,0,0-17,17l12,12a12,12,0,0,0,17-17ZM48,128a12,12,0,0,0-12-12H20a12,12,0,0,0,0,24H36A12,12,0,0,0,48,128Zm80,80a12,12,0,0,0-12,12v16a12,12,0,0,0,24,0V220A12,12,0,0,0,128,208Zm108-92H220a12,12,0,0,0,0,24h16a12,12,0,0,0,0-24Z"}))],["duotone",a.createElement(a.Fragment,null,a.createElement("path",{d:"M184,128a56,56,0,1,1-56-56A56,56,0,0,1,184,128Z",opacity:"0.2"}),a.createElement("path",{d:"M120,40V16a8,8,0,0,1,16,0V40a8,8,0,0,1-16,0Zm72,88a64,64,0,1,1-64-64A64.07,64.07,0,0,1,192,128Zm-16,0a48,48,0,1,0-48,48A48.05,48.05,0,0,0,176,128ZM58.34,69.66A8,8,0,0,0,69.66,58.34l-16-16A8,8,0,0,0,42.34,53.66Zm0,116.68-16,16a8,8,0,0,0,11.32,11.32l16-16a8,8,0,0,0-11.32-11.32ZM192,72a8,8,0,0,0,5.66-2.34l16-16a8,8,0,0,0-11.32-11.32l-16,16A8,8,0,0,0,192,72Zm5.66,114.34a8,8,0,0,0-11.32,11.32l16,16a8,8,0,0,0,11.32-11.32ZM48,128a8,8,0,0,0-8-8H16a8,8,0,0,0,0,16H40A8,8,0,0,0,48,128Zm80,80a8,8,0,0,0-8,8v24a8,8,0,0,0,16,0V216A8,8,0,0,0,128,208Zm112-88H216a8,8,0,0,0,0,16h24a8,8,0,0,0,0-16Z"}))],["fill",a.createElement(a.Fragment,null,a.createElement("path",{d:"M120,40V16a8,8,0,0,1,16,0V40a8,8,0,0,1-16,0Zm8,24a64,64,0,1,0,64,64A64.07,64.07,0,0,0,128,64ZM58.34,69.66A8,8,0,0,0,69.66,58.34l-16-16A8,8,0,0,0,42.34,53.66Zm0,116.68-16,16a8,8,0,0,0,11.32,11.32l16-16a8,8,0,0,0-11.32-11.32ZM192,72a8,8,0,0,0,5.66-2.34l16-16a8,8,0,0,0-11.32-11.32l-16,16A8,8,0,0,0,192,72Zm5.66,114.34a8,8,0,0,0-11.32,11.32l16,16a8,8,0,0,0,11.32-11.32ZM48,128a8,8,0,0,0-8-8H16a8,8,0,0,0,0,16H40A8,8,0,0,0,48,128Zm80,80a8,8,0,0,0-8,8v24a8,8,0,0,0,16,0V216A8,8,0,0,0,128,208Zm112-88H216a8,8,0,0,0,0,16h24a8,8,0,0,0,0-16Z"}))],["light",a.createElement(a.Fragment,null,a.createElement("path",{d:"M122,40V16a6,6,0,0,1,12,0V40a6,6,0,0,1-12,0Zm68,88a62,62,0,1,1-62-62A62.07,62.07,0,0,1,190,128Zm-12,0a50,50,0,1,0-50,50A50.06,50.06,0,0,0,178,128ZM59.76,68.24a6,6,0,1,0,8.48-8.48l-16-16a6,6,0,0,0-8.48,8.48Zm0,119.52-16,16a6,6,0,1,0,8.48,8.48l16-16a6,6,0,1,0-8.48-8.48ZM192,70a6,6,0,0,0,4.24-1.76l16-16a6,6,0,0,0-8.48-8.48l-16,16A6,6,0,0,0,192,70Zm4.24,117.76a6,6,0,0,0-8.48,8.48l16,16a6,6,0,0,0,8.48-8.48ZM46,128a6,6,0,0,0-6-6H16a6,6,0,0,0,0,12H40A6,6,0,0,0,46,128Zm82,82a6,6,0,0,0-6,6v24a6,6,0,0,0,12,0V216A6,6,0,0,0,128,210Zm112-88H216a6,6,0,0,0,0,12h24a6,6,0,0,0,0-12Z"}))],["regular",a.createElement(a.Fragment,null,a.createElement("path",{d:"M120,40V16a8,8,0,0,1,16,0V40a8,8,0,0,1-16,0Zm72,88a64,64,0,1,1-64-64A64.07,64.07,0,0,1,192,128Zm-16,0a48,48,0,1,0-48,48A48.05,48.05,0,0,0,176,128ZM58.34,69.66A8,8,0,0,0,69.66,58.34l-16-16A8,8,0,0,0,42.34,53.66Zm0,116.68-16,16a8,8,0,0,0,11.32,11.32l16-16a8,8,0,0,0-11.32-11.32ZM192,72a8,8,0,0,0,5.66-2.34l16-16a8,8,0,0,0-11.32-11.32l-16,16A8,8,0,0,0,192,72Zm5.66,114.34a8,8,0,0,0-11.32,11.32l16,16a8,8,0,0,0,11.32-11.32ZM48,128a8,8,0,0,0-8-8H16a8,8,0,0,0,0,16H40A8,8,0,0,0,48,128Zm80,80a8,8,0,0,0-8,8v24a8,8,0,0,0,16,0V216A8,8,0,0,0,128,208Zm112-88H216a8,8,0,0,0,0,16h24a8,8,0,0,0,0-16Z"}))],["thin",a.createElement(a.Fragment,null,a.createElement("path",{d:"M124,40V16a4,4,0,0,1,8,0V40a4,4,0,0,1-8,0Zm64,88a60,60,0,1,1-60-60A60.07,60.07,0,0,1,188,128Zm-8,0a52,52,0,1,0-52,52A52.06,52.06,0,0,0,180,128ZM61.17,66.83a4,4,0,0,0,5.66-5.66l-16-16a4,4,0,0,0-5.66,5.66Zm0,122.34-16,16a4,4,0,0,0,5.66,5.66l16-16a4,4,0,0,0-5.66-5.66ZM192,68a4,4,0,0,0,2.83-1.17l16-16a4,4,0,1,0-5.66-5.66l-16,16A4,4,0,0,0,192,68Zm2.83,121.17a4,4,0,0,0-5.66,5.66l16,16a4,4,0,0,0,5.66-5.66ZM40,124H16a4,4,0,0,0,0,8H40a4,4,0,0,0,0-8Zm88,88a4,4,0,0,0-4,4v24a4,4,0,0,0,8,0V216A4,4,0,0,0,128,212Zm112-88H216a4,4,0,0,0,0,8h24a4,4,0,0,0,0-8Z"}))]]),r=a.forwardRef((t,l)=>a.createElement(n,{ref:l,...t,weights:f}));r.displayName="MoonIcon";const N=r,c=a.forwardRef((t,l)=>a.createElement(n,{ref:l,...t,weights:u}));c.displayName="SunIcon";const j=c,F=()=>{const{theme:t,toggleTheme:l}=i(o=>o),s="surface-base flex flex-col items-center gap-3 p-6 text-center transition-colors hover:bg-hover-subtle";return e.jsx(d,{title:"Settings",description:"Customize your Ocean Brain experience",children:e.jsxs("div",{className:"grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",children:[e.jsxs("button",{type:"button",className:s,onClick:l,children:[e.jsx("span",{className:"text-3xl",children:t==="dark"?e.jsx(N,{className:"h-8 w-8 text-fg-secondary",weight:"fill"}):e.jsx(j,{className:"h-8 w-8 text-fg-secondary",weight:"fill"})}),e.jsx("span",{className:"font-semibold",children:"Theme"}),e.jsx("span",{className:"text-xs font-medium text-fg-tertiary",children:t==="dark"?"Dark mode":"Light mode"})]}),e.jsxs(m,{to:Z,className:s,children:[e.jsx(p,{className:"h-8 w-8 text-fg-secondary"}),e.jsx("span",{className:"font-semibold",children:"MCP"}),e.jsx("span",{className:"text-xs font-medium text-fg-tertiary",children:"Manage AI integration access"})]}),e.jsxs(m,{to:A,search:{page:1},className:s,children:[e.jsx(M,{className:"h-8 w-8 text-fg-secondary"}),e.jsx("span",{className:"font-semibold",children:"Trash"}),e.jsx("span",{className:"text-xs font-medium text-fg-tertiary",children:"Restore deleted notes"})]}),e.jsxs(m,{to:h,search:{page:1},className:s,children:[e.jsx(E,{className:"h-8 w-8 text-fg-secondary"}),e.jsx("span",{className:"font-semibold",children:"Manage Image"}),e.jsx("span",{className:"text-xs font-medium text-fg-tertiary",children:"Upload and organize images"})]}),e.jsxs(m,{to:g,search:{page:1},className:s,children:[e.jsx(x,{className:"h-8 w-8 text-fg-secondary"}),e.jsx("span",{className:"font-semibold",children:"Placeholder"}),e.jsx("span",{className:"text-xs font-medium text-fg-tertiary",children:"Manage template variables"})]})]})})};export{F as default};
@@ -0,0 +1 @@
1
+ import{j as e}from"./note-vendor-BofYbzmZ.js";import{k as x,q as d,ae as g,A as y,v as j,H as I,P as A,Q as E,E as N,L as v,af as M,B as T,f as S,S as c,e as w,a7 as G}from"./index-40Y2UsVr.js";import"./graph-vendor-CUxe67Lr.js";import{I as _}from"./Image-B5R7gF2P.js";import{S as b}from"./SurfaceCard-yzVU4Qkx.js";import{f as C,d as P}from"./image.api-DJgOBt8S.js";import{c as R,n as k}from"./Trash.es-B3KWD8_C.js";import"./note-core-BCgMq5QA.js";const q=t=>{const{data:n}=x({queryKey:d.images.list(t.searchParams),async queryFn(){const r=await C({offset:t.searchParams.offset,limit:t.searchParams.limit});if(r.type==="error")throw r;return r.allImages}});return t.render(n)},L=240,Q=20,D=4,m=w(G),J=()=>{const t=g(),n=y(),r=m.useNavigate(),{page:o}=m.useSearch(),{containerRef:u,limit:i}=j({minItemWidth:L,gap:Q,rows:D}),f=I({mutationFn:P,onSuccess:s=>{if(s.type==="error")throw s;n.invalidateQueries({queryKey:d.images.listAll(),exact:!1})}}),h=async s=>{await t("Are you really sure?")&&f.mutate(s)};return e.jsx(A,{title:"Images",variant:"subtle",description:"Manage images uploaded to your notes",children:e.jsx("div",{ref:u,children:e.jsx(E,{fallback:e.jsxs("div",{className:"grid gap-4",style:{gridTemplateColumns:"repeat(auto-fill, minmax(240px, 1fr))"},children:[e.jsx(c,{height:"200px"}),e.jsx(c,{height:"200px"}),e.jsx(c,{height:"200px"})]}),errorTitle:"Failed to load images",errorDescription:"Retry loading uploaded image metadata.",resetKeys:[o,i],children:e.jsx(q,{searchParams:{offset:(o-1)*i,limit:i},render:({images:s,totalCount:l})=>s.length===0?e.jsx(N,{title:"There are no images",description:"Try drag and drop an image on the note editor."}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"grid gap-4",style:{gridTemplateColumns:"repeat(auto-fill, minmax(240px, 1fr))"},children:s.map(a=>e.jsxs(b,{className:"overflow-hidden p-0",children:[e.jsx(v,{to:M,params:{id:a.id},className:"block overflow-hidden",children:e.jsx(_,{className:"h-48 w-full object-cover transition-transform duration-200 hover:scale-[1.02]",src:a.url,alt:a.id})}),e.jsxs("div",{className:"flex items-center justify-between border-t border-border-subtle px-3 py-2.5",children:[e.jsxs("span",{className:"flex items-center gap-1.5 text-sm font-medium text-fg-tertiary",children:[e.jsx(R,{className:"h-3.5 w-3.5"}),a.referenceCount]}),e.jsx(T,{variant:"ghost",size:"icon-sm",disabled:a.referenceCount>0,onClick:()=>h(a.id),children:e.jsx(k,{className:"h-4 w-4"})})]})]},a.id))}),l&&i<l&&e.jsx(S,{page:o,last:Math.ceil(l/i),onChange:a=>{r({search:p=>({...p,page:a})})}})]})})})})})};export{J as default};
@@ -0,0 +1 @@
1
+ import{j as e}from"./note-vendor-BofYbzmZ.js";import{p as y,ag as b,L as f,N as C,w as E,ah as A,ae as w,z as v,A as I,u as h,q as d,ai as M,P as T,a7 as p,a as S,aj as Z,B as u,ak as _,e as D,af as F}from"./index-40Y2UsVr.js";import{I as R}from"./Image-B5R7gF2P.js";import{S as x}from"./SurfaceCard-yzVU4Qkx.js";import{a}from"./graph-vendor-CUxe67Lr.js";import{a as q,d as z}from"./image.api-DJgOBt8S.js";import{c as G,n as k}from"./Trash.es-B3KWD8_C.js";import{I as B}from"./Image.es-Dld9r9MJ.js";import"./note-core-BCgMq5QA.js";const O=new Map([["bold",a.createElement(a.Fragment,null,a.createElement("path",{d:"M178,36c-20.09,0-37.92,7.93-50,21.56C115.92,43.93,98.09,36,78,36a66.08,66.08,0,0,0-66,66c0,72.34,105.81,130.14,110.31,132.57a12,12,0,0,0,11.38,0C138.19,232.14,244,174.34,244,102A66.08,66.08,0,0,0,178,36Zm-5.49,142.36A328.69,328.69,0,0,1,128,210.16a328.69,328.69,0,0,1-44.51-31.8C61.82,159.77,36,131.42,36,102A42,42,0,0,1,78,60c17.8,0,32.7,9.4,38.89,24.54a12,12,0,0,0,22.22,0C145.3,69.4,160.2,60,178,60a42,42,0,0,1,42,42C220,131.42,194.18,159.77,172.51,178.36Z"}))],["duotone",a.createElement(a.Fragment,null,a.createElement("path",{d:"M232,102c0,66-104,122-104,122S24,168,24,102A54,54,0,0,1,78,48c22.59,0,41.94,12.31,50,32,8.06-19.69,27.41-32,50-32A54,54,0,0,1,232,102Z",opacity:"0.2"}),a.createElement("path",{d:"M178,40c-20.65,0-38.73,8.88-50,23.89C116.73,48.88,98.65,40,78,40a62.07,62.07,0,0,0-62,62c0,70,103.79,126.66,108.21,129a8,8,0,0,0,7.58,0C136.21,228.66,240,172,240,102A62.07,62.07,0,0,0,178,40ZM128,214.8C109.74,204.16,32,155.69,32,102A46.06,46.06,0,0,1,78,56c19.45,0,35.78,10.36,42.6,27a8,8,0,0,0,14.8,0c6.82-16.67,23.15-27,42.6-27a46.06,46.06,0,0,1,46,46C224,155.61,146.24,204.15,128,214.8Z"}))],["fill",a.createElement(a.Fragment,null,a.createElement("path",{d:"M240,102c0,70-103.79,126.66-108.21,129a8,8,0,0,1-7.58,0C119.79,228.66,16,172,16,102A62.07,62.07,0,0,1,78,40c20.65,0,38.73,8.88,50,23.89C139.27,48.88,157.35,40,178,40A62.07,62.07,0,0,1,240,102Z"}))],["light",a.createElement(a.Fragment,null,a.createElement("path",{d:"M178,42c-21,0-39.26,9.47-50,25.34C117.26,51.47,99,42,78,42a60.07,60.07,0,0,0-60,60c0,29.2,18.2,59.59,54.1,90.31a334.68,334.68,0,0,0,53.06,37,6,6,0,0,0,5.68,0,334.68,334.68,0,0,0,53.06-37C219.8,161.59,238,131.2,238,102A60.07,60.07,0,0,0,178,42ZM128,217.11C111.59,207.64,30,157.72,30,102A48.05,48.05,0,0,1,78,54c20.28,0,37.31,10.83,44.45,28.27a6,6,0,0,0,11.1,0C140.69,64.83,157.72,54,178,54a48.05,48.05,0,0,1,48,48C226,157.72,144.41,207.64,128,217.11Z"}))],["regular",a.createElement(a.Fragment,null,a.createElement("path",{d:"M178,40c-20.65,0-38.73,8.88-50,23.89C116.73,48.88,98.65,40,78,40a62.07,62.07,0,0,0-62,62c0,70,103.79,126.66,108.21,129a8,8,0,0,0,7.58,0C136.21,228.66,240,172,240,102A62.07,62.07,0,0,0,178,40ZM128,214.8C109.74,204.16,32,155.69,32,102A46.06,46.06,0,0,1,78,56c19.45,0,35.78,10.36,42.6,27a8,8,0,0,0,14.8,0c6.82-16.67,23.15-27,42.6-27a46.06,46.06,0,0,1,46,46C224,155.61,146.24,204.15,128,214.8Z"}))],["thin",a.createElement(a.Fragment,null,a.createElement("path",{d:"M178,44c-21.44,0-39.92,10.19-50,27.07C117.92,54.19,99.44,44,78,44a58.07,58.07,0,0,0-58,58c0,28.59,18,58.47,53.4,88.79a333.81,333.81,0,0,0,52.7,36.73,4,4,0,0,0,3.8,0,333.81,333.81,0,0,0,52.7-36.73C218,160.47,236,130.59,236,102A58.07,58.07,0,0,0,178,44ZM128,219.42c-14-8-100-59.35-100-117.42A50.06,50.06,0,0,1,78,52c21.11,0,38.85,11.31,46.3,29.51a4,4,0,0,0,7.4,0C139.15,63.31,156.89,52,178,52a50.06,50.06,0,0,1,50,50C228,160,142,211.46,128,219.42Z"}))]]),j=a.forwardRef((i,c)=>a.createElement(y,{ref:c,...i,weights:O}));j.displayName="HeartIcon";const L=j;function U({id:i,title:c,tags:t,createdAt:o,updatedAt:m}){const n=new Date(Number(o)),r=b(Number(m));return e.jsx("div",{className:"border-b-2 border-dashed border-border-subtle last:border-b-0",children:e.jsxs("div",{className:"py-4 flex flex-col gap-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-fg-tertiary text-xs font-medium",children:r}),e.jsxs("span",{className:"text-fg-placeholder text-xs",children:["(",n.toDateString(),")"]})]}),e.jsx(f,{className:"font-bold text-fg-default hover:text-accent-primary transition-colors",to:C,params:{id:i},children:c||"Untitled"}),t&&t.length>0&&e.jsx("div",{className:"flex flex-wrap gap-1.5",children:t.map(l=>e.jsx(f,{to:E,params:{id:l.id},search:{page:1},children:e.jsx(A,{name:l.name})},l.id))})]})})}const g=D(F),Y=()=>{const i=w(),c=v(),{id:t}=g.useParams(),o=g.useNavigate(),m=I(),{data:n}=h({queryKey:d.images.detail(t??""),async queryFn(){const s=await q(t);if(s.type==="error")throw s;return s.image},enabled:!!t}),{data:r}=h({queryKey:d.images.notes(t??""),async queryFn(){const s=await M(n.url);if(s.type==="error")throw s;return s.imageNotes},enabled:!!n}),l=!r||(r?.length||0)>0,N=async()=>{if(!l&&await i("Are you really sure?")){const s=await z(t);if(s.type==="error"){c(s.errors[0].message);return}if(!s.deleteImage){c("Failed to delete image");return}o({to:p,search:{page:1}})}};return e.jsxs(T,{title:"Image Detail",variant:"none",children:[e.jsxs(f,{to:p,search:{page:1},className:"mb-4 inline-flex items-center gap-1 text-sm font-medium text-fg-secondary transition-colors hover:text-fg-default",children:[e.jsx(S,{size:16}),"Back to Images"]}),e.jsxs("div",{className:"flex flex-col gap-6 lg:flex-row",children:[n&&e.jsx("div",{className:"w-full lg:w-[400px] lg:flex-shrink-0",children:e.jsxs(x,{className:"overflow-hidden p-0",children:[e.jsx("div",{className:"flex items-center justify-center bg-muted/20 p-4",children:e.jsx(R,{className:"max-h-80 w-auto max-w-full rounded-[14px] object-contain",src:n.url})}),e.jsxs("div",{className:"flex flex-col gap-3 border-t border-border-subtle p-4",children:[e.jsx("div",{className:"flex items-center justify-between",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(G,{size:14,className:"text-fg-tertiary"}),e.jsxs("span",{className:"text-sm font-medium text-fg-secondary",children:[r?.length||0," ",(r?.length||0)===1?"reference":"references"]})]})}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(Z,{content:l?"Cannot delete while referenced by notes":"Delete this image",side:"bottom",children:e.jsxs(u,{variant:"soft-danger",size:"sm",className:"flex-1",disabled:l,onClick:N,children:[e.jsx(k,{size:16}),e.jsx("span",{children:"Delete"})]})}),e.jsxs(u,{variant:"primary",size:"sm",className:"flex-1",onClick:async()=>{await _("heroBanner",n.url),await m.invalidateQueries({queryKey:d.ui.heroBanner(),exact:!0})},children:[e.jsx(L,{size:16,className:"text-fg-secondary"}),e.jsx("span",{children:"Set hero banner"})]})]})]})]})}),e.jsx("div",{className:"flex-1 min-w-0",children:r&&r.length>0?e.jsxs(x,{className:"p-4",children:[e.jsx("p",{className:"mb-3 border-b border-border-subtle pb-2 text-sm font-semibold text-fg-default",children:"Referenced Notes"}),e.jsx("ul",{className:"flex flex-col",children:r.map(s=>e.jsx("li",{children:e.jsx(U,{...s})},s.id))})]}):e.jsxs(x,{className:"flex flex-col items-center justify-center p-6 text-center",children:[e.jsx(B,{size:28,className:"mb-2 text-fg-disabled"}),e.jsx("p",{className:"text-sm font-semibold text-fg-secondary",children:"No notes reference this image"}),e.jsx("p",{className:"mt-1 text-sm text-fg-secondary",children:"This image can be safely deleted"})]})})]})]})};export{Y as default};
@@ -0,0 +1 @@
1
+ import{j as e}from"./note-vendor-BofYbzmZ.js";import{aa as r,z as C,A as M,u as N,H as o,P as w,ab as P,B as g,V as i,X as S,W as T}from"./index-40Y2UsVr.js";import{a as k}from"./graph-vendor-CUxe67Lr.js";import{C as v}from"./Callout-B2kPcDrq.js";import{S as c}from"./SurfaceCard-yzVU4Qkx.js";import"./note-core-BCgMq5QA.js";const A=async()=>{const{data:s}=await r.get("/api/mcp-admin/status");return s},F=async s=>{const{data:a}=await r.post("/api/mcp-admin/enabled",{enabled:s});return a},R=async()=>{const{data:s}=await r.post("/api/mcp-admin/token/rotate");return s},L=async()=>{const{data:s}=await r.post("/api/mcp-admin/token/revoke");return s},n=["mcp-admin","status"],q=s=>JSON.stringify({mcpServers:{"ocean-brain":{command:"npx",args:["-y","ocean-brain","mcp","--server",s,"--token-file","/path/to/token.txt"]}}},null,2),K=()=>{const s=C(),a=M(),[d,f]=k.useState(()=>window.location.origin),[l,u]=k.useState(""),{data:m,isLoading:j}=N({queryKey:n,queryFn:A}),p=o({mutationFn:F,onSuccess:t=>{a.setQueryData(n,t),s(t.enabled?"MCP access enabled.":"MCP access disabled.")}}),x=o({mutationFn:R,onSuccess:async({token:t})=>{u(t),s("A new MCP token has been issued."),await a.invalidateQueries({queryKey:n})}}),b=o({mutationFn:L,onSuccess:t=>{u(""),a.setQueryData(n,t),s("The active MCP token has been revoked.")}}),h=m?.enabled??!1,y=!j&&!p.isPending;return e.jsx(w,{title:"MCP",description:"Manage MCP access and issue a single service token",children:e.jsxs("div",{className:"grid grid-cols-1 gap-4",children:[e.jsx(c,{className:"p-4 space-y-4",children:e.jsxs("div",{className:"mb-4 flex items-center justify-between gap-4 border-b border-border-subtle pb-4",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-base font-semibold text-fg-default",children:"MCP Access"}),e.jsx("p",{className:"text-xs font-medium text-fg-tertiary",children:"Allow or block MCP requests at the server level."})]}),e.jsx("div",{className:"inline-flex items-center",children:e.jsx(P,{"aria-label":"Allow MCP access",checked:h,disabled:!y,onCheckedChange:()=>{p.mutate(!h)}})})]})}),e.jsxs(c,{className:"p-4 space-y-4",children:[e.jsxs("div",{className:"mb-4 border-b border-border-subtle pb-4",children:[e.jsx("h2",{className:"text-base font-semibold text-fg-default",children:"Token Management"}),e.jsx("p",{className:"text-xs font-medium text-fg-tertiary",children:"Ocean Brain supports one active MCP token per service."})]}),e.jsx(v,{children:"Rotating token invalidates previous token immediately."}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(g,{onClick:()=>x.mutate(void 0),isLoading:x.isPending,children:"Rotate token"}),e.jsx(g,{variant:"soft-danger",onClick:()=>b.mutate(),isLoading:b.isPending,disabled:!m?.hasActiveToken,children:"Revoke token"})]}),l&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(i,{htmlFor:"issued-mcp-token",children:"Issued Token"}),e.jsx(S,{id:"issued-mcp-token",rows:3,readOnly:!0,value:l})]})]}),e.jsxs(c,{className:"p-4 space-y-4",children:[e.jsxs("div",{className:"mb-4 border-b border-border-subtle pb-4",children:[e.jsx("h2",{className:"text-base font-semibold text-fg-default",children:"Connection Guide"}),e.jsx("p",{className:"text-xs font-medium text-fg-tertiary",children:"Default server URL uses current origin. Change it when registering a public host."})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(i,{htmlFor:"mcp-server-url",children:"MCP Server URL"}),e.jsx(T,{id:"mcp-server-url",value:d,onChange:t=>f(t.target.value)})]}),e.jsxs(v,{children:["Recommended: ",e.jsx("code",{children:"--token-file"}),". For quick local tests, ",e.jsx("code",{children:"--token"})," also works."]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(i,{children:"Recommended (.mcp.json with token file)"}),e.jsx("pre",{className:"overflow-x-auto rounded-[14px] border border-border-subtle bg-surface px-4 py-3 text-xs text-fg-secondary",children:q(d)})]})]})]})})};export{K as default};
@@ -0,0 +1,34 @@
1
+ import{j as e}from"./note-vendor-BofYbzmZ.js";import{p as O,g as y,z as $,A as H,q as x,al as I,u as q,H as P,P as Z,B as f,Y as k,am as F,an as v,ao as Q,M as p,V as g,W as j,F as T,f as K,e as B,a8 as U}from"./index-40Y2UsVr.js";import{a as t}from"./graph-vendor-CUxe67Lr.js";import{C as z}from"./Callout-B2kPcDrq.js";import{n as X,M as Y}from"./ModalActionRow-CES9L_Gy.js";import{S as C}from"./SurfaceCard-yzVU4Qkx.js";import"./note-core-BCgMq5QA.js";const G=new Map([["bold",t.createElement(t.Fragment,null,t.createElement("path",{d:"M216.49,168.49a12,12,0,0,1-17,0L128,97,56.49,168.49a12,12,0,0,1-17-17l80-80a12,12,0,0,1,17,0l80,80A12,12,0,0,1,216.49,168.49Z"}))],["duotone",t.createElement(t.Fragment,null,t.createElement("path",{d:"M208,160H48l80-80Z",opacity:"0.2"}),t.createElement("path",{d:"M213.66,154.34l-80-80a8,8,0,0,0-11.32,0l-80,80A8,8,0,0,0,48,168H208a8,8,0,0,0,5.66-13.66ZM67.31,152,128,91.31,188.69,152Z"}))],["fill",t.createElement(t.Fragment,null,t.createElement("path",{d:"M215.39,163.06A8,8,0,0,1,208,168H48a8,8,0,0,1-5.66-13.66l80-80a8,8,0,0,1,11.32,0l80,80A8,8,0,0,1,215.39,163.06Z"}))],["light",t.createElement(t.Fragment,null,t.createElement("path",{d:"M212.24,164.24a6,6,0,0,1-8.48,0L128,88.49,52.24,164.24a6,6,0,0,1-8.48-8.48l80-80a6,6,0,0,1,8.48,0l80,80A6,6,0,0,1,212.24,164.24Z"}))],["regular",t.createElement(t.Fragment,null,t.createElement("path",{d:"M213.66,165.66a8,8,0,0,1-11.32,0L128,91.31,53.66,165.66a8,8,0,0,1-11.32-11.32l80-80a8,8,0,0,1,11.32,0l80,80A8,8,0,0,1,213.66,165.66Z"}))],["thin",t.createElement(t.Fragment,null,t.createElement("path",{d:"M210.83,162.83a4,4,0,0,1-5.66,0L128,85.66,50.83,162.83a4,4,0,0,1-5.66-5.66l80-80a4,4,0,0,1,5.66,0l80,80A4,4,0,0,1,210.83,162.83Z"}))]]),S=t.forwardRef((l,r)=>t.createElement(O,{ref:r,...l,weights:G}));S.displayName="CaretUpIcon";const V=S,b=["id","name","template","replacement","createdAt","updatedAt"],W=new Set(b),J=`query FetchPlaceholders(
2
+ $searchFilter: SearchFilterInput,
3
+ $pagination: PaginationInput
4
+ ) {
5
+ allPlaceholders(
6
+ searchFilter: $searchFilter,
7
+ pagination: $pagination
8
+ ) {
9
+ totalCount
10
+ placeholders {
11
+ __PLACEHOLDER_FIELDS__ }
12
+ }
13
+ }`,ee=l=>{const r=l&&l.length>0?l.filter(n=>W.has(n)):b;return Array.from(new Set(r)).map(n=>" "+n).join(`
14
+ `)+`
15
+ `},te=async({limit:l=25,offset:r=0,query:d="",fields:n}={})=>{const h=ee(n),c=J.replace("__PLACEHOLDER_FIELDS__",h);return y(c,{searchFilter:{query:d},pagination:{limit:l,offset:r}})},ae=l=>y(`mutation CreatePlaceholder(
16
+ $name: String!,
17
+ $template: String!,
18
+ $replacement: String!
19
+ ) {
20
+ createPlaceholder(
21
+ name: $name,
22
+ template: $template,
23
+ replacement: $replacement
24
+ ) {
25
+ id
26
+ name
27
+ template
28
+ replacement
29
+ createdAt
30
+ updatedAt
31
+ }
32
+ }`,l),le=l=>y(`mutation DeletePlaceholder($id: ID!) {
33
+ deletePlaceholder(id: $id)
34
+ }`,{id:l}),L="p-4",A=B(U),me=()=>{const l=$(),r=H(),d=A.useNavigate(),{page:n}=A.useSearch(),[h,c]=t.useState(!1),[u,N]=t.useState(!1),[s,m]=t.useState({name:"",template:"",replacement:""}),i=25,_=x.placeholders.list({limit:i,offset:(n-1)*i}),[w]=t.useState(I),{data:o,isLoading:M}=q({queryKey:_,queryFn:async()=>{const a=await te({offset:(n-1)*i,limit:i});if(a.type==="error")throw a;return a.allPlaceholders}}),E=P({mutationFn:ae,onSuccess:async()=>{l("Placeholder added successfully"),c(!1),m({name:"",template:"",replacement:""}),await r.invalidateQueries({queryKey:x.placeholders.listAll(),exact:!1})}}),R=P({mutationFn:le,onSuccess:async()=>{l("Placeholder deleted successfully"),await r.invalidateQueries({queryKey:x.placeholders.listAll(),exact:!1})}});return e.jsxs(Z,{title:"Placeholders",variant:"subtle",description:"Manage template variables for note cloning",children:[e.jsx(z,{className:"mb-4",children:e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{children:"Placeholders will be replaced with new note data during cloning."}),e.jsx(f,{variant:"subtle",size:"icon-sm",onClick:()=>c(!0),children:e.jsx(X,{width:20,height:20})})]})}),e.jsxs("div",{className:"mt-3 flex flex-col gap-3",children:[e.jsxs("button",{type:"button",onClick:()=>N(!u),className:"focus-ring-soft surface-base flex items-center justify-between gap-2 rounded-[18px] px-4 py-3 text-left text-sm font-semibold text-fg-default transition-colors hover:bg-hover-subtle",children:[e.jsx("div",{children:"System Placeholders"}),e.jsx("div",{className:"flex h-6 w-6 items-center justify-center text-fg-tertiary",children:u?e.jsx(V,{}):e.jsx(k,{})})]}),u&&e.jsx("div",{className:"grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3",children:w.map(a=>e.jsxs(C,{className:L,children:[e.jsx("div",{className:"text-sm font-semibold text-fg-default",children:a.name}),e.jsxs("div",{className:"text-xs font-medium text-fg-tertiary",children:[F,a.template,v," = '",a.replacement,"'"]})]},a.name))}),!M&&o?.placeholders&&o.placeholders.length>0&&e.jsx("div",{className:"grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3",children:o.placeholders.map(a=>e.jsxs(C,{className:`${L} relative`,children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("div",{className:"text-sm font-semibold text-fg-default",children:a.name}),e.jsx("button",{type:"button",className:"focus-ring-soft inline-flex h-8 w-8 items-center justify-center rounded-[10px] text-fg-tertiary transition-colors hover:bg-hover-subtle hover:text-fg-default",onClick:()=>R.mutate(a.id.toString()),children:e.jsx(Q,{})})]}),e.jsxs("div",{className:"text-xs font-medium text-fg-tertiary",children:[F,a.template,v," = '",a.replacement,"'"]})]},a.id))})]}),e.jsxs(p,{isOpen:h,onClose:()=>c(!1),children:[e.jsx(p.Header,{title:"Add Placeholder",onClose:()=>c(!1)}),e.jsx(p.Body,{children:e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx(g,{htmlFor:"name",children:"Name:"}),e.jsx(j,{id:"name",type:"text",value:s.name,onChange:a=>m({...s,name:a.target.value}),placeholder:"Description of this placeholder"}),e.jsx(g,{htmlFor:"template",children:"Placeholder:"}),e.jsx(j,{id:"template",type:"text",value:s.template,onChange:a=>m({...s,template:a.target.value}),placeholder:"note_app"}),e.jsx(g,{htmlFor:"replacement",children:"Replacement:"}),e.jsx(j,{id:"replacement",type:"text",value:s.replacement,onChange:a=>m({...s,replacement:a.target.value}),placeholder:"Ocean Brain"})]})}),e.jsx(p.Footer,{children:e.jsxs(Y,{children:[e.jsx(f,{variant:"ghost",onClick:()=>c(!1),children:"Cancel"}),e.jsx(f,{variant:"primary",isLoading:E.isPending,onClick:()=>{if(!s.name||!s.template||!s.replacement){l("All fields are required");return}E.mutate({name:s.name,template:s.template,replacement:s.replacement})},children:"Add"})]})})]}),e.jsx(T,{fallback:null,children:o?.totalCount&&i<o.totalCount&&e.jsx(K,{page:n,last:Math.ceil(o.totalCount/i),onChange:a=>{d({search:D=>({...D,page:a})})}})})]})};export{me as default};
@@ -0,0 +1 @@
1
+ import{j as e}from"./note-vendor-BofYbzmZ.js";import{P as h,Q as p,S as d,e as f,a1 as y,A as g,z as j,k as b,ac as v,q as i,H as N,ad as T,N as S,F as q,a2 as E,B as R,f as Q,E as w,d as C}from"./index-40Y2UsVr.js";import"./graph-vendor-CUxe67Lr.js";import{S as K}from"./SurfaceCard-yzVU4Qkx.js";import"./note-core-BCgMq5QA.js";const a=25,c=f(y),x=t=>C(t).format("YYYY-MM-DD HH:mm"),k=()=>{const{page:t}=c.useSearch(),u=c.useNavigate(),r=g(),m=j(),{data:l}=b({queryKey:i.notes.trash({limit:a,offset:(t-1)*a}),queryFn:async()=>{const s=await v({limit:a,offset:(t-1)*a});if(s.type==="error")throw s;return s.trashedNotes}}),o=N({mutationFn:T,onSuccess:async s=>{if(s.type==="error")throw s;await Promise.all([r.invalidateQueries({queryKey:i.notes.all(),exact:!1}),r.invalidateQueries({queryKey:i.tags.all(),exact:!1}),r.invalidateQueries({queryKey:i.reminders.all(),exact:!1}),r.invalidateQueries({queryKey:i.images.all(),exact:!1}),r.invalidateQueries({queryKey:["calendar"],exact:!1})]),m("The note has been restored."),u({to:S,params:{id:s.restoreTrashedNote.id}})},onError:()=>{m("Failed to restore the note.")}});return e.jsx(q,{fallback:e.jsx(w,{title:"Trash is empty",description:"Deleted notes stay here until you restore them or retention cleanup removes them."}),children:l.notes.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"grid gap-4",children:l.notes.map(s=>e.jsx(K,{className:"p-4",children:e.jsxs("div",{className:"flex items-start justify-between gap-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("h2",{className:"text-base font-semibold text-fg-default",children:s.title}),s.pinned&&e.jsxs("span",{className:"inline-flex items-center gap-1 rounded-full border border-border-subtle bg-hover-subtle px-2 py-0.5 text-xs font-medium text-fg-secondary",children:[e.jsx(E,{className:"h-3.5 w-3.5"}),"Pinned"]})]}),e.jsxs("div",{className:"text-sm text-fg-secondary",children:["Deleted ",x(s.deletedAt)]}),e.jsxs("div",{className:"text-xs text-fg-tertiary",children:["Last edited ",x(s.updatedAt)]}),s.tagNames.length>0&&e.jsx("div",{className:"flex flex-wrap gap-2",children:s.tagNames.map(n=>e.jsx("span",{className:"rounded-full border border-border-subtle bg-hover-subtle px-2 py-0.5 text-xs font-medium text-fg-secondary",children:n},`${s.id}-${n}`))})]}),e.jsx(R,{variant:"subtle",isLoading:o.isPending&&o.variables===s.id,onClick:()=>o.mutate(s.id),children:"Restore"})]})},s.id))}),l.totalCount>a&&e.jsx(Q,{page:t,last:Math.ceil(l.totalCount/a),onChange:s=>{u({search:n=>({...n,page:s})})}})]})})},H=()=>{const{page:t}=c.useSearch();return e.jsx(h,{title:"Trash",variant:"subtle",description:"Restore notes removed from your active workspace before retention cleanup clears them",children:e.jsx(p,{fallback:e.jsxs("div",{className:"grid gap-4",children:[e.jsx(d,{height:"128px"}),e.jsx(d,{height:"128px"}),e.jsx(d,{height:"128px"})]}),errorTitle:"Failed to load trash",errorDescription:"Retry loading deleted notes.",resetKeys:[t],children:e.jsx(k,{})})})};export{H as default};
@@ -1,4 +1,4 @@
1
- import{j as y}from"./note-vendor-BofYbzmZ.js";import{c as u,l as f,q as n,Y as R,a1 as $}from"./index-CF5_ZCYN.js";import{a as l}from"./graph-vendor-CUxe67Lr.js";const g=(e={})=>({limit:e.limit??10,offset:e.offset??0}),D=async(e,t)=>u(`
1
+ import{j as y}from"./note-vendor-BofYbzmZ.js";import{g as u,k as f,q as n,z as R,A as $}from"./index-40Y2UsVr.js";import{a as l}from"./graph-vendor-CUxe67Lr.js";const g=(e={})=>({limit:e.limit??10,offset:e.offset??0}),D=async(e,t)=>u(`
2
2
  query FetchNoteReminders($noteId: ID!, $pagination: PaginationInput) {
3
3
  noteReminders(noteId: $noteId, pagination: $pagination) {
4
4
  totalCount
@@ -6,11 +6,11 @@
6
6
  <link rel="icon" type="image/png" href="/icon.png" />
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
8
  <title>Ocean Brain</title>
9
- <script type="module" crossorigin src="/assets/index-CF5_ZCYN.js"></script>
9
+ <script type="module" crossorigin src="/assets/index-40Y2UsVr.js"></script>
10
10
  <link rel="modulepreload" crossorigin href="/assets/graph-vendor-CUxe67Lr.js">
11
11
  <link rel="modulepreload" crossorigin href="/assets/note-core-BCgMq5QA.js">
12
12
  <link rel="modulepreload" crossorigin href="/assets/note-vendor-BofYbzmZ.js">
13
- <link rel="stylesheet" crossorigin href="/assets/index-DjZk2Gpg.css">
13
+ <link rel="stylesheet" crossorigin href="/assets/index-BnxpTwtL.css">
14
14
  </head>
15
15
 
16
16
  <body>
@@ -1,18 +1,106 @@
1
1
  import express from "express";
2
- import session from "express-session";
2
+ import path from "path";
3
3
  import { createHandler } from "graphql-http/lib/use/express";
4
4
  import logger from "./modules/logger.js";
5
5
  import { paths } from "./paths.js";
6
6
  import schema from "./schema/index.js";
7
- import router from "./urls.js";
8
- var app_default = express().use(logger).use(express.static(paths.clientDist, { extensions: ["html"] })).use("/assets/images/", express.static(paths.imageDir)).use(session({
9
- secret: "my-secret",
10
- resave: false,
11
- saveUninitialized: false
12
- })).use(express.json({ limit: "50mb" })).use("/api", router).use("/graphql", createHandler({ schema })).get(/.*/, (req, res) => {
13
- res.sendFile(paths.clientIndex);
14
- });
7
+ import { createApiRouter } from "./urls.js";
8
+ import { createSessionMiddleware, isAuthenticatedRequest, requireSessionForGraphql } from "./modules/auth-guard.js";
9
+ import {
10
+ createMcpAuthMiddleware,
11
+ createReadOnlyMcpValidationRule
12
+ } from "./modules/mcp-auth.js";
13
+ import { createMcpAdminService } from "./modules/mcp-admin.js";
14
+ import {
15
+ createLoginPageHandler,
16
+ createLoginPageSubmitHandler,
17
+ createLogoutPageHandler
18
+ } from "./views/auth.js";
19
+ import useAsync from "./modules/use-async.js";
20
+ import { createErrorHandler } from "./modules/error-handler.js";
21
+ import {
22
+ createMcpCreateNoteHandler,
23
+ createMcpDeleteNoteHandler,
24
+ createMcpUpdateNoteHandler
25
+ } from "./views/note.js";
26
+ import { createMcpCreateTagHandler } from "./views/tag.js";
27
+ import { purgeExpiredNoteSnapshots } from "./modules/note-snapshot.js";
28
+ import { purgeExpiredTrashedNotes } from "./modules/note-trash.js";
29
+ const shouldBlockClientRoute = (authConfig, requestPath, authenticated) => {
30
+ if (authConfig.mode !== "password" || authenticated) {
31
+ return false;
32
+ }
33
+ if (requestPath.startsWith("/api") || requestPath.startsWith("/graphql") || requestPath.startsWith("/auth")) {
34
+ return false;
35
+ }
36
+ return path.extname(requestPath) === "";
37
+ };
38
+ const createApp = (authConfig) => {
39
+ const mcpAdminService = createMcpAdminService();
40
+ return createAppWithMcpAuth(authConfig, mcpAdminService);
41
+ };
42
+ const createAppWithMcpAuth = (authConfig, mcpAdminService) => {
43
+ const app = express();
44
+ app.locals.authConfig = authConfig;
45
+ void Promise.all([
46
+ purgeExpiredNoteSnapshots(),
47
+ purgeExpiredTrashedNotes()
48
+ ]).catch((error) => {
49
+ const message = error instanceof Error ? error.message : "Unknown recovery cleanup error";
50
+ process.stderr.write(`[recovery] Startup cleanup failed: ${message}
51
+ `);
52
+ });
53
+ app.use(logger).use(createSessionMiddleware(authConfig)).use(express.urlencoded({ extended: false })).use(express.json({ limit: "50mb" })).use("/assets/images/", express.static(paths.imageDir)).post(
54
+ "/api/mcp/notes/create",
55
+ createMcpAuthMiddleware(authConfig, mcpAdminService),
56
+ useAsync(createMcpCreateNoteHandler())
57
+ ).post(
58
+ "/api/mcp/notes/update",
59
+ createMcpAuthMiddleware(authConfig, mcpAdminService),
60
+ useAsync(createMcpUpdateNoteHandler())
61
+ ).post(
62
+ "/api/mcp/tags/create",
63
+ createMcpAuthMiddleware(authConfig, mcpAdminService),
64
+ useAsync(createMcpCreateTagHandler())
65
+ ).post(
66
+ "/api/mcp/notes/delete",
67
+ createMcpAuthMiddleware(authConfig, mcpAdminService),
68
+ useAsync(createMcpDeleteNoteHandler())
69
+ ).use("/api", createApiRouter(authConfig, mcpAdminService)).get("/auth/login", createLoginPageHandler(authConfig)).post("/auth/login", createLoginPageSubmitHandler(authConfig)).post("/auth/logout", createLogoutPageHandler(authConfig)).use("/graphql/mcp", createMcpAuthMiddleware(authConfig, mcpAdminService), createHandler({
70
+ schema,
71
+ context: (req) => ({
72
+ authMode: authConfig.mode,
73
+ isAuthenticated: isAuthenticatedRequest(req.raw),
74
+ req: req.raw,
75
+ res: req.context.res
76
+ }),
77
+ validationRules: (_req, _args, specifiedRules) => {
78
+ return [...specifiedRules, createReadOnlyMcpValidationRule()];
79
+ }
80
+ })).use("/graphql", requireSessionForGraphql(authConfig), createHandler({
81
+ schema,
82
+ context: (req) => ({
83
+ authMode: authConfig.mode,
84
+ isAuthenticated: isAuthenticatedRequest(req.raw),
85
+ req: req.raw,
86
+ res: req.context.res
87
+ })
88
+ })).use((req, res, next) => {
89
+ if (shouldBlockClientRoute(authConfig, req.path, isAuthenticatedRequest(req))) {
90
+ const redirectPath = encodeURIComponent(req.originalUrl || "/");
91
+ res.redirect(303, `/auth/login?next=${redirectPath}`);
92
+ return;
93
+ }
94
+ next();
95
+ }).use(express.static(paths.clientDist, { extensions: ["html"] })).get(/.*/, (_req, res) => {
96
+ res.sendFile(paths.clientIndex);
97
+ }).use(createErrorHandler());
98
+ return app;
99
+ };
100
+ var app_default = createApp;
15
101
  export {
102
+ createApp,
103
+ createAppWithMcpAuth,
16
104
  app_default as default
17
105
  };
18
106
  //# sourceMappingURL=app.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/app.ts"],"sourcesContent":["import express from 'express';\nimport session from 'express-session';\nimport { createHandler } from 'graphql-http/lib/use/express';\n\nimport logger from './modules/logger.js';\nimport { paths } from './paths.js';\nimport schema from './schema/index.js';\nimport router from './urls.js';\n\nexport default express()\n .use(logger)\n .use(express.static(paths.clientDist, { extensions: ['html'] }))\n .use('/assets/images/', express.static(paths.imageDir))\n .use(session({\n secret: 'my-secret',\n resave: false,\n saveUninitialized: false\n }))\n .use(express.json({ limit: '50mb' }))\n .use('/api', router)\n .use('/graphql', createHandler({ schema }))\n .get(/.*/, (req, res) => {\n res.sendFile(paths.clientIndex);\n });\n"],"mappings":"AAAA,OAAO,aAAa;AACpB,OAAO,aAAa;AACpB,SAAS,qBAAqB;AAE9B,OAAO,YAAY;AACnB,SAAS,aAAa;AACtB,OAAO,YAAY;AACnB,OAAO,YAAY;AAEnB,IAAO,cAAQ,QAAQ,EAClB,IAAI,MAAM,EACV,IAAI,QAAQ,OAAO,MAAM,YAAY,EAAE,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,EAC9D,IAAI,mBAAmB,QAAQ,OAAO,MAAM,QAAQ,CAAC,EACrD,IAAI,QAAQ;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,mBAAmB;AACvB,CAAC,CAAC,EACD,IAAI,QAAQ,KAAK,EAAE,OAAO,OAAO,CAAC,CAAC,EACnC,IAAI,QAAQ,MAAM,EAClB,IAAI,YAAY,cAAc,EAAE,OAAO,CAAC,CAAC,EACzC,IAAI,MAAM,CAAC,KAAK,QAAQ;AACrB,MAAI,SAAS,MAAM,WAAW;AAClC,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/app.ts"],"sourcesContent":["import express from 'express';\nimport path from 'path';\nimport { createHandler } from 'graphql-http/lib/use/express';\n\nimport logger from './modules/logger.js';\nimport { paths } from './paths.js';\nimport schema from './schema/index.js';\nimport { createApiRouter } from './urls.js';\nimport { createSessionMiddleware, isAuthenticatedRequest, requireSessionForGraphql } from './modules/auth-guard.js';\nimport type { AuthConfig } from './modules/auth-mode.js';\nimport {\n createMcpAuthMiddleware,\n createReadOnlyMcpValidationRule\n} from './modules/mcp-auth.js';\nimport { createMcpAdminService, type McpAdminService } from './modules/mcp-admin.js';\nimport {\n createLoginPageHandler,\n createLoginPageSubmitHandler,\n createLogoutPageHandler\n} from './views/auth.js';\nimport useAsync from './modules/use-async.js';\nimport { createErrorHandler } from './modules/error-handler.js';\nimport {\n createMcpCreateNoteHandler,\n createMcpDeleteNoteHandler,\n createMcpUpdateNoteHandler\n} from './views/note.js';\nimport { createMcpCreateTagHandler } from './views/tag.js';\nimport { purgeExpiredNoteSnapshots } from './modules/note-snapshot.js';\nimport { purgeExpiredTrashedNotes } from './modules/note-trash.js';\n\nconst shouldBlockClientRoute = (authConfig: AuthConfig, requestPath: string, authenticated: boolean) => {\n if (authConfig.mode !== 'password' || authenticated) {\n return false;\n }\n\n if (requestPath.startsWith('/api') || requestPath.startsWith('/graphql') || requestPath.startsWith('/auth')) {\n return false;\n }\n\n return path.extname(requestPath) === '';\n};\n\nexport const createApp = (authConfig: AuthConfig) => {\n const mcpAdminService = createMcpAdminService();\n return createAppWithMcpAuth(authConfig, mcpAdminService);\n};\n\nexport const createAppWithMcpAuth = (authConfig: AuthConfig, mcpAdminService: McpAdminService) => {\n const app = express();\n app.locals.authConfig = authConfig;\n\n void Promise.all([\n purgeExpiredNoteSnapshots(),\n purgeExpiredTrashedNotes()\n ]).catch((error) => {\n const message = error instanceof Error ? error.message : 'Unknown recovery cleanup error';\n process.stderr.write(`[recovery] Startup cleanup failed: ${message}\\n`);\n });\n\n app.use(logger)\n .use(createSessionMiddleware(authConfig))\n .use(express.urlencoded({ extended: false }))\n .use(express.json({ limit: '50mb' }))\n .use('/assets/images/', express.static(paths.imageDir))\n .post(\n '/api/mcp/notes/create',\n createMcpAuthMiddleware(authConfig, mcpAdminService),\n useAsync(createMcpCreateNoteHandler())\n )\n .post(\n '/api/mcp/notes/update',\n createMcpAuthMiddleware(authConfig, mcpAdminService),\n useAsync(createMcpUpdateNoteHandler())\n )\n .post(\n '/api/mcp/tags/create',\n createMcpAuthMiddleware(authConfig, mcpAdminService),\n useAsync(createMcpCreateTagHandler())\n )\n .post(\n '/api/mcp/notes/delete',\n createMcpAuthMiddleware(authConfig, mcpAdminService),\n useAsync(createMcpDeleteNoteHandler())\n )\n .use('/api', createApiRouter(authConfig, mcpAdminService))\n .get('/auth/login', createLoginPageHandler(authConfig))\n .post('/auth/login', createLoginPageSubmitHandler(authConfig))\n .post('/auth/logout', createLogoutPageHandler(authConfig))\n .use('/graphql/mcp', createMcpAuthMiddleware(authConfig, mcpAdminService), createHandler({\n schema,\n context: (req) => ({\n authMode: authConfig.mode,\n isAuthenticated: isAuthenticatedRequest(req.raw),\n req: req.raw,\n res: req.context.res\n }),\n validationRules: (_req, _args, specifiedRules) => {\n return [...specifiedRules, createReadOnlyMcpValidationRule()];\n }\n }))\n .use('/graphql', requireSessionForGraphql(authConfig), createHandler({\n schema,\n context: (req) => ({\n authMode: authConfig.mode,\n isAuthenticated: isAuthenticatedRequest(req.raw),\n req: req.raw,\n res: req.context.res\n })\n }))\n .use((req, res, next) => {\n if (shouldBlockClientRoute(authConfig, req.path, isAuthenticatedRequest(req))) {\n const redirectPath = encodeURIComponent(req.originalUrl || '/');\n res.redirect(303, `/auth/login?next=${redirectPath}`);\n return;\n }\n\n next();\n })\n .use(express.static(paths.clientDist, { extensions: ['html'] }))\n .get(/.*/, (_req, res) => {\n res.sendFile(paths.clientIndex);\n })\n .use(createErrorHandler());\n\n return app;\n};\n\nexport default createApp;\n"],"mappings":"AAAA,OAAO,aAAa;AACpB,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAE9B,OAAO,YAAY;AACnB,SAAS,aAAa;AACtB,OAAO,YAAY;AACnB,SAAS,uBAAuB;AAChC,SAAS,yBAAyB,wBAAwB,gCAAgC;AAE1F;AAAA,EACI;AAAA,EACA;AAAA,OACG;AACP,SAAS,6BAAmD;AAC5D;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,OACG;AACP,OAAO,cAAc;AACrB,SAAS,0BAA0B;AACnC;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,OACG;AACP,SAAS,iCAAiC;AAC1C,SAAS,iCAAiC;AAC1C,SAAS,gCAAgC;AAEzC,MAAM,yBAAyB,CAAC,YAAwB,aAAqB,kBAA2B;AACpG,MAAI,WAAW,SAAS,cAAc,eAAe;AACjD,WAAO;AAAA,EACX;AAEA,MAAI,YAAY,WAAW,MAAM,KAAK,YAAY,WAAW,UAAU,KAAK,YAAY,WAAW,OAAO,GAAG;AACzG,WAAO;AAAA,EACX;AAEA,SAAO,KAAK,QAAQ,WAAW,MAAM;AACzC;AAEO,MAAM,YAAY,CAAC,eAA2B;AACjD,QAAM,kBAAkB,sBAAsB;AAC9C,SAAO,qBAAqB,YAAY,eAAe;AAC3D;AAEO,MAAM,uBAAuB,CAAC,YAAwB,oBAAqC;AAC9F,QAAM,MAAM,QAAQ;AACpB,MAAI,OAAO,aAAa;AAExB,OAAK,QAAQ,IAAI;AAAA,IACb,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA,EAC7B,CAAC,EAAE,MAAM,CAAC,UAAU;AAChB,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,YAAQ,OAAO,MAAM,sCAAsC,OAAO;AAAA,CAAI;AAAA,EAC1E,CAAC;AAED,MAAI,IAAI,MAAM,EACT,IAAI,wBAAwB,UAAU,CAAC,EACvC,IAAI,QAAQ,WAAW,EAAE,UAAU,MAAM,CAAC,CAAC,EAC3C,IAAI,QAAQ,KAAK,EAAE,OAAO,OAAO,CAAC,CAAC,EACnC,IAAI,mBAAmB,QAAQ,OAAO,MAAM,QAAQ,CAAC,EACrD;AAAA,IACG;AAAA,IACA,wBAAwB,YAAY,eAAe;AAAA,IACnD,SAAS,2BAA2B,CAAC;AAAA,EACzC,EACC;AAAA,IACG;AAAA,IACA,wBAAwB,YAAY,eAAe;AAAA,IACnD,SAAS,2BAA2B,CAAC;AAAA,EACzC,EACC;AAAA,IACG;AAAA,IACA,wBAAwB,YAAY,eAAe;AAAA,IACnD,SAAS,0BAA0B,CAAC;AAAA,EACxC,EACC;AAAA,IACG;AAAA,IACA,wBAAwB,YAAY,eAAe;AAAA,IACnD,SAAS,2BAA2B,CAAC;AAAA,EACzC,EACC,IAAI,QAAQ,gBAAgB,YAAY,eAAe,CAAC,EACxD,IAAI,eAAe,uBAAuB,UAAU,CAAC,EACrD,KAAK,eAAe,6BAA6B,UAAU,CAAC,EAC5D,KAAK,gBAAgB,wBAAwB,UAAU,CAAC,EACxD,IAAI,gBAAgB,wBAAwB,YAAY,eAAe,GAAG,cAAc;AAAA,IACrF;AAAA,IACA,SAAS,CAAC,SAAS;AAAA,MACf,UAAU,WAAW;AAAA,MACrB,iBAAiB,uBAAuB,IAAI,GAAG;AAAA,MAC/C,KAAK,IAAI;AAAA,MACT,KAAK,IAAI,QAAQ;AAAA,IACrB;AAAA,IACA,iBAAiB,CAAC,MAAM,OAAO,mBAAmB;AAC9C,aAAO,CAAC,GAAG,gBAAgB,gCAAgC,CAAC;AAAA,IAChE;AAAA,EACJ,CAAC,CAAC,EACD,IAAI,YAAY,yBAAyB,UAAU,GAAG,cAAc;AAAA,IACjE;AAAA,IACA,SAAS,CAAC,SAAS;AAAA,MACf,UAAU,WAAW;AAAA,MACrB,iBAAiB,uBAAuB,IAAI,GAAG;AAAA,MAC/C,KAAK,IAAI;AAAA,MACT,KAAK,IAAI,QAAQ;AAAA,IACrB;AAAA,EACJ,CAAC,CAAC,EACD,IAAI,CAAC,KAAK,KAAK,SAAS;AACrB,QAAI,uBAAuB,YAAY,IAAI,MAAM,uBAAuB,GAAG,CAAC,GAAG;AAC3E,YAAM,eAAe,mBAAmB,IAAI,eAAe,GAAG;AAC9D,UAAI,SAAS,KAAK,oBAAoB,YAAY,EAAE;AACpD;AAAA,IACJ;AAEA,SAAK;AAAA,EACT,CAAC,EACA,IAAI,QAAQ,OAAO,MAAM,YAAY,EAAE,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,EAC9D,IAAI,MAAM,CAAC,MAAM,QAAQ;AACtB,QAAI,SAAS,MAAM,WAAW;AAAA,EAClC,CAAC,EACA,IAAI,mBAAmB,CAAC;AAE7B,SAAO;AACX;AAEA,IAAO,cAAQ;","names":[]}
@@ -1,5 +1,19 @@
1
- import app from "./app.js";
1
+ import { createApp } from "./app.js";
2
+ import { logAuthConfig, resolveAuthConfig } from "./modules/auth-mode.js";
2
3
  const PORT = Number(process.env.PORT || 6683);
3
4
  const HOST = process.env.HOST || "0.0.0.0";
4
- app.listen(PORT, HOST, () => console.log(`http server listen on ${HOST}:${PORT}`));
5
+ try {
6
+ const authConfig = resolveAuthConfig(process.env);
7
+ logAuthConfig(authConfig);
8
+ const app = createApp(authConfig);
9
+ app.listen(PORT, HOST, () => {
10
+ process.stdout.write(`http server listen on ${HOST}:${PORT} (auth: ${authConfig.mode})
11
+ `);
12
+ });
13
+ } catch (error) {
14
+ const message = error instanceof Error ? error.message : "Unknown auth configuration error";
15
+ process.stderr.write(`[auth] Startup failed: ${message}
16
+ `);
17
+ process.exit(1);
18
+ }
5
19
  //# sourceMappingURL=main.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/main.ts"],"sourcesContent":["import app from './app.js';\n\nconst PORT = Number(process.env.PORT || 6683);\nconst HOST = process.env.HOST || '0.0.0.0';\n\napp.listen(PORT, HOST, () => console.log(`http server listen on ${HOST}:${PORT}`));\n"],"mappings":"AAAA,OAAO,SAAS;AAEhB,MAAM,OAAO,OAAO,QAAQ,IAAI,QAAQ,IAAI;AAC5C,MAAM,OAAO,QAAQ,IAAI,QAAQ;AAEjC,IAAI,OAAO,MAAM,MAAM,MAAM,QAAQ,IAAI,yBAAyB,IAAI,IAAI,IAAI,EAAE,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/main.ts"],"sourcesContent":["import { createApp } from './app.js';\nimport { logAuthConfig, resolveAuthConfig } from './modules/auth-mode.js';\n\nconst PORT = Number(process.env.PORT || 6683);\nconst HOST = process.env.HOST || '0.0.0.0';\n\ntry {\n const authConfig = resolveAuthConfig(process.env);\n\n logAuthConfig(authConfig);\n\n const app = createApp(authConfig);\n\n app.listen(PORT, HOST, () => {\n process.stdout.write(`http server listen on ${HOST}:${PORT} (auth: ${authConfig.mode})\\n`);\n });\n} catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown auth configuration error';\n process.stderr.write(`[auth] Startup failed: ${message}\\n`);\n process.exit(1);\n}\n"],"mappings":"AAAA,SAAS,iBAAiB;AAC1B,SAAS,eAAe,yBAAyB;AAEjD,MAAM,OAAO,OAAO,QAAQ,IAAI,QAAQ,IAAI;AAC5C,MAAM,OAAO,QAAQ,IAAI,QAAQ;AAEjC,IAAI;AACA,QAAM,aAAa,kBAAkB,QAAQ,GAAG;AAEhD,gBAAc,UAAU;AAExB,QAAM,MAAM,UAAU,UAAU;AAEhC,MAAI,OAAO,MAAM,MAAM,MAAM;AACzB,YAAQ,OAAO,MAAM,yBAAyB,IAAI,IAAI,IAAI,WAAW,WAAW,IAAI;AAAA,CAAK;AAAA,EAC7F,CAAC;AACL,SAAS,OAAO;AACZ,QAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,UAAQ,OAAO,MAAM,0BAA0B,OAAO;AAAA,CAAI;AAC1D,UAAQ,KAAK,CAAC;AAClB;","names":[]}
@@ -0,0 +1,73 @@
1
+ import session from "express-session";
2
+ import { GraphQLError } from "graphql";
3
+ const JSON_HEADERS = { "Content-Type": "application/json" };
4
+ const buildUnauthorizedPayload = () => ({
5
+ code: "UNAUTHORIZED",
6
+ message: "Authentication required"
7
+ });
8
+ const buildUnauthorizedGraphqlPayload = () => ({
9
+ errors: [{
10
+ message: "Authentication required",
11
+ extensions: { code: "UNAUTHORIZED" }
12
+ }]
13
+ });
14
+ const isAuthenticatedRequest = (req) => Boolean(req.session?.authenticated);
15
+ const createSessionMiddleware = (authConfig) => {
16
+ if (authConfig.mode !== "password" || !authConfig.sessionSecret) {
17
+ return (_req, _res, next) => next();
18
+ }
19
+ return session({
20
+ secret: authConfig.sessionSecret,
21
+ name: "ocean-brain.sid",
22
+ resave: false,
23
+ saveUninitialized: false,
24
+ cookie: {
25
+ httpOnly: true,
26
+ sameSite: "lax"
27
+ }
28
+ });
29
+ };
30
+ const requireSessionForWrite = (authConfig) => {
31
+ return (req, res, next) => {
32
+ if (authConfig.mode === "disabled" || isAuthenticatedRequest(req)) {
33
+ next();
34
+ return;
35
+ }
36
+ res.status(401).set(JSON_HEADERS).json(buildUnauthorizedPayload()).end();
37
+ };
38
+ };
39
+ const requireSessionForGraphql = (authConfig) => {
40
+ return (req, res, next) => {
41
+ if (authConfig.mode === "disabled" || isAuthenticatedRequest(req)) {
42
+ next();
43
+ return;
44
+ }
45
+ res.status(401).set(JSON_HEADERS).json(buildUnauthorizedGraphqlPayload()).end();
46
+ };
47
+ };
48
+ const createMutationAuthValidationRule = () => {
49
+ return (context) => {
50
+ return {
51
+ OperationDefinition(node) {
52
+ if (node.operation !== "mutation") {
53
+ return;
54
+ }
55
+ context.reportError(new GraphQLError(
56
+ "Authentication required",
57
+ {
58
+ nodes: [node],
59
+ extensions: { code: "UNAUTHORIZED" }
60
+ }
61
+ ));
62
+ }
63
+ };
64
+ };
65
+ };
66
+ export {
67
+ createMutationAuthValidationRule,
68
+ createSessionMiddleware,
69
+ isAuthenticatedRequest,
70
+ requireSessionForGraphql,
71
+ requireSessionForWrite
72
+ };
73
+ //# sourceMappingURL=auth-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/modules/auth-guard.ts"],"sourcesContent":["import session from 'express-session';\nimport type { NextFunction, Request, Response, RequestHandler } from 'express';\nimport type { ValidationRule } from 'graphql';\nimport { GraphQLError } from 'graphql';\n\nimport type { AuthConfig } from './auth-mode.js';\n\nconst JSON_HEADERS = { 'Content-Type': 'application/json' };\n\nconst buildUnauthorizedPayload = () => ({\n code: 'UNAUTHORIZED',\n message: 'Authentication required'\n});\n\nconst buildUnauthorizedGraphqlPayload = () => ({\n errors: [{\n message: 'Authentication required',\n extensions: { code: 'UNAUTHORIZED' }\n }]\n});\n\nexport const isAuthenticatedRequest = (req: Request) => Boolean(req.session?.authenticated);\n\nexport const createSessionMiddleware = (authConfig: AuthConfig): RequestHandler => {\n if (authConfig.mode !== 'password' || !authConfig.sessionSecret) {\n return (_req, _res, next) => next();\n }\n\n return session({\n secret: authConfig.sessionSecret,\n name: 'ocean-brain.sid',\n resave: false,\n saveUninitialized: false,\n cookie: {\n httpOnly: true,\n sameSite: 'lax'\n }\n });\n};\n\nexport const requireSessionForWrite = (authConfig: AuthConfig): RequestHandler => {\n return (req: Request, res: Response, next: NextFunction) => {\n if (authConfig.mode === 'disabled' || isAuthenticatedRequest(req)) {\n next();\n return;\n }\n\n res\n .status(401)\n .set(JSON_HEADERS)\n .json(buildUnauthorizedPayload())\n .end();\n };\n};\n\nexport const requireSessionForGraphql = (authConfig: AuthConfig): RequestHandler => {\n return (req: Request, res: Response, next: NextFunction) => {\n if (authConfig.mode === 'disabled' || isAuthenticatedRequest(req)) {\n next();\n return;\n }\n\n res\n .status(401)\n .set(JSON_HEADERS)\n .json(buildUnauthorizedGraphqlPayload())\n .end();\n };\n};\n\nexport const createMutationAuthValidationRule = (): ValidationRule => {\n return (context) => {\n return {\n OperationDefinition(node) {\n if (node.operation !== 'mutation') {\n return;\n }\n\n context.reportError(new GraphQLError(\n 'Authentication required',\n {\n nodes: [node],\n extensions: { code: 'UNAUTHORIZED' }\n }\n ));\n }\n };\n };\n};\n"],"mappings":"AAAA,OAAO,aAAa;AAGpB,SAAS,oBAAoB;AAI7B,MAAM,eAAe,EAAE,gBAAgB,mBAAmB;AAE1D,MAAM,2BAA2B,OAAO;AAAA,EACpC,MAAM;AAAA,EACN,SAAS;AACb;AAEA,MAAM,kCAAkC,OAAO;AAAA,EAC3C,QAAQ,CAAC;AAAA,IACL,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,eAAe;AAAA,EACvC,CAAC;AACL;AAEO,MAAM,yBAAyB,CAAC,QAAiB,QAAQ,IAAI,SAAS,aAAa;AAEnF,MAAM,0BAA0B,CAAC,eAA2C;AAC/E,MAAI,WAAW,SAAS,cAAc,CAAC,WAAW,eAAe;AAC7D,WAAO,CAAC,MAAM,MAAM,SAAS,KAAK;AAAA,EACtC;AAEA,SAAO,QAAQ;AAAA,IACX,QAAQ,WAAW;AAAA,IACnB,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,mBAAmB;AAAA,IACnB,QAAQ;AAAA,MACJ,UAAU;AAAA,MACV,UAAU;AAAA,IACd;AAAA,EACJ,CAAC;AACL;AAEO,MAAM,yBAAyB,CAAC,eAA2C;AAC9E,SAAO,CAAC,KAAc,KAAe,SAAuB;AACxD,QAAI,WAAW,SAAS,cAAc,uBAAuB,GAAG,GAAG;AAC/D,WAAK;AACL;AAAA,IACJ;AAEA,QACK,OAAO,GAAG,EACV,IAAI,YAAY,EAChB,KAAK,yBAAyB,CAAC,EAC/B,IAAI;AAAA,EACb;AACJ;AAEO,MAAM,2BAA2B,CAAC,eAA2C;AAChF,SAAO,CAAC,KAAc,KAAe,SAAuB;AACxD,QAAI,WAAW,SAAS,cAAc,uBAAuB,GAAG,GAAG;AAC/D,WAAK;AACL;AAAA,IACJ;AAEA,QACK,OAAO,GAAG,EACV,IAAI,YAAY,EAChB,KAAK,gCAAgC,CAAC,EACtC,IAAI;AAAA,EACb;AACJ;AAEO,MAAM,mCAAmC,MAAsB;AAClE,SAAO,CAAC,YAAY;AAChB,WAAO;AAAA,MACH,oBAAoB,MAAM;AACtB,YAAI,KAAK,cAAc,YAAY;AAC/B;AAAA,QACJ;AAEA,gBAAQ,YAAY,IAAI;AAAA,UACpB;AAAA,UACA;AAAA,YACI,OAAO,CAAC,IAAI;AAAA,YACZ,YAAY,EAAE,MAAM,eAAe;AAAA,UACvC;AAAA,QACJ,CAAC;AAAA,MACL;AAAA,IACJ;AAAA,EACJ;AACJ;","names":[]}
@@ -0,0 +1,51 @@
1
+ const isTruthy = (value) => {
2
+ if (!value) {
3
+ return false;
4
+ }
5
+ return ["1", "true", "yes", "on"].includes(value.trim().toLowerCase());
6
+ };
7
+ const ensurePasswordModeRequirements = (env) => {
8
+ if (!env.OCEAN_BRAIN_PASSWORD) {
9
+ throw new Error(
10
+ "Missing OCEAN_BRAIN_PASSWORD. Set OCEAN_BRAIN_PASSWORD to enable password auth mode."
11
+ );
12
+ }
13
+ if (!env.OCEAN_BRAIN_SESSION_SECRET) {
14
+ throw new Error(
15
+ "Missing OCEAN_BRAIN_SESSION_SECRET. Set OCEAN_BRAIN_SESSION_SECRET when password auth mode is enabled."
16
+ );
17
+ }
18
+ };
19
+ const resolveAuthConfig = (env) => {
20
+ const allowInsecureNoAuth = isTruthy(env.OCEAN_BRAIN_ALLOW_INSECURE_NO_AUTH);
21
+ if (allowInsecureNoAuth) {
22
+ return {
23
+ mode: "disabled",
24
+ source: "auto"
25
+ };
26
+ }
27
+ if (env.OCEAN_BRAIN_PASSWORD) {
28
+ ensurePasswordModeRequirements(env);
29
+ return {
30
+ mode: "password",
31
+ password: env.OCEAN_BRAIN_PASSWORD,
32
+ sessionSecret: env.OCEAN_BRAIN_SESSION_SECRET,
33
+ source: "auto"
34
+ };
35
+ }
36
+ throw new Error(
37
+ "Unable to resolve auth mode. Set OCEAN_BRAIN_PASSWORD and OCEAN_BRAIN_SESSION_SECRET for password mode, or set OCEAN_BRAIN_ALLOW_INSECURE_NO_AUTH=true for disabled mode."
38
+ );
39
+ };
40
+ const logAuthConfig = (authConfig) => {
41
+ if (authConfig.mode === "disabled") {
42
+ process.stderr.write("[auth] Running in disabled mode. Authentication is not required for write access.\n");
43
+ return;
44
+ }
45
+ process.stdout.write("[auth] Running in password mode. Write access requires an authenticated session.\n");
46
+ };
47
+ export {
48
+ logAuthConfig,
49
+ resolveAuthConfig
50
+ };
51
+ //# sourceMappingURL=auth-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/modules/auth-mode.ts"],"sourcesContent":["export type AuthMode = 'password' | 'disabled';\n\nexport interface AuthConfig {\n mode: AuthMode;\n password?: string;\n sessionSecret?: string;\n source: 'auto' | 'override';\n}\n\nexport interface AuthModeEnvironment {\n [key: string]: string | undefined;\n OCEAN_BRAIN_ALLOW_INSECURE_NO_AUTH?: string;\n OCEAN_BRAIN_PASSWORD?: string;\n OCEAN_BRAIN_SESSION_SECRET?: string;\n}\n\nconst isTruthy = (value?: string) => {\n if (!value) {\n return false;\n }\n\n return ['1', 'true', 'yes', 'on'].includes(value.trim().toLowerCase());\n};\n\nconst ensurePasswordModeRequirements = (env: AuthModeEnvironment) => {\n if (!env.OCEAN_BRAIN_PASSWORD) {\n throw new Error(\n 'Missing OCEAN_BRAIN_PASSWORD. Set OCEAN_BRAIN_PASSWORD to enable password auth mode.'\n );\n }\n\n if (!env.OCEAN_BRAIN_SESSION_SECRET) {\n throw new Error(\n 'Missing OCEAN_BRAIN_SESSION_SECRET. Set OCEAN_BRAIN_SESSION_SECRET when password auth mode is enabled.'\n );\n }\n};\n\nexport const resolveAuthConfig = (env: AuthModeEnvironment): AuthConfig => {\n const allowInsecureNoAuth = isTruthy(env.OCEAN_BRAIN_ALLOW_INSECURE_NO_AUTH);\n\n if (allowInsecureNoAuth) {\n return {\n mode: 'disabled',\n source: 'auto'\n };\n }\n\n if (env.OCEAN_BRAIN_PASSWORD) {\n ensurePasswordModeRequirements(env);\n\n return {\n mode: 'password',\n password: env.OCEAN_BRAIN_PASSWORD,\n sessionSecret: env.OCEAN_BRAIN_SESSION_SECRET,\n source: 'auto'\n };\n }\n\n throw new Error(\n 'Unable to resolve auth mode. Set OCEAN_BRAIN_PASSWORD and OCEAN_BRAIN_SESSION_SECRET for password mode, or set OCEAN_BRAIN_ALLOW_INSECURE_NO_AUTH=true for disabled mode.'\n );\n};\n\nexport const logAuthConfig = (authConfig: AuthConfig) => {\n if (authConfig.mode === 'disabled') {\n process.stderr.write('[auth] Running in disabled mode. Authentication is not required for write access.\\n');\n return;\n }\n\n process.stdout.write('[auth] Running in password mode. Write access requires an authenticated session.\\n');\n};\n"],"mappings":"AAgBA,MAAM,WAAW,CAAC,UAAmB;AACjC,MAAI,CAAC,OAAO;AACR,WAAO;AAAA,EACX;AAEA,SAAO,CAAC,KAAK,QAAQ,OAAO,IAAI,EAAE,SAAS,MAAM,KAAK,EAAE,YAAY,CAAC;AACzE;AAEA,MAAM,iCAAiC,CAAC,QAA6B;AACjE,MAAI,CAAC,IAAI,sBAAsB;AAC3B,UAAM,IAAI;AAAA,MACN;AAAA,IACJ;AAAA,EACJ;AAEA,MAAI,CAAC,IAAI,4BAA4B;AACjC,UAAM,IAAI;AAAA,MACN;AAAA,IACJ;AAAA,EACJ;AACJ;AAEO,MAAM,oBAAoB,CAAC,QAAyC;AACvE,QAAM,sBAAsB,SAAS,IAAI,kCAAkC;AAE3E,MAAI,qBAAqB;AACrB,WAAO;AAAA,MACH,MAAM;AAAA,MACN,QAAQ;AAAA,IACZ;AAAA,EACJ;AAEA,MAAI,IAAI,sBAAsB;AAC1B,mCAA+B,GAAG;AAElC,WAAO;AAAA,MACH,MAAM;AAAA,MACN,UAAU,IAAI;AAAA,MACd,eAAe,IAAI;AAAA,MACnB,QAAQ;AAAA,IACZ;AAAA,EACJ;AAEA,QAAM,IAAI;AAAA,IACN;AAAA,EACJ;AACJ;AAEO,MAAM,gBAAgB,CAAC,eAA2B;AACrD,MAAI,WAAW,SAAS,YAAY;AAChC,YAAQ,OAAO,MAAM,qFAAqF;AAC1G;AAAA,EACJ;AAEA,UAAQ,OAAO,MAAM,oFAAoF;AAC7G;","names":[]}
@@ -9,8 +9,17 @@ const comparePassword = async (password, storedHash) => {
9
9
  const newHash = crypto.pbkdf2Sync(password, salt, 1e3, 64, "sha512").toString("hex");
10
10
  return hash === newHash;
11
11
  };
12
+ const compareSharedSecret = (expected, received) => {
13
+ const expectedBuffer = Buffer.from(expected, "utf8");
14
+ const receivedBuffer = Buffer.from(received, "utf8");
15
+ if (expectedBuffer.length !== receivedBuffer.length) {
16
+ return false;
17
+ }
18
+ return crypto.timingSafeEqual(expectedBuffer, receivedBuffer);
19
+ };
12
20
  export {
13
21
  comparePassword,
22
+ compareSharedSecret,
14
23
  createPasswordHash
15
24
  };
16
25
  //# sourceMappingURL=auth.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modules/auth.ts"],"sourcesContent":["import crypto from 'crypto';\n\nexport const createPasswordHash = async (password: string) => {\n const salt = crypto.randomBytes(16).toString('hex');\n const hash = crypto.pbkdf2Sync(password, salt, 1000, 64, 'sha512').toString('hex');\n return `${salt}:${hash}`;\n};\n\nexport const comparePassword = async (password: string, storedHash: string) => {\n const [salt, hash] = storedHash.split(':');\n const newHash = crypto.pbkdf2Sync(password, salt, 1000, 64, 'sha512').toString('hex');\n return hash === newHash;\n};\n"],"mappings":"AAAA,OAAO,YAAY;AAEZ,MAAM,qBAAqB,OAAO,aAAqB;AAC1D,QAAM,OAAO,OAAO,YAAY,EAAE,EAAE,SAAS,KAAK;AAClD,QAAM,OAAO,OAAO,WAAW,UAAU,MAAM,KAAM,IAAI,QAAQ,EAAE,SAAS,KAAK;AACjF,SAAO,GAAG,IAAI,IAAI,IAAI;AAC1B;AAEO,MAAM,kBAAkB,OAAO,UAAkB,eAAuB;AAC3E,QAAM,CAAC,MAAM,IAAI,IAAI,WAAW,MAAM,GAAG;AACzC,QAAM,UAAU,OAAO,WAAW,UAAU,MAAM,KAAM,IAAI,QAAQ,EAAE,SAAS,KAAK;AACpF,SAAO,SAAS;AACpB;","names":[]}
1
+ {"version":3,"sources":["../../src/modules/auth.ts"],"sourcesContent":["import crypto from 'crypto';\n\nexport const createPasswordHash = async (password: string) => {\n const salt = crypto.randomBytes(16).toString('hex');\n const hash = crypto.pbkdf2Sync(password, salt, 1000, 64, 'sha512').toString('hex');\n return `${salt}:${hash}`;\n};\n\nexport const comparePassword = async (password: string, storedHash: string) => {\n const [salt, hash] = storedHash.split(':');\n const newHash = crypto.pbkdf2Sync(password, salt, 1000, 64, 'sha512').toString('hex');\n return hash === newHash;\n};\n\nexport const compareSharedSecret = (expected: string, received: string) => {\n const expectedBuffer = Buffer.from(expected, 'utf8');\n const receivedBuffer = Buffer.from(received, 'utf8');\n\n if (expectedBuffer.length !== receivedBuffer.length) {\n return false;\n }\n\n return crypto.timingSafeEqual(expectedBuffer, receivedBuffer);\n};\n"],"mappings":"AAAA,OAAO,YAAY;AAEZ,MAAM,qBAAqB,OAAO,aAAqB;AAC1D,QAAM,OAAO,OAAO,YAAY,EAAE,EAAE,SAAS,KAAK;AAClD,QAAM,OAAO,OAAO,WAAW,UAAU,MAAM,KAAM,IAAI,QAAQ,EAAE,SAAS,KAAK;AACjF,SAAO,GAAG,IAAI,IAAI,IAAI;AAC1B;AAEO,MAAM,kBAAkB,OAAO,UAAkB,eAAuB;AAC3E,QAAM,CAAC,MAAM,IAAI,IAAI,WAAW,MAAM,GAAG;AACzC,QAAM,UAAU,OAAO,WAAW,UAAU,MAAM,KAAM,IAAI,QAAQ,EAAE,SAAS,KAAK;AACpF,SAAO,SAAS;AACpB;AAEO,MAAM,sBAAsB,CAAC,UAAkB,aAAqB;AACvE,QAAM,iBAAiB,OAAO,KAAK,UAAU,MAAM;AACnD,QAAM,iBAAiB,OAAO,KAAK,UAAU,MAAM;AAEnD,MAAI,eAAe,WAAW,eAAe,QAAQ;AACjD,WAAO;AAAA,EACX;AAEA,SAAO,OAAO,gBAAgB,gBAAgB,cAAc;AAChE;","names":[]}
@@ -40,7 +40,13 @@ async function blocksToMarkdown(contentJson) {
40
40
  return "";
41
41
  }
42
42
  }
43
+ async function markdownToBlocksJson(markdown) {
44
+ const editor = getEditor();
45
+ const blocks = await editor.tryParseMarkdownToBlocks(markdown);
46
+ return JSON.stringify(blocks);
47
+ }
43
48
  export {
44
- blocksToMarkdown
49
+ blocksToMarkdown,
50
+ markdownToBlocksJson
45
51
  };
46
52
  //# sourceMappingURL=blocknote.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modules/blocknote.ts"],"sourcesContent":["import { ServerBlockNoteEditor } from '@blocknote/server-util';\n\ninterface BlockNote {\n id?: string;\n type: string;\n props?: Record<string, unknown>;\n content?: BlockNote[];\n children?: BlockNote[];\n text?: string;\n styles?: Record<string, unknown>;\n}\n\nfunction preprocessCustomInlineContent(blocks: BlockNote[]): BlockNote[] {\n return blocks.map((block) => ({\n ...block,\n content: block.content?.map((inline) => {\n if (inline.type === 'reference') {\n return {\n type: 'text',\n text: `[[${inline.props?.title || inline.props?.id || ''}]]`,\n styles: {}\n };\n }\n if (inline.type === 'tag') {\n const tag = (inline.props?.tag as string)?.replace(/^@/, '') || '';\n return {\n type: 'text',\n text: `#${tag}`,\n styles: {}\n };\n }\n return inline;\n }),\n children: block.children?.length\n ? preprocessCustomInlineContent(block.children)\n : []\n }));\n}\n\nlet editorInstance: ServerBlockNoteEditor | null = null;\n\nfunction getEditor(): ServerBlockNoteEditor {\n if (!editorInstance) {\n editorInstance = ServerBlockNoteEditor.create();\n }\n return editorInstance;\n}\n\nexport async function blocksToMarkdown(contentJson: string): Promise<string> {\n try {\n const blocks = JSON.parse(contentJson);\n const processed = preprocessCustomInlineContent(blocks);\n const editor = getEditor();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return await editor.blocksToMarkdownLossy(processed as any);\n } catch {\n return '';\n }\n}\n"],"mappings":"AAAA,SAAS,6BAA6B;AAYtC,SAAS,8BAA8B,QAAkC;AACrE,SAAO,OAAO,IAAI,CAAC,WAAW;AAAA,IAC1B,GAAG;AAAA,IACH,SAAS,MAAM,SAAS,IAAI,CAAC,WAAW;AACpC,UAAI,OAAO,SAAS,aAAa;AAC7B,eAAO;AAAA,UACH,MAAM;AAAA,UACN,MAAM,KAAK,OAAO,OAAO,SAAS,OAAO,OAAO,MAAM,EAAE;AAAA,UACxD,QAAQ,CAAC;AAAA,QACb;AAAA,MACJ;AACA,UAAI,OAAO,SAAS,OAAO;AACvB,cAAM,MAAO,OAAO,OAAO,KAAgB,QAAQ,MAAM,EAAE,KAAK;AAChE,eAAO;AAAA,UACH,MAAM;AAAA,UACN,MAAM,IAAI,GAAG;AAAA,UACb,QAAQ,CAAC;AAAA,QACb;AAAA,MACJ;AACA,aAAO;AAAA,IACX,CAAC;AAAA,IACD,UAAU,MAAM,UAAU,SACpB,8BAA8B,MAAM,QAAQ,IAC5C,CAAC;AAAA,EACX,EAAE;AACN;AAEA,IAAI,iBAA+C;AAEnD,SAAS,YAAmC;AACxC,MAAI,CAAC,gBAAgB;AACjB,qBAAiB,sBAAsB,OAAO;AAAA,EAClD;AACA,SAAO;AACX;AAEA,eAAsB,iBAAiB,aAAsC;AACzE,MAAI;AACA,UAAM,SAAS,KAAK,MAAM,WAAW;AACrC,UAAM,YAAY,8BAA8B,MAAM;AACtD,UAAM,SAAS,UAAU;AAEzB,WAAO,MAAM,OAAO,sBAAsB,SAAgB;AAAA,EAC9D,QAAQ;AACJ,WAAO;AAAA,EACX;AACJ;","names":[]}
1
+ {"version":3,"sources":["../../src/modules/blocknote.ts"],"sourcesContent":["import { ServerBlockNoteEditor } from '@blocknote/server-util';\n\ninterface BlockNote {\n id?: string;\n type: string;\n props?: Record<string, unknown>;\n content?: BlockNote[];\n children?: BlockNote[];\n text?: string;\n styles?: Record<string, unknown>;\n}\n\nfunction preprocessCustomInlineContent(blocks: BlockNote[]): BlockNote[] {\n return blocks.map((block) => ({\n ...block,\n content: block.content?.map((inline) => {\n if (inline.type === 'reference') {\n return {\n type: 'text',\n text: `[[${inline.props?.title || inline.props?.id || ''}]]`,\n styles: {}\n };\n }\n if (inline.type === 'tag') {\n const tag = (inline.props?.tag as string)?.replace(/^@/, '') || '';\n return {\n type: 'text',\n text: `#${tag}`,\n styles: {}\n };\n }\n return inline;\n }),\n children: block.children?.length\n ? preprocessCustomInlineContent(block.children)\n : []\n }));\n}\n\nlet editorInstance: ServerBlockNoteEditor | null = null;\n\nfunction getEditor(): ServerBlockNoteEditor {\n if (!editorInstance) {\n editorInstance = ServerBlockNoteEditor.create();\n }\n return editorInstance;\n}\n\nexport async function blocksToMarkdown(contentJson: string): Promise<string> {\n try {\n const blocks = JSON.parse(contentJson);\n const processed = preprocessCustomInlineContent(blocks);\n const editor = getEditor();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return await editor.blocksToMarkdownLossy(processed as any);\n } catch {\n return '';\n }\n}\n\nexport async function markdownToBlocksJson(markdown: string): Promise<string> {\n const editor = getEditor();\n const blocks = await editor.tryParseMarkdownToBlocks(markdown);\n return JSON.stringify(blocks);\n}\n"],"mappings":"AAAA,SAAS,6BAA6B;AAYtC,SAAS,8BAA8B,QAAkC;AACrE,SAAO,OAAO,IAAI,CAAC,WAAW;AAAA,IAC1B,GAAG;AAAA,IACH,SAAS,MAAM,SAAS,IAAI,CAAC,WAAW;AACpC,UAAI,OAAO,SAAS,aAAa;AAC7B,eAAO;AAAA,UACH,MAAM;AAAA,UACN,MAAM,KAAK,OAAO,OAAO,SAAS,OAAO,OAAO,MAAM,EAAE;AAAA,UACxD,QAAQ,CAAC;AAAA,QACb;AAAA,MACJ;AACA,UAAI,OAAO,SAAS,OAAO;AACvB,cAAM,MAAO,OAAO,OAAO,KAAgB,QAAQ,MAAM,EAAE,KAAK;AAChE,eAAO;AAAA,UACH,MAAM;AAAA,UACN,MAAM,IAAI,GAAG;AAAA,UACb,QAAQ,CAAC;AAAA,QACb;AAAA,MACJ;AACA,aAAO;AAAA,IACX,CAAC;AAAA,IACD,UAAU,MAAM,UAAU,SACpB,8BAA8B,MAAM,QAAQ,IAC5C,CAAC;AAAA,EACX,EAAE;AACN;AAEA,IAAI,iBAA+C;AAEnD,SAAS,YAAmC;AACxC,MAAI,CAAC,gBAAgB;AACjB,qBAAiB,sBAAsB,OAAO;AAAA,EAClD;AACA,SAAO;AACX;AAEA,eAAsB,iBAAiB,aAAsC;AACzE,MAAI;AACA,UAAM,SAAS,KAAK,MAAM,WAAW;AACrC,UAAM,YAAY,8BAA8B,MAAM;AACtD,UAAM,SAAS,UAAU;AAEzB,WAAO,MAAM,OAAO,sBAAsB,SAAgB;AAAA,EAC9D,QAAQ;AACJ,WAAO;AAAA,EACX;AACJ;AAEA,eAAsB,qBAAqB,UAAmC;AAC1E,QAAM,SAAS,UAAU;AACzB,QAAM,SAAS,MAAM,OAAO,yBAAyB,QAAQ;AAC7D,SAAO,KAAK,UAAU,MAAM;AAChC;","names":[]}
@@ -0,0 +1,41 @@
1
+ class AppError extends Error {
2
+ code;
3
+ status;
4
+ constructor(status, code, message) {
5
+ super(message);
6
+ this.name = "AppError";
7
+ this.status = status;
8
+ this.code = code;
9
+ }
10
+ }
11
+ const createAppError = (status, code, message) => {
12
+ return new AppError(status, code, message);
13
+ };
14
+ const createErrorHandler = () => {
15
+ return (error, _req, res, next) => {
16
+ if (res.headersSent) {
17
+ next(error);
18
+ return;
19
+ }
20
+ if (error instanceof AppError) {
21
+ res.status(error.status).json({
22
+ code: error.code,
23
+ message: error.message
24
+ }).end();
25
+ return;
26
+ }
27
+ const message = error instanceof Error ? error.stack || error.message : String(error);
28
+ process.stderr.write(`[error] ${message}
29
+ `);
30
+ res.status(500).json({
31
+ code: "INTERNAL_SERVER_ERROR",
32
+ message: "Internal Server Error"
33
+ }).end();
34
+ };
35
+ };
36
+ export {
37
+ AppError,
38
+ createAppError,
39
+ createErrorHandler
40
+ };
41
+ //# sourceMappingURL=error-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/modules/error-handler.ts"],"sourcesContent":["import type { ErrorRequestHandler } from 'express';\n\nexport class AppError extends Error {\n code: string;\n status: number;\n\n constructor(status: number, code: string, message: string) {\n super(message);\n this.name = 'AppError';\n this.status = status;\n this.code = code;\n }\n}\n\nexport const createAppError = (status: number, code: string, message: string) => {\n return new AppError(status, code, message);\n};\n\nexport const createErrorHandler = (): ErrorRequestHandler => {\n return (error, _req, res, next) => {\n if (res.headersSent) {\n next(error);\n return;\n }\n\n if (error instanceof AppError) {\n res.status(error.status).json({\n code: error.code,\n message: error.message\n }).end();\n return;\n }\n\n const message = error instanceof Error ? error.stack || error.message : String(error);\n process.stderr.write(`[error] ${message}\\n`);\n\n res.status(500).json({\n code: 'INTERNAL_SERVER_ERROR',\n message: 'Internal Server Error'\n }).end();\n };\n};\n"],"mappings":"AAEO,MAAM,iBAAiB,MAAM;AAAA,EAChC;AAAA,EACA;AAAA,EAEA,YAAY,QAAgB,MAAc,SAAiB;AACvD,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AAAA,EAChB;AACJ;AAEO,MAAM,iBAAiB,CAAC,QAAgB,MAAc,YAAoB;AAC7E,SAAO,IAAI,SAAS,QAAQ,MAAM,OAAO;AAC7C;AAEO,MAAM,qBAAqB,MAA2B;AACzD,SAAO,CAAC,OAAO,MAAM,KAAK,SAAS;AAC/B,QAAI,IAAI,aAAa;AACjB,WAAK,KAAK;AACV;AAAA,IACJ;AAEA,QAAI,iBAAiB,UAAU;AAC3B,UAAI,OAAO,MAAM,MAAM,EAAE,KAAK;AAAA,QAC1B,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,MACnB,CAAC,EAAE,IAAI;AACP;AAAA,IACJ;AAEA,UAAM,UAAU,iBAAiB,QAAQ,MAAM,SAAS,MAAM,UAAU,OAAO,KAAK;AACpF,YAAQ,OAAO,MAAM,WAAW,OAAO;AAAA,CAAI;AAE3C,QAAI,OAAO,GAAG,EAAE,KAAK;AAAA,MACjB,MAAM;AAAA,MACN,SAAS;AAAA,IACb,CAAC,EAAE,IAAI;AAAA,EACX;AACJ;","names":[]}