@open-mercato/core 0.4.5-develop-754ef4d2f0 → 0.4.5-develop-9f9549ebc8

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 (434) hide show
  1. package/dist/generated/entities/message/index.js +65 -0
  2. package/dist/generated/entities/message/index.js.map +7 -0
  3. package/dist/generated/entities/message_access_token/index.js +19 -0
  4. package/dist/generated/entities/message_access_token/index.js.map +7 -0
  5. package/dist/generated/entities/message_confirmation/index.js +21 -0
  6. package/dist/generated/entities/message_confirmation/index.js.map +7 -0
  7. package/dist/generated/entities/message_object/index.js +23 -0
  8. package/dist/generated/entities/message_object/index.js.map +7 -0
  9. package/dist/generated/entities/message_recipient/index.js +31 -0
  10. package/dist/generated/entities/message_recipient/index.js.map +7 -0
  11. package/dist/generated/entities.ids.generated.js +8 -0
  12. package/dist/generated/entities.ids.generated.js.map +2 -2
  13. package/dist/generated/entity-fields-registry.js +10 -0
  14. package/dist/generated/entity-fields-registry.js.map +2 -2
  15. package/dist/modules/auth/components/AclEditor.js +4 -2
  16. package/dist/modules/auth/components/AclEditor.js.map +2 -2
  17. package/dist/modules/auth/frontend/reset.js +3 -3
  18. package/dist/modules/auth/frontend/reset.js.map +2 -2
  19. package/dist/modules/customers/backend/customers/deals/[id]/page.js +27 -8
  20. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  21. package/dist/modules/customers/lib/messageObjectPreviews.js +131 -0
  22. package/dist/modules/customers/lib/messageObjectPreviews.js.map +7 -0
  23. package/dist/modules/customers/message-objects.js +71 -0
  24. package/dist/modules/customers/message-objects.js.map +7 -0
  25. package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js +51 -0
  26. package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js.map +7 -0
  27. package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js +35 -0
  28. package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js.map +7 -0
  29. package/dist/modules/customers/widgets/messages/index.js +7 -0
  30. package/dist/modules/customers/widgets/messages/index.js.map +7 -0
  31. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +35 -6
  32. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
  33. package/dist/modules/messages/acl.js +15 -0
  34. package/dist/modules/messages/acl.js.map +7 -0
  35. package/dist/modules/messages/api/[id]/actions/[actionId]/route.js +92 -0
  36. package/dist/modules/messages/api/[id]/actions/[actionId]/route.js.map +7 -0
  37. package/dist/modules/messages/api/[id]/archive/route.js +120 -0
  38. package/dist/modules/messages/api/[id]/archive/route.js.map +7 -0
  39. package/dist/modules/messages/api/[id]/attachments/route.js +195 -0
  40. package/dist/modules/messages/api/[id]/attachments/route.js.map +7 -0
  41. package/dist/modules/messages/api/[id]/confirmation/route.js +67 -0
  42. package/dist/modules/messages/api/[id]/confirmation/route.js.map +7 -0
  43. package/dist/modules/messages/api/[id]/conversation/archive/route.js +68 -0
  44. package/dist/modules/messages/api/[id]/conversation/archive/route.js.map +7 -0
  45. package/dist/modules/messages/api/[id]/conversation/read/route.js +68 -0
  46. package/dist/modules/messages/api/[id]/conversation/read/route.js.map +7 -0
  47. package/dist/modules/messages/api/[id]/conversation/route.js +68 -0
  48. package/dist/modules/messages/api/[id]/conversation/route.js.map +7 -0
  49. package/dist/modules/messages/api/[id]/forward/route.js +85 -0
  50. package/dist/modules/messages/api/[id]/forward/route.js.map +7 -0
  51. package/dist/modules/messages/api/[id]/forward-preview/route.js +70 -0
  52. package/dist/modules/messages/api/[id]/forward-preview/route.js.map +7 -0
  53. package/dist/modules/messages/api/[id]/read/route.js +120 -0
  54. package/dist/modules/messages/api/[id]/read/route.js.map +7 -0
  55. package/dist/modules/messages/api/[id]/reply/route.js +87 -0
  56. package/dist/modules/messages/api/[id]/reply/route.js.map +7 -0
  57. package/dist/modules/messages/api/[id]/route.js +350 -0
  58. package/dist/modules/messages/api/[id]/route.js.map +7 -0
  59. package/dist/modules/messages/api/object-types/route.js +54 -0
  60. package/dist/modules/messages/api/object-types/route.js.map +7 -0
  61. package/dist/modules/messages/api/openapi.js +261 -0
  62. package/dist/modules/messages/api/openapi.js.map +7 -0
  63. package/dist/modules/messages/api/route.js +262 -0
  64. package/dist/modules/messages/api/route.js.map +7 -0
  65. package/dist/modules/messages/api/token/[token]/route.js +99 -0
  66. package/dist/modules/messages/api/token/[token]/route.js.map +7 -0
  67. package/dist/modules/messages/api/types/route.js +40 -0
  68. package/dist/modules/messages/api/types/route.js.map +7 -0
  69. package/dist/modules/messages/api/unread-count/route.js +43 -0
  70. package/dist/modules/messages/api/unread-count/route.js.map +7 -0
  71. package/dist/modules/messages/backend/messages/[id]/page.js +10 -0
  72. package/dist/modules/messages/backend/messages/[id]/page.js.map +7 -0
  73. package/dist/modules/messages/backend/messages/[id]/page.meta.js +16 -0
  74. package/dist/modules/messages/backend/messages/[id]/page.meta.js.map +7 -0
  75. package/dist/modules/messages/backend/messages/compose/page.js +10 -0
  76. package/dist/modules/messages/backend/messages/compose/page.js.map +7 -0
  77. package/dist/modules/messages/backend/messages/compose/page.meta.js +17 -0
  78. package/dist/modules/messages/backend/messages/compose/page.meta.js.map +7 -0
  79. package/dist/modules/messages/backend/page.js +10 -0
  80. package/dist/modules/messages/backend/page.js.map +7 -0
  81. package/dist/modules/messages/backend/page.meta.js +33 -0
  82. package/dist/modules/messages/backend/page.meta.js.map +7 -0
  83. package/dist/modules/messages/commands/actions.js +265 -0
  84. package/dist/modules/messages/commands/actions.js.map +7 -0
  85. package/dist/modules/messages/commands/attachments.js +217 -0
  86. package/dist/modules/messages/commands/attachments.js.map +7 -0
  87. package/dist/modules/messages/commands/confirmations.js +151 -0
  88. package/dist/modules/messages/commands/confirmations.js.map +7 -0
  89. package/dist/modules/messages/commands/conversation.js +240 -0
  90. package/dist/modules/messages/commands/conversation.js.map +7 -0
  91. package/dist/modules/messages/commands/messages.js +748 -0
  92. package/dist/modules/messages/commands/messages.js.map +7 -0
  93. package/dist/modules/messages/commands/recipients.js +259 -0
  94. package/dist/modules/messages/commands/recipients.js.map +7 -0
  95. package/dist/modules/messages/commands/shared.js +258 -0
  96. package/dist/modules/messages/commands/shared.js.map +7 -0
  97. package/dist/modules/messages/commands/tokens.js +69 -0
  98. package/dist/modules/messages/commands/tokens.js.map +7 -0
  99. package/dist/modules/messages/components/ComposeMessagePageClient.js +24 -0
  100. package/dist/modules/messages/components/ComposeMessagePageClient.js.map +7 -0
  101. package/dist/modules/messages/components/MessageDetailPageClient.js +261 -0
  102. package/dist/modules/messages/components/MessageDetailPageClient.js.map +7 -0
  103. package/dist/modules/messages/components/MessagesInboxPageClient.js +390 -0
  104. package/dist/modules/messages/components/MessagesInboxPageClient.js.map +7 -0
  105. package/dist/modules/messages/components/confirmation/MessageConfirmationActions.js +31 -0
  106. package/dist/modules/messages/components/confirmation/MessageConfirmationActions.js.map +7 -0
  107. package/dist/modules/messages/components/confirmation/MessageConfirmationContent.js +69 -0
  108. package/dist/modules/messages/components/confirmation/MessageConfirmationContent.js.map +7 -0
  109. package/dist/modules/messages/components/defaults/DefaultMessageActions.js +31 -0
  110. package/dist/modules/messages/components/defaults/DefaultMessageActions.js.map +7 -0
  111. package/dist/modules/messages/components/defaults/DefaultMessageContent.js +19 -0
  112. package/dist/modules/messages/components/defaults/DefaultMessageContent.js.map +7 -0
  113. package/dist/modules/messages/components/defaults/DefaultMessageListItem.js +90 -0
  114. package/dist/modules/messages/components/defaults/DefaultMessageListItem.js.map +7 -0
  115. package/dist/modules/messages/components/defaults/MessageRecordObjectDetail.js +86 -0
  116. package/dist/modules/messages/components/defaults/MessageRecordObjectDetail.js.map +7 -0
  117. package/dist/modules/messages/components/defaults/MessageRecordObjectPreview.js +61 -0
  118. package/dist/modules/messages/components/defaults/MessageRecordObjectPreview.js.map +7 -0
  119. package/dist/modules/messages/components/message-detail/detail-panels.js +27 -0
  120. package/dist/modules/messages/components/message-detail/detail-panels.js.map +7 -0
  121. package/dist/modules/messages/components/message-detail/hooks/useMessageDetails.js +52 -0
  122. package/dist/modules/messages/components/message-detail/hooks/useMessageDetails.js.map +7 -0
  123. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsActions.js +289 -0
  124. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsActions.js.map +7 -0
  125. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js +103 -0
  126. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js.map +7 -0
  127. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.js +78 -0
  128. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.js.map +7 -0
  129. package/dist/modules/messages/components/message-detail/panels/MainMessageHeader.js +94 -0
  130. package/dist/modules/messages/components/message-detail/panels/MainMessageHeader.js.map +7 -0
  131. package/dist/modules/messages/components/message-detail/panels/MessageHeader.js +110 -0
  132. package/dist/modules/messages/components/message-detail/panels/MessageHeader.js.map +7 -0
  133. package/dist/modules/messages/components/message-detail/panels/MessageListComponent.js +58 -0
  134. package/dist/modules/messages/components/message-detail/panels/MessageListComponent.js.map +7 -0
  135. package/dist/modules/messages/components/message-detail/panels/actions-panel.js +51 -0
  136. package/dist/modules/messages/components/message-detail/panels/actions-panel.js.map +7 -0
  137. package/dist/modules/messages/components/message-detail/panels/attachments-panel.js +66 -0
  138. package/dist/modules/messages/components/message-detail/panels/attachments-panel.js.map +7 -0
  139. package/dist/modules/messages/components/message-detail/panels/body-panel.js +20 -0
  140. package/dist/modules/messages/components/message-detail/panels/body-panel.js.map +7 -0
  141. package/dist/modules/messages/components/message-detail/panels/composer-dialogs.js +36 -0
  142. package/dist/modules/messages/components/message-detail/panels/composer-dialogs.js.map +7 -0
  143. package/dist/modules/messages/components/message-detail/panels/dialogs.js +96 -0
  144. package/dist/modules/messages/components/message-detail/panels/dialogs.js.map +7 -0
  145. package/dist/modules/messages/components/message-detail/panels/index.js +25 -0
  146. package/dist/modules/messages/components/message-detail/panels/index.js.map +7 -0
  147. package/dist/modules/messages/components/message-detail/panels/meta-panel.js +14 -0
  148. package/dist/modules/messages/components/message-detail/panels/meta-panel.js.map +7 -0
  149. package/dist/modules/messages/components/message-detail/panels/objects-panel.js +51 -0
  150. package/dist/modules/messages/components/message-detail/panels/objects-panel.js.map +7 -0
  151. package/dist/modules/messages/components/message-detail/panels/thread-panel.js +54 -0
  152. package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +7 -0
  153. package/dist/modules/messages/components/message-detail/types.js +1 -0
  154. package/dist/modules/messages/components/message-detail/types.js.map +7 -0
  155. package/dist/modules/messages/components/message-detail/utils.js +54 -0
  156. package/dist/modules/messages/components/message-detail/utils.js.map +7 -0
  157. package/dist/modules/messages/components/utils/PriorityBadge.js +52 -0
  158. package/dist/modules/messages/components/utils/PriorityBadge.js.map +7 -0
  159. package/dist/modules/messages/components/utils/typeUiRegistry.js +77 -0
  160. package/dist/modules/messages/components/utils/typeUiRegistry.js.map +7 -0
  161. package/dist/modules/messages/data/entities.js +309 -0
  162. package/dist/modules/messages/data/entities.js.map +7 -0
  163. package/dist/modules/messages/data/validators.js +272 -0
  164. package/dist/modules/messages/data/validators.js.map +7 -0
  165. package/dist/modules/messages/emails/MessageEmail.js +108 -0
  166. package/dist/modules/messages/emails/MessageEmail.js.map +7 -0
  167. package/dist/modules/messages/events.js +24 -0
  168. package/dist/modules/messages/events.js.map +7 -0
  169. package/dist/modules/messages/frontend/messages/view/[token]/page.js +247 -0
  170. package/dist/modules/messages/frontend/messages/view/[token]/page.js.map +7 -0
  171. package/dist/modules/messages/frontend/messages/view/[token]/page.meta.js +9 -0
  172. package/dist/modules/messages/frontend/messages/view/[token]/page.meta.js.map +7 -0
  173. package/dist/modules/messages/index.js +21 -0
  174. package/dist/modules/messages/index.js.map +7 -0
  175. package/dist/modules/messages/lib/actions.js +141 -0
  176. package/dist/modules/messages/lib/actions.js.map +7 -0
  177. package/dist/modules/messages/lib/attachments.js +131 -0
  178. package/dist/modules/messages/lib/attachments.js.map +7 -0
  179. package/dist/modules/messages/lib/constants.js +7 -0
  180. package/dist/modules/messages/lib/constants.js.map +7 -0
  181. package/dist/modules/messages/lib/email-sender.js +201 -0
  182. package/dist/modules/messages/lib/email-sender.js.map +7 -0
  183. package/dist/modules/messages/lib/forwarding.js +179 -0
  184. package/dist/modules/messages/lib/forwarding.js.map +7 -0
  185. package/dist/modules/messages/lib/message-objects-registry.js +49 -0
  186. package/dist/modules/messages/lib/message-objects-registry.js.map +7 -0
  187. package/dist/modules/messages/lib/message-types-registry.js +41 -0
  188. package/dist/modules/messages/lib/message-types-registry.js.map +7 -0
  189. package/dist/modules/messages/lib/object-validation.js +20 -0
  190. package/dist/modules/messages/lib/object-validation.js.map +7 -0
  191. package/dist/modules/messages/lib/operationMetadata.js +21 -0
  192. package/dist/modules/messages/lib/operationMetadata.js.map +7 -0
  193. package/dist/modules/messages/lib/priorityUtils.js +61 -0
  194. package/dist/modules/messages/lib/priorityUtils.js.map +7 -0
  195. package/dist/modules/messages/lib/routeHelpers.js +44 -0
  196. package/dist/modules/messages/lib/routeHelpers.js.map +7 -0
  197. package/dist/modules/messages/message-objects.js +7 -0
  198. package/dist/modules/messages/message-objects.js.map +7 -0
  199. package/dist/modules/messages/message-types.js +67 -0
  200. package/dist/modules/messages/message-types.js.map +7 -0
  201. package/dist/modules/messages/migrations/Migration20260213181243.js +31 -0
  202. package/dist/modules/messages/migrations/Migration20260213181243.js.map +7 -0
  203. package/dist/modules/messages/migrations/Migration20260215165126.js +16 -0
  204. package/dist/modules/messages/migrations/Migration20260215165126.js.map +7 -0
  205. package/dist/modules/messages/notifications.js +27 -0
  206. package/dist/modules/messages/notifications.js.map +7 -0
  207. package/dist/modules/messages/setup.js +21 -0
  208. package/dist/modules/messages/setup.js.map +7 -0
  209. package/dist/modules/messages/subscribers/message-notification.js +108 -0
  210. package/dist/modules/messages/subscribers/message-notification.js.map +7 -0
  211. package/dist/modules/messages/workers/send-email.worker.js +253 -0
  212. package/dist/modules/messages/workers/send-email.worker.js.map +7 -0
  213. package/dist/modules/sales/backend/sales/documents/[id]/page.js +30 -11
  214. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  215. package/dist/modules/sales/commands/payments.js +12 -6
  216. package/dist/modules/sales/commands/payments.js.map +2 -2
  217. package/dist/modules/sales/lib/messageObjectPreviews.js +114 -0
  218. package/dist/modules/sales/lib/messageObjectPreviews.js.map +7 -0
  219. package/dist/modules/sales/message-objects.js +57 -0
  220. package/dist/modules/sales/message-objects.js.map +7 -0
  221. package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js +51 -0
  222. package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js.map +7 -0
  223. package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js +36 -0
  224. package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js.map +7 -0
  225. package/dist/modules/sales/widgets/messages/index.js +7 -0
  226. package/dist/modules/sales/widgets/messages/index.js.map +7 -0
  227. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +55 -1
  228. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
  229. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +60 -1
  230. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
  231. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +2 -19
  232. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  233. package/dist/modules/staff/components/LeaveRequestDetail.js +112 -0
  234. package/dist/modules/staff/components/LeaveRequestDetail.js.map +7 -0
  235. package/dist/modules/staff/components/LeaveRequestForm.js +3 -1
  236. package/dist/modules/staff/components/LeaveRequestForm.js.map +2 -2
  237. package/dist/modules/staff/components/LeaveRequestPreview.js +43 -0
  238. package/dist/modules/staff/components/LeaveRequestPreview.js.map +7 -0
  239. package/dist/modules/staff/lib/messageObjectPreviews.js +148 -0
  240. package/dist/modules/staff/lib/messageObjectPreviews.js.map +7 -0
  241. package/dist/modules/staff/message-objects.js +104 -0
  242. package/dist/modules/staff/message-objects.js.map +7 -0
  243. package/dist/modules/staff/message-types.js +23 -0
  244. package/dist/modules/staff/message-types.js.map +7 -0
  245. package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js +51 -0
  246. package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js.map +7 -0
  247. package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js +34 -0
  248. package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js.map +7 -0
  249. package/dist/modules/staff/widgets/messages/index.js +7 -0
  250. package/dist/modules/staff/widgets/messages/index.js.map +7 -0
  251. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +6 -6
  252. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  253. package/generated/entities/message/index.ts +31 -0
  254. package/generated/entities/message_access_token/index.ts +8 -0
  255. package/generated/entities/message_confirmation/index.ts +9 -0
  256. package/generated/entities/message_object/index.ts +10 -0
  257. package/generated/entities/message_recipient/index.ts +14 -0
  258. package/generated/entities.ids.generated.ts +8 -0
  259. package/generated/entity-fields-registry.ts +10 -0
  260. package/jest.setup.ts +5 -0
  261. package/package.json +2 -2
  262. package/src/modules/attachments/i18n/de.json +4 -0
  263. package/src/modules/attachments/i18n/en.json +4 -0
  264. package/src/modules/attachments/i18n/es.json +4 -0
  265. package/src/modules/attachments/i18n/pl.json +4 -0
  266. package/src/modules/auth/components/AclEditor.tsx +4 -2
  267. package/src/modules/auth/frontend/reset.tsx +3 -3
  268. package/src/modules/auth/i18n/de.json +5 -0
  269. package/src/modules/auth/i18n/en.json +5 -0
  270. package/src/modules/auth/i18n/es.json +5 -0
  271. package/src/modules/auth/i18n/pl.json +5 -0
  272. package/src/modules/catalog/i18n/de.json +21 -0
  273. package/src/modules/catalog/i18n/en.json +21 -0
  274. package/src/modules/catalog/i18n/es.json +21 -0
  275. package/src/modules/catalog/i18n/pl.json +21 -0
  276. package/src/modules/currencies/i18n/de.json +6 -0
  277. package/src/modules/currencies/i18n/en.json +6 -0
  278. package/src/modules/currencies/i18n/es.json +6 -0
  279. package/src/modules/currencies/i18n/pl.json +6 -0
  280. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +20 -4
  281. package/src/modules/customers/i18n/de.json +26 -1
  282. package/src/modules/customers/i18n/en.json +25 -0
  283. package/src/modules/customers/i18n/es.json +25 -0
  284. package/src/modules/customers/i18n/pl.json +25 -0
  285. package/src/modules/customers/lib/messageObjectPreviews.ts +154 -0
  286. package/src/modules/customers/message-objects.ts +70 -0
  287. package/src/modules/customers/widgets/messages/CustomerMessageObjectDetail.tsx +57 -0
  288. package/src/modules/customers/widgets/messages/CustomerMessageObjectPreview.tsx +49 -0
  289. package/src/modules/customers/widgets/messages/index.ts +2 -0
  290. package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +41 -5
  291. package/src/modules/dashboards/i18n/de.json +5 -1
  292. package/src/modules/dashboards/i18n/en.json +5 -1
  293. package/src/modules/dashboards/i18n/es.json +5 -1
  294. package/src/modules/dashboards/i18n/pl.json +5 -1
  295. package/src/modules/dictionaries/i18n/de.json +14 -1
  296. package/src/modules/dictionaries/i18n/en.json +14 -1
  297. package/src/modules/dictionaries/i18n/es.json +14 -1
  298. package/src/modules/dictionaries/i18n/pl.json +14 -1
  299. package/src/modules/feature_toggles/i18n/de.json +3 -0
  300. package/src/modules/feature_toggles/i18n/en.json +3 -0
  301. package/src/modules/feature_toggles/i18n/es.json +3 -0
  302. package/src/modules/feature_toggles/i18n/pl.json +3 -0
  303. package/src/modules/messages/acl.ts +11 -0
  304. package/src/modules/messages/api/[id]/actions/[actionId]/route.ts +103 -0
  305. package/src/modules/messages/api/[id]/archive/route.ts +138 -0
  306. package/src/modules/messages/api/[id]/attachments/route.ts +217 -0
  307. package/src/modules/messages/api/[id]/confirmation/route.ts +73 -0
  308. package/src/modules/messages/api/[id]/conversation/archive/route.ts +69 -0
  309. package/src/modules/messages/api/[id]/conversation/read/route.ts +69 -0
  310. package/src/modules/messages/api/[id]/conversation/route.ts +69 -0
  311. package/src/modules/messages/api/[id]/forward/route.ts +87 -0
  312. package/src/modules/messages/api/[id]/forward-preview/route.ts +75 -0
  313. package/src/modules/messages/api/[id]/read/route.ts +138 -0
  314. package/src/modules/messages/api/[id]/reply/route.ts +89 -0
  315. package/src/modules/messages/api/[id]/route.ts +401 -0
  316. package/src/modules/messages/api/object-types/route.ts +54 -0
  317. package/src/modules/messages/api/openapi.ts +261 -0
  318. package/src/modules/messages/api/route.ts +374 -0
  319. package/src/modules/messages/api/token/[token]/route.ts +103 -0
  320. package/src/modules/messages/api/types/route.ts +39 -0
  321. package/src/modules/messages/api/unread-count/route.ts +55 -0
  322. package/src/modules/messages/backend/messages/[id]/page.meta.ts +12 -0
  323. package/src/modules/messages/backend/messages/[id]/page.tsx +12 -0
  324. package/src/modules/messages/backend/messages/compose/page.meta.ts +13 -0
  325. package/src/modules/messages/backend/messages/compose/page.tsx +12 -0
  326. package/src/modules/messages/backend/page.meta.ts +31 -0
  327. package/src/modules/messages/backend/page.tsx +12 -0
  328. package/src/modules/messages/commands/actions.ts +307 -0
  329. package/src/modules/messages/commands/attachments.ts +227 -0
  330. package/src/modules/messages/commands/confirmations.ts +183 -0
  331. package/src/modules/messages/commands/conversation.ts +292 -0
  332. package/src/modules/messages/commands/messages.ts +845 -0
  333. package/src/modules/messages/commands/recipients.ts +281 -0
  334. package/src/modules/messages/commands/shared.ts +350 -0
  335. package/src/modules/messages/commands/tokens.ts +80 -0
  336. package/src/modules/messages/components/ComposeMessagePageClient.tsx +23 -0
  337. package/src/modules/messages/components/MessageDetailPageClient.tsx +287 -0
  338. package/src/modules/messages/components/MessagesInboxPageClient.tsx +469 -0
  339. package/src/modules/messages/components/confirmation/MessageConfirmationActions.tsx +35 -0
  340. package/src/modules/messages/components/confirmation/MessageConfirmationContent.tsx +88 -0
  341. package/src/modules/messages/components/defaults/DefaultMessageActions.tsx +37 -0
  342. package/src/modules/messages/components/defaults/DefaultMessageContent.tsx +21 -0
  343. package/src/modules/messages/components/defaults/DefaultMessageListItem.tsx +102 -0
  344. package/src/modules/messages/components/defaults/MessageRecordObjectDetail.tsx +114 -0
  345. package/src/modules/messages/components/defaults/MessageRecordObjectPreview.tsx +74 -0
  346. package/src/modules/messages/components/message-detail/detail-panels.ts +13 -0
  347. package/src/modules/messages/components/message-detail/hooks/useMessageDetails.ts +56 -0
  348. package/src/modules/messages/components/message-detail/hooks/useMessageDetailsActions.ts +367 -0
  349. package/src/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.ts +134 -0
  350. package/src/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.ts +102 -0
  351. package/src/modules/messages/components/message-detail/panels/MainMessageHeader.tsx +108 -0
  352. package/src/modules/messages/components/message-detail/panels/MessageHeader.tsx +144 -0
  353. package/src/modules/messages/components/message-detail/panels/MessageListComponent.tsx +63 -0
  354. package/src/modules/messages/components/message-detail/panels/actions-panel.tsx +66 -0
  355. package/src/modules/messages/components/message-detail/panels/attachments-panel.tsx +86 -0
  356. package/src/modules/messages/components/message-detail/panels/body-panel.tsx +32 -0
  357. package/src/modules/messages/components/message-detail/panels/composer-dialogs.tsx +42 -0
  358. package/src/modules/messages/components/message-detail/panels/dialogs.tsx +107 -0
  359. package/src/modules/messages/components/message-detail/panels/index.ts +11 -0
  360. package/src/modules/messages/components/message-detail/panels/meta-panel.tsx +19 -0
  361. package/src/modules/messages/components/message-detail/panels/objects-panel.tsx +65 -0
  362. package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +65 -0
  363. package/src/modules/messages/components/message-detail/types.ts +114 -0
  364. package/src/modules/messages/components/message-detail/utils.ts +62 -0
  365. package/src/modules/messages/components/utils/PriorityBadge.tsx +63 -0
  366. package/src/modules/messages/components/utils/typeUiRegistry.ts +106 -0
  367. package/src/modules/messages/data/entities.ts +284 -0
  368. package/src/modules/messages/data/validators.ts +297 -0
  369. package/src/modules/messages/emails/MessageEmail.tsx +143 -0
  370. package/src/modules/messages/events.ts +24 -0
  371. package/src/modules/messages/frontend/messages/view/[token]/page.meta.ts +5 -0
  372. package/src/modules/messages/frontend/messages/view/[token]/page.tsx +389 -0
  373. package/src/modules/messages/i18n/de.json +240 -0
  374. package/src/modules/messages/i18n/en.json +240 -0
  375. package/src/modules/messages/i18n/es.json +240 -0
  376. package/src/modules/messages/i18n/pl.json +240 -0
  377. package/src/modules/messages/index.ts +19 -0
  378. package/src/modules/messages/lib/actions.ts +204 -0
  379. package/src/modules/messages/lib/attachments.ts +197 -0
  380. package/src/modules/messages/lib/constants.ts +2 -0
  381. package/src/modules/messages/lib/email-sender.ts +255 -0
  382. package/src/modules/messages/lib/forwarding.ts +240 -0
  383. package/src/modules/messages/lib/message-objects-registry.ts +60 -0
  384. package/src/modules/messages/lib/message-types-registry.ts +48 -0
  385. package/src/modules/messages/lib/object-validation.ts +26 -0
  386. package/src/modules/messages/lib/operationMetadata.ts +43 -0
  387. package/src/modules/messages/lib/priorityUtils.ts +76 -0
  388. package/src/modules/messages/lib/routeHelpers.ts +65 -0
  389. package/src/modules/messages/message-objects.ts +5 -0
  390. package/src/modules/messages/message-types.ts +65 -0
  391. package/src/modules/messages/migrations/.snapshot-open-mercato.json +957 -0
  392. package/src/modules/messages/migrations/Migration20260213181243.ts +34 -0
  393. package/src/modules/messages/migrations/Migration20260215165126.ts +16 -0
  394. package/src/modules/messages/notifications.ts +25 -0
  395. package/src/modules/messages/setup.ts +19 -0
  396. package/src/modules/messages/subscribers/message-notification.ts +138 -0
  397. package/src/modules/messages/workers/send-email.worker.ts +321 -0
  398. package/src/modules/query_index/i18n/es.json +2 -2
  399. package/src/modules/resources/i18n/de.json +57 -0
  400. package/src/modules/resources/i18n/en.json +57 -0
  401. package/src/modules/resources/i18n/es.json +57 -0
  402. package/src/modules/resources/i18n/pl.json +57 -0
  403. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +23 -7
  404. package/src/modules/sales/commands/payments.ts +12 -6
  405. package/src/modules/sales/i18n/de.json +26 -0
  406. package/src/modules/sales/i18n/en.json +26 -0
  407. package/src/modules/sales/i18n/es.json +26 -0
  408. package/src/modules/sales/i18n/pl.json +26 -0
  409. package/src/modules/sales/lib/messageObjectPreviews.ts +150 -0
  410. package/src/modules/sales/message-objects.ts +56 -0
  411. package/src/modules/sales/widgets/messages/SalesDocumentMessageDetail.tsx +57 -0
  412. package/src/modules/sales/widgets/messages/SalesDocumentMessagePreview.tsx +46 -0
  413. package/src/modules/sales/widgets/messages/index.ts +2 -0
  414. package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +54 -0
  415. package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +58 -0
  416. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +2 -32
  417. package/src/modules/staff/components/LeaveRequestDetail.tsx +135 -0
  418. package/src/modules/staff/components/LeaveRequestForm.tsx +3 -0
  419. package/src/modules/staff/components/LeaveRequestPreview.tsx +74 -0
  420. package/src/modules/staff/i18n/de.json +22 -0
  421. package/src/modules/staff/i18n/en.json +22 -0
  422. package/src/modules/staff/i18n/es.json +22 -0
  423. package/src/modules/staff/i18n/pl.json +22 -0
  424. package/src/modules/staff/lib/messageObjectPreviews.ts +182 -0
  425. package/src/modules/staff/message-objects.ts +102 -0
  426. package/src/modules/staff/message-types.ts +21 -0
  427. package/src/modules/staff/widgets/messages/StaffMessageObjectDetail.tsx +57 -0
  428. package/src/modules/staff/widgets/messages/StaffMessageObjectPreview.tsx +44 -0
  429. package/src/modules/staff/widgets/messages/index.ts +2 -0
  430. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +6 -6
  431. package/src/modules/workflows/i18n/de.json +41 -0
  432. package/src/modules/workflows/i18n/en.json +41 -0
  433. package/src/modules/workflows/i18n/es.json +41 -0
  434. package/src/modules/workflows/i18n/pl.json +41 -0
@@ -0,0 +1,261 @@
1
+ import { z } from 'zod'
2
+ import {
3
+ attachmentIdsPayloadSchema,
4
+ composeMessageSchema,
5
+ executeActionSchema,
6
+ forwardMessageSchema,
7
+ listMessagesSchema,
8
+ messageObjectTypesQuerySchema,
9
+ messageActionDataSchema,
10
+ messageActionSchema,
11
+ messageObjectSchema,
12
+ messageRecipientSchema,
13
+ replyMessageSchema,
14
+ unlinkAttachmentPayloadSchema,
15
+ updateDraftSchema,
16
+ } from '../data/validators'
17
+
18
+ export const messageAttachmentSchema = z.object({
19
+ id: z.string().uuid(),
20
+ fileName: z.string(),
21
+ fileSize: z.number(),
22
+ mimeType: z.string(),
23
+ url: z.string(),
24
+ })
25
+
26
+ export const messageListItemSchema = z.object({
27
+ id: z.string().uuid(),
28
+ type: z.string(),
29
+ visibility: z.enum(['public', 'internal']).nullable().optional(),
30
+ sourceEntityType: z.string().nullable().optional(),
31
+ sourceEntityId: z.string().uuid().nullable().optional(),
32
+ externalEmail: z.string().nullable().optional(),
33
+ externalName: z.string().nullable().optional(),
34
+ subject: z.string(),
35
+ bodyPreview: z.string(),
36
+ senderUserId: z.string().uuid(),
37
+ senderName: z.string().nullable().optional(),
38
+ senderEmail: z.string().nullable().optional(),
39
+ priority: z.string(),
40
+ status: z.string(),
41
+ hasObjects: z.boolean(),
42
+ objectCount: z.number(),
43
+ hasAttachments: z.boolean(),
44
+ attachmentCount: z.number(),
45
+ recipientCount: z.number(),
46
+ hasActions: z.boolean(),
47
+ actionTaken: z.string().nullable().optional(),
48
+ sentAt: z.string().nullable().optional(),
49
+ readAt: z.string().nullable().optional(),
50
+ threadId: z.string().uuid().nullable().optional(),
51
+ })
52
+
53
+ export const messageThreadItemSchema = z.object({
54
+ id: z.string().uuid(),
55
+ senderUserId: z.string().uuid(),
56
+ senderName: z.string().nullable().optional(),
57
+ senderEmail: z.string().nullable().optional(),
58
+ body: z.string(),
59
+ bodyFormat: z.enum(['text', 'markdown']).optional(),
60
+ sentAt: z.string().nullable().optional(),
61
+ })
62
+
63
+ export const messageDetailResponseSchema = z.object({
64
+ id: z.string().uuid(),
65
+ type: z.string(),
66
+ isDraft: z.boolean(),
67
+ canEditDraft: z.boolean(),
68
+ visibility: z.enum(['public', 'internal']).nullable().optional(),
69
+ sourceEntityType: z.string().nullable().optional(),
70
+ sourceEntityId: z.string().uuid().nullable().optional(),
71
+ externalEmail: z.string().nullable().optional(),
72
+ externalName: z.string().nullable().optional(),
73
+ typeDefinition: z.object({
74
+ labelKey: z.string(),
75
+ icon: z.string(),
76
+ color: z.string().optional().nullable(),
77
+ allowReply: z.boolean(),
78
+ allowForward: z.boolean(),
79
+ ui: z.object({
80
+ listItemComponent: z.string().nullable().optional(),
81
+ contentComponent: z.string().nullable().optional(),
82
+ actionsComponent: z.string().nullable().optional(),
83
+ }).nullable().optional(),
84
+ }),
85
+ threadId: z.string().uuid().nullable().optional(),
86
+ parentMessageId: z.string().uuid().nullable().optional(),
87
+ senderUserId: z.string().uuid(),
88
+ senderName: z.string().nullable().optional(),
89
+ senderEmail: z.string().nullable().optional(),
90
+ subject: z.string(),
91
+ body: z.string(),
92
+ bodyFormat: z.enum(['text', 'markdown']),
93
+ priority: z.string(),
94
+ sentAt: z.string().nullable().optional(),
95
+ actionData: messageActionDataSchema.optional().nullable(),
96
+ actionTaken: z.string().nullable().optional(),
97
+ actionTakenAt: z.string().nullable().optional(),
98
+ actionTakenByUserId: z.string().uuid().nullable().optional(),
99
+ recipients: z.array(z.object({
100
+ userId: z.string().uuid(),
101
+ type: z.enum(['to', 'cc', 'bcc']),
102
+ status: z.string(),
103
+ readAt: z.string().nullable().optional(),
104
+ })),
105
+ objects: z.array(z.object({
106
+ id: z.string().uuid(),
107
+ entityModule: z.string(),
108
+ entityType: z.string(),
109
+ entityId: z.string().uuid(),
110
+ actionRequired: z.boolean(),
111
+ actionType: z.string().nullable().optional(),
112
+ actionLabel: z.string().nullable().optional(),
113
+ snapshot: z.record(z.string(), z.unknown()).nullable().optional(),
114
+ preview: z.object({
115
+ title: z.string(),
116
+ subtitle: z.string().optional(),
117
+ status: z.string().optional(),
118
+ statusColor: z.string().optional(),
119
+ metadata: z.record(z.string(), z.string()).optional(),
120
+ }).nullable().optional(),
121
+ })),
122
+ thread: z.array(messageThreadItemSchema),
123
+ isRead: z.boolean(),
124
+ })
125
+
126
+ export const messageTokenResponseSchema = z.object({
127
+ id: z.string().uuid(),
128
+ type: z.string(),
129
+ subject: z.string(),
130
+ body: z.string(),
131
+ bodyFormat: z.enum(['text', 'markdown']),
132
+ priority: z.enum(['low', 'normal', 'high', 'urgent']),
133
+ senderUserId: z.string().uuid(),
134
+ sentAt: z.string().nullable().optional(),
135
+ actionData: messageActionDataSchema.optional().nullable(),
136
+ actionTaken: z.string().nullable().optional(),
137
+ actionTakenAt: z.string().nullable().optional(),
138
+ actionTakenByUserId: z.string().uuid().nullable().optional(),
139
+ objects: z.array(z.object({
140
+ id: z.string().uuid(),
141
+ entityModule: z.string(),
142
+ entityType: z.string(),
143
+ entityId: z.string().uuid(),
144
+ actionRequired: z.boolean(),
145
+ actionType: z.string().nullable().optional(),
146
+ actionLabel: z.string().nullable().optional(),
147
+ snapshot: z.record(z.string(), z.unknown()).nullable().optional(),
148
+ })),
149
+ requiresAuth: z.boolean(),
150
+ recipientUserId: z.string().uuid(),
151
+ })
152
+
153
+ export const unreadCountResponseSchema = z.object({
154
+ unreadCount: z.number(),
155
+ })
156
+
157
+ export const messageConfirmationResponseSchema = z.object({
158
+ messageId: z.string().uuid(),
159
+ confirmed: z.boolean(),
160
+ confirmedAt: z.string().nullable(),
161
+ confirmedByUserId: z.string().uuid().nullable(),
162
+ })
163
+
164
+ export const actionResultResponseSchema = z.object({
165
+ ok: z.boolean(),
166
+ actionId: z.string(),
167
+ result: z.record(z.string(), z.unknown()).optional(),
168
+ })
169
+
170
+ export const forwardResponseSchema = z.object({
171
+ id: z.string().uuid(),
172
+ })
173
+
174
+ export const forwardPreviewResponseSchema = z.object({
175
+ subject: z.string(),
176
+ body: z.string(),
177
+ })
178
+
179
+ export const conversationMutationResponseSchema = z.object({
180
+ ok: z.boolean(),
181
+ affectedCount: z.number().int().min(0),
182
+ })
183
+
184
+ export const composeResponseSchema = z.object({
185
+ id: z.string().uuid(),
186
+ threadId: z.string().uuid().nullable().optional(),
187
+ })
188
+
189
+ export const messageAttachmentResponseSchema = z.object({
190
+ attachments: z.array(messageAttachmentSchema),
191
+ })
192
+
193
+ export const okResponseSchema = z.object({
194
+ ok: z.boolean(),
195
+ id: z.string().uuid().optional(),
196
+ message: z.string().optional(),
197
+ })
198
+
199
+ export const errorResponseSchema = z.object({
200
+ error: z.string(),
201
+ })
202
+
203
+ export const messageTypeResponseItemSchema = z.object({
204
+ type: z.string(),
205
+ module: z.string(),
206
+ labelKey: z.string(),
207
+ icon: z.string(),
208
+ color: z.string().nullable().optional(),
209
+ allowReply: z.boolean(),
210
+ allowForward: z.boolean(),
211
+ actionsExpireAfterHours: z.number().int().nullable().optional(),
212
+ ui: z.object({
213
+ listItemComponent: z.string().nullable().optional(),
214
+ contentComponent: z.string().nullable().optional(),
215
+ actionsComponent: z.string().nullable().optional(),
216
+ }).nullable().optional(),
217
+ })
218
+
219
+ export const messageTypeListResponseSchema = z.object({
220
+ items: z.array(messageTypeResponseItemSchema),
221
+ })
222
+
223
+ export const messageObjectTypeActionResponseSchema = z.object({
224
+ id: z.string(),
225
+ labelKey: z.string(),
226
+ variant: z.enum(['default', 'secondary', 'destructive', 'outline']).optional(),
227
+ icon: z.string().optional(),
228
+ commandId: z.string().optional(),
229
+ href: z.string().optional(),
230
+ isTerminal: z.boolean().optional(),
231
+ confirmRequired: z.boolean().optional(),
232
+ confirmMessage: z.string().optional(),
233
+ })
234
+
235
+ export const messageObjectTypeResponseItemSchema = z.object({
236
+ module: z.string(),
237
+ entityType: z.string(),
238
+ labelKey: z.string(),
239
+ icon: z.string(),
240
+ actions: z.array(messageObjectTypeActionResponseSchema),
241
+ })
242
+
243
+ export const messageObjectTypeListResponseSchema = z.object({
244
+ items: z.array(messageObjectTypeResponseItemSchema),
245
+ })
246
+
247
+ export {
248
+ messageActionDataSchema,
249
+ messageActionSchema,
250
+ messageObjectSchema,
251
+ messageRecipientSchema,
252
+ composeMessageSchema,
253
+ listMessagesSchema,
254
+ forwardMessageSchema,
255
+ replyMessageSchema,
256
+ updateDraftSchema,
257
+ executeActionSchema,
258
+ messageObjectTypesQuerySchema,
259
+ attachmentIdsPayloadSchema,
260
+ unlinkAttachmentPayloadSchema,
261
+ }
@@ -0,0 +1,374 @@
1
+ import { z } from 'zod'
2
+ import type { EntityManager } from '@mikro-orm/postgresql'
3
+ import type { Knex } from 'knex'
4
+ import type { CommandBus } from '@open-mercato/shared/lib/commands/command-bus'
5
+ import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi/types'
6
+ import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
7
+ import { User } from '../../auth/data/entities'
8
+ import { MessageObject } from '../data/entities'
9
+ import { composeMessageSchema, listMessagesSchema } from '../data/validators'
10
+ import { MESSAGE_ATTACHMENT_ENTITY_ID } from '../lib/constants'
11
+ import { getMessageType } from '../lib/message-types-registry'
12
+ import { validateMessageObjectsForType } from '../lib/object-validation'
13
+ import { attachOperationMetadataHeader } from '../lib/operationMetadata'
14
+ import { canUseMessageEmailFeature, resolveMessageContext } from '../lib/routeHelpers'
15
+ import { MessageCommandExecuteResult } from '../commands/shared'
16
+ import {
17
+ composeMessageSchema as composeSchema,
18
+ composeResponseSchema,
19
+ listMessagesSchema as listSchema,
20
+ messageListItemSchema,
21
+ } from './openapi'
22
+
23
+ type MessageCommandExecuteResultWithThreadId = MessageCommandExecuteResult & {
24
+ threadId: string
25
+ }
26
+
27
+ function getKnex(em: EntityManager): Knex {
28
+ return (em.getConnection() as unknown as { getKnex: () => Knex }).getKnex()
29
+ }
30
+
31
+ type MessageListRow = {
32
+ id: string
33
+ type: string
34
+ visibility: 'public' | 'internal' | null
35
+ source_entity_type: string | null
36
+ source_entity_id: string | null
37
+ external_email: string | null
38
+ external_name: string | null
39
+ subject: string
40
+ body: string
41
+ sender_user_id: string
42
+ priority: string
43
+ recipient_status: string | null
44
+ is_draft: boolean
45
+ action_data: { actions?: unknown[] } | null
46
+ action_taken: string | null
47
+ sent_at: string | null
48
+ read_at: string | null
49
+ thread_id: string | null
50
+ }
51
+
52
+ type AttachmentCountRow = {
53
+ record_id: string
54
+ count: string | number
55
+ }
56
+
57
+ type RecipientCountRow = {
58
+ message_id: string
59
+ count: string | number
60
+ }
61
+
62
+ export const metadata = {
63
+ GET: { requireAuth: true, requireFeatures: ['messages.view'] },
64
+ POST: { requireAuth: true, requireFeatures: ['messages.compose'] },
65
+ }
66
+
67
+ export async function GET(req: Request) {
68
+ const { ctx, scope } = await resolveMessageContext(req)
69
+ const em = ctx.container.resolve('em') as EntityManager
70
+ const url = new URL(req.url)
71
+ const params = Object.fromEntries(url.searchParams)
72
+ const input = listMessagesSchema.parse(params)
73
+ const knex = getKnex(em)
74
+
75
+ let query = knex('messages as m')
76
+ .where('m.tenant_id', scope.tenantId)
77
+ .whereNull('m.deleted_at')
78
+
79
+ if (scope.organizationId) {
80
+ query = query.where('m.organization_id', scope.organizationId)
81
+ } else {
82
+ query = query.whereNull('m.organization_id')
83
+ }
84
+
85
+ const joinRecipient = () => {
86
+ query = query.leftJoin('message_recipients as r', function () {
87
+ this.on('m.id', '=', 'r.message_id').andOn('r.recipient_user_id', '=', knex.raw('?', [scope.userId]))
88
+ })
89
+ }
90
+
91
+ switch (input.folder) {
92
+ case 'inbox':
93
+ joinRecipient()
94
+ query = query
95
+ .whereNotNull('r.message_id')
96
+ .whereNull('r.deleted_at')
97
+ .whereNull('r.archived_at')
98
+ .where('m.is_draft', false)
99
+ break
100
+ case 'archived':
101
+ joinRecipient()
102
+ query = query
103
+ .whereNotNull('r.message_id')
104
+ .whereNull('r.deleted_at')
105
+ .whereNotNull('r.archived_at')
106
+ break
107
+ case 'sent':
108
+ query = query
109
+ .where('m.sender_user_id', scope.userId)
110
+ .where('m.is_draft', false)
111
+ joinRecipient()
112
+ break
113
+ case 'drafts':
114
+ query = query
115
+ .where('m.sender_user_id', scope.userId)
116
+ .where('m.is_draft', true)
117
+ joinRecipient()
118
+ break
119
+ case 'all':
120
+ joinRecipient()
121
+ query = query.where(function () {
122
+ this.where('m.sender_user_id', scope.userId).orWhereNotNull('r.message_id')
123
+ })
124
+ break
125
+ default: {
126
+ const unsupportedFolder: never = input.folder
127
+ throw new Error(`Unsupported folder: ${String(unsupportedFolder)}`)
128
+ }
129
+ }
130
+
131
+ if (input.status) {
132
+ query = query.where('r.status', input.status)
133
+ }
134
+
135
+ if (input.type) {
136
+ query = query.where('m.type', input.type)
137
+ }
138
+
139
+ if (input.visibility) {
140
+ query = query.where('m.visibility', input.visibility)
141
+ }
142
+
143
+ if (input.sourceEntityType) {
144
+ query = query.where('m.source_entity_type', input.sourceEntityType)
145
+ }
146
+
147
+ if (input.sourceEntityId) {
148
+ query = query.where('m.source_entity_id', input.sourceEntityId)
149
+ }
150
+
151
+ if (input.externalEmail) {
152
+ query = query.whereILike('m.external_email', `%${input.externalEmail}%`)
153
+ }
154
+
155
+ if (input.senderId) {
156
+ query = query.where('m.sender_user_id', input.senderId)
157
+ }
158
+
159
+ if (input.search) {
160
+ query = query.where(function () {
161
+ this.whereILike('m.subject', `%${input.search}%`).orWhereILike('m.body', `%${input.search}%`)
162
+ })
163
+ }
164
+
165
+ if (input.since) {
166
+ query = query.where('m.sent_at', '>', new Date(input.since))
167
+ }
168
+
169
+ if (input.hasObjects !== undefined) {
170
+ const subquery = knex('message_objects').select(1).whereRaw('message_objects.message_id = m.id')
171
+ query = input.hasObjects ? query.whereExists(subquery) : query.whereNotExists(subquery)
172
+ }
173
+
174
+ if (input.hasAttachments !== undefined) {
175
+ const subquery = knex('attachments')
176
+ .select(1)
177
+ .where('attachments.entity_id', MESSAGE_ATTACHMENT_ENTITY_ID)
178
+ .whereRaw('attachments.record_id = m.id')
179
+ query = input.hasAttachments ? query.whereExists(subquery) : query.whereNotExists(subquery)
180
+ }
181
+
182
+ if (input.hasActions !== undefined) {
183
+ query = input.hasActions ? query.whereNotNull('m.action_data') : query.whereNull('m.action_data')
184
+ }
185
+
186
+ const countResult = await query.clone().count('* as count').first()
187
+ const total = Number(countResult?.count ?? 0)
188
+
189
+ const offset = (input.page - 1) * input.pageSize
190
+ const messages = await query
191
+ .select('m.*', 'r.status as recipient_status', 'r.read_at')
192
+ .orderBy('m.sent_at', 'desc')
193
+ .offset(offset)
194
+ .limit(input.pageSize)
195
+
196
+ const typedMessages = messages as MessageListRow[]
197
+ const messageIds = typedMessages.map((message) => message.id)
198
+ const objects = messageIds.length > 0
199
+ ? await em.find(MessageObject, { messageId: { $in: messageIds } })
200
+ : []
201
+
202
+ const objectsByMessage = objects.reduce((acc, obj) => {
203
+ if (!acc[obj.messageId]) acc[obj.messageId] = []
204
+ acc[obj.messageId].push(obj)
205
+ return acc
206
+ }, {} as Record<string, MessageObject[]>)
207
+
208
+ const attachmentCounts: AttachmentCountRow[] = messageIds.length > 0
209
+ ? await getKnex(em)('attachments')
210
+ .select('record_id')
211
+ .count('* as count')
212
+ .where('entity_id', MESSAGE_ATTACHMENT_ENTITY_ID)
213
+ .whereIn('record_id', messageIds)
214
+ .groupBy('record_id')
215
+ : []
216
+
217
+ const attachmentCountByMessage = attachmentCounts.reduce((acc: Record<string, number>, row) => {
218
+ acc[row.record_id] = Number(row.count)
219
+ return acc
220
+ }, {})
221
+
222
+ const recipientCounts: RecipientCountRow[] = messageIds.length > 0
223
+ ? await getKnex(em)('message_recipients')
224
+ .select('message_id')
225
+ .count('* as count')
226
+ .whereIn('message_id', messageIds)
227
+ .whereNull('deleted_at')
228
+ .groupBy('message_id')
229
+ : []
230
+
231
+ const recipientCountByMessage = recipientCounts.reduce((acc: Record<string, number>, row) => {
232
+ acc[row.message_id] = Number(row.count)
233
+ return acc
234
+ }, {})
235
+
236
+ const senderUserIds = Array.from(new Set(typedMessages.map((message) => message.sender_user_id).filter(Boolean)))
237
+ const senderUsers = senderUserIds.length > 0
238
+ ? await findWithDecryption(
239
+ em,
240
+ User,
241
+ { id: { $in: senderUserIds } },
242
+ undefined,
243
+ { tenantId: scope.tenantId, organizationId: scope.organizationId }
244
+ )
245
+ : []
246
+
247
+ const senderMetaById = new Map<string, { name: string | null; email: string | null }>()
248
+ senderUsers.forEach((user) => {
249
+ const name = typeof user.name === 'string' && user.name.trim().length ? user.name.trim() : null
250
+ senderMetaById.set(user.id, { name, email: user.email ?? null })
251
+ })
252
+
253
+ return Response.json({
254
+ items: typedMessages.map((message) => ({
255
+ ...(senderMetaById.get(message.sender_user_id)
256
+ ? {
257
+ senderName: senderMetaById.get(message.sender_user_id)?.name ?? null,
258
+ senderEmail: senderMetaById.get(message.sender_user_id)?.email ?? null,
259
+ }
260
+ : { senderName: null, senderEmail: null }),
261
+ id: message.id,
262
+ type: message.type,
263
+ visibility: message.visibility,
264
+ sourceEntityType: message.source_entity_type,
265
+ sourceEntityId: message.source_entity_id,
266
+ externalEmail: message.external_email,
267
+ externalName: message.external_name,
268
+ subject: message.subject,
269
+ bodyPreview: message.body.substring(0, 150) + (message.body.length > 150 ? '...' : ''),
270
+ senderUserId: message.sender_user_id,
271
+ priority: message.priority,
272
+ status: message.recipient_status ?? (message.is_draft ? 'draft' : 'sent'),
273
+ hasObjects: (objectsByMessage[message.id] || []).length > 0,
274
+ objectCount: (objectsByMessage[message.id] || []).length,
275
+ hasAttachments: (attachmentCountByMessage[message.id] || 0) > 0,
276
+ attachmentCount: attachmentCountByMessage[message.id] || 0,
277
+ recipientCount: recipientCountByMessage[message.id] || 0,
278
+ hasActions:
279
+ Boolean(message.action_data?.actions?.length)
280
+ || Boolean(getMessageType(message.type)?.defaultActions?.length)
281
+ || (objectsByMessage[message.id] || []).some((item) => item.actionRequired && Boolean(item.actionType)),
282
+ actionTaken: message.action_taken,
283
+ sentAt: message.sent_at,
284
+ readAt: message.read_at,
285
+ threadId: message.thread_id,
286
+ })),
287
+ page: input.page,
288
+ pageSize: input.pageSize,
289
+ total,
290
+ totalPages: Math.ceil(total / input.pageSize),
291
+ })
292
+ }
293
+
294
+ export async function POST(req: Request) {
295
+ const { ctx, scope } = await resolveMessageContext(req)
296
+ const commandBus = ctx.container.resolve('commandBus') as CommandBus
297
+ const body = await req.json().catch(() => ({}))
298
+ const input = composeMessageSchema.parse(body)
299
+
300
+ const isPublicVisibility = input.visibility === 'public'
301
+ const sendViaEmail = isPublicVisibility ? true : input.sendViaEmail
302
+ if (sendViaEmail && !(await canUseMessageEmailFeature(ctx, scope))) {
303
+ return Response.json({ error: 'Missing feature: messages.email' }, { status: 403 })
304
+ }
305
+
306
+ if (input.objects?.length) {
307
+ const objectValidationError = validateMessageObjectsForType(input.type, input.objects)
308
+ if (objectValidationError) {
309
+ return Response.json({ error: objectValidationError }, { status: 400 })
310
+ }
311
+ }
312
+
313
+ const { result, logEntry } = await commandBus.execute('messages.messages.compose', {
314
+ input: {
315
+ ...input,
316
+ sendViaEmail,
317
+ tenantId: scope.tenantId,
318
+ organizationId: scope.organizationId,
319
+ userId: scope.userId,
320
+ },
321
+ ctx: {
322
+ container: ctx.container,
323
+ auth: ctx.auth ?? null,
324
+ organizationScope: null,
325
+ selectedOrganizationId: scope.organizationId,
326
+ organizationIds: scope.organizationId ? [scope.organizationId] : null,
327
+ request: req,
328
+ },
329
+ })
330
+ const { id: messageId, threadId: responseThreadId } = result as unknown as MessageCommandExecuteResultWithThreadId
331
+
332
+ const response = Response.json({ id: messageId, threadId: responseThreadId }, { status: 201 })
333
+ attachOperationMetadataHeader(response, logEntry, {
334
+ resourceKind: 'messages.message',
335
+ resourceId: messageId,
336
+ })
337
+ return response
338
+ }
339
+
340
+ export const openApi: OpenApiRouteDoc = {
341
+ tag: 'Messages',
342
+ methods: {
343
+ GET: {
344
+ summary: 'List messages',
345
+ query: listSchema,
346
+ responses: [
347
+ {
348
+ status: 200,
349
+ description: 'Message list',
350
+ schema: z.object({
351
+ items: z.array(messageListItemSchema),
352
+ page: z.number(),
353
+ pageSize: z.number(),
354
+ total: z.number(),
355
+ totalPages: z.number(),
356
+ }),
357
+ },
358
+ ],
359
+ },
360
+ POST: {
361
+ summary: 'Compose a message',
362
+ requestBody: {
363
+ schema: composeSchema,
364
+ },
365
+ responses: [
366
+ {
367
+ status: 201,
368
+ description: 'Message created',
369
+ schema: composeResponseSchema,
370
+ },
371
+ ],
372
+ },
373
+ },
374
+ }