@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,281 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql'
2
+ import { z } from 'zod'
3
+ import { registerCommand, type CommandHandler } from '@open-mercato/shared/lib/commands'
4
+ import { extractUndoPayload, type UndoPayload } from '@open-mercato/shared/lib/commands/undo'
5
+ import { Message, MessageRecipient } from '../data/entities'
6
+ import { emitMessagesEvent, type MessagesEventId } from '../events'
7
+ import { assertOrganizationAccess, type MessageRecipientSnapshot, type MessageScopeInput } from './shared'
8
+
9
+ const recipientMutationSchema = z.object({
10
+ messageId: z.string().uuid(),
11
+ tenantId: z.string().uuid(),
12
+ organizationId: z.string().uuid().nullable(),
13
+ userId: z.string().uuid(),
14
+ })
15
+
16
+ type RecipientMutationInput = z.infer<typeof recipientMutationSchema>
17
+
18
+ type RecipientUndoPayload = UndoPayload<MessageRecipientSnapshot>
19
+
20
+ function toIso(value: Date | null | undefined): string | null {
21
+ return value ? value.toISOString() : null
22
+ }
23
+
24
+ function toDate(value: string | null | undefined): Date | null {
25
+ if (!value) return null
26
+ return new Date(value)
27
+ }
28
+
29
+ async function loadRecipientForMutation(em: EntityManager, input: RecipientMutationInput) {
30
+ const message = await em.findOne(Message, {
31
+ id: input.messageId,
32
+ tenantId: input.tenantId,
33
+ deletedAt: null,
34
+ })
35
+ if (!message) throw new Error('Message not found')
36
+ assertOrganizationAccess(input as MessageScopeInput, message)
37
+
38
+ const recipient = await em.findOne(MessageRecipient, {
39
+ messageId: input.messageId,
40
+ recipientUserId: input.userId,
41
+ deletedAt: null,
42
+ })
43
+ if (!recipient) throw new Error('Access denied')
44
+
45
+ return { message, recipient }
46
+ }
47
+
48
+ function snapshotRecipient(recipient: MessageRecipient): MessageRecipientSnapshot {
49
+ return {
50
+ id: recipient.id,
51
+ messageId: recipient.messageId,
52
+ recipientUserId: recipient.recipientUserId,
53
+ recipientType: recipient.recipientType,
54
+ status: recipient.status,
55
+ readAt: toIso(recipient.readAt),
56
+ archivedAt: toIso(recipient.archivedAt),
57
+ deletedAt: toIso(recipient.deletedAt),
58
+ }
59
+ }
60
+
61
+ function buildLog(actionLabel: string, payload: RecipientUndoPayload, input: RecipientMutationInput) {
62
+ return {
63
+ actionLabel,
64
+ resourceKind: 'messages.message',
65
+ resourceId: input.messageId,
66
+ tenantId: input.tenantId,
67
+ organizationId: input.organizationId,
68
+ payload: { undo: payload },
69
+ snapshotBefore: payload.before ?? null,
70
+ snapshotAfter: payload.after ?? null,
71
+ }
72
+ }
73
+
74
+ function applyRecipientSnapshot(recipient: MessageRecipient, snapshot: MessageRecipientSnapshot) {
75
+ recipient.status = snapshot.status
76
+ recipient.readAt = toDate(snapshot.readAt)
77
+ recipient.archivedAt = toDate(snapshot.archivedAt)
78
+ recipient.deletedAt = toDate(snapshot.deletedAt)
79
+ }
80
+
81
+ async function emitRecipientMutationEvent(
82
+ eventId: MessagesEventId,
83
+ input: RecipientMutationInput,
84
+ ): Promise<void> {
85
+ await emitMessagesEvent(
86
+ eventId,
87
+ {
88
+ messageId: input.messageId,
89
+ recipientUserId: input.userId,
90
+ userId: input.userId,
91
+ tenantId: input.tenantId,
92
+ organizationId: input.organizationId,
93
+ },
94
+ { persistent: true },
95
+ )
96
+ }
97
+
98
+ const markReadCommand: CommandHandler<unknown, { ok: true }> = {
99
+ id: 'messages.recipients.mark_read',
100
+ async prepare(rawInput, ctx) {
101
+ const input = recipientMutationSchema.parse(rawInput)
102
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
103
+ const { recipient } = await loadRecipientForMutation(em, input)
104
+ return { before: snapshotRecipient(recipient) }
105
+ },
106
+ async execute(rawInput, ctx) {
107
+ const input = recipientMutationSchema.parse(rawInput)
108
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
109
+ const { recipient } = await loadRecipientForMutation(em, input)
110
+ if (recipient.status !== 'read') {
111
+ recipient.status = 'read'
112
+ recipient.readAt = new Date()
113
+ await em.flush()
114
+ await emitRecipientMutationEvent('messages.message.read', input)
115
+ }
116
+ return { ok: true }
117
+ },
118
+ async captureAfter(rawInput, _result, ctx) {
119
+ const input = recipientMutationSchema.parse(rawInput)
120
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
121
+ const { recipient } = await loadRecipientForMutation(em, input)
122
+ return snapshotRecipient(recipient)
123
+ },
124
+ async buildLog({ input, snapshots }) {
125
+ const parsed = recipientMutationSchema.parse(input)
126
+ return buildLog('Mark message as read', {
127
+ before: (snapshots.before as MessageRecipientSnapshot | undefined) ?? null,
128
+ after: (snapshots.after as MessageRecipientSnapshot | undefined) ?? null,
129
+ }, parsed)
130
+ },
131
+ undo: async ({ logEntry, ctx }) => {
132
+ const undo = extractUndoPayload<RecipientUndoPayload>(logEntry)
133
+ const before = undo?.before
134
+ if (!before) return
135
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
136
+ const recipient = await em.findOne(MessageRecipient, { id: before.id })
137
+ if (!recipient) return
138
+ applyRecipientSnapshot(recipient, before)
139
+ await em.flush()
140
+ },
141
+ }
142
+
143
+ const markUnreadCommand: CommandHandler<unknown, { ok: true }> = {
144
+ id: 'messages.recipients.mark_unread',
145
+ async prepare(rawInput, ctx) {
146
+ const input = recipientMutationSchema.parse(rawInput)
147
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
148
+ const { recipient } = await loadRecipientForMutation(em, input)
149
+ return { before: snapshotRecipient(recipient) }
150
+ },
151
+ async execute(rawInput, ctx) {
152
+ const input = recipientMutationSchema.parse(rawInput)
153
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
154
+ const { recipient } = await loadRecipientForMutation(em, input)
155
+ if (recipient.status !== 'unread' || recipient.readAt !== null) {
156
+ recipient.status = 'unread'
157
+ recipient.readAt = null
158
+ await em.flush()
159
+ await emitRecipientMutationEvent('messages.message.marked_unread', input)
160
+ }
161
+ return { ok: true }
162
+ },
163
+ async captureAfter(rawInput, _result, ctx) {
164
+ const input = recipientMutationSchema.parse(rawInput)
165
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
166
+ const { recipient } = await loadRecipientForMutation(em, input)
167
+ return snapshotRecipient(recipient)
168
+ },
169
+ async buildLog({ input, snapshots }) {
170
+ const parsed = recipientMutationSchema.parse(input)
171
+ return buildLog('Mark message as unread', {
172
+ before: (snapshots.before as MessageRecipientSnapshot | undefined) ?? null,
173
+ after: (snapshots.after as MessageRecipientSnapshot | undefined) ?? null,
174
+ }, parsed)
175
+ },
176
+ undo: async ({ logEntry, ctx }) => {
177
+ const undo = extractUndoPayload<RecipientUndoPayload>(logEntry)
178
+ const before = undo?.before
179
+ if (!before) return
180
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
181
+ const recipient = await em.findOne(MessageRecipient, { id: before.id })
182
+ if (!recipient) return
183
+ applyRecipientSnapshot(recipient, before)
184
+ await em.flush()
185
+ },
186
+ }
187
+
188
+ const archiveRecipientCommand: CommandHandler<unknown, { ok: true }> = {
189
+ id: 'messages.recipients.archive',
190
+ async prepare(rawInput, ctx) {
191
+ const input = recipientMutationSchema.parse(rawInput)
192
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
193
+ const { recipient } = await loadRecipientForMutation(em, input)
194
+ return { before: snapshotRecipient(recipient) }
195
+ },
196
+ async execute(rawInput, ctx) {
197
+ const input = recipientMutationSchema.parse(rawInput)
198
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
199
+ const { recipient } = await loadRecipientForMutation(em, input)
200
+ if (recipient.status !== 'archived' || recipient.archivedAt === null) {
201
+ recipient.archivedAt = new Date()
202
+ recipient.status = 'archived'
203
+ await em.flush()
204
+ await emitRecipientMutationEvent('messages.message.archived', input)
205
+ }
206
+ return { ok: true }
207
+ },
208
+ async captureAfter(rawInput, _result, ctx) {
209
+ const input = recipientMutationSchema.parse(rawInput)
210
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
211
+ const { recipient } = await loadRecipientForMutation(em, input)
212
+ return snapshotRecipient(recipient)
213
+ },
214
+ async buildLog({ input, snapshots }) {
215
+ const parsed = recipientMutationSchema.parse(input)
216
+ return buildLog('Archive message', {
217
+ before: (snapshots.before as MessageRecipientSnapshot | undefined) ?? null,
218
+ after: (snapshots.after as MessageRecipientSnapshot | undefined) ?? null,
219
+ }, parsed)
220
+ },
221
+ undo: async ({ logEntry, ctx }) => {
222
+ const undo = extractUndoPayload<RecipientUndoPayload>(logEntry)
223
+ const before = undo?.before
224
+ if (!before) return
225
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
226
+ const recipient = await em.findOne(MessageRecipient, { id: before.id })
227
+ if (!recipient) return
228
+ applyRecipientSnapshot(recipient, before)
229
+ await em.flush()
230
+ },
231
+ }
232
+
233
+ const unarchiveRecipientCommand: CommandHandler<unknown, { ok: true }> = {
234
+ id: 'messages.recipients.unarchive',
235
+ async prepare(rawInput, ctx) {
236
+ const input = recipientMutationSchema.parse(rawInput)
237
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
238
+ const { recipient } = await loadRecipientForMutation(em, input)
239
+ return { before: snapshotRecipient(recipient) }
240
+ },
241
+ async execute(rawInput, ctx) {
242
+ const input = recipientMutationSchema.parse(rawInput)
243
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
244
+ const { recipient } = await loadRecipientForMutation(em, input)
245
+ if (recipient.archivedAt !== null || recipient.status === 'archived') {
246
+ recipient.archivedAt = null
247
+ recipient.status = recipient.readAt ? 'read' : 'unread'
248
+ await em.flush()
249
+ await emitRecipientMutationEvent('messages.message.unarchived', input)
250
+ }
251
+ return { ok: true }
252
+ },
253
+ async captureAfter(rawInput, _result, ctx) {
254
+ const input = recipientMutationSchema.parse(rawInput)
255
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
256
+ const { recipient } = await loadRecipientForMutation(em, input)
257
+ return snapshotRecipient(recipient)
258
+ },
259
+ async buildLog({ input, snapshots }) {
260
+ const parsed = recipientMutationSchema.parse(input)
261
+ return buildLog('Unarchive message', {
262
+ before: (snapshots.before as MessageRecipientSnapshot | undefined) ?? null,
263
+ after: (snapshots.after as MessageRecipientSnapshot | undefined) ?? null,
264
+ }, parsed)
265
+ },
266
+ undo: async ({ logEntry, ctx }) => {
267
+ const undo = extractUndoPayload<RecipientUndoPayload>(logEntry)
268
+ const before = undo?.before
269
+ if (!before) return
270
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
271
+ const recipient = await em.findOne(MessageRecipient, { id: before.id })
272
+ if (!recipient) return
273
+ applyRecipientSnapshot(recipient, before)
274
+ await em.flush()
275
+ },
276
+ }
277
+
278
+ registerCommand(markReadCommand)
279
+ registerCommand(markUnreadCommand)
280
+ registerCommand(archiveRecipientCommand)
281
+ registerCommand(unarchiveRecipientCommand)
@@ -0,0 +1,350 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql'
2
+ import { Message, MessageObject, MessageRecipient, type MessageActionData, type RecipientStatus } from '../data/entities'
3
+ import { MESSAGE_ATTACHMENT_ENTITY_ID } from '../lib/constants'
4
+
5
+ export type MessageCommandExecuteResult = {
6
+ id: string
7
+ externalEmail: string | null
8
+ recipientUserIds: string[]
9
+ }
10
+
11
+ export type MessageScopeInput = {
12
+ tenantId: string
13
+ organizationId: string | null
14
+ userId: string
15
+ }
16
+
17
+ export type MessageRecipientSnapshot = {
18
+ id: string
19
+ messageId: string
20
+ recipientUserId: string
21
+ recipientType: 'to' | 'cc' | 'bcc'
22
+ status: RecipientStatus
23
+ readAt: string | null
24
+ archivedAt: string | null
25
+ deletedAt: string | null
26
+ }
27
+
28
+ export type MessageObjectSnapshot = {
29
+ id: string
30
+ messageId: string
31
+ entityModule: string
32
+ entityType: string
33
+ entityId: string
34
+ actionRequired: boolean
35
+ actionType: string | null
36
+ actionLabel: string | null
37
+ entitySnapshot: Record<string, unknown> | null
38
+ }
39
+
40
+ export type MessageSnapshot = {
41
+ id: string
42
+ type: string
43
+ visibility: 'public' | 'internal' | null
44
+ sourceEntityType: string | null
45
+ sourceEntityId: string | null
46
+ externalEmail: string | null
47
+ externalName: string | null
48
+ threadId: string | null
49
+ parentMessageId: string | null
50
+ senderUserId: string
51
+ subject: string
52
+ body: string
53
+ bodyFormat: 'text' | 'markdown'
54
+ priority: 'low' | 'normal' | 'high' | 'urgent'
55
+ status: 'draft' | 'sent'
56
+ isDraft: boolean
57
+ sentAt: string | null
58
+ actionData: MessageActionData | null
59
+ actionResult: Record<string, unknown> | null
60
+ actionTaken: string | null
61
+ actionTakenByUserId: string | null
62
+ actionTakenAt: string | null
63
+ sendViaEmail: boolean
64
+ tenantId: string
65
+ organizationId: string | null
66
+ deletedAt: string | null
67
+ }
68
+
69
+ export type MessageAggregateSnapshot = {
70
+ message: MessageSnapshot
71
+ recipients: MessageRecipientSnapshot[]
72
+ objects: MessageObjectSnapshot[]
73
+ attachmentIds: string[]
74
+ }
75
+
76
+ function toIso(value: Date | null | undefined): string | null {
77
+ return value ? value.toISOString() : null
78
+ }
79
+
80
+ function toDate(value: string | null | undefined): Date | null {
81
+ if (!value) return null
82
+ return new Date(value)
83
+ }
84
+
85
+ function hasOrganizationAccess(scopeOrganizationId: string | null, messageOrganizationId: string | null | undefined): boolean {
86
+ if (scopeOrganizationId) {
87
+ return messageOrganizationId === scopeOrganizationId
88
+ }
89
+ return messageOrganizationId == null
90
+ }
91
+
92
+ export function assertOrganizationAccess(scope: MessageScopeInput, message: Message): void {
93
+ if (!hasOrganizationAccess(scope.organizationId, message.organizationId)) {
94
+ throw new Error('Access denied')
95
+ }
96
+ }
97
+
98
+ export async function getAttachmentIdsForMessage(
99
+ em: EntityManager,
100
+ messageId: string,
101
+ scope: { tenantId: string; organizationId: string | null },
102
+ ): Promise<string[]> {
103
+ const { Attachment } = await import('@open-mercato/core/modules/attachments/data/entities')
104
+ const attachments = await em.find(Attachment, {
105
+ entityId: MESSAGE_ATTACHMENT_ENTITY_ID,
106
+ recordId: messageId,
107
+ tenantId: scope.tenantId,
108
+ organizationId: scope.organizationId,
109
+ })
110
+ return attachments.map((item) => item.id)
111
+ }
112
+
113
+ export async function loadMessageAggregateSnapshot(
114
+ em: EntityManager,
115
+ messageId: string,
116
+ scope?: { tenantId: string; organizationId: string | null },
117
+ ): Promise<MessageAggregateSnapshot | null> {
118
+ const where: Record<string, unknown> = { id: messageId }
119
+ if (scope) {
120
+ where.tenantId = scope.tenantId
121
+ where.organizationId = scope.organizationId
122
+ }
123
+ const message = await em.findOne(Message, where)
124
+ if (!message) return null
125
+ const recipients = await em.find(MessageRecipient, { messageId })
126
+ const objects = await em.find(MessageObject, { messageId })
127
+ const attachmentIds = await getAttachmentIdsForMessage(em, messageId, {
128
+ tenantId: message.tenantId,
129
+ organizationId: message.organizationId ?? null,
130
+ })
131
+
132
+ return {
133
+ message: {
134
+ id: message.id,
135
+ type: message.type,
136
+ visibility: message.visibility ?? null,
137
+ sourceEntityType: message.sourceEntityType ?? null,
138
+ sourceEntityId: message.sourceEntityId ?? null,
139
+ externalEmail: message.externalEmail ?? null,
140
+ externalName: message.externalName ?? null,
141
+ threadId: message.threadId ?? null,
142
+ parentMessageId: message.parentMessageId ?? null,
143
+ senderUserId: message.senderUserId,
144
+ subject: message.subject,
145
+ body: message.body,
146
+ bodyFormat: message.bodyFormat,
147
+ priority: message.priority,
148
+ status: message.status,
149
+ isDraft: message.isDraft,
150
+ sentAt: toIso(message.sentAt),
151
+ actionData: (message.actionData as MessageActionData | null) ?? null,
152
+ actionResult: message.actionResult ?? null,
153
+ actionTaken: message.actionTaken ?? null,
154
+ actionTakenByUserId: message.actionTakenByUserId ?? null,
155
+ actionTakenAt: toIso(message.actionTakenAt),
156
+ sendViaEmail: message.sendViaEmail,
157
+ tenantId: message.tenantId,
158
+ organizationId: message.organizationId ?? null,
159
+ deletedAt: toIso(message.deletedAt),
160
+ },
161
+ recipients: recipients.map((item) => ({
162
+ id: item.id,
163
+ messageId: item.messageId,
164
+ recipientUserId: item.recipientUserId,
165
+ recipientType: item.recipientType,
166
+ status: item.status,
167
+ readAt: toIso(item.readAt),
168
+ archivedAt: toIso(item.archivedAt),
169
+ deletedAt: toIso(item.deletedAt),
170
+ })),
171
+ objects: objects.map((item) => ({
172
+ id: item.id,
173
+ messageId: item.messageId,
174
+ entityModule: item.entityModule,
175
+ entityType: item.entityType,
176
+ entityId: item.entityId,
177
+ actionRequired: item.actionRequired,
178
+ actionType: item.actionType ?? null,
179
+ actionLabel: item.actionLabel ?? null,
180
+ entitySnapshot: item.entitySnapshot ?? null,
181
+ })),
182
+ attachmentIds,
183
+ }
184
+ }
185
+
186
+ export async function restoreMessageAggregateSnapshot(
187
+ em: EntityManager,
188
+ snapshot: MessageAggregateSnapshot,
189
+ ): Promise<void> {
190
+ const existingMessage = await em.findOne(Message, { id: snapshot.message.id })
191
+ if (!existingMessage) {
192
+ const created = em.create(Message, {
193
+ id: snapshot.message.id,
194
+ type: snapshot.message.type,
195
+ visibility: snapshot.message.visibility,
196
+ sourceEntityType: snapshot.message.sourceEntityType,
197
+ sourceEntityId: snapshot.message.sourceEntityId,
198
+ externalEmail: snapshot.message.externalEmail,
199
+ externalName: snapshot.message.externalName,
200
+ threadId: snapshot.message.threadId,
201
+ parentMessageId: snapshot.message.parentMessageId,
202
+ senderUserId: snapshot.message.senderUserId,
203
+ subject: snapshot.message.subject,
204
+ body: snapshot.message.body,
205
+ bodyFormat: snapshot.message.bodyFormat,
206
+ priority: snapshot.message.priority,
207
+ status: snapshot.message.status,
208
+ isDraft: snapshot.message.isDraft,
209
+ sentAt: toDate(snapshot.message.sentAt),
210
+ actionData: snapshot.message.actionData as MessageActionData,
211
+ actionResult: snapshot.message.actionResult,
212
+ actionTaken: snapshot.message.actionTaken,
213
+ actionTakenByUserId: snapshot.message.actionTakenByUserId,
214
+ actionTakenAt: toDate(snapshot.message.actionTakenAt),
215
+ sendViaEmail: snapshot.message.sendViaEmail,
216
+ tenantId: snapshot.message.tenantId,
217
+ organizationId: snapshot.message.organizationId,
218
+ deletedAt: toDate(snapshot.message.deletedAt),
219
+ })
220
+ em.persist(created)
221
+ } else {
222
+ existingMessage.type = snapshot.message.type
223
+ existingMessage.visibility = snapshot.message.visibility
224
+ existingMessage.sourceEntityType = snapshot.message.sourceEntityType
225
+ existingMessage.sourceEntityId = snapshot.message.sourceEntityId
226
+ existingMessage.externalEmail = snapshot.message.externalEmail
227
+ existingMessage.externalName = snapshot.message.externalName
228
+ existingMessage.threadId = snapshot.message.threadId
229
+ existingMessage.parentMessageId = snapshot.message.parentMessageId
230
+ existingMessage.senderUserId = snapshot.message.senderUserId
231
+ existingMessage.subject = snapshot.message.subject
232
+ existingMessage.body = snapshot.message.body
233
+ existingMessage.bodyFormat = snapshot.message.bodyFormat
234
+ existingMessage.priority = snapshot.message.priority
235
+ existingMessage.status = snapshot.message.status
236
+ existingMessage.isDraft = snapshot.message.isDraft
237
+ existingMessage.sentAt = toDate(snapshot.message.sentAt)
238
+ existingMessage.actionData = snapshot.message.actionData as MessageActionData
239
+ existingMessage.actionResult = snapshot.message.actionResult
240
+ existingMessage.actionTaken = snapshot.message.actionTaken
241
+ existingMessage.actionTakenByUserId = snapshot.message.actionTakenByUserId
242
+ existingMessage.actionTakenAt = toDate(snapshot.message.actionTakenAt)
243
+ existingMessage.sendViaEmail = snapshot.message.sendViaEmail
244
+ existingMessage.tenantId = snapshot.message.tenantId
245
+ existingMessage.organizationId = snapshot.message.organizationId
246
+ existingMessage.deletedAt = toDate(snapshot.message.deletedAt)
247
+ }
248
+
249
+ const existingRecipients = await em.find(MessageRecipient, { messageId: snapshot.message.id })
250
+ const recipientById = new Map(existingRecipients.map((item) => [item.id, item]))
251
+ const snapshotRecipientIds = new Set(snapshot.recipients.map((item) => item.id))
252
+ for (const current of existingRecipients) {
253
+ if (!snapshotRecipientIds.has(current.id)) {
254
+ em.remove(current)
255
+ }
256
+ }
257
+ for (const recipient of snapshot.recipients) {
258
+ const existing = recipientById.get(recipient.id)
259
+ if (!existing) {
260
+ em.persist(em.create(MessageRecipient, {
261
+ id: recipient.id,
262
+ messageId: recipient.messageId,
263
+ recipientUserId: recipient.recipientUserId,
264
+ recipientType: recipient.recipientType,
265
+ status: recipient.status,
266
+ readAt: toDate(recipient.readAt),
267
+ archivedAt: toDate(recipient.archivedAt),
268
+ deletedAt: toDate(recipient.deletedAt),
269
+ }))
270
+ continue
271
+ }
272
+ existing.messageId = recipient.messageId
273
+ existing.recipientUserId = recipient.recipientUserId
274
+ existing.recipientType = recipient.recipientType
275
+ existing.status = recipient.status
276
+ existing.readAt = toDate(recipient.readAt)
277
+ existing.archivedAt = toDate(recipient.archivedAt)
278
+ existing.deletedAt = toDate(recipient.deletedAt)
279
+ }
280
+
281
+ const existingObjects = await em.find(MessageObject, { messageId: snapshot.message.id })
282
+ const objectById = new Map(existingObjects.map((item) => [item.id, item]))
283
+ const snapshotObjectIds = new Set(snapshot.objects.map((item) => item.id))
284
+ for (const current of existingObjects) {
285
+ if (!snapshotObjectIds.has(current.id)) {
286
+ em.remove(current)
287
+ }
288
+ }
289
+ for (const object of snapshot.objects) {
290
+ const existing = objectById.get(object.id)
291
+ if (!existing) {
292
+ em.persist(em.create(MessageObject, {
293
+ id: object.id,
294
+ messageId: object.messageId,
295
+ entityModule: object.entityModule,
296
+ entityType: object.entityType,
297
+ entityId: object.entityId,
298
+ actionRequired: object.actionRequired,
299
+ actionType: object.actionType,
300
+ actionLabel: object.actionLabel,
301
+ entitySnapshot: object.entitySnapshot,
302
+ }))
303
+ continue
304
+ }
305
+ existing.messageId = object.messageId
306
+ existing.entityModule = object.entityModule
307
+ existing.entityType = object.entityType
308
+ existing.entityId = object.entityId
309
+ existing.actionRequired = object.actionRequired
310
+ existing.actionType = object.actionType
311
+ existing.actionLabel = object.actionLabel
312
+ existing.entitySnapshot = object.entitySnapshot
313
+ }
314
+
315
+ const { Attachment } = await import('@open-mercato/core/modules/attachments/data/entities')
316
+ await em.nativeDelete(Attachment, {
317
+ entityId: MESSAGE_ATTACHMENT_ENTITY_ID,
318
+ recordId: snapshot.message.id,
319
+ tenantId: snapshot.message.tenantId,
320
+ organizationId: snapshot.message.organizationId,
321
+ id: { $nin: snapshot.attachmentIds.length > 0 ? snapshot.attachmentIds : ['00000000-0000-0000-0000-000000000000'] },
322
+ })
323
+ if (snapshot.attachmentIds.length > 0) {
324
+ const attachments = await em.find(Attachment, {
325
+ id: { $in: snapshot.attachmentIds },
326
+ tenantId: snapshot.message.tenantId,
327
+ organizationId: snapshot.message.organizationId,
328
+ })
329
+ for (const attachment of attachments) {
330
+ attachment.entityId = MESSAGE_ATTACHMENT_ENTITY_ID
331
+ attachment.recordId = snapshot.message.id
332
+ }
333
+ }
334
+
335
+ await em.flush()
336
+ }
337
+
338
+ export function buildCommandLogBase(
339
+ actionLabel: string,
340
+ resourceId: string,
341
+ snapshot: { tenantId: string; organizationId: string | null },
342
+ ) {
343
+ return {
344
+ actionLabel,
345
+ resourceKind: 'messages.message',
346
+ resourceId,
347
+ tenantId: snapshot.tenantId,
348
+ organizationId: snapshot.organizationId,
349
+ }
350
+ }