@open-mercato/core 0.6.5-develop.4384.1.ce2ec6eaaa → 0.6.5-develop.4393.1.de282b5dfd

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 (533) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/channel_ingest_dead_letter/index.js +25 -0
  3. package/dist/generated/entities/channel_ingest_dead_letter/index.js.map +7 -0
  4. package/dist/generated/entities/channel_thread_mapping/index.js +25 -0
  5. package/dist/generated/entities/channel_thread_mapping/index.js.map +7 -0
  6. package/dist/generated/entities/channel_thread_token/index.js +17 -0
  7. package/dist/generated/entities/channel_thread_token/index.js.map +7 -0
  8. package/dist/generated/entities/communication_channel/index.js +43 -0
  9. package/dist/generated/entities/communication_channel/index.js.map +7 -0
  10. package/dist/generated/entities/customer_interaction/index.js +4 -0
  11. package/dist/generated/entities/customer_interaction/index.js.map +2 -2
  12. package/dist/generated/entities/external_conversation/index.js +25 -0
  13. package/dist/generated/entities/external_conversation/index.js.map +7 -0
  14. package/dist/generated/entities/external_message/index.js +25 -0
  15. package/dist/generated/entities/external_message/index.js.map +7 -0
  16. package/dist/generated/entities/integration_credentials/index.js +3 -1
  17. package/dist/generated/entities/integration_credentials/index.js.map +2 -2
  18. package/dist/generated/entities/message/index.js +2 -0
  19. package/dist/generated/entities/message/index.js.map +2 -2
  20. package/dist/generated/entities/message_channel_link/index.js +33 -0
  21. package/dist/generated/entities/message_channel_link/index.js.map +7 -0
  22. package/dist/generated/entities/message_reaction/index.js +25 -0
  23. package/dist/generated/entities/message_reaction/index.js.map +7 -0
  24. package/dist/generated/entities.ids.generated.js +11 -0
  25. package/dist/generated/entities.ids.generated.js.map +2 -2
  26. package/dist/generated/entity-fields-registry.js +117 -0
  27. package/dist/generated/entity-fields-registry.js.map +2 -2
  28. package/dist/helpers/integration/authFixtures.js +2 -1
  29. package/dist/helpers/integration/authFixtures.js.map +2 -2
  30. package/dist/helpers/integration/communicationChannelsFixtures.js +58 -0
  31. package/dist/helpers/integration/communicationChannelsFixtures.js.map +7 -0
  32. package/dist/modules/communication_channels/acl.js +47 -0
  33. package/dist/modules/communication_channels/acl.js.map +7 -0
  34. package/dist/modules/communication_channels/api/delete/channels/[id]/route.js +133 -0
  35. package/dist/modules/communication_channels/api/delete/channels/[id]/route.js.map +7 -0
  36. package/dist/modules/communication_channels/api/delete/messages/[messageId]/reactions/[reactionId]/route.js +113 -0
  37. package/dist/modules/communication_channels/api/delete/messages/[messageId]/reactions/[reactionId]/route.js.map +7 -0
  38. package/dist/modules/communication_channels/api/get/channels/[id]/health/route.js +138 -0
  39. package/dist/modules/communication_channels/api/get/channels/[id]/health/route.js.map +7 -0
  40. package/dist/modules/communication_channels/api/get/channels/[id]/route.js +93 -0
  41. package/dist/modules/communication_channels/api/get/channels/[id]/route.js.map +7 -0
  42. package/dist/modules/communication_channels/api/get/channels/route.js +96 -0
  43. package/dist/modules/communication_channels/api/get/channels/route.js.map +7 -0
  44. package/dist/modules/communication_channels/api/get/me/channels/route.js +82 -0
  45. package/dist/modules/communication_channels/api/get/me/channels/route.js.map +7 -0
  46. package/dist/modules/communication_channels/api/get/oauth/[provider]/callback/route.js +274 -0
  47. package/dist/modules/communication_channels/api/get/oauth/[provider]/callback/route.js.map +7 -0
  48. package/dist/modules/communication_channels/api/post/channels/[id]/import-history/route.js +168 -0
  49. package/dist/modules/communication_channels/api/post/channels/[id]/import-history/route.js.map +7 -0
  50. package/dist/modules/communication_channels/api/post/channels/[id]/poll-now/route.js +143 -0
  51. package/dist/modules/communication_channels/api/post/channels/[id]/poll-now/route.js.map +7 -0
  52. package/dist/modules/communication_channels/api/post/channels/[id]/push/register/route.js +127 -0
  53. package/dist/modules/communication_channels/api/post/channels/[id]/push/register/route.js.map +7 -0
  54. package/dist/modules/communication_channels/api/post/channels/[id]/set-primary/route.js +99 -0
  55. package/dist/modules/communication_channels/api/post/channels/[id]/set-primary/route.js.map +7 -0
  56. package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js +197 -0
  57. package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js.map +7 -0
  58. package/dist/modules/communication_channels/api/post/channels/connect/credentials/route.js +124 -0
  59. package/dist/modules/communication_channels/api/post/channels/connect/credentials/route.js.map +7 -0
  60. package/dist/modules/communication_channels/api/post/messages/[messageId]/reactions/route.js +120 -0
  61. package/dist/modules/communication_channels/api/post/messages/[messageId]/reactions/route.js.map +7 -0
  62. package/dist/modules/communication_channels/api/post/oauth/[provider]/initiate/route.js +157 -0
  63. package/dist/modules/communication_channels/api/post/oauth/[provider]/initiate/route.js.map +7 -0
  64. package/dist/modules/communication_channels/api/post/send-as-user/route.js +115 -0
  65. package/dist/modules/communication_channels/api/post/send-as-user/route.js.map +7 -0
  66. package/dist/modules/communication_channels/api/post/test-seed/route.js +217 -0
  67. package/dist/modules/communication_channels/api/post/test-seed/route.js.map +7 -0
  68. package/dist/modules/communication_channels/api/post/webhook/[provider]/route.js +175 -0
  69. package/dist/modules/communication_channels/api/post/webhook/[provider]/route.js.map +7 -0
  70. package/dist/modules/communication_channels/api/post/webhooks/gmail/route.js +123 -0
  71. package/dist/modules/communication_channels/api/post/webhooks/gmail/route.js.map +7 -0
  72. package/dist/modules/communication_channels/api/put/threads/[threadId]/assign/route.js +117 -0
  73. package/dist/modules/communication_channels/api/put/threads/[threadId]/assign/route.js.map +7 -0
  74. package/dist/modules/communication_channels/backend/communication_channels/channels/[id]/page.js +180 -0
  75. package/dist/modules/communication_channels/backend/communication_channels/channels/[id]/page.js.map +7 -0
  76. package/dist/modules/communication_channels/backend/communication_channels/channels/[id]/page.meta.js +36 -0
  77. package/dist/modules/communication_channels/backend/communication_channels/channels/[id]/page.meta.js.map +7 -0
  78. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js +107 -0
  79. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +7 -0
  80. package/dist/modules/communication_channels/backend/communication_channels/channels/page.meta.js +38 -0
  81. package/dist/modules/communication_channels/backend/communication_channels/channels/page.meta.js.map +7 -0
  82. package/dist/modules/communication_channels/backend/profile/communication-channels/page.js +727 -0
  83. package/dist/modules/communication_channels/backend/profile/communication-channels/page.js.map +7 -0
  84. package/dist/modules/communication_channels/backend/profile/communication-channels/page.meta.js +38 -0
  85. package/dist/modules/communication_channels/backend/profile/communication-channels/page.meta.js.map +7 -0
  86. package/dist/modules/communication_channels/commands/connect-credential-channel.js +154 -0
  87. package/dist/modules/communication_channels/commands/connect-credential-channel.js.map +7 -0
  88. package/dist/modules/communication_channels/commands/delete-channel.js +137 -0
  89. package/dist/modules/communication_channels/commands/delete-channel.js.map +7 -0
  90. package/dist/modules/communication_channels/commands/deliver-outbound-message.js +400 -0
  91. package/dist/modules/communication_channels/commands/deliver-outbound-message.js.map +7 -0
  92. package/dist/modules/communication_channels/commands/disconnect-channel.js +163 -0
  93. package/dist/modules/communication_channels/commands/disconnect-channel.js.map +7 -0
  94. package/dist/modules/communication_channels/commands/ingest-inbound-message.js +413 -0
  95. package/dist/modules/communication_channels/commands/ingest-inbound-message.js.map +7 -0
  96. package/dist/modules/communication_channels/commands/interceptors.js +68 -0
  97. package/dist/modules/communication_channels/commands/interceptors.js.map +7 -0
  98. package/dist/modules/communication_channels/commands/process-inbound-reaction.js +198 -0
  99. package/dist/modules/communication_channels/commands/process-inbound-reaction.js.map +7 -0
  100. package/dist/modules/communication_channels/commands/push-register.js +146 -0
  101. package/dist/modules/communication_channels/commands/push-register.js.map +7 -0
  102. package/dist/modules/communication_channels/commands/push-renew.js +23 -0
  103. package/dist/modules/communication_channels/commands/push-renew.js.map +7 -0
  104. package/dist/modules/communication_channels/commands/push-unregister.js +108 -0
  105. package/dist/modules/communication_channels/commands/push-unregister.js.map +7 -0
  106. package/dist/modules/communication_channels/commands/queue-import-history.js +113 -0
  107. package/dist/modules/communication_channels/commands/queue-import-history.js.map +7 -0
  108. package/dist/modules/communication_channels/commands/reassign-conversation.js +193 -0
  109. package/dist/modules/communication_channels/commands/reassign-conversation.js.map +7 -0
  110. package/dist/modules/communication_channels/commands/set-primary-channel.js +114 -0
  111. package/dist/modules/communication_channels/commands/set-primary-channel.js.map +7 -0
  112. package/dist/modules/communication_channels/commands/toggle-outbound-reaction.js +260 -0
  113. package/dist/modules/communication_channels/commands/toggle-outbound-reaction.js.map +7 -0
  114. package/dist/modules/communication_channels/data/enrichers.js +286 -0
  115. package/dist/modules/communication_channels/data/enrichers.js.map +7 -0
  116. package/dist/modules/communication_channels/data/entities.js +447 -0
  117. package/dist/modules/communication_channels/data/entities.js.map +7 -0
  118. package/dist/modules/communication_channels/data/extensions.js +67 -0
  119. package/dist/modules/communication_channels/data/extensions.js.map +7 -0
  120. package/dist/modules/communication_channels/data/validators.js +123 -0
  121. package/dist/modules/communication_channels/data/validators.js.map +7 -0
  122. package/dist/modules/communication_channels/di.js +35 -0
  123. package/dist/modules/communication_channels/di.js.map +7 -0
  124. package/dist/modules/communication_channels/encryption.js +12 -0
  125. package/dist/modules/communication_channels/encryption.js.map +7 -0
  126. package/dist/modules/communication_channels/events.js +124 -0
  127. package/dist/modules/communication_channels/events.js.map +7 -0
  128. package/dist/modules/communication_channels/index.js +20 -0
  129. package/dist/modules/communication_channels/index.js.map +7 -0
  130. package/dist/modules/communication_channels/lib/access-control.js +43 -0
  131. package/dist/modules/communication_channels/lib/access-control.js.map +7 -0
  132. package/dist/modules/communication_channels/lib/adapter-compat.js +36 -0
  133. package/dist/modules/communication_channels/lib/adapter-compat.js.map +7 -0
  134. package/dist/modules/communication_channels/lib/adapter-registry-singleton.js +22 -0
  135. package/dist/modules/communication_channels/lib/adapter-registry-singleton.js.map +7 -0
  136. package/dist/modules/communication_channels/lib/adapter.js +1 -0
  137. package/dist/modules/communication_channels/lib/adapter.js.map +7 -0
  138. package/dist/modules/communication_channels/lib/connect-channel.js +95 -0
  139. package/dist/modules/communication_channels/lib/connect-channel.js.map +7 -0
  140. package/dist/modules/communication_channels/lib/contact-resolver.js +79 -0
  141. package/dist/modules/communication_channels/lib/contact-resolver.js.map +7 -0
  142. package/dist/modules/communication_channels/lib/credential-refresh.js +97 -0
  143. package/dist/modules/communication_channels/lib/credential-refresh.js.map +7 -0
  144. package/dist/modules/communication_channels/lib/dead-letter.js +62 -0
  145. package/dist/modules/communication_channels/lib/dead-letter.js.map +7 -0
  146. package/dist/modules/communication_channels/lib/email-capabilities.js +47 -0
  147. package/dist/modules/communication_channels/lib/email-capabilities.js.map +7 -0
  148. package/dist/modules/communication_channels/lib/email-contact.js +14 -0
  149. package/dist/modules/communication_channels/lib/email-contact.js.map +7 -0
  150. package/dist/modules/communication_channels/lib/email-mime.js +259 -0
  151. package/dist/modules/communication_channels/lib/email-mime.js.map +7 -0
  152. package/dist/modules/communication_channels/lib/error-classification.js +101 -0
  153. package/dist/modules/communication_channels/lib/error-classification.js.map +7 -0
  154. package/dist/modules/communication_channels/lib/gmail-pubsub-jwt.js +185 -0
  155. package/dist/modules/communication_channels/lib/gmail-pubsub-jwt.js.map +7 -0
  156. package/dist/modules/communication_channels/lib/mutation-guards.js +114 -0
  157. package/dist/modules/communication_channels/lib/mutation-guards.js.map +7 -0
  158. package/dist/modules/communication_channels/lib/oauth-client-config.js +32 -0
  159. package/dist/modules/communication_channels/lib/oauth-client-config.js.map +7 -0
  160. package/dist/modules/communication_channels/lib/oauth-state.js +128 -0
  161. package/dist/modules/communication_channels/lib/oauth-state.js.map +7 -0
  162. package/dist/modules/communication_channels/lib/oauth-token.js +45 -0
  163. package/dist/modules/communication_channels/lib/oauth-token.js.map +7 -0
  164. package/dist/modules/communication_channels/lib/pg-errors.js +11 -0
  165. package/dist/modules/communication_channels/lib/pg-errors.js.map +7 -0
  166. package/dist/modules/communication_channels/lib/provider-health.js +24 -0
  167. package/dist/modules/communication_channels/lib/provider-health.js.map +7 -0
  168. package/dist/modules/communication_channels/lib/push-state.js +19 -0
  169. package/dist/modules/communication_channels/lib/push-state.js.map +7 -0
  170. package/dist/modules/communication_channels/lib/queue.js +54 -0
  171. package/dist/modules/communication_channels/lib/queue.js.map +7 -0
  172. package/dist/modules/communication_channels/lib/reaction-processor-types.js +5 -0
  173. package/dist/modules/communication_channels/lib/reaction-processor-types.js.map +7 -0
  174. package/dist/modules/communication_channels/lib/reaction-semantics.js +11 -0
  175. package/dist/modules/communication_channels/lib/reaction-semantics.js.map +7 -0
  176. package/dist/modules/communication_channels/lib/registry.js +67 -0
  177. package/dist/modules/communication_channels/lib/registry.js.map +7 -0
  178. package/dist/modules/communication_channels/lib/route-mutation-guard.js +43 -0
  179. package/dist/modules/communication_channels/lib/route-mutation-guard.js.map +7 -0
  180. package/dist/modules/communication_channels/lib/sanitize-channel-html.js +96 -0
  181. package/dist/modules/communication_channels/lib/sanitize-channel-html.js.map +7 -0
  182. package/dist/modules/communication_channels/lib/send-as-user.js +194 -0
  183. package/dist/modules/communication_channels/lib/send-as-user.js.map +7 -0
  184. package/dist/modules/communication_channels/lib/system-user.js +22 -0
  185. package/dist/modules/communication_channels/lib/system-user.js.map +7 -0
  186. package/dist/modules/communication_channels/lib/test-seed.js +68 -0
  187. package/dist/modules/communication_channels/lib/test-seed.js.map +7 -0
  188. package/dist/modules/communication_channels/lib/thread-matcher.js +263 -0
  189. package/dist/modules/communication_channels/lib/thread-matcher.js.map +7 -0
  190. package/dist/modules/communication_channels/lib/thread-token.js +219 -0
  191. package/dist/modules/communication_channels/lib/thread-token.js.map +7 -0
  192. package/dist/modules/communication_channels/lib/use-connect-channel.js +61 -0
  193. package/dist/modules/communication_channels/lib/use-connect-channel.js.map +7 -0
  194. package/dist/modules/communication_channels/migrations/Migration20260526134719_communication_channels.js +50 -0
  195. package/dist/modules/communication_channels/migrations/Migration20260526134719_communication_channels.js.map +7 -0
  196. package/dist/modules/communication_channels/migrations/Migration20260527195446_communication_channels.js +19 -0
  197. package/dist/modules/communication_channels/migrations/Migration20260527195446_communication_channels.js.map +7 -0
  198. package/dist/modules/communication_channels/migrations/Migration20260529231848_communication_channels.js +13 -0
  199. package/dist/modules/communication_channels/migrations/Migration20260529231848_communication_channels.js.map +7 -0
  200. package/dist/modules/communication_channels/migrations/Migration20260531120000_communication_channels.js +17 -0
  201. package/dist/modules/communication_channels/migrations/Migration20260531120000_communication_channels.js.map +7 -0
  202. package/dist/modules/communication_channels/notifications.client.js +51 -0
  203. package/dist/modules/communication_channels/notifications.client.js.map +7 -0
  204. package/dist/modules/communication_channels/notifications.handlers.js +53 -0
  205. package/dist/modules/communication_channels/notifications.handlers.js.map +7 -0
  206. package/dist/modules/communication_channels/notifications.js +56 -0
  207. package/dist/modules/communication_channels/notifications.js.map +7 -0
  208. package/dist/modules/communication_channels/setup.js +105 -0
  209. package/dist/modules/communication_channels/setup.js.map +7 -0
  210. package/dist/modules/communication_channels/subscribers/channel-requires-reauth-notification.js +71 -0
  211. package/dist/modules/communication_channels/subscribers/channel-requires-reauth-notification.js.map +7 -0
  212. package/dist/modules/communication_channels/subscribers/outbound-bridge.js +103 -0
  213. package/dist/modules/communication_channels/subscribers/outbound-bridge.js.map +7 -0
  214. package/dist/modules/communication_channels/subscribers/user-deleted-cascade.js +51 -0
  215. package/dist/modules/communication_channels/subscribers/user-deleted-cascade.js.map +7 -0
  216. package/dist/modules/communication_channels/widgets/components.js +7 -0
  217. package/dist/modules/communication_channels/widgets/components.js.map +7 -0
  218. package/dist/modules/communication_channels/widgets/injection/channel-badge/widget.client.js +18 -0
  219. package/dist/modules/communication_channels/widgets/injection/channel-badge/widget.client.js.map +7 -0
  220. package/dist/modules/communication_channels/widgets/injection/channel-badge/widget.js +30 -0
  221. package/dist/modules/communication_channels/widgets/injection/channel-badge/widget.js.map +7 -0
  222. package/dist/modules/communication_channels/widgets/injection/channel-info-panel/widget.client.js +185 -0
  223. package/dist/modules/communication_channels/widgets/injection/channel-info-panel/widget.client.js.map +7 -0
  224. package/dist/modules/communication_channels/widgets/injection/channel-info-panel/widget.js +17 -0
  225. package/dist/modules/communication_channels/widgets/injection/channel-info-panel/widget.js.map +7 -0
  226. package/dist/modules/communication_channels/widgets/injection/channel-payload-renderer/widget.client.js +44 -0
  227. package/dist/modules/communication_channels/widgets/injection/channel-payload-renderer/widget.client.js.map +7 -0
  228. package/dist/modules/communication_channels/widgets/injection/channel-payload-renderer/widget.js +17 -0
  229. package/dist/modules/communication_channels/widgets/injection/channel-payload-renderer/widget.js.map +7 -0
  230. package/dist/modules/communication_channels/widgets/injection/profile-channels-menu/widget.js +23 -0
  231. package/dist/modules/communication_channels/widgets/injection/profile-channels-menu/widget.js.map +7 -0
  232. package/dist/modules/communication_channels/widgets/injection/reaction-bar/widget.client.js +141 -0
  233. package/dist/modules/communication_channels/widgets/injection/reaction-bar/widget.client.js.map +7 -0
  234. package/dist/modules/communication_channels/widgets/injection/reaction-bar/widget.js +17 -0
  235. package/dist/modules/communication_channels/widgets/injection/reaction-bar/widget.js.map +7 -0
  236. package/dist/modules/communication_channels/widgets/injection-table.js +38 -0
  237. package/dist/modules/communication_channels/widgets/injection-table.js.map +7 -0
  238. package/dist/modules/communication_channels/widgets/notifications/ChannelRequiresReauthRenderer.js +25 -0
  239. package/dist/modules/communication_channels/widgets/notifications/ChannelRequiresReauthRenderer.js.map +7 -0
  240. package/dist/modules/communication_channels/widgets/notifications/MessageReceivedRenderer.js +19 -0
  241. package/dist/modules/communication_channels/widgets/notifications/MessageReceivedRenderer.js.map +7 -0
  242. package/dist/modules/communication_channels/widgets/notifications/index.js +7 -0
  243. package/dist/modules/communication_channels/widgets/notifications/index.js.map +7 -0
  244. package/dist/modules/communication_channels/workers/channel-import-history.js +185 -0
  245. package/dist/modules/communication_channels/workers/channel-import-history.js.map +7 -0
  246. package/dist/modules/communication_channels/workers/gmail-history-sync.js +154 -0
  247. package/dist/modules/communication_channels/workers/gmail-history-sync.js.map +7 -0
  248. package/dist/modules/communication_channels/workers/gmail-renew-watch.js +95 -0
  249. package/dist/modules/communication_channels/workers/gmail-renew-watch.js.map +7 -0
  250. package/dist/modules/communication_channels/workers/inbound-processor.js +56 -0
  251. package/dist/modules/communication_channels/workers/inbound-processor.js.map +7 -0
  252. package/dist/modules/communication_channels/workers/outbound-delivery.js +85 -0
  253. package/dist/modules/communication_channels/workers/outbound-delivery.js.map +7 -0
  254. package/dist/modules/communication_channels/workers/poll-channel.js +240 -0
  255. package/dist/modules/communication_channels/workers/poll-channel.js.map +7 -0
  256. package/dist/modules/communication_channels/workers/poll-tick.js +132 -0
  257. package/dist/modules/communication_channels/workers/poll-tick.js.map +7 -0
  258. package/dist/modules/communication_channels/workers/reaction-processor.js +192 -0
  259. package/dist/modules/communication_channels/workers/reaction-processor.js.map +7 -0
  260. package/dist/modules/customers/acl.js +18 -0
  261. package/dist/modules/customers/acl.js.map +2 -2
  262. package/dist/modules/customers/api/activities/route.js +9 -0
  263. package/dist/modules/customers/api/activities/route.js.map +2 -2
  264. package/dist/modules/customers/api/companies/[id]/route.js +18 -7
  265. package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
  266. package/dist/modules/customers/api/interactions/[id]/visibility/route.js +151 -0
  267. package/dist/modules/customers/api/interactions/[id]/visibility/route.js.map +7 -0
  268. package/dist/modules/customers/api/interactions/counts/route.js +6 -0
  269. package/dist/modules/customers/api/interactions/counts/route.js.map +2 -2
  270. package/dist/modules/customers/api/interactions/route.js +26 -7
  271. package/dist/modules/customers/api/interactions/route.js.map +2 -2
  272. package/dist/modules/customers/api/people/[id]/email-threads/route.js +82 -0
  273. package/dist/modules/customers/api/people/[id]/email-threads/route.js.map +7 -0
  274. package/dist/modules/customers/api/people/[id]/emails/route.js +157 -0
  275. package/dist/modules/customers/api/people/[id]/emails/route.js.map +7 -0
  276. package/dist/modules/customers/api/people/[id]/route.js +12 -4
  277. package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
  278. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +10 -0
  279. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  280. package/dist/modules/customers/commands/deals.js +46 -5
  281. package/dist/modules/customers/commands/deals.js.map +2 -2
  282. package/dist/modules/customers/commands/interactions.js +16 -0
  283. package/dist/modules/customers/commands/interactions.js.map +2 -2
  284. package/dist/modules/customers/components/detail/ActivityCard.js +32 -0
  285. package/dist/modules/customers/components/detail/ActivityCard.js.map +2 -2
  286. package/dist/modules/customers/components/detail/ComposeEmailDialog.js +242 -0
  287. package/dist/modules/customers/components/detail/ComposeEmailDialog.js.map +7 -0
  288. package/dist/modules/customers/components/detail/DealForm.js +2 -1
  289. package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
  290. package/dist/modules/customers/components/detail/DealsSection.js +10 -0
  291. package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
  292. package/dist/modules/customers/components/detail/EmailCardActions.js +179 -0
  293. package/dist/modules/customers/components/detail/EmailCardActions.js.map +7 -0
  294. package/dist/modules/customers/components/detail/EmailReplyForwardActions.js +52 -0
  295. package/dist/modules/customers/components/detail/EmailReplyForwardActions.js.map +7 -0
  296. package/dist/modules/customers/components/detail/PersonDetailTabs.js +7 -1
  297. package/dist/modules/customers/components/detail/PersonDetailTabs.js.map +2 -2
  298. package/dist/modules/customers/components/detail/PersonEmailThreadsTab.js +366 -0
  299. package/dist/modules/customers/components/detail/PersonEmailThreadsTab.js.map +7 -0
  300. package/dist/modules/customers/data/enrichers.js +133 -2
  301. package/dist/modules/customers/data/enrichers.js.map +2 -2
  302. package/dist/modules/customers/data/entities.js +18 -0
  303. package/dist/modules/customers/data/entities.js.map +2 -2
  304. package/dist/modules/customers/data/extensions.js +16 -0
  305. package/dist/modules/customers/data/extensions.js.map +7 -0
  306. package/dist/modules/customers/encryption.js +11 -0
  307. package/dist/modules/customers/encryption.js.map +2 -2
  308. package/dist/modules/customers/events.js +4 -1
  309. package/dist/modules/customers/events.js.map +2 -2
  310. package/dist/modules/customers/lib/findPeopleByAddresses.js +64 -0
  311. package/dist/modules/customers/lib/findPeopleByAddresses.js.map +7 -0
  312. package/dist/modules/customers/lib/kysely.js.map +2 -2
  313. package/dist/modules/customers/lib/link-channel-message-handler.js +303 -0
  314. package/dist/modules/customers/lib/link-channel-message-handler.js.map +7 -0
  315. package/dist/modules/customers/lib/personEmailThreads.js +205 -0
  316. package/dist/modules/customers/lib/personEmailThreads.js.map +7 -0
  317. package/dist/modules/customers/lib/visibilityFilter.js +51 -0
  318. package/dist/modules/customers/lib/visibilityFilter.js.map +7 -0
  319. package/dist/modules/customers/migrations/Migration20260527012240_customers.js +20 -0
  320. package/dist/modules/customers/migrations/Migration20260527012240_customers.js.map +7 -0
  321. package/dist/modules/customers/setup.js +2 -1
  322. package/dist/modules/customers/setup.js.map +2 -2
  323. package/dist/modules/customers/subscribers/link-channel-message-received.js +12 -0
  324. package/dist/modules/customers/subscribers/link-channel-message-received.js.map +7 -0
  325. package/dist/modules/customers/subscribers/link-channel-message-sent.js +12 -0
  326. package/dist/modules/customers/subscribers/link-channel-message-sent.js.map +7 -0
  327. package/dist/modules/integrations/data/entities.js +8 -1
  328. package/dist/modules/integrations/data/entities.js.map +2 -2
  329. package/dist/modules/integrations/lib/credentials-service.js +29 -14
  330. package/dist/modules/integrations/lib/credentials-service.js.map +2 -2
  331. package/dist/modules/integrations/migrations/Migration20260526154136_integrations.js +15 -0
  332. package/dist/modules/integrations/migrations/Migration20260526154136_integrations.js.map +7 -0
  333. package/dist/modules/messages/commands/messages.js +70 -8
  334. package/dist/modules/messages/commands/messages.js.map +2 -2
  335. package/dist/modules/messages/components/ComposeMessagePageClient.js +24 -13
  336. package/dist/modules/messages/components/ComposeMessagePageClient.js.map +2 -2
  337. package/dist/modules/messages/components/MessageDetailPageClient.js +39 -2
  338. package/dist/modules/messages/components/MessageDetailPageClient.js.map +2 -2
  339. package/dist/modules/messages/components/MessagesInboxPageClient.js +1 -0
  340. package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
  341. package/dist/modules/messages/data/entities.js +8 -1
  342. package/dist/modules/messages/data/entities.js.map +2 -2
  343. package/dist/modules/messages/migrations/Migration20260531130000.js +15 -0
  344. package/dist/modules/messages/migrations/Migration20260531130000.js.map +7 -0
  345. package/dist/modules/messages/widgets/injection-table.js +7 -0
  346. package/dist/modules/messages/widgets/injection-table.js.map +7 -0
  347. package/generated/entities/channel_ingest_dead_letter/index.ts +11 -0
  348. package/generated/entities/channel_thread_mapping/index.ts +11 -0
  349. package/generated/entities/channel_thread_token/index.ts +7 -0
  350. package/generated/entities/communication_channel/index.ts +20 -0
  351. package/generated/entities/customer_interaction/index.ts +2 -0
  352. package/generated/entities/external_conversation/index.ts +11 -0
  353. package/generated/entities/external_message/index.ts +11 -0
  354. package/generated/entities/integration_credentials/index.ts +1 -0
  355. package/generated/entities/message/index.ts +1 -0
  356. package/generated/entities/message_channel_link/index.ts +15 -0
  357. package/generated/entities/message_reaction/index.ts +11 -0
  358. package/generated/entities.ids.generated.ts +11 -0
  359. package/generated/entity-fields-registry.ts +117 -0
  360. package/package.json +9 -7
  361. package/src/helpers/integration/authFixtures.ts +4 -1
  362. package/src/helpers/integration/communicationChannelsFixtures.ts +124 -0
  363. package/src/modules/communication_channels/acl.ts +43 -0
  364. package/src/modules/communication_channels/api/delete/channels/[id]/route.ts +163 -0
  365. package/src/modules/communication_channels/api/delete/messages/[messageId]/reactions/[reactionId]/route.ts +143 -0
  366. package/src/modules/communication_channels/api/get/channels/[id]/health/route.ts +173 -0
  367. package/src/modules/communication_channels/api/get/channels/[id]/route.ts +111 -0
  368. package/src/modules/communication_channels/api/get/channels/route.ts +109 -0
  369. package/src/modules/communication_channels/api/get/me/channels/route.ts +100 -0
  370. package/src/modules/communication_channels/api/get/oauth/[provider]/callback/route.ts +355 -0
  371. package/src/modules/communication_channels/api/post/channels/[id]/import-history/route.ts +206 -0
  372. package/src/modules/communication_channels/api/post/channels/[id]/poll-now/route.ts +174 -0
  373. package/src/modules/communication_channels/api/post/channels/[id]/push/register/route.ts +158 -0
  374. package/src/modules/communication_channels/api/post/channels/[id]/set-primary/route.ts +114 -0
  375. package/src/modules/communication_channels/api/post/channels/[id]/test-send/route.ts +241 -0
  376. package/src/modules/communication_channels/api/post/channels/connect/credentials/route.ts +134 -0
  377. package/src/modules/communication_channels/api/post/messages/[messageId]/reactions/route.ts +143 -0
  378. package/src/modules/communication_channels/api/post/oauth/[provider]/initiate/route.ts +192 -0
  379. package/src/modules/communication_channels/api/post/send-as-user/route.ts +125 -0
  380. package/src/modules/communication_channels/api/post/test-seed/route.ts +267 -0
  381. package/src/modules/communication_channels/api/post/webhook/[provider]/route.ts +227 -0
  382. package/src/modules/communication_channels/api/post/webhooks/gmail/route.ts +161 -0
  383. package/src/modules/communication_channels/api/put/threads/[threadId]/assign/route.ts +132 -0
  384. package/src/modules/communication_channels/backend/communication_channels/channels/[id]/page.meta.ts +34 -0
  385. package/src/modules/communication_channels/backend/communication_channels/channels/[id]/page.tsx +250 -0
  386. package/src/modules/communication_channels/backend/communication_channels/channels/page.meta.ts +36 -0
  387. package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +137 -0
  388. package/src/modules/communication_channels/backend/profile/communication-channels/page.meta.ts +36 -0
  389. package/src/modules/communication_channels/backend/profile/communication-channels/page.tsx +907 -0
  390. package/src/modules/communication_channels/commands/connect-credential-channel.ts +243 -0
  391. package/src/modules/communication_channels/commands/delete-channel.ts +193 -0
  392. package/src/modules/communication_channels/commands/deliver-outbound-message.ts +579 -0
  393. package/src/modules/communication_channels/commands/disconnect-channel.ts +241 -0
  394. package/src/modules/communication_channels/commands/ingest-inbound-message.ts +602 -0
  395. package/src/modules/communication_channels/commands/interceptors.ts +104 -0
  396. package/src/modules/communication_channels/commands/process-inbound-reaction.ts +265 -0
  397. package/src/modules/communication_channels/commands/push-register.ts +203 -0
  398. package/src/modules/communication_channels/commands/push-renew.ts +49 -0
  399. package/src/modules/communication_channels/commands/push-unregister.ts +168 -0
  400. package/src/modules/communication_channels/commands/queue-import-history.ts +180 -0
  401. package/src/modules/communication_channels/commands/reassign-conversation.ts +273 -0
  402. package/src/modules/communication_channels/commands/set-primary-channel.ts +154 -0
  403. package/src/modules/communication_channels/commands/toggle-outbound-reaction.ts +347 -0
  404. package/src/modules/communication_channels/data/enrichers.ts +413 -0
  405. package/src/modules/communication_channels/data/entities.ts +546 -0
  406. package/src/modules/communication_channels/data/extensions.ts +76 -0
  407. package/src/modules/communication_channels/data/validators.ts +138 -0
  408. package/src/modules/communication_channels/di.ts +40 -0
  409. package/src/modules/communication_channels/encryption.ts +44 -0
  410. package/src/modules/communication_channels/events.ts +122 -0
  411. package/src/modules/communication_channels/i18n/de.json +138 -0
  412. package/src/modules/communication_channels/i18n/en.json +138 -0
  413. package/src/modules/communication_channels/i18n/es.json +138 -0
  414. package/src/modules/communication_channels/i18n/pl.json +138 -0
  415. package/src/modules/communication_channels/index.ts +19 -0
  416. package/src/modules/communication_channels/lib/access-control.ts +110 -0
  417. package/src/modules/communication_channels/lib/adapter-compat.ts +57 -0
  418. package/src/modules/communication_channels/lib/adapter-registry-singleton.ts +35 -0
  419. package/src/modules/communication_channels/lib/adapter.ts +605 -0
  420. package/src/modules/communication_channels/lib/connect-channel.ts +163 -0
  421. package/src/modules/communication_channels/lib/contact-resolver.ts +162 -0
  422. package/src/modules/communication_channels/lib/credential-refresh.ts +197 -0
  423. package/src/modules/communication_channels/lib/dead-letter.ts +87 -0
  424. package/src/modules/communication_channels/lib/email-capabilities.ts +60 -0
  425. package/src/modules/communication_channels/lib/email-contact.ts +17 -0
  426. package/src/modules/communication_channels/lib/email-mime.ts +425 -0
  427. package/src/modules/communication_channels/lib/error-classification.ts +144 -0
  428. package/src/modules/communication_channels/lib/gmail-pubsub-jwt.ts +278 -0
  429. package/src/modules/communication_channels/lib/mutation-guards.ts +215 -0
  430. package/src/modules/communication_channels/lib/oauth-client-config.ts +79 -0
  431. package/src/modules/communication_channels/lib/oauth-state.ts +228 -0
  432. package/src/modules/communication_channels/lib/oauth-token.ts +81 -0
  433. package/src/modules/communication_channels/lib/pg-errors.ts +12 -0
  434. package/src/modules/communication_channels/lib/provider-health.ts +47 -0
  435. package/src/modules/communication_channels/lib/push-state.ts +38 -0
  436. package/src/modules/communication_channels/lib/queue.ts +66 -0
  437. package/src/modules/communication_channels/lib/reaction-processor-types.ts +51 -0
  438. package/src/modules/communication_channels/lib/reaction-semantics.ts +48 -0
  439. package/src/modules/communication_channels/lib/registry.ts +99 -0
  440. package/src/modules/communication_channels/lib/route-mutation-guard.ts +68 -0
  441. package/src/modules/communication_channels/lib/sanitize-channel-html.ts +129 -0
  442. package/src/modules/communication_channels/lib/send-as-user.ts +284 -0
  443. package/src/modules/communication_channels/lib/system-user.ts +74 -0
  444. package/src/modules/communication_channels/lib/test-seed.ts +140 -0
  445. package/src/modules/communication_channels/lib/thread-matcher.ts +430 -0
  446. package/src/modules/communication_channels/lib/thread-token.ts +355 -0
  447. package/src/modules/communication_channels/lib/use-connect-channel.ts +73 -0
  448. package/src/modules/communication_channels/migrations/.snapshot-open-mercato.json +2142 -0
  449. package/src/modules/communication_channels/migrations/Migration20260526134719_communication_channels.ts +55 -0
  450. package/src/modules/communication_channels/migrations/Migration20260527195446_communication_channels.ts +20 -0
  451. package/src/modules/communication_channels/migrations/Migration20260529231848_communication_channels.ts +13 -0
  452. package/src/modules/communication_channels/migrations/Migration20260531120000_communication_channels.ts +24 -0
  453. package/src/modules/communication_channels/notifications.client.ts +50 -0
  454. package/src/modules/communication_channels/notifications.handlers.ts +86 -0
  455. package/src/modules/communication_channels/notifications.ts +52 -0
  456. package/src/modules/communication_channels/setup.ts +158 -0
  457. package/src/modules/communication_channels/subscribers/channel-requires-reauth-notification.ts +118 -0
  458. package/src/modules/communication_channels/subscribers/outbound-bridge.ts +175 -0
  459. package/src/modules/communication_channels/subscribers/user-deleted-cascade.ts +100 -0
  460. package/src/modules/communication_channels/widgets/components.ts +36 -0
  461. package/src/modules/communication_channels/widgets/injection/channel-badge/widget.client.tsx +38 -0
  462. package/src/modules/communication_channels/widgets/injection/channel-badge/widget.ts +51 -0
  463. package/src/modules/communication_channels/widgets/injection/channel-info-panel/widget.client.tsx +278 -0
  464. package/src/modules/communication_channels/widgets/injection/channel-info-panel/widget.ts +24 -0
  465. package/src/modules/communication_channels/widgets/injection/channel-payload-renderer/widget.client.tsx +63 -0
  466. package/src/modules/communication_channels/widgets/injection/channel-payload-renderer/widget.ts +29 -0
  467. package/src/modules/communication_channels/widgets/injection/profile-channels-menu/widget.ts +34 -0
  468. package/src/modules/communication_channels/widgets/injection/reaction-bar/widget.client.tsx +177 -0
  469. package/src/modules/communication_channels/widgets/injection/reaction-bar/widget.ts +26 -0
  470. package/src/modules/communication_channels/widgets/injection-table.ts +47 -0
  471. package/src/modules/communication_channels/widgets/notifications/ChannelRequiresReauthRenderer.tsx +48 -0
  472. package/src/modules/communication_channels/widgets/notifications/MessageReceivedRenderer.tsx +45 -0
  473. package/src/modules/communication_channels/widgets/notifications/index.ts +2 -0
  474. package/src/modules/communication_channels/workers/channel-import-history.ts +252 -0
  475. package/src/modules/communication_channels/workers/gmail-history-sync.ts +223 -0
  476. package/src/modules/communication_channels/workers/gmail-renew-watch.ts +141 -0
  477. package/src/modules/communication_channels/workers/inbound-processor.ts +114 -0
  478. package/src/modules/communication_channels/workers/outbound-delivery.ts +155 -0
  479. package/src/modules/communication_channels/workers/poll-channel.ts +391 -0
  480. package/src/modules/communication_channels/workers/poll-tick.ts +210 -0
  481. package/src/modules/communication_channels/workers/reaction-processor.ts +264 -0
  482. package/src/modules/customers/acl.ts +18 -0
  483. package/src/modules/customers/api/activities/route.ts +13 -0
  484. package/src/modules/customers/api/companies/[id]/route.ts +21 -1
  485. package/src/modules/customers/api/interactions/[id]/visibility/route.ts +179 -0
  486. package/src/modules/customers/api/interactions/counts/route.ts +10 -0
  487. package/src/modules/customers/api/interactions/route.ts +51 -5
  488. package/src/modules/customers/api/people/[id]/email-threads/route.ts +92 -0
  489. package/src/modules/customers/api/people/[id]/emails/route.ts +184 -0
  490. package/src/modules/customers/api/people/[id]/route.ts +17 -2
  491. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +11 -1
  492. package/src/modules/customers/commands/deals.ts +65 -6
  493. package/src/modules/customers/commands/interactions.ts +30 -0
  494. package/src/modules/customers/components/detail/ActivityCard.tsx +48 -0
  495. package/src/modules/customers/components/detail/ComposeEmailDialog.tsx +329 -0
  496. package/src/modules/customers/components/detail/DealForm.tsx +2 -1
  497. package/src/modules/customers/components/detail/DealsSection.tsx +26 -0
  498. package/src/modules/customers/components/detail/EmailCardActions.tsx +258 -0
  499. package/src/modules/customers/components/detail/EmailReplyForwardActions.tsx +53 -0
  500. package/src/modules/customers/components/detail/PersonDetailTabs.tsx +8 -1
  501. package/src/modules/customers/components/detail/PersonEmailThreadsTab.tsx +448 -0
  502. package/src/modules/customers/data/enrichers.ts +252 -1
  503. package/src/modules/customers/data/entities.ts +46 -1
  504. package/src/modules/customers/data/extensions.ts +26 -0
  505. package/src/modules/customers/encryption.ts +11 -0
  506. package/src/modules/customers/events.ts +4 -0
  507. package/src/modules/customers/i18n/de.json +41 -0
  508. package/src/modules/customers/i18n/en.json +41 -0
  509. package/src/modules/customers/i18n/es.json +41 -0
  510. package/src/modules/customers/i18n/pl.json +41 -0
  511. package/src/modules/customers/lib/findPeopleByAddresses.ts +107 -0
  512. package/src/modules/customers/lib/kysely.ts +16 -0
  513. package/src/modules/customers/lib/link-channel-message-handler.ts +571 -0
  514. package/src/modules/customers/lib/personEmailThreads.ts +325 -0
  515. package/src/modules/customers/lib/visibilityFilter.ts +152 -0
  516. package/src/modules/customers/migrations/.snapshot-open-mercato.json +61 -0
  517. package/src/modules/customers/migrations/Migration20260527012240_customers.ts +23 -0
  518. package/src/modules/customers/setup.ts +1 -0
  519. package/src/modules/customers/subscribers/link-channel-message-received.ts +21 -0
  520. package/src/modules/customers/subscribers/link-channel-message-sent.ts +21 -0
  521. package/src/modules/integrations/AGENTS.md +9 -0
  522. package/src/modules/integrations/data/entities.ts +21 -1
  523. package/src/modules/integrations/lib/credentials-service.ts +49 -13
  524. package/src/modules/integrations/migrations/.snapshot-open-mercato.json +26 -1
  525. package/src/modules/integrations/migrations/Migration20260526154136_integrations.ts +15 -0
  526. package/src/modules/messages/commands/messages.ts +101 -8
  527. package/src/modules/messages/components/ComposeMessagePageClient.tsx +17 -0
  528. package/src/modules/messages/components/MessageDetailPageClient.tsx +43 -0
  529. package/src/modules/messages/components/MessagesInboxPageClient.tsx +4 -0
  530. package/src/modules/messages/data/entities.ts +11 -0
  531. package/src/modules/messages/migrations/.snapshot-open-mercato.json +18 -0
  532. package/src/modules/messages/migrations/Migration20260531130000.ts +15 -0
  533. package/src/modules/messages/widgets/injection-table.ts +29 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/integrations/lib/credentials-service.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { decryptWithAesGcm, encryptWithAesGcm } from '@open-mercato/shared/lib/encryption/aes'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { createKmsService } from '@open-mercato/shared/lib/encryption/kms'\nimport { parseDecryptedFieldValue } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'\nimport {\n getBundle,\n getIntegration,\n resolveIntegrationCredentialsSchema,\n type IntegrationScope,\n} from '@open-mercato/shared/modules/integrations/types'\nimport { EncryptionMap } from '../../entities/data/entities'\nimport { IntegrationCredentials } from '../data/entities'\n\nconst ENCRYPTED_CREDENTIALS_BLOB_KEY = '__om_encrypted_credentials_blob_v1'\nconst CREDENTIALS_ENCRYPTION_UNAVAILABLE_MESSAGE =\n 'Integration credentials encryption key is unavailable. Configure Vault KMS or TENANT_DATA_ENCRYPTION_FALLBACK_KEY.'\n\nexport class CredentialsEncryptionUnavailableError extends Error {\n constructor() {\n super(CREDENTIALS_ENCRYPTION_UNAVAILABLE_MESSAGE)\n this.name = 'CredentialsEncryptionUnavailableError'\n }\n}\n\nexport function isCredentialsEncryptionUnavailableError(error: unknown): error is CredentialsEncryptionUnavailableError {\n return error instanceof CredentialsEncryptionUnavailableError\n}\n\nfunction isRecordValue(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction normalizeCredentialsRecord(value: unknown): Record<string, unknown> {\n if (isRecordValue(value)) return value\n if (typeof value !== 'string') return {}\n\n const parsed = parseDecryptedFieldValue(value)\n return isRecordValue(parsed) ? parsed : {}\n}\n\nexport function createCredentialsService(em: EntityManager) {\n const credentialsEncryptionSpec = [{ field: 'credentials' }]\n\n async function ensureCredentialsEncryptionMap(scope: IntegrationScope): Promise<void> {\n const existing = await findOneWithDecryption(\n em,\n EncryptionMap,\n {\n entityId: 'integrations:integration_credentials',\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n\n if (!existing) {\n const created = em.create(EncryptionMap, {\n entityId: 'integrations:integration_credentials',\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n fieldsJson: credentialsEncryptionSpec,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(created)\n return\n }\n\n existing.fieldsJson = credentialsEncryptionSpec\n existing.isActive = true\n }\n\n async function resolveCredentialsDek(scope: IntegrationScope): Promise<string> {\n const kms = createKmsService()\n const existing = await kms.getTenantDek(scope.tenantId)\n if (existing?.key) return existing.key\n\n const created = await kms.createTenantDek(scope.tenantId)\n if (created?.key) return created.key\n\n throw new CredentialsEncryptionUnavailableError()\n }\n\n async function encryptCredentialsBlob(\n credentials: Record<string, unknown>,\n scope: IntegrationScope,\n ): Promise<Record<string, unknown>> {\n const dek = await resolveCredentialsDek(scope)\n const payload = encryptWithAesGcm(JSON.stringify(credentials), dek)\n return { [ENCRYPTED_CREDENTIALS_BLOB_KEY]: payload.value }\n }\n\n async function decryptCredentialsBlob(\n credentialsInput: unknown,\n scope: IntegrationScope,\n ): Promise<Record<string, unknown>> {\n const credentials = normalizeCredentialsRecord(credentialsInput)\n const encrypted = credentials[ENCRYPTED_CREDENTIALS_BLOB_KEY]\n if (typeof encrypted !== 'string' || !encrypted) return credentials\n\n const dek = await resolveCredentialsDek(scope)\n const decryptedRaw = decryptWithAesGcm(encrypted, dek)\n if (!decryptedRaw) return {}\n\n try {\n const parsed = JSON.parse(decryptedRaw) as unknown\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {}\n } catch {\n return {}\n }\n }\n\n return {\n async getRaw(integrationId: string, scope: IntegrationScope): Promise<Record<string, unknown> | null> {\n const row = await findOneWithDecryption(\n em,\n IntegrationCredentials,\n {\n integrationId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n if (!row) return null\n return decryptCredentialsBlob(row.credentials, scope)\n },\n\n async resolve(integrationId: string, scope: IntegrationScope): Promise<Record<string, unknown> | null> {\n const direct = await this.getRaw(integrationId, scope)\n if (direct) return direct\n\n const definition = getIntegration(integrationId)\n if (!definition?.bundleId) return null\n return this.getRaw(definition.bundleId, scope)\n },\n\n async save(integrationId: string, credentials: Record<string, unknown>, scope: IntegrationScope): Promise<void> {\n const encryptedCredentials = await encryptCredentialsBlob(credentials, scope)\n await ensureCredentialsEncryptionMap(scope)\n\n const row = await findOneWithDecryption(\n em,\n IntegrationCredentials,\n {\n integrationId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n\n if (row) {\n row.credentials = encryptedCredentials\n await em.flush()\n return\n }\n\n const created = em.create(IntegrationCredentials, {\n integrationId,\n credentials: encryptedCredentials,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n await em.persist(created).flush()\n },\n\n async saveField(\n integrationId: string,\n fieldKey: string,\n value: unknown,\n scope: IntegrationScope,\n ): Promise<Record<string, unknown>> {\n const current = (await this.getRaw(integrationId, scope)) ?? {}\n const updated = { ...current, [fieldKey]: value }\n await this.save(integrationId, updated, scope)\n return updated\n },\n\n getSchema(integrationId: string) {\n const definition = getIntegration(integrationId)\n if (!definition) return undefined\n\n if (definition.bundleId) {\n const bundle = getBundle(definition.bundleId)\n return bundle?.credentials ?? resolveIntegrationCredentialsSchema(integrationId)\n }\n\n return definition.credentials ?? resolveIntegrationCredentialsSchema(integrationId)\n },\n }\n}\n\nexport type CredentialsService = ReturnType<typeof createCredentialsService>\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { decryptWithAesGcm, encryptWithAesGcm } from '@open-mercato/shared/lib/encryption/aes'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { createKmsService } from '@open-mercato/shared/lib/encryption/kms'\nimport { parseDecryptedFieldValue } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'\nimport {\n getBundle,\n getIntegration,\n resolveIntegrationCredentialsSchema,\n type IntegrationScope,\n} from '@open-mercato/shared/modules/integrations/types'\nimport { EncryptionMap } from '../../entities/data/entities'\nimport { IntegrationCredentials } from '../data/entities'\n\nconst ENCRYPTED_CREDENTIALS_BLOB_KEY = '__om_encrypted_credentials_blob_v1'\nconst CREDENTIALS_ENCRYPTION_UNAVAILABLE_MESSAGE =\n 'Integration credentials encryption key is unavailable. Configure Vault KMS or TENANT_DATA_ENCRYPTION_FALLBACK_KEY.'\n\nexport class CredentialsEncryptionUnavailableError extends Error {\n constructor() {\n super(CREDENTIALS_ENCRYPTION_UNAVAILABLE_MESSAGE)\n this.name = 'CredentialsEncryptionUnavailableError'\n }\n}\n\nexport function isCredentialsEncryptionUnavailableError(error: unknown): error is CredentialsEncryptionUnavailableError {\n return error instanceof CredentialsEncryptionUnavailableError\n}\n\nfunction isRecordValue(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction normalizeCredentialsRecord(value: unknown): Record<string, unknown> {\n if (isRecordValue(value)) return value\n if (typeof value !== 'string') return {}\n\n const parsed = parseDecryptedFieldValue(value)\n return isRecordValue(parsed) ? parsed : {}\n}\n\n/**\n * Build the where-filter for credential lookups.\n *\n * Per-user scoping (added 2026-05-26): when `scope.userId` is set, the filter\n * matches the row owned by that user \u2014 different users on the same tenant get\n * their OWN row for the same provider. When `scope.userId` is `undefined` /\n * `null`, the filter matches tenant-wide credentials (existing behaviour,\n * e.g. shared Stripe/Akeneo API keys).\n *\n * The partial unique index `integration_credentials_user_lookup_idx` enforces\n * uniqueness across `(integration_id, organization_id, tenant_id, user_id)`\n * when `user_id IS NOT NULL`.\n */\nexport function buildCredentialsFilter(integrationId: string, scope: IntegrationScope) {\n const base = {\n integrationId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n } as Record<string, unknown>\n if (scope.userId) {\n base.userId = scope.userId\n } else {\n base.userId = null\n }\n return base\n}\n\nexport function createCredentialsService(em: EntityManager) {\n const credentialsEncryptionSpec = [{ field: 'credentials' }]\n\n async function ensureCredentialsEncryptionMap(scope: IntegrationScope): Promise<void> {\n const existing = await findOneWithDecryption(\n em,\n EncryptionMap,\n {\n entityId: 'integrations:integration_credentials',\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n\n if (!existing) {\n const created = em.create(EncryptionMap, {\n entityId: 'integrations:integration_credentials',\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n fieldsJson: credentialsEncryptionSpec,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(created)\n return\n }\n\n existing.fieldsJson = credentialsEncryptionSpec\n existing.isActive = true\n }\n\n async function resolveCredentialsDek(scope: IntegrationScope): Promise<string> {\n const kms = createKmsService()\n const existing = await kms.getTenantDek(scope.tenantId)\n if (existing?.key) return existing.key\n\n const created = await kms.createTenantDek(scope.tenantId)\n if (created?.key) return created.key\n\n throw new CredentialsEncryptionUnavailableError()\n }\n\n async function encryptCredentialsBlob(\n credentials: Record<string, unknown>,\n scope: IntegrationScope,\n ): Promise<Record<string, unknown>> {\n const dek = await resolveCredentialsDek(scope)\n const payload = encryptWithAesGcm(JSON.stringify(credentials), dek)\n return { [ENCRYPTED_CREDENTIALS_BLOB_KEY]: payload.value }\n }\n\n async function decryptCredentialsBlob(\n credentialsInput: unknown,\n scope: IntegrationScope,\n ): Promise<Record<string, unknown>> {\n const credentials = normalizeCredentialsRecord(credentialsInput)\n const encrypted = credentials[ENCRYPTED_CREDENTIALS_BLOB_KEY]\n if (typeof encrypted !== 'string' || !encrypted) return credentials\n\n const dek = await resolveCredentialsDek(scope)\n const decryptedRaw = decryptWithAesGcm(encrypted, dek)\n if (!decryptedRaw) return {}\n\n try {\n const parsed = JSON.parse(decryptedRaw) as unknown\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {}\n } catch {\n return {}\n }\n }\n\n return {\n async getRaw(integrationId: string, scope: IntegrationScope): Promise<Record<string, unknown> | null> {\n let row = await findOneWithDecryption(\n em,\n IntegrationCredentials,\n buildCredentialsFilter(integrationId, scope),\n undefined,\n scope,\n )\n // Spec 2026-05-21 (email-integration-foundation) \"Hub credentials store\":\n // per-user secrets resolve as `WHERE user_id = currentUser.id OR user_id IS NULL`.\n // A user-scoped read of a TENANT-WIDE integration (sync_excel, Stripe, Akeneo,\n // S3, the channel OAuth *client* config) MUST still find the shared\n // `user_id = NULL` row \u2014 the per-user row takes precedence, and we only fall\n // back to the tenant-wide row when the user has none of their own. Writes stay\n // strict (`save` uses the unmodified filter) so a per-user save never clobbers\n // the shared credential.\n if (!row && scope.userId) {\n row = await findOneWithDecryption(\n em,\n IntegrationCredentials,\n buildCredentialsFilter(integrationId, { ...scope, userId: null }),\n undefined,\n scope,\n )\n }\n if (!row) return null\n return decryptCredentialsBlob(row.credentials, scope)\n },\n\n async resolve(integrationId: string, scope: IntegrationScope): Promise<Record<string, unknown> | null> {\n const direct = await this.getRaw(integrationId, scope)\n if (direct) return direct\n\n const definition = getIntegration(integrationId)\n if (!definition?.bundleId) return null\n return this.getRaw(definition.bundleId, scope)\n },\n\n async save(integrationId: string, credentials: Record<string, unknown>, scope: IntegrationScope): Promise<void> {\n const encryptedCredentials = await encryptCredentialsBlob(credentials, scope)\n await ensureCredentialsEncryptionMap(scope)\n\n const row = await findOneWithDecryption(\n em,\n IntegrationCredentials,\n buildCredentialsFilter(integrationId, scope),\n undefined,\n scope,\n )\n\n if (row) {\n row.credentials = encryptedCredentials\n await em.flush()\n return\n }\n\n const created = em.create(IntegrationCredentials, {\n integrationId,\n credentials: encryptedCredentials,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n ...(scope.userId ? { userId: scope.userId } : {}),\n })\n await em.persist(created).flush()\n },\n\n async saveField(\n integrationId: string,\n fieldKey: string,\n value: unknown,\n scope: IntegrationScope,\n ): Promise<Record<string, unknown>> {\n const current = (await this.getRaw(integrationId, scope)) ?? {}\n const updated = { ...current, [fieldKey]: value }\n await this.save(integrationId, updated, scope)\n return updated\n },\n\n getSchema(integrationId: string) {\n const definition = getIntegration(integrationId)\n if (!definition) return undefined\n\n if (definition.bundleId) {\n const bundle = getBundle(definition.bundleId)\n return bundle?.credentials ?? resolveIntegrationCredentialsSchema(integrationId)\n }\n\n return definition.credentials ?? resolveIntegrationCredentialsSchema(integrationId)\n },\n }\n}\n\nexport type CredentialsService = ReturnType<typeof createCredentialsService>\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,15 @@
1
+ import { Migration } from "@mikro-orm/migrations";
2
+ class Migration20260526154136_integrations extends Migration {
3
+ up() {
4
+ this.addSql(`alter table "integration_credentials" add "user_id" uuid null;`);
5
+ this.addSql(`create unique index "integration_credentials_user_lookup_idx" on "integration_credentials" ("integration_id", "organization_id", "tenant_id", "user_id") where "user_id" is not null and "deleted_at" is null;`);
6
+ }
7
+ down() {
8
+ this.addSql(`drop index "integration_credentials_user_lookup_idx";`);
9
+ this.addSql(`alter table "integration_credentials" drop column "user_id";`);
10
+ }
11
+ }
12
+ export {
13
+ Migration20260526154136_integrations
14
+ };
15
+ //# sourceMappingURL=Migration20260526154136_integrations.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/integrations/migrations/Migration20260526154136_integrations.ts"],
4
+ "sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260526154136_integrations extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`alter table \"integration_credentials\" add \"user_id\" uuid null;`);\n this.addSql(`create unique index \"integration_credentials_user_lookup_idx\" on \"integration_credentials\" (\"integration_id\", \"organization_id\", \"tenant_id\", \"user_id\") where \"user_id\" is not null and \"deleted_at\" is null;`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`drop index \"integration_credentials_user_lookup_idx\";`);\n this.addSql(`alter table \"integration_credentials\" drop column \"user_id\";`);\n }\n\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,6CAA6C,UAAU;AAAA,EAEzD,KAA2B;AAClC,SAAK,OAAO,gEAAgE;AAC5E,SAAK,OAAO,gNAAgN;AAAA,EAC9N;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,uDAAuD;AACnE,SAAK,OAAO,8DAA8D;AAAA,EAC5E;AAEF;",
6
+ "names": []
7
+ }
@@ -78,7 +78,11 @@ const scopeSchema = z.object({
78
78
  const composeCommandSchema = composeMessageSchema.safeExtend({
79
79
  tenantId: scopeSchema.shape.tenantId,
80
80
  organizationId: scopeSchema.shape.organizationId,
81
- userId: scopeSchema.shape.userId
81
+ userId: scopeSchema.shape.userId,
82
+ // Optional dedup key (inbound email ingest sets it; other callers leave it
83
+ // undefined). When set, a re-issued compose returns the first message instead
84
+ // of creating a duplicate.
85
+ idempotencyKey: z.string().min(1).max(255).optional()
82
86
  });
83
87
  const updateDraftCommandSchema = updateDraftSchema.safeExtend({
84
88
  messageId: z.string().uuid(),
@@ -134,6 +138,30 @@ async function requireMessageById(em, scope, messageId) {
134
138
  assertOrganizationAccess(scope, message);
135
139
  return message;
136
140
  }
141
+ function isUniqueViolation(err) {
142
+ if (!err || typeof err !== "object") return false;
143
+ const code = err.code;
144
+ if (code === "23505") return true;
145
+ const message = err.message;
146
+ return typeof message === "string" && /duplicate key value|unique constraint/i.test(message);
147
+ }
148
+ async function buildComposeResultFromExisting(em, message) {
149
+ const recipients = await findWithDecryption(
150
+ em,
151
+ MessageRecipient,
152
+ { messageId: message.id, deletedAt: null },
153
+ void 0,
154
+ { tenantId: message.tenantId, organizationId: message.organizationId ?? null }
155
+ );
156
+ return {
157
+ id: message.id,
158
+ threadId: message.threadId ?? null,
159
+ externalEmail: message.externalEmail ?? null,
160
+ isDraft: message.isDraft,
161
+ recipientUserIds: recipients.map((recipient) => recipient.recipientUserId),
162
+ deduplicated: true
163
+ };
164
+ }
137
165
  const composeMessageCommand = {
138
166
  id: "messages.messages.compose",
139
167
  async execute(rawInput, ctx) {
@@ -143,16 +171,33 @@ const composeMessageCommand = {
143
171
  if (objectValidationError) throw new Error(objectValidationError);
144
172
  }
145
173
  const em = ctx.container.resolve("em").fork();
174
+ const scope = { tenantId: input.tenantId, organizationId: input.organizationId };
175
+ if (input.idempotencyKey) {
176
+ const existing = await findOneWithDecryption(
177
+ em,
178
+ Message,
179
+ { tenantId: input.tenantId, idempotencyKey: input.idempotencyKey },
180
+ void 0,
181
+ scope
182
+ );
183
+ if (existing) return buildComposeResultFromExisting(em, existing);
184
+ }
146
185
  let messageId = "";
147
186
  let responseThreadId = null;
148
187
  let responseExternalEmail = null;
149
- await em.transactional(async (trx) => {
150
- const threadId = input.parentMessageId ? (await trx.findOne(Message, {
151
- id: input.parentMessageId,
152
- tenantId: input.tenantId,
153
- organizationId: input.organizationId,
154
- deletedAt: null
155
- }))?.threadId ?? input.parentMessageId : void 0;
188
+ const composeTx = em.transactional(async (trx) => {
189
+ const threadId = input.parentMessageId ? (await findOneWithDecryption(
190
+ trx,
191
+ Message,
192
+ {
193
+ id: input.parentMessageId,
194
+ tenantId: input.tenantId,
195
+ organizationId: input.organizationId,
196
+ deletedAt: null
197
+ },
198
+ void 0,
199
+ scope
200
+ ))?.threadId ?? input.parentMessageId : void 0;
156
201
  const isPublicVisibility = input.visibility === "public";
157
202
  const sendViaEmail = isPublicVisibility ? true : input.sendViaEmail;
158
203
  const message = trx.create(Message, {
@@ -174,6 +219,7 @@ const composeMessageCommand = {
174
219
  sentAt: input.isDraft ? null : /* @__PURE__ */ new Date(),
175
220
  actionData: input.actionData,
176
221
  sendViaEmail,
222
+ idempotencyKey: input.idempotencyKey ?? null,
177
223
  tenantId: input.tenantId,
178
224
  organizationId: input.organizationId
179
225
  });
@@ -226,6 +272,21 @@ const composeMessageCommand = {
226
272
  responseThreadId = message.threadId ?? null;
227
273
  responseExternalEmail = message.externalEmail ?? null;
228
274
  });
275
+ try {
276
+ await composeTx;
277
+ } catch (err) {
278
+ if (input.idempotencyKey && isUniqueViolation(err)) {
279
+ const existing = await findOneWithDecryption(
280
+ em.fork(),
281
+ Message,
282
+ { tenantId: input.tenantId, idempotencyKey: input.idempotencyKey },
283
+ void 0,
284
+ scope
285
+ );
286
+ if (existing) return buildComposeResultFromExisting(em.fork(), existing);
287
+ }
288
+ throw err;
289
+ }
229
290
  if (!input.isDraft) {
230
291
  await emitMessageSentEvent(ctx.container, {
231
292
  messageId,
@@ -255,6 +316,7 @@ const composeMessageCommand = {
255
316
  return loadMessageAggregateSnapshot(em, result.id);
256
317
  },
257
318
  buildLog: async ({ input, result, snapshots }) => {
319
+ if (result.deduplicated) return { skipLog: true };
258
320
  const parsed = composeCommandSchema.parse(input);
259
321
  return {
260
322
  actionLabel: parsed.isDraft ? "Create draft message" : "Compose message",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/messages/commands/messages.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport { registerCommand, type CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport { extractUndoPayload, type UndoPayload } from '@open-mercato/shared/lib/commands/undo'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { Message, MessageObject, MessageRecipient, type MessageActionData } from '../data/entities'\nimport { emitMessagesEvent } from '../events'\nimport {\n composeMessageSchema,\n forwardMessageSchema,\n replyMessageSchema,\n updateDraftSchema,\n} from '../data/validators'\nimport { linkAttachmentsToMessage, linkLibraryAttachmentsToMessage, copyAttachmentsForForwardMessages } from '../lib/attachments'\nimport { MESSAGE_ATTACHMENT_ENTITY_ID, MESSAGE_ENTITY_ID } from '../lib/constants'\nimport { getMessageTypeOrDefault } from '../lib/message-types-registry'\nimport { validateMessageObjectsForType } from '../lib/object-validation'\nimport { buildForwardBodyFromLegacyInput, buildForwardPreviewFromThreadSlice, buildForwardThreadSlice } from '../lib/forwarding'\nimport {\n assertOrganizationAccess,\n loadMessageAggregateSnapshot,\n restoreMessageAggregateSnapshot,\n type MessageAggregateSnapshot,\n type MessageScopeInput,\n} from './shared'\n\ntype MessageSentEventPayload = {\n messageId: string\n senderUserId: string\n recipientUserIds: string[]\n sendViaEmail: boolean\n externalEmail?: string | null\n forwardedFrom?: string\n replyTo?: string\n tenantId: string\n organizationId?: string | null\n}\n\ntype ContainerWithResolve = {\n resolve: (name: string) => unknown\n}\n\nasync function emitMessageSentEvent(_container: ContainerWithResolve, payload: MessageSentEventPayload) {\n await emitMessagesEvent('messages.message.sent', payload, { persistent: true })\n}\n\nasync function emitMessageDeletedEvent(_container: ContainerWithResolve, payload: {\n messageId: string\n actorUserId: string\n target: 'sender' | 'recipient'\n tenantId: string\n organizationId: string | null\n}) {\n await emitMessagesEvent(\n 'messages.message.deleted',\n { ...payload, recipientUserId: payload.actorUserId },\n { persistent: true },\n )\n}\n\nasync function emitMessageGloballyDeletedEvent(_container: ContainerWithResolve, payload: {\n messageId: string\n actorUserId: string\n recipientUserIds: string[]\n tenantId: string\n organizationId: string | null\n}) {\n const audience = Array.from(new Set([payload.actorUserId, ...payload.recipientUserIds]))\n await emitMessagesEvent(\n 'messages.message.deleted',\n {\n messageId: payload.messageId,\n actorUserId: payload.actorUserId,\n target: 'global',\n recipientUserIds: audience,\n tenantId: payload.tenantId,\n organizationId: payload.organizationId,\n },\n { persistent: true },\n )\n}\n\nasync function emitMessageIndexUpsert(\n container: ContainerWithResolve,\n payload: {\n messageId: string\n tenantId: string\n organizationId: string | null\n },\n) {\n let bus: { emitEvent: (name: string, body: unknown, options?: unknown) => Promise<void> } | null = null\n try {\n bus = container.resolve('eventBus') as { emitEvent: (name: string, body: unknown, options?: unknown) => Promise<void> }\n } catch {\n bus = null\n }\n\n if (!bus) return\n\n await bus.emitEvent(\n 'query_index.upsert_one',\n {\n entityType: MESSAGE_ENTITY_ID,\n recordId: payload.messageId,\n tenantId: payload.tenantId,\n organizationId: payload.organizationId,\n crudAction: 'updated',\n coverageBaseDelta: 1,\n },\n {\n tenantId: payload.tenantId,\n organizationId: payload.organizationId,\n },\n ).catch(() => undefined)\n}\n\nconst scopeSchema = z.object({\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid().nullable(),\n userId: z.string().uuid(),\n})\n\nconst composeCommandSchema = composeMessageSchema.safeExtend({\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\nconst updateDraftCommandSchema = updateDraftSchema.safeExtend({\n messageId: z.string().uuid(),\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\nconst replyCommandSchema = replyMessageSchema.safeExtend({\n messageId: z.string().uuid(),\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\nconst forwardCommandSchema = forwardMessageSchema.safeExtend({\n messageId: z.string().uuid(),\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\nconst deleteForActorCommandSchema = z.object({\n messageId: z.string().uuid(),\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\ntype ComposeCommandInput = z.infer<typeof composeCommandSchema>\ntype UpdateDraftCommandInput = z.infer<typeof updateDraftCommandSchema>\ntype ReplyCommandInput = z.infer<typeof replyCommandSchema>\ntype ForwardCommandInput = z.infer<typeof forwardCommandSchema>\ntype DeleteForActorCommandInput = z.infer<typeof deleteForActorCommandSchema>\n\ntype MessageDeleteUndoState = {\n messageId: string\n messageDeletedAt: string | null\n recipientId: string | null\n recipientStatus: 'unread' | 'read' | 'archived' | 'deleted' | null\n recipientDeletedAt: string | null\n}\n\nfunction toIso(value: Date | null | undefined): string | null {\n return value ? value.toISOString() : null\n}\n\nfunction toDate(value: string | null | undefined): Date | null {\n if (!value) return null\n return new Date(value)\n}\n\nfunction buildReplySubject(subject: string): string {\n if (/^re:\\s*/i.test(subject)) return subject\n return `Re: ${subject}`\n}\n\nasync function requireMessageById(\n em: EntityManager,\n scope: MessageScopeInput,\n messageId: string,\n) {\n const message = await findOneWithDecryption(\n em,\n Message,\n {\n id: messageId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n },\n )\n if (!message) throw new Error('Message not found')\n assertOrganizationAccess(scope, message)\n return message\n}\n\nconst composeMessageCommand: CommandHandler<unknown, { id: string; threadId: string | null; externalEmail: string | null; isDraft: boolean; recipientUserIds: string[] }> = {\n id: 'messages.messages.compose',\n async execute(rawInput, ctx) {\n const input = composeCommandSchema.parse(rawInput)\n if (input.objects?.length) {\n const objectValidationError = validateMessageObjectsForType(input.type, input.objects)\n if (objectValidationError) throw new Error(objectValidationError)\n }\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let messageId = ''\n let responseThreadId: string | null = null\n let responseExternalEmail: string | null = null\n\n await em.transactional(async (trx) => {\n const threadId = input.parentMessageId\n ? (\n await trx.findOne(Message, {\n id: input.parentMessageId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n deletedAt: null,\n })\n )?.threadId ?? input.parentMessageId\n : undefined\n\n const isPublicVisibility = input.visibility === 'public'\n const sendViaEmail = isPublicVisibility ? true : input.sendViaEmail\n const message = trx.create(Message, {\n type: input.type,\n visibility: input.visibility ?? null,\n sourceEntityType: input.sourceEntityType,\n sourceEntityId: input.sourceEntityId,\n externalEmail: input.externalEmail,\n externalName: input.externalName,\n threadId: threadId ?? undefined,\n parentMessageId: input.parentMessageId,\n senderUserId: input.userId,\n subject: input.subject,\n body: input.body,\n bodyFormat: input.bodyFormat,\n priority: input.priority,\n status: input.isDraft ? 'draft' : 'sent',\n isDraft: input.isDraft ?? false,\n sentAt: input.isDraft ? null : new Date(),\n actionData: input.actionData as MessageActionData | undefined,\n sendViaEmail,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n await trx.persist(message).flush()\n if (!threadId && !input.isDraft && !message.threadId) {\n message.threadId = message.id\n await trx.flush()\n }\n\n for (const recipient of input.recipients) {\n trx.persist(trx.create(MessageRecipient, {\n messageId: message.id,\n recipientUserId: recipient.userId,\n recipientType: recipient.type,\n status: 'unread',\n }))\n }\n\n if (input.objects) {\n for (const obj of input.objects) {\n trx.persist(trx.create(MessageObject, {\n messageId: message.id,\n entityModule: obj.entityModule,\n entityType: obj.entityType,\n entityId: obj.entityId,\n actionRequired: obj.actionRequired,\n actionType: obj.actionType,\n actionLabel: obj.actionLabel,\n }))\n }\n }\n\n await trx.flush()\n\n if (input.attachmentIds?.length) {\n await linkAttachmentsToMessage(\n trx,\n message.id,\n input.attachmentIds,\n input.organizationId,\n input.tenantId,\n )\n }\n\n if (input.attachmentRecordId) {\n await linkLibraryAttachmentsToMessage(\n trx,\n message.id,\n input.attachmentRecordId,\n input.organizationId,\n input.tenantId,\n )\n }\n\n messageId = message.id\n responseThreadId = message.threadId ?? null\n responseExternalEmail = message.externalEmail ?? null\n })\n\n if (!input.isDraft) {\n await emitMessageSentEvent(ctx.container, {\n messageId,\n senderUserId: input.userId,\n recipientUserIds: input.recipients.map((recipient) => recipient.userId),\n sendViaEmail: input.visibility === 'public' ? true : input.sendViaEmail,\n externalEmail: responseExternalEmail,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n }\n\n await emitMessageIndexUpsert(ctx.container, {\n messageId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n return {\n id: messageId,\n threadId: responseThreadId,\n externalEmail: responseExternalEmail,\n isDraft: input.isDraft,\n recipientUserIds: input.recipients.map((recipient) => recipient.userId),\n }\n },\n async captureAfter(_input, result, ctx) {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadMessageAggregateSnapshot(em, result.id)\n },\n buildLog: async ({ input, result, snapshots }) => {\n const parsed = composeCommandSchema.parse(input)\n return {\n actionLabel: parsed.isDraft ? 'Create draft message' : 'Compose message',\n resourceKind: 'messages.message',\n resourceId: result.id,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n after: (snapshots.after as MessageAggregateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<MessageAggregateSnapshot>,\n },\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageAggregateSnapshot>>(logEntry)\n const after = undo?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: after.message.id })\n if (!message) return\n message.deletedAt = new Date()\n await em.flush()\n if (!after.message.isDraft) {\n await emitMessageGloballyDeletedEvent(ctx.container, {\n messageId: after.message.id,\n actorUserId: after.message.senderUserId,\n recipientUserIds: after.recipients.map((recipient) => recipient.recipientUserId),\n tenantId: after.message.tenantId,\n organizationId: after.message.organizationId,\n })\n }\n },\n}\n\nconst updateDraftCommand: CommandHandler<unknown, { ok: true; id: string }> = {\n id: 'messages.messages.update_draft',\n async prepare(rawInput, ctx) {\n const input = updateDraftCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadMessageAggregateSnapshot(em, input.messageId, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const input = updateDraftCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireMessageById(em, input, input.messageId)\n\n if (message.senderUserId !== input.userId) throw new Error('Access denied')\n if (!message.isDraft) throw new Error('Only draft messages can be edited')\n\n const isSending = input.isDraft === false\n const preloadedRecipients = isSending && !input.recipients\n ? await findWithDecryption(\n em,\n MessageRecipient,\n { messageId: message.id, deletedAt: null },\n undefined,\n {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n },\n )\n : null\n\n const nextMessageType = input.type ?? message.type\n if (input.objects) {\n const objectValidationError = validateMessageObjectsForType(nextMessageType, input.objects)\n if (objectValidationError) throw new Error(objectValidationError)\n } else if (input.type !== undefined) {\n const existingObjects = await em.find(MessageObject, { messageId: message.id })\n if (existingObjects.length > 0) {\n const objectValidationError = validateMessageObjectsForType(\n nextMessageType,\n existingObjects.map((item) => ({\n entityModule: item.entityModule,\n entityType: item.entityType,\n entityId: item.entityId,\n })),\n )\n if (objectValidationError) throw new Error(objectValidationError)\n }\n }\n\n await withAtomicFlush(em, [async () => {\n if (input.type !== undefined) message.type = input.type\n if (input.visibility !== undefined) message.visibility = input.visibility\n if (input.sourceEntityType !== undefined) message.sourceEntityType = input.sourceEntityType\n if (input.sourceEntityId !== undefined) message.sourceEntityId = input.sourceEntityId\n if (input.externalEmail !== undefined) message.externalEmail = input.externalEmail\n if (input.externalName !== undefined) message.externalName = input.externalName\n if (input.subject !== undefined) message.subject = input.subject\n if (input.body !== undefined) message.body = input.body\n if (input.bodyFormat !== undefined) message.bodyFormat = input.bodyFormat\n if (input.priority !== undefined) message.priority = input.priority\n if (input.actionData !== undefined) message.actionData = input.actionData\n if (input.sendViaEmail !== undefined) message.sendViaEmail = input.sendViaEmail\n\n if (input.recipients) {\n await em.nativeDelete(MessageRecipient, { messageId: message.id })\n for (const recipient of input.recipients) {\n em.persist(em.create(MessageRecipient, {\n messageId: message.id,\n recipientUserId: recipient.userId,\n recipientType: recipient.type,\n status: 'unread',\n }))\n }\n }\n\n if (input.objects) {\n await em.nativeDelete(MessageObject, { messageId: message.id })\n for (const object of input.objects) {\n em.persist(em.create(MessageObject, {\n messageId: message.id,\n entityModule: object.entityModule,\n entityType: object.entityType,\n entityId: object.entityId,\n actionRequired: object.actionRequired,\n actionType: object.actionType,\n actionLabel: object.actionLabel,\n }))\n }\n }\n\n if (input.attachmentIds) {\n const { Attachment } = await import('@open-mercato/core/modules/attachments/data/entities')\n if (input.attachmentIds.length === 0) {\n await em.nativeDelete(Attachment, {\n entityId: MESSAGE_ATTACHMENT_ENTITY_ID,\n recordId: message.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n } else {\n await em.nativeDelete(Attachment, {\n entityId: MESSAGE_ATTACHMENT_ENTITY_ID,\n recordId: message.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n id: { $nin: input.attachmentIds },\n })\n }\n await linkAttachmentsToMessage(\n em,\n message.id,\n input.attachmentIds,\n input.organizationId,\n input.tenantId,\n )\n }\n\n if (isSending) {\n const finalVisibility = input.visibility ?? message.visibility\n const finalSubject = input.subject ?? message.subject\n const finalBody = input.body ?? message.body\n const finalRecipientCount = input.recipients\n ? input.recipients.length\n : (preloadedRecipients?.length ?? 0)\n\n if (finalVisibility !== 'public' && finalRecipientCount === 0) {\n throw new Error('at least one recipient is required')\n }\n if (!finalSubject?.trim()) throw new Error('subject is required')\n if (!finalBody?.trim()) throw new Error('body is required')\n\n message.isDraft = false\n message.status = 'sent'\n message.sentAt = new Date()\n if (!message.threadId) message.threadId = message.id\n }\n }], { transaction: true })\n\n await emitMessageIndexUpsert(ctx.container, {\n messageId: message.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n if (isSending) {\n const recipientUserIds = input.recipients\n ? input.recipients.map((r) => r.userId)\n : (preloadedRecipients ?? []).map((r) => r.recipientUserId)\n const resolvedVisibility = input.visibility ?? message.visibility\n const resolvedSendViaEmail = input.sendViaEmail ?? message.sendViaEmail\n await emitMessageSentEvent(ctx.container, {\n messageId: message.id,\n senderUserId: input.userId,\n recipientUserIds,\n sendViaEmail: resolvedVisibility === 'public' ? true : resolvedSendViaEmail,\n externalEmail: message.externalEmail ?? null,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n }\n\n return { ok: true, id: message.id }\n },\n async captureAfter(rawInput, _result, ctx) {\n const input = updateDraftCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadMessageAggregateSnapshot(em, input.messageId, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n },\n buildLog: async ({ input, snapshots }) => {\n const parsed = updateDraftCommandSchema.parse(input)\n return {\n actionLabel: parsed.isDraft === false ? 'Send draft message' : 'Update draft message',\n resourceKind: 'messages.message',\n resourceId: parsed.messageId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n before: (snapshots.before as MessageAggregateSnapshot | undefined) ?? null,\n after: (snapshots.after as MessageAggregateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<MessageAggregateSnapshot>,\n },\n snapshotBefore: snapshots.before ?? null,\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageAggregateSnapshot>>(logEntry)\n const before = undo?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n await restoreMessageAggregateSnapshot(em, before)\n },\n}\n\nconst replyMessageCommand: CommandHandler<unknown, { id: string; externalEmail: string | null; recipientUserIds: string[] }> = {\n id: 'messages.messages.reply',\n async execute(rawInput, ctx) {\n const input = replyCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const original = await requireMessageById(em, input, input.messageId)\n const ownRecipient = await em.findOne(MessageRecipient, {\n messageId: original.id,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (original.senderUserId !== input.userId && !ownRecipient) throw new Error('Access denied')\n\n const messageType = getMessageTypeOrDefault(original.type)\n if (messageType.allowReply === false) throw new Error('Reply is not allowed for this message type')\n\n const recipientIds = new Set(\n (input.recipients ?? [])\n .map((recipient) => recipient.userId)\n .filter((recipientUserId) => recipientUserId !== input.userId),\n )\n\n if (recipientIds.size === 0) {\n const originalRecipients = await em.find(MessageRecipient, { messageId: original.id, deletedAt: null })\n if (input.replyAll) {\n if (original.senderUserId !== input.userId) recipientIds.add(original.senderUserId)\n for (const recipient of originalRecipients) {\n if (recipient.recipientUserId !== input.userId) recipientIds.add(recipient.recipientUserId)\n }\n } else if (original.senderUserId !== input.userId) {\n recipientIds.add(original.senderUserId)\n } else {\n for (const recipient of originalRecipients) {\n if (recipient.recipientUserId !== input.userId) {\n recipientIds.add(recipient.recipientUserId)\n break\n }\n }\n }\n\n if (recipientIds.size === 0 && original.senderUserId === input.userId) {\n recipientIds.add(input.userId)\n }\n }\n if (recipientIds.size === 0) throw new Error('No recipients available for reply')\n\n let messageId = ''\n let responseExternalEmail: string | null = null\n await em.transactional(async (trx) => {\n const message = trx.create(Message, {\n type: original.type,\n visibility: original.visibility ?? null,\n sourceEntityType: original.sourceEntityType,\n sourceEntityId: original.sourceEntityId,\n externalEmail: original.externalEmail,\n externalName: original.externalName,\n threadId: original.threadId ?? original.id,\n parentMessageId: original.id,\n senderUserId: input.userId,\n subject: buildReplySubject(original.subject),\n body: input.body,\n bodyFormat: input.bodyFormat,\n priority: original.priority,\n status: 'sent',\n isDraft: false,\n sentAt: new Date(),\n sendViaEmail: input.sendViaEmail,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n await trx.persist(message).flush()\n for (const recipientUserId of recipientIds) {\n trx.persist(trx.create(MessageRecipient, {\n messageId: message.id,\n recipientUserId,\n recipientType: 'to',\n status: 'unread',\n }))\n }\n await trx.flush()\n if (input.attachmentIds?.length) {\n await linkAttachmentsToMessage(\n trx,\n message.id,\n input.attachmentIds,\n input.organizationId,\n input.tenantId,\n )\n }\n if (input.attachmentRecordId) {\n await linkLibraryAttachmentsToMessage(\n trx,\n message.id,\n input.attachmentRecordId,\n input.organizationId,\n input.tenantId,\n )\n }\n messageId = message.id\n responseExternalEmail = message.externalEmail ?? null\n })\n\n await emitMessageSentEvent(ctx.container, {\n messageId,\n senderUserId: input.userId,\n recipientUserIds: Array.from(recipientIds),\n sendViaEmail: input.sendViaEmail,\n externalEmail: responseExternalEmail,\n replyTo: original.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n await emitMessageIndexUpsert(ctx.container, {\n messageId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n return {\n id: messageId,\n externalEmail: responseExternalEmail,\n recipientUserIds: Array.from(recipientIds),\n }\n },\n async captureAfter(_input, result, ctx) {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadMessageAggregateSnapshot(em, result.id)\n },\n buildLog: async ({ input, result, snapshots }) => {\n const parsed = replyCommandSchema.parse(input)\n return {\n actionLabel: 'Reply to message',\n resourceKind: 'messages.message',\n resourceId: result.id,\n parentResourceKind: 'messages.message',\n parentResourceId: parsed.messageId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n after: (snapshots.after as MessageAggregateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<MessageAggregateSnapshot>,\n },\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageAggregateSnapshot>>(logEntry)\n const after = undo?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: after.message.id })\n if (!message) return\n message.deletedAt = new Date()\n await em.flush()\n await emitMessageGloballyDeletedEvent(ctx.container, {\n messageId: after.message.id,\n actorUserId: after.message.senderUserId,\n recipientUserIds: after.recipients.map((recipient) => recipient.recipientUserId),\n tenantId: after.message.tenantId,\n organizationId: after.message.organizationId,\n })\n },\n}\n\nconst forwardMessageCommand: CommandHandler<unknown, { id: string; externalEmail: string | null; recipientUserIds: string[] }> = {\n id: 'messages.messages.forward',\n async execute(rawInput, ctx) {\n const input = forwardCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const original = await requireMessageById(em, input, input.messageId)\n const isRecipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (original.senderUserId !== input.userId && !isRecipient) throw new Error('Access denied')\n\n const messageType = getMessageTypeOrDefault(original.type)\n if (messageType.allowForward === false) throw new Error('Forward is not allowed for this message type')\n\n const originalObjects = await em.find(MessageObject, { messageId: input.messageId })\n const forwardThreadSlice = await buildForwardThreadSlice(em, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n }, original)\n const generatedPreview = await buildForwardPreviewFromThreadSlice(em, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n }, original, forwardThreadSlice)\n const forwardedBody = typeof input.body === 'string'\n ? input.body\n : buildForwardBodyFromLegacyInput(generatedPreview.body, input.additionalBody)\n let newMessageId = ''\n let responseExternalEmail: string | null = null\n await em.transactional(async (trx) => {\n const newMessage = trx.create(Message, {\n type: original.type,\n visibility: original.visibility ?? null,\n sourceEntityType: original.sourceEntityType,\n sourceEntityId: original.sourceEntityId,\n externalEmail: original.externalEmail,\n externalName: original.externalName,\n threadId: original.threadId ?? original.id,\n parentMessageId: original.id,\n senderUserId: input.userId,\n subject: `Fwd: ${original.subject}`,\n body: forwardedBody,\n bodyFormat: original.bodyFormat,\n priority: original.priority,\n status: 'sent',\n isDraft: false,\n sentAt: new Date(),\n sendViaEmail: input.sendViaEmail,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n await trx.persist(newMessage).flush()\n for (const recipient of input.recipients) {\n trx.persist(trx.create(MessageRecipient, {\n messageId: newMessage.id,\n recipientUserId: recipient.userId,\n recipientType: recipient.type,\n status: 'unread',\n }))\n }\n for (const obj of originalObjects) {\n trx.persist(trx.create(MessageObject, {\n messageId: newMessage.id,\n entityModule: obj.entityModule,\n entityType: obj.entityType,\n entityId: obj.entityId,\n actionRequired: obj.actionRequired,\n actionType: obj.actionType,\n actionLabel: obj.actionLabel,\n entitySnapshot: obj.entitySnapshot,\n }))\n }\n await trx.flush()\n if (input.includeAttachments !== false) {\n await copyAttachmentsForForwardMessages(\n trx,\n forwardThreadSlice.map((item) => item.id),\n newMessage.id,\n input.organizationId,\n input.tenantId,\n )\n }\n newMessageId = newMessage.id\n responseExternalEmail = newMessage.externalEmail ?? null\n })\n\n await emitMessageSentEvent(ctx.container, {\n messageId: newMessageId,\n senderUserId: input.userId,\n recipientUserIds: input.recipients.map((item) => item.userId),\n sendViaEmail: input.sendViaEmail,\n externalEmail: responseExternalEmail,\n forwardedFrom: original.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n await emitMessageIndexUpsert(ctx.container, {\n messageId: newMessageId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n return {\n id: newMessageId,\n externalEmail: responseExternalEmail,\n recipientUserIds: input.recipients.map((item) => item.userId),\n }\n },\n async captureAfter(_input, result, ctx) {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadMessageAggregateSnapshot(em, result.id)\n },\n buildLog: async ({ input, result, snapshots }) => {\n const parsed = forwardCommandSchema.parse(input)\n return {\n actionLabel: 'Forward message',\n resourceKind: 'messages.message',\n resourceId: result.id,\n parentResourceKind: 'messages.message',\n parentResourceId: parsed.messageId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n after: (snapshots.after as MessageAggregateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<MessageAggregateSnapshot>,\n },\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageAggregateSnapshot>>(logEntry)\n const after = undo?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: after.message.id })\n if (!message) return\n message.deletedAt = new Date()\n await em.flush()\n await emitMessageGloballyDeletedEvent(ctx.container, {\n messageId: after.message.id,\n actorUserId: after.message.senderUserId,\n recipientUserIds: after.recipients.map((recipient) => recipient.recipientUserId),\n tenantId: after.message.tenantId,\n organizationId: after.message.organizationId,\n })\n },\n}\n\nconst deleteForActorCommand: CommandHandler<unknown, { ok: true }> = {\n id: 'messages.messages.delete_for_actor',\n async prepare(rawInput, ctx) {\n const input = deleteForActorCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireMessageById(em, input, input.messageId)\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n return {\n before: {\n messageId: message.id,\n messageDeletedAt: toIso(message.deletedAt),\n recipientId: recipient?.id ?? null,\n recipientStatus: recipient?.status ?? null,\n recipientDeletedAt: toIso(recipient?.deletedAt),\n } satisfies MessageDeleteUndoState,\n }\n },\n async execute(rawInput, ctx) {\n const input = deleteForActorCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireMessageById(em, input, input.messageId)\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (recipient) {\n recipient.status = 'deleted'\n recipient.deletedAt = new Date()\n await em.flush()\n await emitMessageDeletedEvent(ctx.container, {\n messageId: input.messageId,\n actorUserId: input.userId,\n target: 'recipient',\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n return { ok: true }\n }\n if (message.senderUserId === input.userId) {\n const recipientRows = await em.find(MessageRecipient, { messageId: input.messageId })\n message.deletedAt = new Date()\n await em.flush()\n const recipientUserIds = recipientRows\n .map((row) => row.recipientUserId)\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n await emitMessageGloballyDeletedEvent(ctx.container, {\n messageId: input.messageId,\n actorUserId: input.userId,\n recipientUserIds,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n return { ok: true }\n }\n throw new Error('Access denied')\n },\n async captureAfter(rawInput, _result, ctx) {\n const input = deleteForActorCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: input.messageId, tenantId: input.tenantId })\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n })\n return {\n messageId: input.messageId,\n messageDeletedAt: toIso(message?.deletedAt),\n recipientId: recipient?.id ?? null,\n recipientStatus: recipient?.status ?? null,\n recipientDeletedAt: toIso(recipient?.deletedAt),\n } satisfies MessageDeleteUndoState\n },\n buildLog: async ({ input, snapshots }) => {\n const parsed = deleteForActorCommandSchema.parse(input)\n return {\n actionLabel: 'Delete message for actor',\n resourceKind: 'messages.message',\n resourceId: parsed.messageId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n before: (snapshots.before as MessageDeleteUndoState | undefined) ?? null,\n after: (snapshots.after as MessageDeleteUndoState | undefined) ?? null,\n } satisfies UndoPayload<MessageDeleteUndoState>,\n },\n snapshotBefore: snapshots.before ?? null,\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageDeleteUndoState>>(logEntry)\n const before = undo?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: before.messageId })\n if (message) {\n message.deletedAt = toDate(before.messageDeletedAt)\n }\n if (before.recipientId) {\n const recipient = await em.findOne(MessageRecipient, { id: before.recipientId })\n if (recipient) {\n recipient.status = (before.recipientStatus ?? 'unread') as MessageRecipient['status']\n recipient.deletedAt = toDate(before.recipientDeletedAt)\n }\n }\n await em.flush()\n },\n}\n\nregisterCommand(composeMessageCommand)\nregisterCommand(updateDraftCommand)\nregisterCommand(replyMessageCommand)\nregisterCommand(forwardMessageCommand)\nregisterCommand(deleteForActorCommand)\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport { registerCommand, type CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport { extractUndoPayload, type UndoPayload } from '@open-mercato/shared/lib/commands/undo'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { Message, MessageObject, MessageRecipient, type MessageActionData } from '../data/entities'\nimport { emitMessagesEvent } from '../events'\nimport {\n composeMessageSchema,\n forwardMessageSchema,\n replyMessageSchema,\n updateDraftSchema,\n} from '../data/validators'\nimport { linkAttachmentsToMessage, linkLibraryAttachmentsToMessage, copyAttachmentsForForwardMessages } from '../lib/attachments'\nimport { MESSAGE_ATTACHMENT_ENTITY_ID, MESSAGE_ENTITY_ID } from '../lib/constants'\nimport { getMessageTypeOrDefault } from '../lib/message-types-registry'\nimport { validateMessageObjectsForType } from '../lib/object-validation'\nimport { buildForwardBodyFromLegacyInput, buildForwardPreviewFromThreadSlice, buildForwardThreadSlice } from '../lib/forwarding'\nimport {\n assertOrganizationAccess,\n loadMessageAggregateSnapshot,\n restoreMessageAggregateSnapshot,\n type MessageAggregateSnapshot,\n type MessageScopeInput,\n} from './shared'\n\ntype MessageSentEventPayload = {\n messageId: string\n senderUserId: string\n recipientUserIds: string[]\n sendViaEmail: boolean\n externalEmail?: string | null\n forwardedFrom?: string\n replyTo?: string\n tenantId: string\n organizationId?: string | null\n}\n\ntype ContainerWithResolve = {\n resolve: (name: string) => unknown\n}\n\nasync function emitMessageSentEvent(_container: ContainerWithResolve, payload: MessageSentEventPayload) {\n await emitMessagesEvent('messages.message.sent', payload, { persistent: true })\n}\n\nasync function emitMessageDeletedEvent(_container: ContainerWithResolve, payload: {\n messageId: string\n actorUserId: string\n target: 'sender' | 'recipient'\n tenantId: string\n organizationId: string | null\n}) {\n await emitMessagesEvent(\n 'messages.message.deleted',\n { ...payload, recipientUserId: payload.actorUserId },\n { persistent: true },\n )\n}\n\nasync function emitMessageGloballyDeletedEvent(_container: ContainerWithResolve, payload: {\n messageId: string\n actorUserId: string\n recipientUserIds: string[]\n tenantId: string\n organizationId: string | null\n}) {\n const audience = Array.from(new Set([payload.actorUserId, ...payload.recipientUserIds]))\n await emitMessagesEvent(\n 'messages.message.deleted',\n {\n messageId: payload.messageId,\n actorUserId: payload.actorUserId,\n target: 'global',\n recipientUserIds: audience,\n tenantId: payload.tenantId,\n organizationId: payload.organizationId,\n },\n { persistent: true },\n )\n}\n\nasync function emitMessageIndexUpsert(\n container: ContainerWithResolve,\n payload: {\n messageId: string\n tenantId: string\n organizationId: string | null\n },\n) {\n let bus: { emitEvent: (name: string, body: unknown, options?: unknown) => Promise<void> } | null = null\n try {\n bus = container.resolve('eventBus') as { emitEvent: (name: string, body: unknown, options?: unknown) => Promise<void> }\n } catch {\n bus = null\n }\n\n if (!bus) return\n\n await bus.emitEvent(\n 'query_index.upsert_one',\n {\n entityType: MESSAGE_ENTITY_ID,\n recordId: payload.messageId,\n tenantId: payload.tenantId,\n organizationId: payload.organizationId,\n crudAction: 'updated',\n coverageBaseDelta: 1,\n },\n {\n tenantId: payload.tenantId,\n organizationId: payload.organizationId,\n },\n ).catch(() => undefined)\n}\n\nconst scopeSchema = z.object({\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid().nullable(),\n userId: z.string().uuid(),\n})\n\nconst composeCommandSchema = composeMessageSchema.safeExtend({\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n // Optional dedup key (inbound email ingest sets it; other callers leave it\n // undefined). When set, a re-issued compose returns the first message instead\n // of creating a duplicate.\n idempotencyKey: z.string().min(1).max(255).optional(),\n})\n\nconst updateDraftCommandSchema = updateDraftSchema.safeExtend({\n messageId: z.string().uuid(),\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\nconst replyCommandSchema = replyMessageSchema.safeExtend({\n messageId: z.string().uuid(),\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\nconst forwardCommandSchema = forwardMessageSchema.safeExtend({\n messageId: z.string().uuid(),\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\nconst deleteForActorCommandSchema = z.object({\n messageId: z.string().uuid(),\n tenantId: scopeSchema.shape.tenantId,\n organizationId: scopeSchema.shape.organizationId,\n userId: scopeSchema.shape.userId,\n})\n\ntype ComposeCommandInput = z.infer<typeof composeCommandSchema>\ntype UpdateDraftCommandInput = z.infer<typeof updateDraftCommandSchema>\ntype ReplyCommandInput = z.infer<typeof replyCommandSchema>\ntype ForwardCommandInput = z.infer<typeof forwardCommandSchema>\ntype DeleteForActorCommandInput = z.infer<typeof deleteForActorCommandSchema>\n\ntype MessageDeleteUndoState = {\n messageId: string\n messageDeletedAt: string | null\n recipientId: string | null\n recipientStatus: 'unread' | 'read' | 'archived' | 'deleted' | null\n recipientDeletedAt: string | null\n}\n\nfunction toIso(value: Date | null | undefined): string | null {\n return value ? value.toISOString() : null\n}\n\nfunction toDate(value: string | null | undefined): Date | null {\n if (!value) return null\n return new Date(value)\n}\n\nfunction buildReplySubject(subject: string): string {\n if (/^re:\\s*/i.test(subject)) return subject\n return `Re: ${subject}`\n}\n\nasync function requireMessageById(\n em: EntityManager,\n scope: MessageScopeInput,\n messageId: string,\n) {\n const message = await findOneWithDecryption(\n em,\n Message,\n {\n id: messageId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n },\n )\n if (!message) throw new Error('Message not found')\n assertOrganizationAccess(scope, message)\n return message\n}\n\nfunction isUniqueViolation(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false\n const code = (err as { code?: string }).code\n if (code === '23505') return true\n const message = (err as { message?: string }).message\n return typeof message === 'string' && /duplicate key value|unique constraint/i.test(message)\n}\n\ntype ComposeMessageResult = {\n id: string\n threadId: string | null\n externalEmail: string | null\n isDraft: boolean\n recipientUserIds: string[]\n /**\n * True when this was an idempotent replay \u2014 an existing message was returned\n * and nothing was written. Signals `buildLog` to skip the audit/undo entry.\n */\n deduplicated?: boolean\n}\n\nasync function buildComposeResultFromExisting(\n em: EntityManager,\n message: Message,\n): Promise<ComposeMessageResult> {\n const recipients = await findWithDecryption(\n em,\n MessageRecipient,\n { messageId: message.id, deletedAt: null },\n undefined,\n { tenantId: message.tenantId, organizationId: message.organizationId ?? null },\n )\n return {\n id: message.id,\n threadId: message.threadId ?? null,\n externalEmail: message.externalEmail ?? null,\n isDraft: message.isDraft,\n recipientUserIds: recipients.map((recipient) => recipient.recipientUserId),\n deduplicated: true,\n }\n}\n\nconst composeMessageCommand: CommandHandler<unknown, { id: string; threadId: string | null; externalEmail: string | null; isDraft: boolean; recipientUserIds: string[]; deduplicated?: boolean }> = {\n id: 'messages.messages.compose',\n async execute(rawInput, ctx) {\n const input = composeCommandSchema.parse(rawInput)\n if (input.objects?.length) {\n const objectValidationError = validateMessageObjectsForType(input.type, input.objects)\n if (objectValidationError) throw new Error(objectValidationError)\n }\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const scope = { tenantId: input.tenantId, organizationId: input.organizationId }\n\n // Idempotency fast-path: a retried inbound-email ingest re-issues compose\n // for the same source message (the first attempt committed the message but a\n // downstream transient failure rolled the ingest back). Return that message\n // so the retry cannot create a duplicate.\n if (input.idempotencyKey) {\n const existing = await findOneWithDecryption(\n em,\n Message,\n { tenantId: input.tenantId, idempotencyKey: input.idempotencyKey },\n undefined,\n scope,\n )\n if (existing) return buildComposeResultFromExisting(em, existing)\n }\n\n let messageId = ''\n let responseThreadId: string | null = null\n let responseExternalEmail: string | null = null\n\n const composeTx = em.transactional(async (trx) => {\n const threadId = input.parentMessageId\n ? (\n await findOneWithDecryption(\n trx,\n Message,\n {\n id: input.parentMessageId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n )?.threadId ?? input.parentMessageId\n : undefined\n\n const isPublicVisibility = input.visibility === 'public'\n const sendViaEmail = isPublicVisibility ? true : input.sendViaEmail\n const message = trx.create(Message, {\n type: input.type,\n visibility: input.visibility ?? null,\n sourceEntityType: input.sourceEntityType,\n sourceEntityId: input.sourceEntityId,\n externalEmail: input.externalEmail,\n externalName: input.externalName,\n threadId: threadId ?? undefined,\n parentMessageId: input.parentMessageId,\n senderUserId: input.userId,\n subject: input.subject,\n body: input.body,\n bodyFormat: input.bodyFormat,\n priority: input.priority,\n status: input.isDraft ? 'draft' : 'sent',\n isDraft: input.isDraft ?? false,\n sentAt: input.isDraft ? null : new Date(),\n actionData: input.actionData as MessageActionData | undefined,\n sendViaEmail,\n idempotencyKey: input.idempotencyKey ?? null,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n await trx.persist(message).flush()\n if (!threadId && !input.isDraft && !message.threadId) {\n message.threadId = message.id\n await trx.flush()\n }\n\n for (const recipient of input.recipients) {\n trx.persist(trx.create(MessageRecipient, {\n messageId: message.id,\n recipientUserId: recipient.userId,\n recipientType: recipient.type,\n status: 'unread',\n }))\n }\n\n if (input.objects) {\n for (const obj of input.objects) {\n trx.persist(trx.create(MessageObject, {\n messageId: message.id,\n entityModule: obj.entityModule,\n entityType: obj.entityType,\n entityId: obj.entityId,\n actionRequired: obj.actionRequired,\n actionType: obj.actionType,\n actionLabel: obj.actionLabel,\n }))\n }\n }\n\n await trx.flush()\n\n if (input.attachmentIds?.length) {\n await linkAttachmentsToMessage(\n trx,\n message.id,\n input.attachmentIds,\n input.organizationId,\n input.tenantId,\n )\n }\n\n if (input.attachmentRecordId) {\n await linkLibraryAttachmentsToMessage(\n trx,\n message.id,\n input.attachmentRecordId,\n input.organizationId,\n input.tenantId,\n )\n }\n\n messageId = message.id\n responseThreadId = message.threadId ?? null\n responseExternalEmail = message.externalEmail ?? null\n })\n try {\n await composeTx\n } catch (err) {\n // Lost a concurrent race on the same idempotency key \u2014 return the message\n // the winning compose created. A propagated 23505 would otherwise be\n // classified permanent and dead-letter the inbound mail.\n if (input.idempotencyKey && isUniqueViolation(err)) {\n const existing = await findOneWithDecryption(\n em.fork(),\n Message,\n { tenantId: input.tenantId, idempotencyKey: input.idempotencyKey },\n undefined,\n scope,\n )\n if (existing) return buildComposeResultFromExisting(em.fork(), existing)\n }\n throw err\n }\n\n if (!input.isDraft) {\n await emitMessageSentEvent(ctx.container, {\n messageId,\n senderUserId: input.userId,\n recipientUserIds: input.recipients.map((recipient) => recipient.userId),\n sendViaEmail: input.visibility === 'public' ? true : input.sendViaEmail,\n externalEmail: responseExternalEmail,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n }\n\n await emitMessageIndexUpsert(ctx.container, {\n messageId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n return {\n id: messageId,\n threadId: responseThreadId,\n externalEmail: responseExternalEmail,\n isDraft: input.isDraft,\n recipientUserIds: input.recipients.map((recipient) => recipient.userId),\n }\n },\n async captureAfter(_input, result, ctx) {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadMessageAggregateSnapshot(em, result.id)\n },\n buildLog: async ({ input, result, snapshots }) => {\n // Idempotent replay: execute returned a pre-existing message without writing\n // anything. Skip the audit entry entirely \u2014 logging it as a fresh \"Compose\n // message\" would both misrepresent the dedup and expose an undo that\n // soft-deletes a legitimately-received inbound message.\n if (result.deduplicated) return { skipLog: true }\n const parsed = composeCommandSchema.parse(input)\n return {\n actionLabel: parsed.isDraft ? 'Create draft message' : 'Compose message',\n resourceKind: 'messages.message',\n resourceId: result.id,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n after: (snapshots.after as MessageAggregateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<MessageAggregateSnapshot>,\n },\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageAggregateSnapshot>>(logEntry)\n const after = undo?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: after.message.id })\n if (!message) return\n message.deletedAt = new Date()\n await em.flush()\n if (!after.message.isDraft) {\n await emitMessageGloballyDeletedEvent(ctx.container, {\n messageId: after.message.id,\n actorUserId: after.message.senderUserId,\n recipientUserIds: after.recipients.map((recipient) => recipient.recipientUserId),\n tenantId: after.message.tenantId,\n organizationId: after.message.organizationId,\n })\n }\n },\n}\n\nconst updateDraftCommand: CommandHandler<unknown, { ok: true; id: string }> = {\n id: 'messages.messages.update_draft',\n async prepare(rawInput, ctx) {\n const input = updateDraftCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadMessageAggregateSnapshot(em, input.messageId, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const input = updateDraftCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireMessageById(em, input, input.messageId)\n\n if (message.senderUserId !== input.userId) throw new Error('Access denied')\n if (!message.isDraft) throw new Error('Only draft messages can be edited')\n\n const isSending = input.isDraft === false\n const preloadedRecipients = isSending && !input.recipients\n ? await findWithDecryption(\n em,\n MessageRecipient,\n { messageId: message.id, deletedAt: null },\n undefined,\n {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n },\n )\n : null\n\n const nextMessageType = input.type ?? message.type\n if (input.objects) {\n const objectValidationError = validateMessageObjectsForType(nextMessageType, input.objects)\n if (objectValidationError) throw new Error(objectValidationError)\n } else if (input.type !== undefined) {\n const existingObjects = await em.find(MessageObject, { messageId: message.id })\n if (existingObjects.length > 0) {\n const objectValidationError = validateMessageObjectsForType(\n nextMessageType,\n existingObjects.map((item) => ({\n entityModule: item.entityModule,\n entityType: item.entityType,\n entityId: item.entityId,\n })),\n )\n if (objectValidationError) throw new Error(objectValidationError)\n }\n }\n\n await withAtomicFlush(em, [async () => {\n if (input.type !== undefined) message.type = input.type\n if (input.visibility !== undefined) message.visibility = input.visibility\n if (input.sourceEntityType !== undefined) message.sourceEntityType = input.sourceEntityType\n if (input.sourceEntityId !== undefined) message.sourceEntityId = input.sourceEntityId\n if (input.externalEmail !== undefined) message.externalEmail = input.externalEmail\n if (input.externalName !== undefined) message.externalName = input.externalName\n if (input.subject !== undefined) message.subject = input.subject\n if (input.body !== undefined) message.body = input.body\n if (input.bodyFormat !== undefined) message.bodyFormat = input.bodyFormat\n if (input.priority !== undefined) message.priority = input.priority\n if (input.actionData !== undefined) message.actionData = input.actionData\n if (input.sendViaEmail !== undefined) message.sendViaEmail = input.sendViaEmail\n\n if (input.recipients) {\n await em.nativeDelete(MessageRecipient, { messageId: message.id })\n for (const recipient of input.recipients) {\n em.persist(em.create(MessageRecipient, {\n messageId: message.id,\n recipientUserId: recipient.userId,\n recipientType: recipient.type,\n status: 'unread',\n }))\n }\n }\n\n if (input.objects) {\n await em.nativeDelete(MessageObject, { messageId: message.id })\n for (const object of input.objects) {\n em.persist(em.create(MessageObject, {\n messageId: message.id,\n entityModule: object.entityModule,\n entityType: object.entityType,\n entityId: object.entityId,\n actionRequired: object.actionRequired,\n actionType: object.actionType,\n actionLabel: object.actionLabel,\n }))\n }\n }\n\n if (input.attachmentIds) {\n const { Attachment } = await import('@open-mercato/core/modules/attachments/data/entities')\n if (input.attachmentIds.length === 0) {\n await em.nativeDelete(Attachment, {\n entityId: MESSAGE_ATTACHMENT_ENTITY_ID,\n recordId: message.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n } else {\n await em.nativeDelete(Attachment, {\n entityId: MESSAGE_ATTACHMENT_ENTITY_ID,\n recordId: message.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n id: { $nin: input.attachmentIds },\n })\n }\n await linkAttachmentsToMessage(\n em,\n message.id,\n input.attachmentIds,\n input.organizationId,\n input.tenantId,\n )\n }\n\n if (isSending) {\n const finalVisibility = input.visibility ?? message.visibility\n const finalSubject = input.subject ?? message.subject\n const finalBody = input.body ?? message.body\n const finalRecipientCount = input.recipients\n ? input.recipients.length\n : (preloadedRecipients?.length ?? 0)\n\n if (finalVisibility !== 'public' && finalRecipientCount === 0) {\n throw new Error('at least one recipient is required')\n }\n if (!finalSubject?.trim()) throw new Error('subject is required')\n if (!finalBody?.trim()) throw new Error('body is required')\n\n message.isDraft = false\n message.status = 'sent'\n message.sentAt = new Date()\n if (!message.threadId) message.threadId = message.id\n }\n }], { transaction: true })\n\n await emitMessageIndexUpsert(ctx.container, {\n messageId: message.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n if (isSending) {\n const recipientUserIds = input.recipients\n ? input.recipients.map((r) => r.userId)\n : (preloadedRecipients ?? []).map((r) => r.recipientUserId)\n const resolvedVisibility = input.visibility ?? message.visibility\n const resolvedSendViaEmail = input.sendViaEmail ?? message.sendViaEmail\n await emitMessageSentEvent(ctx.container, {\n messageId: message.id,\n senderUserId: input.userId,\n recipientUserIds,\n sendViaEmail: resolvedVisibility === 'public' ? true : resolvedSendViaEmail,\n externalEmail: message.externalEmail ?? null,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n }\n\n return { ok: true, id: message.id }\n },\n async captureAfter(rawInput, _result, ctx) {\n const input = updateDraftCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadMessageAggregateSnapshot(em, input.messageId, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n },\n buildLog: async ({ input, snapshots }) => {\n const parsed = updateDraftCommandSchema.parse(input)\n return {\n actionLabel: parsed.isDraft === false ? 'Send draft message' : 'Update draft message',\n resourceKind: 'messages.message',\n resourceId: parsed.messageId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n before: (snapshots.before as MessageAggregateSnapshot | undefined) ?? null,\n after: (snapshots.after as MessageAggregateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<MessageAggregateSnapshot>,\n },\n snapshotBefore: snapshots.before ?? null,\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageAggregateSnapshot>>(logEntry)\n const before = undo?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n await restoreMessageAggregateSnapshot(em, before)\n },\n}\n\nconst replyMessageCommand: CommandHandler<unknown, { id: string; externalEmail: string | null; recipientUserIds: string[] }> = {\n id: 'messages.messages.reply',\n async execute(rawInput, ctx) {\n const input = replyCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const original = await requireMessageById(em, input, input.messageId)\n const ownRecipient = await em.findOne(MessageRecipient, {\n messageId: original.id,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (original.senderUserId !== input.userId && !ownRecipient) throw new Error('Access denied')\n\n const messageType = getMessageTypeOrDefault(original.type)\n if (messageType.allowReply === false) throw new Error('Reply is not allowed for this message type')\n\n const recipientIds = new Set(\n (input.recipients ?? [])\n .map((recipient) => recipient.userId)\n .filter((recipientUserId) => recipientUserId !== input.userId),\n )\n\n if (recipientIds.size === 0) {\n const originalRecipients = await em.find(MessageRecipient, { messageId: original.id, deletedAt: null })\n if (input.replyAll) {\n if (original.senderUserId !== input.userId) recipientIds.add(original.senderUserId)\n for (const recipient of originalRecipients) {\n if (recipient.recipientUserId !== input.userId) recipientIds.add(recipient.recipientUserId)\n }\n } else if (original.senderUserId !== input.userId) {\n recipientIds.add(original.senderUserId)\n } else {\n for (const recipient of originalRecipients) {\n if (recipient.recipientUserId !== input.userId) {\n recipientIds.add(recipient.recipientUserId)\n break\n }\n }\n }\n\n if (recipientIds.size === 0 && original.senderUserId === input.userId) {\n recipientIds.add(input.userId)\n }\n }\n if (recipientIds.size === 0) throw new Error('No recipients available for reply')\n\n let messageId = ''\n let responseExternalEmail: string | null = null\n await em.transactional(async (trx) => {\n const message = trx.create(Message, {\n type: original.type,\n visibility: original.visibility ?? null,\n sourceEntityType: original.sourceEntityType,\n sourceEntityId: original.sourceEntityId,\n externalEmail: original.externalEmail,\n externalName: original.externalName,\n threadId: original.threadId ?? original.id,\n parentMessageId: original.id,\n senderUserId: input.userId,\n subject: buildReplySubject(original.subject),\n body: input.body,\n bodyFormat: input.bodyFormat,\n priority: original.priority,\n status: 'sent',\n isDraft: false,\n sentAt: new Date(),\n sendViaEmail: input.sendViaEmail,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n await trx.persist(message).flush()\n for (const recipientUserId of recipientIds) {\n trx.persist(trx.create(MessageRecipient, {\n messageId: message.id,\n recipientUserId,\n recipientType: 'to',\n status: 'unread',\n }))\n }\n await trx.flush()\n if (input.attachmentIds?.length) {\n await linkAttachmentsToMessage(\n trx,\n message.id,\n input.attachmentIds,\n input.organizationId,\n input.tenantId,\n )\n }\n if (input.attachmentRecordId) {\n await linkLibraryAttachmentsToMessage(\n trx,\n message.id,\n input.attachmentRecordId,\n input.organizationId,\n input.tenantId,\n )\n }\n messageId = message.id\n responseExternalEmail = message.externalEmail ?? null\n })\n\n await emitMessageSentEvent(ctx.container, {\n messageId,\n senderUserId: input.userId,\n recipientUserIds: Array.from(recipientIds),\n sendViaEmail: input.sendViaEmail,\n externalEmail: responseExternalEmail,\n replyTo: original.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n await emitMessageIndexUpsert(ctx.container, {\n messageId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n return {\n id: messageId,\n externalEmail: responseExternalEmail,\n recipientUserIds: Array.from(recipientIds),\n }\n },\n async captureAfter(_input, result, ctx) {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadMessageAggregateSnapshot(em, result.id)\n },\n buildLog: async ({ input, result, snapshots }) => {\n const parsed = replyCommandSchema.parse(input)\n return {\n actionLabel: 'Reply to message',\n resourceKind: 'messages.message',\n resourceId: result.id,\n parentResourceKind: 'messages.message',\n parentResourceId: parsed.messageId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n after: (snapshots.after as MessageAggregateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<MessageAggregateSnapshot>,\n },\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageAggregateSnapshot>>(logEntry)\n const after = undo?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: after.message.id })\n if (!message) return\n message.deletedAt = new Date()\n await em.flush()\n await emitMessageGloballyDeletedEvent(ctx.container, {\n messageId: after.message.id,\n actorUserId: after.message.senderUserId,\n recipientUserIds: after.recipients.map((recipient) => recipient.recipientUserId),\n tenantId: after.message.tenantId,\n organizationId: after.message.organizationId,\n })\n },\n}\n\nconst forwardMessageCommand: CommandHandler<unknown, { id: string; externalEmail: string | null; recipientUserIds: string[] }> = {\n id: 'messages.messages.forward',\n async execute(rawInput, ctx) {\n const input = forwardCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const original = await requireMessageById(em, input, input.messageId)\n const isRecipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (original.senderUserId !== input.userId && !isRecipient) throw new Error('Access denied')\n\n const messageType = getMessageTypeOrDefault(original.type)\n if (messageType.allowForward === false) throw new Error('Forward is not allowed for this message type')\n\n const originalObjects = await em.find(MessageObject, { messageId: input.messageId })\n const forwardThreadSlice = await buildForwardThreadSlice(em, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n }, original)\n const generatedPreview = await buildForwardPreviewFromThreadSlice(em, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n }, original, forwardThreadSlice)\n const forwardedBody = typeof input.body === 'string'\n ? input.body\n : buildForwardBodyFromLegacyInput(generatedPreview.body, input.additionalBody)\n let newMessageId = ''\n let responseExternalEmail: string | null = null\n await em.transactional(async (trx) => {\n const newMessage = trx.create(Message, {\n type: original.type,\n visibility: original.visibility ?? null,\n sourceEntityType: original.sourceEntityType,\n sourceEntityId: original.sourceEntityId,\n externalEmail: original.externalEmail,\n externalName: original.externalName,\n threadId: original.threadId ?? original.id,\n parentMessageId: original.id,\n senderUserId: input.userId,\n subject: `Fwd: ${original.subject}`,\n body: forwardedBody,\n bodyFormat: original.bodyFormat,\n priority: original.priority,\n status: 'sent',\n isDraft: false,\n sentAt: new Date(),\n sendViaEmail: input.sendViaEmail,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n await trx.persist(newMessage).flush()\n for (const recipient of input.recipients) {\n trx.persist(trx.create(MessageRecipient, {\n messageId: newMessage.id,\n recipientUserId: recipient.userId,\n recipientType: recipient.type,\n status: 'unread',\n }))\n }\n for (const obj of originalObjects) {\n trx.persist(trx.create(MessageObject, {\n messageId: newMessage.id,\n entityModule: obj.entityModule,\n entityType: obj.entityType,\n entityId: obj.entityId,\n actionRequired: obj.actionRequired,\n actionType: obj.actionType,\n actionLabel: obj.actionLabel,\n entitySnapshot: obj.entitySnapshot,\n }))\n }\n await trx.flush()\n if (input.includeAttachments !== false) {\n await copyAttachmentsForForwardMessages(\n trx,\n forwardThreadSlice.map((item) => item.id),\n newMessage.id,\n input.organizationId,\n input.tenantId,\n )\n }\n newMessageId = newMessage.id\n responseExternalEmail = newMessage.externalEmail ?? null\n })\n\n await emitMessageSentEvent(ctx.container, {\n messageId: newMessageId,\n senderUserId: input.userId,\n recipientUserIds: input.recipients.map((item) => item.userId),\n sendViaEmail: input.sendViaEmail,\n externalEmail: responseExternalEmail,\n forwardedFrom: original.id,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n await emitMessageIndexUpsert(ctx.container, {\n messageId: newMessageId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n\n return {\n id: newMessageId,\n externalEmail: responseExternalEmail,\n recipientUserIds: input.recipients.map((item) => item.userId),\n }\n },\n async captureAfter(_input, result, ctx) {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadMessageAggregateSnapshot(em, result.id)\n },\n buildLog: async ({ input, result, snapshots }) => {\n const parsed = forwardCommandSchema.parse(input)\n return {\n actionLabel: 'Forward message',\n resourceKind: 'messages.message',\n resourceId: result.id,\n parentResourceKind: 'messages.message',\n parentResourceId: parsed.messageId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n after: (snapshots.after as MessageAggregateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<MessageAggregateSnapshot>,\n },\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageAggregateSnapshot>>(logEntry)\n const after = undo?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: after.message.id })\n if (!message) return\n message.deletedAt = new Date()\n await em.flush()\n await emitMessageGloballyDeletedEvent(ctx.container, {\n messageId: after.message.id,\n actorUserId: after.message.senderUserId,\n recipientUserIds: after.recipients.map((recipient) => recipient.recipientUserId),\n tenantId: after.message.tenantId,\n organizationId: after.message.organizationId,\n })\n },\n}\n\nconst deleteForActorCommand: CommandHandler<unknown, { ok: true }> = {\n id: 'messages.messages.delete_for_actor',\n async prepare(rawInput, ctx) {\n const input = deleteForActorCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireMessageById(em, input, input.messageId)\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n return {\n before: {\n messageId: message.id,\n messageDeletedAt: toIso(message.deletedAt),\n recipientId: recipient?.id ?? null,\n recipientStatus: recipient?.status ?? null,\n recipientDeletedAt: toIso(recipient?.deletedAt),\n } satisfies MessageDeleteUndoState,\n }\n },\n async execute(rawInput, ctx) {\n const input = deleteForActorCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireMessageById(em, input, input.messageId)\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (recipient) {\n recipient.status = 'deleted'\n recipient.deletedAt = new Date()\n await em.flush()\n await emitMessageDeletedEvent(ctx.container, {\n messageId: input.messageId,\n actorUserId: input.userId,\n target: 'recipient',\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n return { ok: true }\n }\n if (message.senderUserId === input.userId) {\n const recipientRows = await em.find(MessageRecipient, { messageId: input.messageId })\n message.deletedAt = new Date()\n await em.flush()\n const recipientUserIds = recipientRows\n .map((row) => row.recipientUserId)\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n await emitMessageGloballyDeletedEvent(ctx.container, {\n messageId: input.messageId,\n actorUserId: input.userId,\n recipientUserIds,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n })\n return { ok: true }\n }\n throw new Error('Access denied')\n },\n async captureAfter(rawInput, _result, ctx) {\n const input = deleteForActorCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: input.messageId, tenantId: input.tenantId })\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n })\n return {\n messageId: input.messageId,\n messageDeletedAt: toIso(message?.deletedAt),\n recipientId: recipient?.id ?? null,\n recipientStatus: recipient?.status ?? null,\n recipientDeletedAt: toIso(recipient?.deletedAt),\n } satisfies MessageDeleteUndoState\n },\n buildLog: async ({ input, snapshots }) => {\n const parsed = deleteForActorCommandSchema.parse(input)\n return {\n actionLabel: 'Delete message for actor',\n resourceKind: 'messages.message',\n resourceId: parsed.messageId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n before: (snapshots.before as MessageDeleteUndoState | undefined) ?? null,\n after: (snapshots.after as MessageDeleteUndoState | undefined) ?? null,\n } satisfies UndoPayload<MessageDeleteUndoState>,\n },\n snapshotBefore: snapshots.before ?? null,\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<MessageDeleteUndoState>>(logEntry)\n const before = undo?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await em.findOne(Message, { id: before.messageId })\n if (message) {\n message.deletedAt = toDate(before.messageDeletedAt)\n }\n if (before.recipientId) {\n const recipient = await em.findOne(MessageRecipient, { id: before.recipientId })\n if (recipient) {\n recipient.status = (before.recipientStatus ?? 'unread') as MessageRecipient['status']\n recipient.deletedAt = toDate(before.recipientDeletedAt)\n }\n }\n await em.flush()\n },\n}\n\nregisterCommand(composeMessageCommand)\nregisterCommand(updateDraftCommand)\nregisterCommand(replyMessageCommand)\nregisterCommand(forwardMessageCommand)\nregisterCommand(deleteForActorCommand)\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,22 +1,33 @@
1
1
  "use client";
2
- import { jsx } from "react/jsx-runtime";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useRouter } from "next/navigation";
4
4
  import { MessageComposer } from "@open-mercato/ui/backend/messages";
5
+ import { InjectionSpot } from "@open-mercato/ui/backend/injection/InjectionSpot";
5
6
  function ComposeMessagePageClient() {
6
7
  const router = useRouter();
7
- return /* @__PURE__ */ jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsx(
8
- MessageComposer,
9
- {
10
- inline: true,
11
- variant: "compose",
12
- onCancel: () => {
13
- router.push("/backend/messages");
14
- },
15
- onSuccess: (result) => {
16
- router.push("/backend/messages");
8
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
9
+ /* @__PURE__ */ jsx(
10
+ InjectionSpot,
11
+ {
12
+ spotId: "crud-form:messages:message:fields",
13
+ context: { form: "compose" },
14
+ data: {}
17
15
  }
18
- }
19
- ) });
16
+ ),
17
+ /* @__PURE__ */ jsx(
18
+ MessageComposer,
19
+ {
20
+ inline: true,
21
+ variant: "compose",
22
+ onCancel: () => {
23
+ router.push("/backend/messages");
24
+ },
25
+ onSuccess: (result) => {
26
+ router.push("/backend/messages");
27
+ }
28
+ }
29
+ )
30
+ ] });
20
31
  }
21
32
  export {
22
33
  ComposeMessagePageClient
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/messages/components/ComposeMessagePageClient.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport { useRouter } from 'next/navigation'\nimport { MessageComposer } from '@open-mercato/ui/backend/messages'\n\nexport function ComposeMessagePageClient() {\n const router = useRouter()\n\n return (\n <div className=\"space-y-4\">\n <MessageComposer\n inline\n variant=\"compose\"\n onCancel={() => {\n router.push('/backend/messages')\n }}\n onSuccess={(result) => {\n router.push('/backend/messages')\n }}\n />\n </div>\n )\n}\n"],
5
- "mappings": ";AAUM;AARN,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;AAEzB,SAAS,2BAA2B;AACzC,QAAM,SAAS,UAAU;AAEzB,SACE,oBAAC,SAAI,WAAU,aACb;AAAA,IAAC;AAAA;AAAA,MACC,QAAM;AAAA,MACN,SAAQ;AAAA,MACR,UAAU,MAAM;AACd,eAAO,KAAK,mBAAmB;AAAA,MACjC;AAAA,MACA,WAAW,CAAC,WAAW;AACrB,eAAO,KAAK,mBAAmB;AAAA,MACjC;AAAA;AAAA,EACF,GACF;AAEJ;",
4
+ "sourcesContent": ["\"use client\"\n\nimport { useRouter } from 'next/navigation'\nimport { MessageComposer } from '@open-mercato/ui/backend/messages'\n// UMES extension surface \u2014 compose page injection spot (SPEC-045d \u00A79.3a).\n// Channel provider packages inject \"composer capabilities\" widgets here\n// (character limit warnings, channel format selector, attachment scoping, etc.).\nimport { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'\n\nexport function ComposeMessagePageClient() {\n const router = useRouter()\n\n return (\n <div className=\"space-y-4\">\n {/*\n Standalone widget mount above the composer \u2014 NOT CrudForm field\n resolution. This page is not a CrudForm, so the `crud-form:*:fields`\n field-event pipeline (onFieldChange, value transformers, etc.) does\n not apply here. Provider packages render composer-capability widgets\n (character-limit warnings, channel format selectors, attachment\n scoping) into this spot purely as additional UI siblings.\n */}\n <InjectionSpot\n spotId=\"crud-form:messages:message:fields\"\n context={{ form: 'compose' }}\n data={{}}\n />\n <MessageComposer\n inline\n variant=\"compose\"\n onCancel={() => {\n router.push('/backend/messages')\n }}\n onSuccess={(result) => {\n router.push('/backend/messages')\n }}\n />\n </div>\n )\n}\n"],
5
+ "mappings": ";AAaI,SASE,KATF;AAXJ,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;AAIhC,SAAS,qBAAqB;AAEvB,SAAS,2BAA2B;AACzC,QAAM,SAAS,UAAU;AAEzB,SACE,qBAAC,SAAI,WAAU,aASb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,QAAO;AAAA,QACP,SAAS,EAAE,MAAM,UAAU;AAAA,QAC3B,MAAM,CAAC;AAAA;AAAA,IACT;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,QAAM;AAAA,QACN,SAAQ;AAAA,QACR,UAAU,MAAM;AACd,iBAAO,KAAK,mBAAmB;AAAA,QACjC;AAAA,QACA,WAAW,CAAC,WAAW;AACrB,iBAAO,KAAK,mBAAmB;AAAA,QACjC;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;",
6
6
  "names": []
7
7
  }