ocean-brain 0.7.5 → 0.8.1

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 (263) hide show
  1. package/dist/index.js +3 -3
  2. package/dist/mcp.js +180 -736
  3. package/package.json +6 -2
  4. package/server/client/dist/assets/ArrowRight.es-CbA8ey6a.js +1 -0
  5. package/server/client/dist/assets/{Calendar-Bc2zJueR.js → Calendar-CgWgr1BV.js} +2 -2
  6. package/server/client/dist/assets/Callout-DKruIT0f.js +1 -0
  7. package/server/client/dist/assets/Copy.es-DFbgpaNJ.js +1 -0
  8. package/server/client/dist/assets/Graph-kCltGRlY.js +1 -0
  9. package/server/client/dist/assets/{Image-DxWhlIDG.js → Image-7W0DZwMo.js} +1 -1
  10. package/server/client/dist/assets/Image.es-5pXLx9TU.js +1 -0
  11. package/server/client/dist/assets/Note-BW6Np_5g.js +20 -0
  12. package/server/client/dist/assets/Plus.es-B0sg64VJ.js +1 -0
  13. package/server/client/dist/assets/Reminders-C10fHQcl.js +1 -0
  14. package/server/client/dist/assets/Search-tf2nV4v0.js +1 -0
  15. package/server/client/dist/assets/{SurfaceCard-CkAVMLPs.js → SurfaceCard-pydtvHfu.js} +1 -1
  16. package/server/client/dist/assets/Tag-uCoYbISy.js +1 -0
  17. package/server/client/dist/assets/TagNotes-CqOcQiRw.js +1 -0
  18. package/server/client/dist/assets/Trash.es-w32Goxfa.js +1 -0
  19. package/server/client/dist/assets/ViewNotes-slPXXoOY.js +1 -0
  20. package/server/client/dist/assets/ViewSectionDialog-brTrsF6G.js +102 -0
  21. package/server/client/dist/assets/Views-B_wsb-XJ.js +1 -0
  22. package/server/client/dist/assets/{graph-vendor-CUxe67Lr.js → graph-vendor-BAF95C0g.js} +2 -2
  23. package/server/client/dist/assets/image.api-CYsjXiMr.js +17 -0
  24. package/server/client/dist/assets/index-BR05aSXr.js +342 -0
  25. package/server/client/dist/assets/{index-D3BfroIT.js → index-D83QbOcw.js} +1 -1
  26. package/server/client/dist/assets/{index-C5BGzDgt.css → index-DPI6YoDt.css} +1 -1
  27. package/server/client/dist/assets/manage-image-BYIhWu56.js +1 -0
  28. package/server/client/dist/assets/{manage-image-detail-C8Q7K7I3.js → manage-image-detail-6KgmQvbN.js} +1 -1
  29. package/server/client/dist/assets/mcp-Dd98N9Hq.js +4 -0
  30. package/server/client/dist/assets/mcp-admin-adapter-DOgBsYpl.js +1 -0
  31. package/server/client/dist/assets/note-core-CMGUaW1v.js +176 -0
  32. package/server/client/dist/assets/note-vendor-Hoz9Q4-4.js +54 -0
  33. package/server/client/dist/assets/{placeholder-Cr_nI8UI.js → placeholder-siHGg9aK.js} +4 -4
  34. package/server/client/dist/assets/{properties-CvYWJWUM.js → properties-CyVRKgcT.js} +1 -1
  35. package/server/client/dist/assets/tag.api-CwmC8crB.js +21 -0
  36. package/server/client/dist/assets/trash-wojQBK9Z.js +1 -0
  37. package/server/client/dist/assets/{useReminderMutate-CDmIEwsw.js → useReminderMutate-DuVKxpBh.js} +1 -1
  38. package/server/client/dist/index.html +5 -5
  39. package/server/dist/app.js +0 -1
  40. package/server/dist/features/auth/http/api.js +0 -1
  41. package/server/dist/features/auth/http/login-page.js +272 -5
  42. package/server/dist/features/auth/http/pages.js +20 -3
  43. package/server/dist/features/auth/service.js +3 -2
  44. package/server/dist/features/cache/graphql/cache.field.resolver.js +0 -1
  45. package/server/dist/features/cache/graphql/cache.mutation.resolver.js +0 -1
  46. package/server/dist/features/cache/graphql/cache.query.resolver.js +0 -1
  47. package/server/dist/features/cache/graphql/cache.resolver.js +0 -1
  48. package/server/dist/features/cache/graphql/cache.type-defs.js +0 -1
  49. package/server/dist/features/cache/graphql/index.js +0 -1
  50. package/server/dist/features/image/graphql/image.field.resolver.js +0 -1
  51. package/server/dist/features/image/graphql/image.mutation.resolver.js +0 -1
  52. package/server/dist/features/image/graphql/image.query.resolver.js +0 -1
  53. package/server/dist/features/image/graphql/image.resolver.js +0 -1
  54. package/server/dist/features/image/graphql/image.type-defs.js +0 -1
  55. package/server/dist/features/image/graphql/index.js +0 -1
  56. package/server/dist/features/image/http/upload.js +34 -24
  57. package/server/dist/features/image/services/delete.js +0 -1
  58. package/server/dist/features/image/services/upload.js +0 -1
  59. package/server/dist/features/image/services/validation.js +110 -0
  60. package/server/dist/features/mcp-admin/http/handlers.js +11 -4
  61. package/server/dist/features/mcp-admin/service.js +0 -1
  62. package/server/dist/features/note/graphql/index.js +0 -1
  63. package/server/dist/features/note/graphql/note.field.resolver.js +0 -1
  64. package/server/dist/features/note/graphql/note.mutation.resolver.js +0 -1
  65. package/server/dist/features/note/graphql/note.query.resolver.js +0 -1
  66. package/server/dist/features/note/graphql/note.resolver.js +0 -1
  67. package/server/dist/features/note/graphql/note.type-defs.js +0 -1
  68. package/server/dist/features/note/http/mcp.js +8 -44
  69. package/server/dist/features/note/services/authoring.js +0 -1
  70. package/server/dist/features/note/services/cleanup.js +2 -3
  71. package/server/dist/features/note/services/content-blocks.js +0 -1
  72. package/server/dist/features/note/services/markdown-intent-write.js +11 -44
  73. package/server/dist/features/note/services/markdown-patch.js +4 -124
  74. package/server/dist/features/note/services/properties.js +0 -1
  75. package/server/dist/features/note/services/search-backfill.js +0 -1
  76. package/server/dist/features/note/services/search.js +0 -1
  77. package/server/dist/features/note/services/snapshot.js +0 -1
  78. package/server/dist/features/note/services/tag-filter.js +0 -1
  79. package/server/dist/features/note/services/trash.js +0 -1
  80. package/server/dist/features/note/services/write-conflict.js +0 -1
  81. package/server/dist/features/note/services/write.js +13 -14
  82. package/server/dist/features/placeholder/graphql/index.js +0 -1
  83. package/server/dist/features/placeholder/graphql/placeholder.field.resolver.js +0 -1
  84. package/server/dist/features/placeholder/graphql/placeholder.mutation.resolver.js +0 -1
  85. package/server/dist/features/placeholder/graphql/placeholder.query.resolver.js +0 -1
  86. package/server/dist/features/placeholder/graphql/placeholder.resolver.js +0 -1
  87. package/server/dist/features/placeholder/graphql/placeholder.type-defs.js +0 -1
  88. package/server/dist/features/reminder/graphql/index.js +0 -1
  89. package/server/dist/features/reminder/graphql/reminder.field.resolver.js +0 -1
  90. package/server/dist/features/reminder/graphql/reminder.mutation.resolver.js +0 -1
  91. package/server/dist/features/reminder/graphql/reminder.query.resolver.js +0 -1
  92. package/server/dist/features/reminder/graphql/reminder.resolver.js +0 -1
  93. package/server/dist/features/reminder/graphql/reminder.type-defs.js +0 -1
  94. package/server/dist/features/tag/graphql/index.js +0 -1
  95. package/server/dist/features/tag/graphql/tag.field.resolver.js +0 -1
  96. package/server/dist/features/tag/graphql/tag.mutation.resolver.js +0 -1
  97. package/server/dist/features/tag/graphql/tag.query.resolver.js +16 -2
  98. package/server/dist/features/tag/graphql/tag.resolver.js +0 -1
  99. package/server/dist/features/tag/graphql/tag.type-defs.js +2 -1
  100. package/server/dist/features/tag/http/mcp.js +0 -1
  101. package/server/dist/features/tag/services/organization.js +0 -1
  102. package/server/dist/features/view/graphql/index.js +0 -1
  103. package/server/dist/features/view/graphql/view.mutation.resolver.js +0 -1
  104. package/server/dist/features/view/graphql/view.query.resolver.js +0 -1
  105. package/server/dist/features/view/graphql/view.resolver.js +0 -1
  106. package/server/dist/features/view/graphql/view.type-defs.js +0 -1
  107. package/server/dist/features/view/services/workspace.js +0 -1
  108. package/server/dist/main.js +0 -1
  109. package/server/dist/models.js +0 -1
  110. package/server/dist/modules/app-version.js +104 -0
  111. package/server/dist/modules/auth-guard.js +0 -1
  112. package/server/dist/modules/auth-mode.js +0 -1
  113. package/server/dist/modules/auth-redirect.js +0 -1
  114. package/server/dist/modules/blocknote-markdown-editor.js +53 -0
  115. package/server/dist/modules/blocknote-tree.js +0 -1
  116. package/server/dist/modules/blocknote.js +10 -4
  117. package/server/dist/modules/data-maintenance.js +0 -1
  118. package/server/dist/modules/error-handler.js +0 -1
  119. package/server/dist/modules/graphql.js +0 -1
  120. package/server/dist/modules/logger.js +0 -1
  121. package/server/dist/modules/mcp-auth.js +62 -2
  122. package/server/dist/modules/mcp-token.js +0 -1
  123. package/server/dist/modules/prisma-runtime.js +0 -1
  124. package/server/dist/modules/rate-limit.js +0 -1
  125. package/server/dist/modules/recovery-retention.js +0 -1
  126. package/server/dist/modules/server-events-handler.js +0 -1
  127. package/server/dist/modules/server-events.js +0 -1
  128. package/server/dist/modules/session-store.js +0 -1
  129. package/server/dist/modules/use-async.js +0 -1
  130. package/server/dist/paths.js +1 -1
  131. package/server/dist/routes/api.js +2 -9
  132. package/server/dist/routes/auth-pages.js +0 -1
  133. package/server/dist/routes/client.js +51 -2
  134. package/server/dist/routes/graphql.js +0 -1
  135. package/server/dist/routes/index.js +0 -1
  136. package/server/dist/routes/mcp.js +0 -1
  137. package/server/dist/schema/index.js +0 -1
  138. package/server/dist/start.js +0 -1
  139. package/server/dist/types/index.js +0 -1
  140. package/server/dist/types/input.js +0 -1
  141. package/server/client/dist/assets/Callout-B4kA_Cvr.js +0 -1
  142. package/server/client/dist/assets/Graph-uq5jfJgt.js +0 -1
  143. package/server/client/dist/assets/Image.es-BpAOJjJT.js +0 -1
  144. package/server/client/dist/assets/Note-Bo8ZYRP-.js +0 -22
  145. package/server/client/dist/assets/Plus.es-Dc_js8AC.js +0 -1
  146. package/server/client/dist/assets/Reminders-lj7Equld.js +0 -1
  147. package/server/client/dist/assets/Search-1wcRO5--.js +0 -1
  148. package/server/client/dist/assets/Tag-CeygwFfv.js +0 -1
  149. package/server/client/dist/assets/TagNotes-B8DqItxw.js +0 -1
  150. package/server/client/dist/assets/Trash.es-OuQVb_SX.js +0 -1
  151. package/server/client/dist/assets/ViewNotes-BH7PbdOD.js +0 -1
  152. package/server/client/dist/assets/ViewSectionTableRenderer-BJwhd5be.js +0 -102
  153. package/server/client/dist/assets/Views-eYFtsdFj.js +0 -1
  154. package/server/client/dist/assets/image.api-C0eYGCeH.js +0 -17
  155. package/server/client/dist/assets/index-jIfkRdY_.js +0 -361
  156. package/server/client/dist/assets/manage-image-C0YwkLIP.js +0 -1
  157. package/server/client/dist/assets/mcp-DHHhTLC8.js +0 -1
  158. package/server/client/dist/assets/note-core-Z6kqulGB.js +0 -180
  159. package/server/client/dist/assets/note-vendor-i1M2FSI2.js +0 -54
  160. package/server/client/dist/assets/trash-DA27aW7L.js +0 -1
  161. package/server/client/dist/fonts/Pretendard-Bold.woff +0 -0
  162. package/server/client/dist/fonts/Pretendard-Regular.woff +0 -0
  163. package/server/dist/app.js.map +0 -1
  164. package/server/dist/features/auth/http/api.js.map +0 -1
  165. package/server/dist/features/auth/http/login-page.js.map +0 -1
  166. package/server/dist/features/auth/http/pages.js.map +0 -1
  167. package/server/dist/features/auth/service.js.map +0 -1
  168. package/server/dist/features/cache/graphql/cache.field.resolver.js.map +0 -1
  169. package/server/dist/features/cache/graphql/cache.mutation.resolver.js.map +0 -1
  170. package/server/dist/features/cache/graphql/cache.query.resolver.js.map +0 -1
  171. package/server/dist/features/cache/graphql/cache.resolver.js.map +0 -1
  172. package/server/dist/features/cache/graphql/cache.type-defs.js.map +0 -1
  173. package/server/dist/features/cache/graphql/index.js.map +0 -1
  174. package/server/dist/features/image/graphql/image.field.resolver.js.map +0 -1
  175. package/server/dist/features/image/graphql/image.mutation.resolver.js.map +0 -1
  176. package/server/dist/features/image/graphql/image.query.resolver.js.map +0 -1
  177. package/server/dist/features/image/graphql/image.resolver.js.map +0 -1
  178. package/server/dist/features/image/graphql/image.type-defs.js.map +0 -1
  179. package/server/dist/features/image/graphql/index.js.map +0 -1
  180. package/server/dist/features/image/http/upload.js.map +0 -1
  181. package/server/dist/features/image/services/delete.js.map +0 -1
  182. package/server/dist/features/image/services/remote-fetch.js +0 -176
  183. package/server/dist/features/image/services/remote-fetch.js.map +0 -1
  184. package/server/dist/features/image/services/upload.js.map +0 -1
  185. package/server/dist/features/mcp-admin/http/handlers.js.map +0 -1
  186. package/server/dist/features/mcp-admin/service.js.map +0 -1
  187. package/server/dist/features/note/graphql/index.js.map +0 -1
  188. package/server/dist/features/note/graphql/note.field.resolver.js.map +0 -1
  189. package/server/dist/features/note/graphql/note.mutation.resolver.js.map +0 -1
  190. package/server/dist/features/note/graphql/note.query.resolver.js.map +0 -1
  191. package/server/dist/features/note/graphql/note.resolver.js.map +0 -1
  192. package/server/dist/features/note/graphql/note.type-defs.js.map +0 -1
  193. package/server/dist/features/note/http/mcp.js.map +0 -1
  194. package/server/dist/features/note/services/authoring.js.map +0 -1
  195. package/server/dist/features/note/services/cleanup.js.map +0 -1
  196. package/server/dist/features/note/services/content-blocks.js.map +0 -1
  197. package/server/dist/features/note/services/markdown-intent-write.js.map +0 -1
  198. package/server/dist/features/note/services/markdown-patch.js.map +0 -1
  199. package/server/dist/features/note/services/properties.js.map +0 -1
  200. package/server/dist/features/note/services/search-backfill.js.map +0 -1
  201. package/server/dist/features/note/services/search.js.map +0 -1
  202. package/server/dist/features/note/services/snapshot.js.map +0 -1
  203. package/server/dist/features/note/services/tag-filter.js.map +0 -1
  204. package/server/dist/features/note/services/trash.js.map +0 -1
  205. package/server/dist/features/note/services/write-conflict.js.map +0 -1
  206. package/server/dist/features/note/services/write.js.map +0 -1
  207. package/server/dist/features/placeholder/graphql/index.js.map +0 -1
  208. package/server/dist/features/placeholder/graphql/placeholder.field.resolver.js.map +0 -1
  209. package/server/dist/features/placeholder/graphql/placeholder.mutation.resolver.js.map +0 -1
  210. package/server/dist/features/placeholder/graphql/placeholder.query.resolver.js.map +0 -1
  211. package/server/dist/features/placeholder/graphql/placeholder.resolver.js.map +0 -1
  212. package/server/dist/features/placeholder/graphql/placeholder.type-defs.js.map +0 -1
  213. package/server/dist/features/reminder/graphql/index.js.map +0 -1
  214. package/server/dist/features/reminder/graphql/reminder.field.resolver.js.map +0 -1
  215. package/server/dist/features/reminder/graphql/reminder.mutation.resolver.js.map +0 -1
  216. package/server/dist/features/reminder/graphql/reminder.query.resolver.js.map +0 -1
  217. package/server/dist/features/reminder/graphql/reminder.resolver.js.map +0 -1
  218. package/server/dist/features/reminder/graphql/reminder.type-defs.js.map +0 -1
  219. package/server/dist/features/tag/graphql/index.js.map +0 -1
  220. package/server/dist/features/tag/graphql/tag.field.resolver.js.map +0 -1
  221. package/server/dist/features/tag/graphql/tag.mutation.resolver.js.map +0 -1
  222. package/server/dist/features/tag/graphql/tag.query.resolver.js.map +0 -1
  223. package/server/dist/features/tag/graphql/tag.resolver.js.map +0 -1
  224. package/server/dist/features/tag/graphql/tag.type-defs.js.map +0 -1
  225. package/server/dist/features/tag/http/mcp.js.map +0 -1
  226. package/server/dist/features/tag/services/organization.js.map +0 -1
  227. package/server/dist/features/view/graphql/index.js.map +0 -1
  228. package/server/dist/features/view/graphql/view.mutation.resolver.js.map +0 -1
  229. package/server/dist/features/view/graphql/view.query.resolver.js.map +0 -1
  230. package/server/dist/features/view/graphql/view.resolver.js.map +0 -1
  231. package/server/dist/features/view/graphql/view.type-defs.js.map +0 -1
  232. package/server/dist/features/view/services/workspace.js.map +0 -1
  233. package/server/dist/main.js.map +0 -1
  234. package/server/dist/models.js.map +0 -1
  235. package/server/dist/modules/auth-guard.js.map +0 -1
  236. package/server/dist/modules/auth-mode.js.map +0 -1
  237. package/server/dist/modules/auth-redirect.js.map +0 -1
  238. package/server/dist/modules/blocknote-tree.js.map +0 -1
  239. package/server/dist/modules/blocknote.js.map +0 -1
  240. package/server/dist/modules/data-maintenance.js.map +0 -1
  241. package/server/dist/modules/error-handler.js.map +0 -1
  242. package/server/dist/modules/graphql.js.map +0 -1
  243. package/server/dist/modules/logger.js.map +0 -1
  244. package/server/dist/modules/mcp-auth.js.map +0 -1
  245. package/server/dist/modules/mcp-token.js.map +0 -1
  246. package/server/dist/modules/prisma-runtime.js.map +0 -1
  247. package/server/dist/modules/rate-limit.js.map +0 -1
  248. package/server/dist/modules/recovery-retention.js.map +0 -1
  249. package/server/dist/modules/server-events-handler.js.map +0 -1
  250. package/server/dist/modules/server-events.js.map +0 -1
  251. package/server/dist/modules/session-store.js.map +0 -1
  252. package/server/dist/modules/use-async.js.map +0 -1
  253. package/server/dist/paths.js.map +0 -1
  254. package/server/dist/routes/api.js.map +0 -1
  255. package/server/dist/routes/auth-pages.js.map +0 -1
  256. package/server/dist/routes/client.js.map +0 -1
  257. package/server/dist/routes/graphql.js.map +0 -1
  258. package/server/dist/routes/index.js.map +0 -1
  259. package/server/dist/routes/mcp.js.map +0 -1
  260. package/server/dist/schema/index.js.map +0 -1
  261. package/server/dist/start.js.map +0 -1
  262. package/server/dist/types/index.js.map +0 -1
  263. package/server/dist/types/input.js.map +0 -1
@@ -5,6 +5,7 @@ import { sanitizeRedirectPath } from "../../modules/auth-redirect.js";
5
5
  import { createAppError } from "../../modules/error-handler.js";
6
6
  const AUTH_SESSION_GENERATION_HEADER = "X-Ocean-Brain-Session-Generation";
7
7
  const AUTH_SESSION_GENERATION = crypto.randomUUID();
8
+ const getSessionGeneration = () => AUTH_SESSION_GENERATION;
8
9
  const createPasswordHash = async (password) => {
9
10
  const salt = crypto.randomBytes(16).toString("hex");
10
11
  const hash = crypto.pbkdf2Sync(password, salt, 1e3, 64, "sha512").toString("hex");
@@ -18,7 +19,7 @@ const comparePassword = async (password, storedHash) => {
18
19
  const compareSharedSecret = compareCommonSharedSecret;
19
20
  const buildSessionResponse = (authConfig, req) => buildAuthSessionResponse(authConfig, Boolean(req.session?.authenticated));
20
21
  const setSessionStatusHeaders = (res) => {
21
- res.set(AUTH_SESSION_GENERATION_HEADER, AUTH_SESSION_GENERATION);
22
+ res.set(AUTH_SESSION_GENERATION_HEADER, getSessionGeneration());
22
23
  res.set("Cache-Control", "no-store");
23
24
  };
24
25
  const refreshCsrfToken = (req) => {
@@ -64,9 +65,9 @@ export {
64
65
  compareSharedSecret,
65
66
  createPasswordHash,
66
67
  destroySession,
68
+ getSessionGeneration,
67
69
  refreshCsrfToken,
68
70
  regenerateSession,
69
71
  sanitizeRedirectPath,
70
72
  setSessionStatusHeaders
71
73
  };
72
- //# sourceMappingURL=service.js.map
@@ -2,4 +2,3 @@ const cacheFieldResolvers = {};
2
2
  export {
3
3
  cacheFieldResolvers
4
4
  };
5
- //# sourceMappingURL=cache.field.resolver.js.map
@@ -46,4 +46,3 @@ export {
46
46
  createDeleteCacheMutationResolver,
47
47
  createSetCacheMutationResolver
48
48
  };
49
- //# sourceMappingURL=cache.mutation.resolver.js.map
@@ -18,4 +18,3 @@ export {
18
18
  createAllCachesQueryResolver,
19
19
  createCacheQueryResolver
20
20
  };
21
- //# sourceMappingURL=cache.query.resolver.js.map
@@ -9,4 +9,3 @@ const cacheResolvers = {
9
9
  export {
10
10
  cacheResolvers
11
11
  };
12
- //# sourceMappingURL=cache.resolver.js.map
@@ -29,4 +29,3 @@ export {
29
29
  cacheType,
30
30
  cacheTypeDefs
31
31
  };
32
- //# sourceMappingURL=cache.type-defs.js.map
@@ -18,4 +18,3 @@ export {
18
18
  createDeleteCacheMutationResolver,
19
19
  createSetCacheMutationResolver
20
20
  };
21
- //# sourceMappingURL=index.js.map
@@ -11,4 +11,3 @@ export {
11
11
  createImageReferenceCountFieldResolver,
12
12
  imageFieldResolvers
13
13
  };
14
- //# sourceMappingURL=image.field.resolver.js.map
@@ -18,4 +18,3 @@ export {
18
18
  createDeleteImageMutationResolver,
19
19
  imageMutationResolvers
20
20
  };
21
- //# sourceMappingURL=image.mutation.resolver.js.map
@@ -37,4 +37,3 @@ export {
37
37
  createImageQueryResolver,
38
38
  imageQueryResolvers
39
39
  };
40
- //# sourceMappingURL=image.query.resolver.js.map
@@ -9,4 +9,3 @@ const imageResolvers = {
9
9
  export {
10
10
  imageResolvers
11
11
  };
12
- //# sourceMappingURL=image.resolver.js.map
@@ -28,4 +28,3 @@ const imageTypeDefs = gql`
28
28
  export {
29
29
  imageTypeDefs
30
30
  };
31
- //# sourceMappingURL=image.type-defs.js.map
@@ -13,4 +13,3 @@ export {
13
13
  imageResolvers,
14
14
  imageTypeDefs
15
15
  };
16
- //# sourceMappingURL=index.js.map
@@ -1,48 +1,58 @@
1
1
  import { createAppError } from "../../../modules/error-handler.js";
2
- import { fetchRemoteImage, RemoteImageFetchError } from "../services/remote-fetch.js";
3
2
  import { persistUploadedImage } from "../services/upload.js";
3
+ import { ImageValidationError, normalizeImageContentType, validateImagePayload } from "../services/validation.js";
4
+ const IMAGE_DATA_URL_PATTERN = /^data:(image\/[a-z0-9.+-]+);base64,([A-Za-z0-9+/]+={0,2})$/i;
4
5
  const createUploadResponse = (image) => {
5
6
  return {
6
7
  id: image.id,
7
8
  url: image.url
8
9
  };
9
10
  };
11
+ const parseImageDataUrl = (image) => {
12
+ const match = IMAGE_DATA_URL_PATTERN.exec(image);
13
+ if (!match || !match[2] || match[2].length % 4 !== 0) {
14
+ return null;
15
+ }
16
+ return {
17
+ base64: match[2],
18
+ contentType: normalizeImageContentType(match[1])
19
+ };
20
+ };
21
+ const createUploadValidationError = (error) => {
22
+ if (error.code === "IMAGE_UNSUPPORTED_CONTENT_TYPE") {
23
+ return createAppError(415, "IMAGE_UPLOAD_UNSUPPORTED_TYPE", "Uploaded image content type is not supported.");
24
+ }
25
+ return createAppError(400, "INVALID_IMAGE_UPLOAD", "Uploaded image content is invalid.");
26
+ };
10
27
  const createUploadImageHandler = (persistImage = persistUploadedImage) => {
11
28
  return async (req, res) => {
12
29
  const { image } = req.body ?? {};
13
- if (typeof image !== "string" || !image.match(/data:image\/\s*(\w+);base64,/)) {
30
+ if (typeof image !== "string") {
14
31
  throw createAppError(400, "INVALID_IMAGE_UPLOAD", "No image uploaded");
15
32
  }
16
- const [info, data] = image.split(",");
17
- const buffer = Buffer.from(data, "base64");
18
- const extension = info.split(";")[0]?.split("/")[1] ?? "";
19
- const uploadedImage = await persistImage({
20
- buffer,
21
- extension
22
- });
23
- res.status(200).json(createUploadResponse(uploadedImage)).end();
24
- };
25
- };
26
- const createUploadImageFromSrcHandler = (fetchImage = fetchRemoteImage, persistImage = persistUploadedImage) => {
27
- return async (req, res) => {
28
- const src = String(req.body?.src ?? "");
33
+ const parsedImage = parseImageDataUrl(image);
34
+ if (!parsedImage) {
35
+ throw createAppError(400, "INVALID_IMAGE_UPLOAD", "No image uploaded");
36
+ }
37
+ let validatedImage;
29
38
  try {
30
- const remoteImage = await fetchImage(src);
31
- const uploadedImage = await persistImage({
32
- buffer: remoteImage.buffer,
33
- extension: remoteImage.extension
39
+ validatedImage = validateImagePayload({
40
+ buffer: Buffer.from(parsedImage.base64, "base64"),
41
+ contentType: parsedImage.contentType
34
42
  });
35
- res.status(200).json(createUploadResponse(uploadedImage)).end();
36
43
  } catch (error) {
37
- if (error instanceof RemoteImageFetchError) {
38
- throw createAppError(error.status, error.code, error.message);
44
+ if (error instanceof ImageValidationError) {
45
+ throw createUploadValidationError(error);
39
46
  }
40
47
  throw error;
41
48
  }
49
+ const uploadedImage = await persistImage({
50
+ buffer: validatedImage.buffer,
51
+ extension: validatedImage.extension
52
+ });
53
+ res.status(200).json(createUploadResponse(uploadedImage)).end();
42
54
  };
43
55
  };
44
56
  export {
45
- createUploadImageFromSrcHandler,
46
57
  createUploadImageHandler
47
58
  };
48
- //# sourceMappingURL=upload.js.map
@@ -49,4 +49,3 @@ export {
49
49
  deleteImageById,
50
50
  resolveStoredImagePath
51
51
  };
52
- //# sourceMappingURL=delete.js.map
@@ -107,4 +107,3 @@ export {
107
107
  hashImageBuffer,
108
108
  persistUploadedImage
109
109
  };
110
- //# sourceMappingURL=upload.js.map
@@ -0,0 +1,110 @@
1
+ class ImageValidationError extends Error {
2
+ code;
3
+ status;
4
+ constructor(code, status, message) {
5
+ super(message);
6
+ this.name = "ImageValidationError";
7
+ this.code = code;
8
+ this.status = status;
9
+ }
10
+ }
11
+ const SUPPORTED_IMAGE_TYPES = /* @__PURE__ */ new Map([
12
+ ["image/png", "png"],
13
+ ["image/jpeg", "jpg"],
14
+ ["image/gif", "gif"],
15
+ ["image/webp", "webp"],
16
+ ["image/bmp", "bmp"],
17
+ ["image/avif", "avif"]
18
+ ]);
19
+ const startsWithBytes = (buffer, bytes) => {
20
+ return bytes.every((byte, index) => buffer[index] === byte);
21
+ };
22
+ const readAscii = (buffer, start, end) => {
23
+ return buffer.subarray(start, end).toString("ascii");
24
+ };
25
+ const hasPngSignature = (buffer) => {
26
+ return buffer.length >= 8 && startsWithBytes(buffer, [137, 80, 78, 71, 13, 10, 26, 10]);
27
+ };
28
+ const hasJpegSignature = (buffer) => {
29
+ return buffer.length >= 3 && startsWithBytes(buffer, [255, 216, 255]);
30
+ };
31
+ const hasGifSignature = (buffer) => {
32
+ return buffer.length >= 6 && ["GIF87a", "GIF89a"].includes(readAscii(buffer, 0, 6));
33
+ };
34
+ const hasWebpSignature = (buffer) => {
35
+ return buffer.length >= 12 && readAscii(buffer, 0, 4) === "RIFF" && readAscii(buffer, 8, 12) === "WEBP";
36
+ };
37
+ const hasBmpSignature = (buffer) => {
38
+ return buffer.length >= 2 && readAscii(buffer, 0, 2) === "BM";
39
+ };
40
+ const hasAvifSignature = (buffer) => {
41
+ if (buffer.length < 16 || readAscii(buffer, 4, 8) !== "ftyp") {
42
+ return false;
43
+ }
44
+ const ftypBoxSize = buffer.readUInt32BE(0);
45
+ if (ftypBoxSize !== 0 && (ftypBoxSize < 16 || ftypBoxSize > buffer.length)) {
46
+ return false;
47
+ }
48
+ const isAvifBrand = (brand) => brand === "avif" || brand === "avis";
49
+ const majorBrand = readAscii(buffer, 8, 12);
50
+ if (isAvifBrand(majorBrand)) {
51
+ return true;
52
+ }
53
+ const boxEnd = ftypBoxSize === 0 ? buffer.length : ftypBoxSize;
54
+ for (let offset = 16; offset + 4 <= boxEnd; offset += 4) {
55
+ const brand = readAscii(buffer, offset, offset + 4);
56
+ if (isAvifBrand(brand)) {
57
+ return true;
58
+ }
59
+ }
60
+ return false;
61
+ };
62
+ const hasExpectedImageSignature = (contentType, buffer) => {
63
+ switch (contentType) {
64
+ case "image/png":
65
+ return hasPngSignature(buffer);
66
+ case "image/jpeg":
67
+ return hasJpegSignature(buffer);
68
+ case "image/gif":
69
+ return hasGifSignature(buffer);
70
+ case "image/webp":
71
+ return hasWebpSignature(buffer);
72
+ case "image/bmp":
73
+ return hasBmpSignature(buffer);
74
+ case "image/avif":
75
+ return hasAvifSignature(buffer);
76
+ default:
77
+ return false;
78
+ }
79
+ };
80
+ const normalizeImageContentType = (contentType) => {
81
+ return contentType?.split(";")[0]?.trim().toLowerCase() ?? "";
82
+ };
83
+ const getSupportedImageExtension = (contentType) => {
84
+ return SUPPORTED_IMAGE_TYPES.get(normalizeImageContentType(contentType));
85
+ };
86
+ const validateImagePayload = ({
87
+ buffer,
88
+ contentType: rawContentType
89
+ }) => {
90
+ const contentType = normalizeImageContentType(rawContentType);
91
+ const extension = SUPPORTED_IMAGE_TYPES.get(contentType);
92
+ if (!extension) {
93
+ throw new ImageValidationError("IMAGE_UNSUPPORTED_CONTENT_TYPE", 415, "Image content type is not supported.");
94
+ }
95
+ const hasExpectedSignature = hasExpectedImageSignature(contentType, buffer);
96
+ if (!hasExpectedSignature) {
97
+ throw new ImageValidationError("IMAGE_INVALID_CONTENT", 415, "Image content does not match the declared type.");
98
+ }
99
+ return {
100
+ buffer,
101
+ contentType,
102
+ extension
103
+ };
104
+ };
105
+ export {
106
+ ImageValidationError,
107
+ getSupportedImageExtension,
108
+ normalizeImageContentType,
109
+ validateImagePayload
110
+ };
@@ -1,8 +1,16 @@
1
+ import { getOceanBrainVersionInfo } from "../../../modules/app-version.js";
1
2
  import { createAppError } from "../../../modules/error-handler.js";
2
3
  import { createMcpAdminService } from "../service.js";
4
+ const createMcpAdminStatusResponse = async (service) => {
5
+ const status = await service.getStatus();
6
+ return {
7
+ ...status,
8
+ server: getOceanBrainVersionInfo()
9
+ };
10
+ };
3
11
  const createMcpAdminStatusHandler = (service = createMcpAdminService()) => {
4
12
  return async (_req, res) => {
5
- const status = await service.getStatus();
13
+ const status = await createMcpAdminStatusResponse(service);
6
14
  res.status(200).json(status).end();
7
15
  };
8
16
  };
@@ -13,7 +21,7 @@ const createMcpAdminSetEnabledHandler = (service = createMcpAdminService()) => {
13
21
  throw createAppError(400, "INVALID_MCP_ENABLED", "enabled must be a boolean.");
14
22
  }
15
23
  await service.setEnabled(enabled);
16
- const status = await service.getStatus();
24
+ const status = await createMcpAdminStatusResponse(service);
17
25
  res.status(200).json(status).end();
18
26
  };
19
27
  };
@@ -29,7 +37,7 @@ const createMcpAdminRotateTokenHandler = (service = createMcpAdminService()) =>
29
37
  const createMcpAdminRevokeTokenHandler = (service = createMcpAdminService()) => {
30
38
  return async (_req, res) => {
31
39
  await service.revokeActiveToken();
32
- const status = await service.getStatus();
40
+ const status = await createMcpAdminStatusResponse(service);
33
41
  res.status(200).json(status).end();
34
42
  };
35
43
  };
@@ -39,4 +47,3 @@ export {
39
47
  createMcpAdminSetEnabledHandler,
40
48
  createMcpAdminStatusHandler
41
49
  };
42
- //# sourceMappingURL=handlers.js.map
@@ -85,4 +85,3 @@ const createMcpAdminService = (db = models) => {
85
85
  export {
86
86
  createMcpAdminService
87
87
  };
88
- //# sourceMappingURL=service.js.map
@@ -5,4 +5,3 @@ export {
5
5
  noteResolvers,
6
6
  noteTypeDefs
7
7
  };
8
- //# sourceMappingURL=index.js.map
@@ -24,4 +24,3 @@ export {
24
24
  noteFieldResolvers,
25
25
  noteSnapshotFieldResolvers
26
26
  };
27
- //# sourceMappingURL=note.field.resolver.js.map
@@ -293,4 +293,3 @@ const noteMutationResolvers = {
293
293
  export {
294
294
  noteMutationResolvers
295
295
  };
296
- //# sourceMappingURL=note.mutation.resolver.js.map
@@ -435,4 +435,3 @@ export {
435
435
  createNoteQueryResolver,
436
436
  noteQueryResolvers
437
437
  };
438
- //# sourceMappingURL=note.query.resolver.js.map
@@ -12,4 +12,3 @@ export {
12
12
  createAllNotesQueryResolver2 as createAllNotesQueryResolver,
13
13
  noteResolvers
14
14
  };
15
- //# sourceMappingURL=note.resolver.js.map
@@ -319,4 +319,3 @@ export {
319
319
  noteType,
320
320
  noteTypeDefs
321
321
  };
322
- //# sourceMappingURL=note.type-defs.js.map
@@ -38,15 +38,6 @@ const resolveOptionalString = (value, code, message) => {
38
38
  }
39
39
  throw createAppError(400, code, message);
40
40
  };
41
- const resolveOptionalBoolean = (value, code, message) => {
42
- if (value === void 0) {
43
- return void 0;
44
- }
45
- if (typeof value === "boolean") {
46
- return value;
47
- }
48
- throw createAppError(400, code, message);
49
- };
50
41
  const resolveMetadataPropertyPatch = (value) => {
51
42
  if (value === void 0) {
52
43
  return void 0;
@@ -117,24 +108,6 @@ const resolveMarkdownWritePolicy = (value) => {
117
108
  }
118
109
  policy.allowNoop = value.allowNoop;
119
110
  }
120
- if (value.maxChangedChars !== void 0) {
121
- if (!isNonNegativeInteger(value.maxChangedChars)) {
122
- throw createAppError(400, "INVALID_MARKDOWN_POLICY", "maxChangedChars must be a non-negative integer.");
123
- }
124
- policy.maxChangedChars = value.maxChangedChars;
125
- }
126
- if (value.maxChangedLines !== void 0) {
127
- if (!isNonNegativeInteger(value.maxChangedLines)) {
128
- throw createAppError(400, "INVALID_MARKDOWN_POLICY", "maxChangedLines must be a non-negative integer.");
129
- }
130
- policy.maxChangedLines = value.maxChangedLines;
131
- }
132
- if (value.diffPreviewMaxChars !== void 0) {
133
- if (!isNonNegativeInteger(value.diffPreviewMaxChars)) {
134
- throw createAppError(400, "INVALID_MARKDOWN_POLICY", "diffPreviewMaxChars must be a non-negative integer.");
135
- }
136
- policy.diffPreviewMaxChars = value.diffPreviewMaxChars;
137
- }
138
111
  if (value.preserveTags !== void 0) {
139
112
  if (!PRESERVATION_POLICIES.has(value.preserveTags)) {
140
113
  throw createAppError(400, "INVALID_MARKDOWN_POLICY", "preserveTags must be boolean or warn.");
@@ -368,7 +341,7 @@ const createMcpNoteWriteBaselineHandler = (findNoteBaseline = async (id) => mode
368
341
  };
369
342
  const createMcpPatchNoteMarkdownHandler = (patchMarkdown = patchNoteMarkdown, emitEvent = emitServerEvent) => {
370
343
  return async (req, res) => {
371
- const { id, expectedUpdatedAt, baseMarkdownSha256, intent, selector, operation, policy, dryRun } = req.body ?? {};
344
+ const { id, expectedUpdatedAt, baseMarkdownSha256, intent, selector, operation, policy } = req.body ?? {};
372
345
  const noteId = resolvePositiveNoteId(id);
373
346
  const resolvedExpectedUpdatedAt = resolveOptionalString(
374
347
  expectedUpdatedAt,
@@ -380,7 +353,6 @@ const createMcpPatchNoteMarkdownHandler = (patchMarkdown = patchNoteMarkdown, em
380
353
  "INVALID_MARKDOWN_HASH",
381
354
  "baseMarkdownSha256 must be a string."
382
355
  );
383
- const resolvedDryRun = resolveOptionalBoolean(dryRun, "INVALID_DRY_RUN", "dryRun must be a boolean.");
384
356
  if (typeof intent !== "string") {
385
357
  throw createAppError(400, "INVALID_PATCH_INTENT", "Patch intent must be a string.");
386
358
  }
@@ -391,8 +363,7 @@ const createMcpPatchNoteMarkdownHandler = (patchMarkdown = patchNoteMarkdown, em
391
363
  intent,
392
364
  selector: resolvePatchSelector(selector),
393
365
  operation: resolvePatchOperation(operation),
394
- policy: resolveMarkdownWritePolicy(policy),
395
- dryRun: resolvedDryRun
366
+ policy: resolveMarkdownWritePolicy(policy)
396
367
  });
397
368
  if (result.status === "applied") {
398
369
  emitEvent({
@@ -407,7 +378,7 @@ const createMcpPatchNoteMarkdownHandler = (patchMarkdown = patchNoteMarkdown, em
407
378
  };
408
379
  const createMcpAppendNoteMarkdownHandler = (appendMarkdown = appendNoteMarkdown, emitEvent = emitServerEvent) => {
409
380
  return async (req, res) => {
410
- const { id, expectedUpdatedAt, baseMarkdownSha256, intent, insertion, placement, separator, policy, dryRun } = req.body ?? {};
381
+ const { id, expectedUpdatedAt, baseMarkdownSha256, intent, insertion, placement, separator, policy } = req.body ?? {};
411
382
  const noteId = resolvePositiveNoteId(id);
412
383
  const resolvedExpectedUpdatedAt = resolveOptionalString(
413
384
  expectedUpdatedAt,
@@ -419,7 +390,6 @@ const createMcpAppendNoteMarkdownHandler = (appendMarkdown = appendNoteMarkdown,
419
390
  "INVALID_MARKDOWN_HASH",
420
391
  "baseMarkdownSha256 must be a string."
421
392
  );
422
- const resolvedDryRun = resolveOptionalBoolean(dryRun, "INVALID_DRY_RUN", "dryRun must be a boolean.");
423
393
  if (typeof intent !== "string") {
424
394
  throw createAppError(400, "INVALID_APPEND_INTENT", "Append intent must be a string.");
425
395
  }
@@ -434,8 +404,7 @@ const createMcpAppendNoteMarkdownHandler = (appendMarkdown = appendNoteMarkdown,
434
404
  insertion,
435
405
  placement: resolveAppendPlacement(placement),
436
406
  separator: resolveSeparator(separator),
437
- policy: resolveMarkdownWritePolicy(policy),
438
- dryRun: resolvedDryRun
407
+ policy: resolveMarkdownWritePolicy(policy)
439
408
  });
440
409
  if (result.status === "applied") {
441
410
  emitEvent({
@@ -450,7 +419,7 @@ const createMcpAppendNoteMarkdownHandler = (appendMarkdown = appendNoteMarkdown,
450
419
  };
451
420
  const createMcpReplaceNoteMarkdownHandler = (replaceMarkdown = replaceNoteMarkdown, emitEvent = emitServerEvent) => {
452
421
  return async (req, res) => {
453
- const { id, expectedUpdatedAt, baseMarkdownSha256, intent, replacement, policy, dryRun } = req.body ?? {};
422
+ const { id, expectedUpdatedAt, baseMarkdownSha256, intent, replacement, policy } = req.body ?? {};
454
423
  const noteId = resolvePositiveNoteId(id);
455
424
  const resolvedExpectedUpdatedAt = resolveOptionalString(
456
425
  expectedUpdatedAt,
@@ -462,7 +431,6 @@ const createMcpReplaceNoteMarkdownHandler = (replaceMarkdown = replaceNoteMarkdo
462
431
  "INVALID_MARKDOWN_HASH",
463
432
  "baseMarkdownSha256 must be a string."
464
433
  );
465
- const resolvedDryRun = resolveOptionalBoolean(dryRun, "INVALID_DRY_RUN", "dryRun must be a boolean.");
466
434
  if (typeof intent !== "string") {
467
435
  throw createAppError(400, "INVALID_REPLACE_INTENT", "Replace intent must be a string.");
468
436
  }
@@ -475,8 +443,7 @@ const createMcpReplaceNoteMarkdownHandler = (replaceMarkdown = replaceNoteMarkdo
475
443
  baseMarkdownSha256: resolvedBaseMarkdownSha256,
476
444
  intent,
477
445
  replacement,
478
- policy: resolveMarkdownWritePolicy(policy),
479
- dryRun: resolvedDryRun
446
+ policy: resolveMarkdownWritePolicy(policy)
480
447
  });
481
448
  if (result.status === "applied") {
482
449
  emitEvent({
@@ -491,11 +458,10 @@ const createMcpReplaceNoteMarkdownHandler = (replaceMarkdown = replaceNoteMarkdo
491
458
  };
492
459
  const createMcpUpdateNoteMetadataHandler = (updateMetadata = updateNoteMetadata, emitEvent = emitServerEvent) => {
493
460
  return async (req, res) => {
494
- const { id, expectedUpdatedAt, title, layout, properties, dryRun } = req.body ?? {};
461
+ const { id, expectedUpdatedAt, title, layout, properties } = req.body ?? {};
495
462
  const noteId = resolvePositiveNoteId(id);
496
463
  const resolvedLayout = resolveNoteLayout(layout);
497
464
  const resolvedProperties = resolveMetadataPropertyPatch(properties);
498
- const resolvedDryRun = resolveOptionalBoolean(dryRun, "INVALID_DRY_RUN", "dryRun must be a boolean.");
499
465
  if (typeof expectedUpdatedAt !== "string") {
500
466
  throw createAppError(400, "INVALID_NOTE_VERSION", "expectedUpdatedAt must be a string.");
501
467
  }
@@ -513,8 +479,7 @@ const createMcpUpdateNoteMetadataHandler = (updateMetadata = updateNoteMetadata,
513
479
  expectedUpdatedAt,
514
480
  ...title !== void 0 ? { title } : {},
515
481
  ...resolvedLayout ? { layout: resolvedLayout } : {},
516
- ...resolvedProperties !== void 0 ? { properties: resolvedProperties } : {},
517
- dryRun: resolvedDryRun
482
+ ...resolvedProperties !== void 0 ? { properties: resolvedProperties } : {}
518
483
  });
519
484
  if (result.status === "applied") {
520
485
  emitEvent({
@@ -558,4 +523,3 @@ export {
558
523
  createMcpUpdateNoteHandler,
559
524
  createMcpUpdateNoteMetadataHandler
560
525
  };
561
- //# sourceMappingURL=mcp.js.map
@@ -168,4 +168,3 @@ export {
168
168
  createNoteFromMarkdown,
169
169
  updateNoteFromMarkdown
170
170
  };
171
- //# sourceMappingURL=authoring.js.map
@@ -76,8 +76,8 @@ const createNoteCleanupService = (deps) => {
76
76
  })),
77
77
  orphanedTagNames: orphanedTags.map((tag) => tag.name),
78
78
  orphanedTagIds: orphanedTags.map((tag) => tag.id),
79
- requiresForce: candidate.requiresForce || orphanedTags.length > 0,
80
- forceReasons: [...candidate.forceReasons, ...orphanedTags.length > 0 ? ["orphan_tags"] : []]
79
+ requiresForce: candidate.requiresForce,
80
+ forceReasons: candidate.forceReasons
81
81
  };
82
82
  };
83
83
  const getDeletePreview = async (id) => {
@@ -196,4 +196,3 @@ export {
196
196
  listNoteCleanupCandidates,
197
197
  normalizeCleanupKeywords
198
198
  };
199
- //# sourceMappingURL=cleanup.js.map
@@ -110,4 +110,3 @@ export {
110
110
  parseNoteContent,
111
111
  syncReferenceTitlesInContent
112
112
  };
113
- //# sourceMappingURL=content-blocks.js.map