@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
@@ -0,0 +1,103 @@
1
+ import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
2
+ import { ChannelThreadMapping, CommunicationChannel, MessageChannelLink } from "../data/entities.js";
3
+ import { Message } from "../../messages/data/entities.js";
4
+ import { COMMUNICATION_CHANNELS_QUEUES, getCommunicationChannelsQueue } from "../lib/queue.js";
5
+ const metadata = {
6
+ event: "messages.message.sent",
7
+ persistent: true,
8
+ id: "communication_channels:outbound-bridge"
9
+ };
10
+ function resolveFromCtx(ctx, name) {
11
+ if (typeof ctx?.resolve === "function") return ctx.resolve(name);
12
+ if (ctx?.container && typeof ctx.container.resolve === "function") {
13
+ return ctx.container.resolve(name);
14
+ }
15
+ throw new Error(`outbound-bridge: subscriber context has no resolver (looking for '${name}')`);
16
+ }
17
+ async function handler(payload, ctx) {
18
+ if (!payload?.messageId || !payload.tenantId) {
19
+ return;
20
+ }
21
+ const em = resolveFromCtx(ctx, "em").fork();
22
+ const dscope = {
23
+ tenantId: payload.tenantId,
24
+ organizationId: payload.organizationId ?? null
25
+ };
26
+ const message = await findOneWithDecryption(
27
+ em,
28
+ Message,
29
+ {
30
+ id: payload.messageId,
31
+ tenantId: payload.tenantId,
32
+ organizationId: payload.organizationId ?? null,
33
+ deletedAt: null
34
+ },
35
+ void 0,
36
+ dscope
37
+ );
38
+ if (!message) return;
39
+ if (message.sourceEntityType === "communication_channels.send_as_user") {
40
+ return;
41
+ }
42
+ if (message.sourceEntityType === "communication_channels.external_conversation") {
43
+ return;
44
+ }
45
+ if (!message.threadId) return;
46
+ const mapping = await findOneWithDecryption(
47
+ em,
48
+ ChannelThreadMapping,
49
+ {
50
+ messageThreadId: message.threadId,
51
+ tenantId: payload.tenantId,
52
+ organizationId: payload.organizationId ?? null
53
+ },
54
+ void 0,
55
+ dscope
56
+ );
57
+ if (!mapping) return;
58
+ const existingLink = await findOneWithDecryption(
59
+ em,
60
+ MessageChannelLink,
61
+ {
62
+ messageId: message.id,
63
+ tenantId: payload.tenantId,
64
+ organizationId: payload.organizationId ?? null
65
+ },
66
+ void 0,
67
+ dscope
68
+ );
69
+ if (existingLink && (existingLink.deliveryStatus === "queued" || existingLink.deliveryStatus === "pending" || existingLink.deliveryStatus === "sent" || existingLink.deliveryStatus === "delivered" || existingLink.deliveryStatus === "read")) {
70
+ return;
71
+ }
72
+ const channel = await findOneWithDecryption(
73
+ em,
74
+ CommunicationChannel,
75
+ {
76
+ id: mapping.channelId,
77
+ tenantId: payload.tenantId,
78
+ organizationId: payload.organizationId ?? null,
79
+ deletedAt: null
80
+ },
81
+ void 0,
82
+ dscope
83
+ );
84
+ if (!channel) return;
85
+ if (channel.userId != null && channel.userId !== message.senderUserId) {
86
+ return;
87
+ }
88
+ const queue = getCommunicationChannelsQueue(COMMUNICATION_CHANNELS_QUEUES.outbound);
89
+ const job = {
90
+ messageId: message.id,
91
+ scope: {
92
+ tenantId: payload.tenantId,
93
+ organizationId: payload.organizationId ?? null
94
+ },
95
+ attempt: 1
96
+ };
97
+ await queue.enqueue(job);
98
+ }
99
+ export {
100
+ handler as default,
101
+ metadata
102
+ };
103
+ //# sourceMappingURL=outbound-bridge.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/communication_channels/subscribers/outbound-bridge.ts"],
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { ChannelThreadMapping, CommunicationChannel, MessageChannelLink } from '../data/entities'\nimport { Message } from '../../messages/data/entities'\nimport { COMMUNICATION_CHANNELS_QUEUES, getCommunicationChannelsQueue } from '../lib/queue'\nimport type { OutboundDeliveryPayload } from '../workers/outbound-delivery'\n\n/**\n * Subscriber: outbound bridge.\n *\n * Listens to `messages.message.sent` and, when the Message lives in a channel-linked\n * thread, enqueues a delivery job to the `communication-channels-outbound` queue.\n *\n * Per the pre-implementation analysis we **re-fetch the Message by ID** rather than\n * trusting the event payload \u2014 this keeps the subscriber decoupled from the\n * `messages.message.sent` payload shape, so any future addition/removal of fields\n * in the messages module doesn't break this bridge.\n *\n * Idempotency: we check for an existing `MessageChannelLink` with `direction='outbound'`\n * and `deliveryStatus IN ('queued','pending','sent','delivered','read')`. If found, we\n * skip \u2014 the message is already delivered or has a delivery in flight. Including the\n * in-flight states ('queued'/'pending') stops a replayed `messages.message.sent` from\n * enqueueing a second delivery job while the worker is mid-send. The command-side check\n * is the authoritative gate, but this cheap subscriber-level check avoids redundant jobs.\n *\n * Internal-only messages (no `ChannelThreadMapping` for the threadId) are skipped\n * silently \u2014 this is the expected steady-state for the majority of platform messages.\n */\nexport const metadata = {\n event: 'messages.message.sent',\n persistent: true,\n id: 'communication_channels:outbound-bridge',\n}\n\ntype MessageSentPayload = {\n messageId: string\n senderUserId?: string\n recipientUserIds?: string[]\n sendViaEmail?: boolean\n externalEmail?: string | null\n tenantId: string\n organizationId?: string | null\n}\n\ntype SubscriberContext = {\n /** Canonical event-bus context: `resolve` is exposed directly (no `.container` wrapper). */\n resolve: <T = unknown>(name: string) => T\n /** Some callers wrap in a `container` \u2014 supported for forward-compat. */\n container?: { resolve: <T = unknown>(name: string) => T }\n}\n\nfunction resolveFromCtx<T = unknown>(ctx: SubscriberContext, name: string): T {\n if (typeof ctx?.resolve === 'function') return ctx.resolve<T>(name)\n if (ctx?.container && typeof ctx.container.resolve === 'function') {\n return ctx.container.resolve<T>(name)\n }\n throw new Error(`outbound-bridge: subscriber context has no resolver (looking for '${name}')`)\n}\n\nexport default async function handler(\n payload: MessageSentPayload,\n ctx: SubscriberContext,\n): Promise<void> {\n if (!payload?.messageId || !payload.tenantId) {\n return\n }\n\n const em = (resolveFromCtx<EntityManager>(ctx, 'em')).fork()\n const dscope = {\n tenantId: payload.tenantId,\n organizationId: payload.organizationId ?? null,\n }\n\n // (a) Re-fetch the Message \u2014 no payload-shape coupling.\n const message = await findOneWithDecryption(\n em,\n Message,\n {\n id: payload.messageId,\n tenantId: payload.tenantId,\n organizationId: payload.organizationId ?? null,\n deletedAt: null,\n },\n undefined,\n dscope,\n )\n if (!message) return\n if (message.sourceEntityType === 'communication_channels.send_as_user') {\n return\n }\n // Inbound ingest path: when `ingest-inbound-message` composes a new platform\n // Message for an incoming email, the messages module also emits\n // `messages.message.sent` (the Message row is fresh and marked sent). Without\n // this guard, we'd treat it as outbound and queue a redundant SMTP delivery \u2014\n // which fails because inbound MCLs carry recipient info in `channelPayload`,\n // not `channelMetadata`, and the failure marker then leaks back onto the\n // inbound link itself.\n if (message.sourceEntityType === 'communication_channels.external_conversation') {\n return\n }\n if (!message.threadId) return // Internal-only; no channel routing.\n\n // (b) Look up the channel mapping by threadId.\n const mapping = await findOneWithDecryption(\n em,\n ChannelThreadMapping,\n {\n messageThreadId: message.threadId,\n tenantId: payload.tenantId,\n organizationId: payload.organizationId ?? null,\n },\n undefined,\n dscope,\n )\n if (!mapping) return // Internal-only thread; skip silently.\n\n // (c) Idempotency \u2014 skip if already delivered.\n const existingLink = await findOneWithDecryption(\n em,\n MessageChannelLink,\n {\n messageId: message.id,\n tenantId: payload.tenantId,\n organizationId: payload.organizationId ?? null,\n },\n undefined,\n dscope,\n )\n if (\n existingLink &&\n (existingLink.deliveryStatus === 'queued' ||\n existingLink.deliveryStatus === 'pending' ||\n existingLink.deliveryStatus === 'sent' ||\n existingLink.deliveryStatus === 'delivered' ||\n existingLink.deliveryStatus === 'read')\n ) {\n return\n }\n\n // (c2) Per-user ownership gate. Outbound delivery sends with the CHANNEL\n // OWNER's credentials (workers/outbound-delivery \u2192 deliver-outbound-message),\n // so we may only bridge a platform message into a per-user channel when the\n // message's sender OWNS that channel. Tenant-wide channels (userId == null \u2014\n // shared inboxes) accept any sender. Without this, composing into another\n // user's channel-linked thread would send from their connected account\n // (impersonation). Mirrors lib/send-as-user and the reaction ownership gate.\n const channel = await findOneWithDecryption(\n em,\n CommunicationChannel,\n {\n id: mapping.channelId,\n tenantId: payload.tenantId,\n organizationId: payload.organizationId ?? null,\n deletedAt: null,\n },\n undefined,\n dscope,\n )\n if (!channel) return\n if (channel.userId != null && channel.userId !== message.senderUserId) {\n return\n }\n\n // (d) Enqueue the delivery worker.\n const queue = getCommunicationChannelsQueue(COMMUNICATION_CHANNELS_QUEUES.outbound)\n const job: OutboundDeliveryPayload = {\n messageId: message.id,\n scope: {\n tenantId: payload.tenantId,\n organizationId: payload.organizationId ?? null,\n },\n attempt: 1,\n }\n await queue.enqueue(job as unknown as Record<string, unknown>)\n}\n"],
5
+ "mappings": "AACA,SAAS,6BAA6B;AACtC,SAAS,sBAAsB,sBAAsB,0BAA0B;AAC/E,SAAS,eAAe;AACxB,SAAS,+BAA+B,qCAAqC;AAwBtE,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAmBA,SAAS,eAA4B,KAAwB,MAAiB;AAC5E,MAAI,OAAO,KAAK,YAAY,WAAY,QAAO,IAAI,QAAW,IAAI;AAClE,MAAI,KAAK,aAAa,OAAO,IAAI,UAAU,YAAY,YAAY;AACjE,WAAO,IAAI,UAAU,QAAW,IAAI;AAAA,EACtC;AACA,QAAM,IAAI,MAAM,qEAAqE,IAAI,IAAI;AAC/F;AAEA,eAAO,QACL,SACA,KACe;AACf,MAAI,CAAC,SAAS,aAAa,CAAC,QAAQ,UAAU;AAC5C;AAAA,EACF;AAEA,QAAM,KAAM,eAA8B,KAAK,IAAI,EAAG,KAAK;AAC3D,QAAM,SAAS;AAAA,IACb,UAAU,QAAQ;AAAA,IAClB,gBAAgB,QAAQ,kBAAkB;AAAA,EAC5C;AAGA,QAAM,UAAU,MAAM;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,MACE,IAAI,QAAQ;AAAA,MACZ,UAAU,QAAQ;AAAA,MAClB,gBAAgB,QAAQ,kBAAkB;AAAA,MAC1C,WAAW;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,CAAC,QAAS;AACd,MAAI,QAAQ,qBAAqB,uCAAuC;AACtE;AAAA,EACF;AAQA,MAAI,QAAQ,qBAAqB,gDAAgD;AAC/E;AAAA,EACF;AACA,MAAI,CAAC,QAAQ,SAAU;AAGvB,QAAM,UAAU,MAAM;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,MACE,iBAAiB,QAAQ;AAAA,MACzB,UAAU,QAAQ;AAAA,MAClB,gBAAgB,QAAQ,kBAAkB;AAAA,IAC5C;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,CAAC,QAAS;AAGd,QAAM,eAAe,MAAM;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,MACE,WAAW,QAAQ;AAAA,MACnB,UAAU,QAAQ;AAAA,MAClB,gBAAgB,QAAQ,kBAAkB;AAAA,IAC5C;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MACE,iBACC,aAAa,mBAAmB,YAC/B,aAAa,mBAAmB,aAChC,aAAa,mBAAmB,UAChC,aAAa,mBAAmB,eAChC,aAAa,mBAAmB,SAClC;AACA;AAAA,EACF;AASA,QAAM,UAAU,MAAM;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,MACE,IAAI,QAAQ;AAAA,MACZ,UAAU,QAAQ;AAAA,MAClB,gBAAgB,QAAQ,kBAAkB;AAAA,MAC1C,WAAW;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,CAAC,QAAS;AACd,MAAI,QAAQ,UAAU,QAAQ,QAAQ,WAAW,QAAQ,cAAc;AACrE;AAAA,EACF;AAGA,QAAM,QAAQ,8BAA8B,8BAA8B,QAAQ;AAClF,QAAM,MAA+B;AAAA,IACnC,WAAW,QAAQ;AAAA,IACnB,OAAO;AAAA,MACL,UAAU,QAAQ;AAAA,MAClB,gBAAgB,QAAQ,kBAAkB;AAAA,IAC5C;AAAA,IACA,SAAS;AAAA,EACX;AACA,QAAM,MAAM,QAAQ,GAAyC;AAC/D;",
6
+ "names": []
7
+ }
@@ -0,0 +1,51 @@
1
+ import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
2
+ import { CommunicationChannel } from "../data/entities.js";
3
+ const metadata = {
4
+ event: "auth.user.deleted",
5
+ persistent: true,
6
+ id: "communication_channels:user-deleted-cascade"
7
+ };
8
+ async function handler(payload, ctx) {
9
+ if (!payload || typeof payload.userId !== "string" || !payload.userId) {
10
+ return;
11
+ }
12
+ if (typeof payload.tenantId !== "string" || !payload.tenantId) {
13
+ return;
14
+ }
15
+ const em = ctx.resolve("em").fork();
16
+ const channels = await findWithDecryption(
17
+ em,
18
+ CommunicationChannel,
19
+ {
20
+ userId: payload.userId,
21
+ tenantId: payload.tenantId,
22
+ ...payload.organizationId !== void 0 ? { organizationId: payload.organizationId ?? null } : {},
23
+ deletedAt: null
24
+ },
25
+ void 0,
26
+ {
27
+ tenantId: payload.tenantId,
28
+ organizationId: payload.organizationId ?? null
29
+ }
30
+ );
31
+ if (channels.length === 0) return;
32
+ let touched = 0;
33
+ for (const channel of channels) {
34
+ if (channel.status === "disconnected" && channel.isActive === false) continue;
35
+ channel.status = "disconnected";
36
+ channel.isActive = false;
37
+ channel.credentialsRef = null;
38
+ channel.lastError = "user-deleted";
39
+ channel.isPrimary = false;
40
+ channel.lastPolledAt = /* @__PURE__ */ new Date();
41
+ touched += 1;
42
+ }
43
+ if (touched > 0) {
44
+ await em.flush();
45
+ }
46
+ }
47
+ export {
48
+ handler as default,
49
+ metadata
50
+ };
51
+ //# sourceMappingURL=user-deleted-cascade.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/communication_channels/subscribers/user-deleted-cascade.ts"],
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CommunicationChannel } from '../data/entities'\n\n/**\n * Subscriber: cascade-disconnect a user's communication channels when the user\n * is deleted (`auth.user.deleted` event).\n *\n * Why a subscriber, not a foreign-key CASCADE: per root `AGENTS.md`, modules\n * don't form direct ORM relationships across the auth module boundary \u2014\n * `CommunicationChannel.userId` is a plain `uuid` column, not a FK. The\n * cascade must therefore happen at the event-bridge layer, here, in response\n * to the auth module's lifecycle event.\n *\n * Effects per matched channel:\n * 1. `status = 'disconnected'` \u2014 stops the polling worker (slice 3b\n * skips channels not in `connected`).\n * 2. `is_active = false` \u2014 hides the channel from the hub admin\n * UI and stops adapter resolution.\n * 3. `credentials_ref = null` \u2014 orphans the encrypted credentials\n * blob in `integration_credentials`\n * (the integrations module's own\n * retention policy then sweeps it).\n * 4. `last_error = 'user-deleted'` \u2014 diagnostic breadcrumb.\n *\n * The channel row itself is NOT hard-deleted \u2014 keeping it preserves the audit\n * trail of which user owned it and the conversation history that still lives\n * in `external_messages` / `messages`. A future tenant-level GDPR sweep can\n * hard-delete on a schedule.\n *\n * Idempotency: the update is conditional on `status != 'disconnected'`, so\n * replays from the event bus are no-ops.\n */\nexport const metadata = {\n event: 'auth.user.deleted',\n persistent: true,\n id: 'communication_channels:user-deleted-cascade',\n}\n\ntype AuthUserDeletedPayload = {\n userId: string\n tenantId?: string\n organizationId?: string | null\n}\n\ntype SubscriberContext = {\n resolve: <T = unknown>(name: string) => T\n}\n\nexport default async function handler(\n payload: AuthUserDeletedPayload,\n ctx: SubscriberContext,\n): Promise<void> {\n if (!payload || typeof payload.userId !== 'string' || !payload.userId) {\n return\n }\n // tenantId MUST be present: an unscoped cascade would touch rows in arbitrary\n // tenants if two tenants ever happened to share a userId (impossible under\n // UUIDv4 but possible after backup-restore). Fail-closed: skip when missing\n // and let an out-of-band sweep clean up.\n if (typeof payload.tenantId !== 'string' || !payload.tenantId) {\n return\n }\n const em = (ctx.resolve('em') as EntityManager).fork()\n\n const channels = await findWithDecryption(\n em,\n CommunicationChannel,\n {\n userId: payload.userId,\n tenantId: payload.tenantId,\n ...(payload.organizationId !== undefined\n ? { organizationId: payload.organizationId ?? null }\n : {}),\n deletedAt: null,\n },\n undefined,\n {\n tenantId: payload.tenantId,\n organizationId: payload.organizationId ?? null,\n },\n )\n if (channels.length === 0) return\n\n let touched = 0\n for (const channel of channels) {\n // Already disconnected \u2192 idempotent skip.\n if (channel.status === 'disconnected' && channel.isActive === false) continue\n channel.status = 'disconnected'\n channel.isActive = false\n channel.credentialsRef = null\n channel.lastError = 'user-deleted'\n channel.isPrimary = false\n channel.lastPolledAt = new Date()\n touched += 1\n }\n if (touched > 0) {\n await em.flush()\n }\n}\n"],
5
+ "mappings": "AACA,SAAS,0BAA0B;AACnC,SAAS,4BAA4B;AA+B9B,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAYA,eAAO,QACL,SACA,KACe;AACf,MAAI,CAAC,WAAW,OAAO,QAAQ,WAAW,YAAY,CAAC,QAAQ,QAAQ;AACrE;AAAA,EACF;AAKA,MAAI,OAAO,QAAQ,aAAa,YAAY,CAAC,QAAQ,UAAU;AAC7D;AAAA,EACF;AACA,QAAM,KAAM,IAAI,QAAQ,IAAI,EAAoB,KAAK;AAErD,QAAM,WAAW,MAAM;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,MACE,QAAQ,QAAQ;AAAA,MAChB,UAAU,QAAQ;AAAA,MAClB,GAAI,QAAQ,mBAAmB,SAC3B,EAAE,gBAAgB,QAAQ,kBAAkB,KAAK,IACjD,CAAC;AAAA,MACL,WAAW;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,MACE,UAAU,QAAQ;AAAA,MAClB,gBAAgB,QAAQ,kBAAkB;AAAA,IAC5C;AAAA,EACF;AACA,MAAI,SAAS,WAAW,EAAG;AAE3B,MAAI,UAAU;AACd,aAAW,WAAW,UAAU;AAE9B,QAAI,QAAQ,WAAW,kBAAkB,QAAQ,aAAa,MAAO;AACrE,YAAQ,SAAS;AACjB,YAAQ,WAAW;AACnB,YAAQ,iBAAiB;AACzB,YAAQ,YAAY;AACpB,YAAQ,YAAY;AACpB,YAAQ,eAAe,oBAAI,KAAK;AAChC,eAAW;AAAA,EACb;AACA,MAAI,UAAU,GAAG;AACf,UAAM,GAAG,MAAM;AAAA,EACjB;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,7 @@
1
+ const componentOverrides = [];
2
+ var components_default = componentOverrides;
3
+ export {
4
+ componentOverrides,
5
+ components_default as default
6
+ };
7
+ //# sourceMappingURL=components.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/communication_channels/widgets/components.ts"],
4
+ "sourcesContent": ["import type { ComponentOverride } from '@open-mercato/shared/modules/widgets/component-registry'\n\n/**\n * Component override scaffold for the Communications Hub.\n *\n * Phase 4 of the email integration spec (`2026-05-21-email-integration-foundation`)\n * adds a `MessagesThreadDetailHeader` override for `channelType=email`. The shipping\n * Messages module renders the header via `MainMessageHeader` and does not yet expose\n * a registered component id \u2014 the header is rendered as a regular React component\n * in `MessageDetailPageClient.tsx`. The override mechanism (this file, plus the\n * `widgets/components.ts` auto-discovery convention) is wired and ready for the\n * Messages module to opt in by registering the component.\n *\n * Today, email-specific affordances (subject / Cc list / attachment count / Gmail\n * labels) are delivered to the Messages thread view via the\n * existing `detail:messages:message:body:after` injection spot's\n * `channel-payload-renderer` widget (slice 2e/2f). That widget renders the same\n * affordances the spec lists as header content, just below the header rather than\n * inside it. Surfacing them inside the header is the v2 upgrade path.\n *\n * Forward-compatible handle ids the hub will target once Messages exposes them:\n * - `section:messages.detail.header` \u2014 primary slot; the email override\n * wraps it with the email banner above\n * the default header.\n * - `data-table:messages:row` \u2014 secondary slot; email-channel rows\n * get a small inline preview of the\n * first-from name + envelope icon.\n *\n * Until Messages calls `registerComponent({ id: 'section:messages.detail.header', ... })`,\n * this file exports an empty array \u2014 the hub honors the override-mechanism\n * contract (downstream apps can target hub-side handles) without inventing\n * fictional component ids the Messages module doesn't surface.\n */\nexport const componentOverrides: ComponentOverride[] = []\n\nexport default componentOverrides\n"],
5
+ "mappings": "AAiCO,MAAM,qBAA0C,CAAC;AAExD,IAAO,qBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,18 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { Tag } from "@open-mercato/ui/primitives/tag";
4
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
5
+ function ChannelBadgeWidget({ channel }) {
6
+ const t = useT();
7
+ if (!channel) return null;
8
+ const providerLabel = channel.providerKey ?? channel.channelType ?? "";
9
+ const variant = channel.direction === "outbound" ? "info" : "success";
10
+ return /* @__PURE__ */ jsx(Tag, { variant, dot: true, children: t(
11
+ `communication_channels.channel.providers.${providerLabel}`,
12
+ providerLabel
13
+ ) });
14
+ }
15
+ export {
16
+ ChannelBadgeWidget as default
17
+ };
18
+ //# sourceMappingURL=widget.client.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/communication_channels/widgets/injection/channel-badge/widget.client.tsx"],
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\ntype ChannelEnrichment = {\n providerKey?: string\n channelType?: string\n direction?: 'inbound' | 'outbound' | string\n deliveryStatus?: string | null\n}\n\nexport type ChannelBadgeProps = {\n channel: ChannelEnrichment | null | undefined\n}\n\n/**\n * Pure presentational badge \u2014 renders the channel provider/type as a `<Tag>`\n * pill. The host (declarative column injection \u2014 see `widget.ts`) feeds the\n * `_channel` enrichment in.\n */\nexport default function ChannelBadgeWidget({ channel }: ChannelBadgeProps) {\n const t = useT()\n if (!channel) return null\n\n const providerLabel = channel.providerKey ?? channel.channelType ?? ''\n const variant: 'success' | 'info' = channel.direction === 'outbound' ? 'info' : 'success'\n\n return (\n <Tag variant={variant} dot>\n {t(\n `communication_channels.channel.providers.${providerLabel}`,\n providerLabel,\n )}\n </Tag>\n )\n}\n"],
5
+ "mappings": ";AA8BI;AA3BJ,SAAS,WAAW;AACpB,SAAS,YAAY;AAkBN,SAAR,mBAAoC,EAAE,QAAQ,GAAsB;AACzE,QAAM,IAAI,KAAK;AACf,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,gBAAgB,QAAQ,eAAe,QAAQ,eAAe;AACpE,QAAM,UAA8B,QAAQ,cAAc,aAAa,SAAS;AAEhF,SACE,oBAAC,OAAI,SAAkB,KAAG,MACvB;AAAA,IACC,4CAA4C,aAAa;AAAA,IACzD;AAAA,EACF,GACF;AAEJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,30 @@
1
+ import * as React from "react";
2
+ import ChannelBadgeWidget from "./widget.client.js";
3
+ const widget = {
4
+ metadata: {
5
+ id: "communication_channels.injection.channel-badge",
6
+ title: "Channel badge",
7
+ description: "Renders a channel-type/provider badge inline in the messages list. Visible whenever a message has an associated MessageChannelLink (= the message was bridged from or to an external channel).",
8
+ features: ["communication_channels.view"],
9
+ priority: 100,
10
+ enabled: true
11
+ },
12
+ columns: [
13
+ {
14
+ id: "communication_channels.channel-badge",
15
+ header: "communication_channels.columns.provider",
16
+ accessorKey: "_channel",
17
+ size: 140,
18
+ cell: ({ getValue }) => {
19
+ const channel = getValue();
20
+ if (!channel) return null;
21
+ return React.createElement(ChannelBadgeWidget, { channel });
22
+ }
23
+ }
24
+ ]
25
+ };
26
+ var widget_default = widget;
27
+ export {
28
+ widget_default as default
29
+ };
30
+ //# sourceMappingURL=widget.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/communication_channels/widgets/injection/channel-badge/widget.ts"],
4
+ "sourcesContent": ["import * as React from 'react'\nimport type { InjectionColumnWidget } from '@open-mercato/shared/modules/widgets/injection'\nimport ChannelBadgeWidget from './widget.client'\n\n/**\n * Channel badge \u2014 renders the channel type/provider icon + label as a `<Tag>`\n * pill in the messages DataTable's columns spot (`data-table:messages:columns`).\n *\n * DataTable's column-injection contract requires a declarative `columns` array\n * of `InjectionColumnDefinition` \u2014 the registry filters out widgets that don't\n * expose `columns`. The cell renderer is a React component that reads the\n * `_channel` enrichment field added by `messageChannelEnricher`.\n *\n * Round-1/round-2 review trail: round-1 shipped this as an\n * `InjectionWidgetModule` with a top-level `Widget` component, which DataTable\n * silently skipped (`if (!('columns' in widget)) continue`). Round-2 R2-H6 / F7\n * (2026-05-26) converted it to the declarative column shape.\n *\n * Provider packages can override this widget via UMES component replacement\n * (`section:communication_channels.channel-badge`) to render brand-specific\n * badges (Slack logo, WhatsApp green badge, etc.).\n */\nconst widget: InjectionColumnWidget = {\n metadata: {\n id: 'communication_channels.injection.channel-badge',\n title: 'Channel badge',\n description:\n 'Renders a channel-type/provider badge inline in the messages list. Visible whenever a message has an associated MessageChannelLink (= the message was bridged from or to an external channel).',\n features: ['communication_channels.view'],\n priority: 100,\n enabled: true,\n },\n columns: [\n {\n id: 'communication_channels.channel-badge',\n header: 'communication_channels.columns.provider',\n accessorKey: '_channel',\n size: 140,\n cell: ({ getValue }) => {\n const channel = getValue() as\n | { providerKey?: string; channelType?: string; direction?: string; deliveryStatus?: string | null }\n | null\n | undefined\n if (!channel) return null\n return React.createElement(ChannelBadgeWidget, { channel })\n },\n },\n ],\n}\n\nexport default widget\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;AAEvB,OAAO,wBAAwB;AAoB/B,MAAM,SAAgC;AAAA,EACpC,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,aACE;AAAA,IACF,UAAU,CAAC,6BAA6B;AAAA,IACxC,UAAU;AAAA,IACV,SAAS;AAAA,EACX;AAAA,EACA,SAAS;AAAA,IACP;AAAA,MACE,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,MAAM;AAAA,MACN,MAAM,CAAC,EAAE,SAAS,MAAM;AACtB,cAAM,UAAU,SAAS;AAIzB,YAAI,CAAC,QAAS,QAAO;AACrB,eAAO,MAAM,cAAc,oBAAoB,EAAE,QAAQ,CAAC;AAAA,MAC5D;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,iBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,185 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { hasFeature } from "@open-mercato/shared/security/features";
5
+ import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
6
+ import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
7
+ import { flash } from "@open-mercato/ui/backend/FlashMessages";
8
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
9
+ import {
10
+ Select,
11
+ SelectContent,
12
+ SelectItem,
13
+ SelectTrigger,
14
+ SelectValue
15
+ } from "@open-mercato/ui/primitives/select";
16
+ const FEATURE_GATE = "communication_channels.assign";
17
+ const CHANNEL_INFO_MUTATION_CONTEXT_ID = "communication-channels-info-panel";
18
+ const UNASSIGNED_VALUE = "__unassigned__";
19
+ function ChannelInfoPanelWidget({
20
+ data,
21
+ context
22
+ }) {
23
+ const t = useT();
24
+ const channel = data?._channel ?? null;
25
+ const contact = data?._channelContact ?? null;
26
+ const { runMutation, retryLastMutation } = useGuardedMutation({
27
+ contextId: CHANNEL_INFO_MUTATION_CONTEXT_ID,
28
+ blockedMessage: t("ui.forms.flash.saveBlocked", "Save blocked by validation")
29
+ });
30
+ const canReassign = hasFeature(context?.userFeatures ?? [], FEATURE_GATE);
31
+ const [assignedUserId, setAssignedUserId] = React.useState(
32
+ contact?.assignedUserId ?? null
33
+ );
34
+ const [savingAssignee, setSavingAssignee] = React.useState(false);
35
+ const [users, setUsers] = React.useState([]);
36
+ const [usersLoaded, setUsersLoaded] = React.useState(false);
37
+ React.useEffect(
38
+ () => setAssignedUserId(contact?.assignedUserId ?? null),
39
+ [contact?.assignedUserId]
40
+ );
41
+ const loadUsers = React.useCallback(async () => {
42
+ if (usersLoaded || !canReassign) return;
43
+ const response = await apiCall("/api/auth/users?page=1&pageSize=50", {
44
+ // Opportunistic dropdown-options fetch: a user may hold
45
+ // `communication_channels.assign` without `auth.users.list`. Suppress the
46
+ // global 403/401 redirect + forbidden flash so the page degrades to an
47
+ // empty assignee list instead of bouncing the whole browser to /login.
48
+ headers: { "x-om-forbidden-redirect": "0", "x-om-unauthorized-redirect": "0" }
49
+ }).catch(() => null);
50
+ if (!response || !response.ok) {
51
+ setUsersLoaded(true);
52
+ return;
53
+ }
54
+ const items = (response.result?.items ?? []).flatMap((u) => {
55
+ if (!u?.id) return [];
56
+ const label = typeof u.name === "string" && u.name.trim().length > 0 && u.name.trim() || typeof u.email === "string" && u.email.trim().length > 0 && u.email.trim() || u.id;
57
+ return [{ id: u.id, label }];
58
+ });
59
+ setUsers(items);
60
+ setUsersLoaded(true);
61
+ }, [canReassign, usersLoaded]);
62
+ const reassign = React.useCallback(
63
+ async (nextAssignedUserId) => {
64
+ const threadId = data?.threadId;
65
+ if (!threadId) {
66
+ flash(
67
+ t(
68
+ "communication_channels.infoPanel.noThread",
69
+ "This message is not on a thread; reassignment unavailable."
70
+ ),
71
+ "error"
72
+ );
73
+ return;
74
+ }
75
+ setSavingAssignee(true);
76
+ try {
77
+ const response = await runMutation({
78
+ operation: () => apiCall(
79
+ `/api/communication_channels/threads/${encodeURIComponent(threadId)}/assign`,
80
+ {
81
+ method: "PUT",
82
+ headers: { "content-type": "application/json" },
83
+ body: JSON.stringify({ assignedUserId: nextAssignedUserId })
84
+ }
85
+ ),
86
+ context: {
87
+ formId: CHANNEL_INFO_MUTATION_CONTEXT_ID,
88
+ resourceKind: "communication_channels.thread",
89
+ resourceId: threadId,
90
+ retryLastMutation
91
+ },
92
+ mutationPayload: { assignedUserId: nextAssignedUserId }
93
+ });
94
+ if (!response.ok) {
95
+ const body = response.result;
96
+ flash(
97
+ body?.error ?? t("communication_channels.infoPanel.reassignError", "Reassignment failed"),
98
+ "error"
99
+ );
100
+ return;
101
+ }
102
+ setAssignedUserId(nextAssignedUserId);
103
+ flash(
104
+ t("communication_channels.infoPanel.reassignSuccess", "Conversation reassigned."),
105
+ "success"
106
+ );
107
+ } catch (err) {
108
+ flash(
109
+ err instanceof Error ? err.message : t("communication_channels.infoPanel.reassignError", "Reassignment failed"),
110
+ "error"
111
+ );
112
+ } finally {
113
+ setSavingAssignee(false);
114
+ }
115
+ },
116
+ [data?.threadId, retryLastMutation, runMutation, t]
117
+ );
118
+ if (!channel) return null;
119
+ return /* @__PURE__ */ jsxs(
120
+ "aside",
121
+ {
122
+ className: "rounded-md border bg-card p-4 text-sm",
123
+ "aria-label": t("communication_channels.infoPanel.aria", "Channel info"),
124
+ children: [
125
+ /* @__PURE__ */ jsx("header", { className: "mb-2 text-overline text-muted-foreground", children: t("communication_channels.infoPanel.title", "Channel info") }),
126
+ /* @__PURE__ */ jsxs("dl", { className: "grid grid-cols-2 gap-1 text-xs", children: [
127
+ /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: t("communication_channels.infoPanel.provider", "Provider") }),
128
+ /* @__PURE__ */ jsx("dd", { children: channel.providerKey }),
129
+ /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: t("communication_channels.infoPanel.type", "Type") }),
130
+ /* @__PURE__ */ jsx("dd", { children: channel.channelType }),
131
+ /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: t("communication_channels.infoPanel.direction", "Direction") }),
132
+ /* @__PURE__ */ jsx("dd", { children: channel.direction }),
133
+ channel.deliveryStatus ? /* @__PURE__ */ jsxs(Fragment, { children: [
134
+ /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: t("communication_channels.infoPanel.status", "Status") }),
135
+ /* @__PURE__ */ jsx("dd", { children: channel.deliveryStatus })
136
+ ] }) : null,
137
+ contact?.contactPersonId ? /* @__PURE__ */ jsxs(Fragment, { children: [
138
+ /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: t("communication_channels.infoPanel.contactPerson", "CRM contact") }),
139
+ /* @__PURE__ */ jsx("dd", { className: "truncate", title: contact.contactPersonId, children: contact.contactPersonId })
140
+ ] }) : null,
141
+ contact?.subject ? /* @__PURE__ */ jsxs(Fragment, { children: [
142
+ /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: t("communication_channels.infoPanel.subject", "Subject") }),
143
+ /* @__PURE__ */ jsx("dd", { className: "col-span-2 truncate", title: contact.subject, children: contact.subject })
144
+ ] }) : null,
145
+ /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: t("communication_channels.infoPanel.assignedTo", "Assigned to") }),
146
+ /* @__PURE__ */ jsx("dd", { className: "col-span-1", children: canReassign ? /* @__PURE__ */ jsxs(
147
+ Select,
148
+ {
149
+ value: assignedUserId ?? UNASSIGNED_VALUE,
150
+ onValueChange: (value) => void reassign(value === UNASSIGNED_VALUE ? null : value),
151
+ onOpenChange: (isOpen) => {
152
+ if (isOpen) void loadUsers();
153
+ },
154
+ disabled: savingAssignee || !data?.threadId,
155
+ children: [
156
+ /* @__PURE__ */ jsx(
157
+ SelectTrigger,
158
+ {
159
+ size: "xs",
160
+ "aria-label": t("communication_channels.infoPanel.assignedTo", "Assigned to"),
161
+ children: /* @__PURE__ */ jsx(
162
+ SelectValue,
163
+ {
164
+ placeholder: t("communication_channels.infoPanel.unassigned", "Unassigned")
165
+ }
166
+ )
167
+ }
168
+ ),
169
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
170
+ /* @__PURE__ */ jsx(SelectItem, { value: UNASSIGNED_VALUE, children: t("communication_channels.infoPanel.unassigned", "Unassigned") }),
171
+ assignedUserId && !users.some((u) => u.id === assignedUserId) ? /* @__PURE__ */ jsx(SelectItem, { value: assignedUserId, children: assignedUserId }) : null,
172
+ users.map((user) => /* @__PURE__ */ jsx(SelectItem, { value: user.id, children: user.label }, user.id))
173
+ ] })
174
+ ]
175
+ }
176
+ ) : /* @__PURE__ */ jsx("span", { className: "truncate", title: assignedUserId ?? "", children: assignedUserId ?? t("communication_channels.infoPanel.unassigned", "Unassigned") }) })
177
+ ] })
178
+ ]
179
+ }
180
+ );
181
+ }
182
+ export {
183
+ ChannelInfoPanelWidget as default
184
+ };
185
+ //# sourceMappingURL=widget.client.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/communication_channels/widgets/injection/channel-info-panel/widget.client.tsx"],
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport { hasFeature } from '@open-mercato/shared/security/features'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\n\ntype ChannelEnrichment = {\n providerKey: string\n channelType: string\n direction: 'inbound' | 'outbound' | string\n deliveryStatus: string | null\n}\n\ntype ChannelContactEnrichment = {\n contactPersonId: string | null\n assignedUserId: string | null\n subject: string | null\n}\n\ntype MessageWithChannelContext = Record<string, unknown> & {\n id?: string\n threadId?: string | null\n _channel?: ChannelEnrichment | null\n _channelContact?: ChannelContactEnrichment | null\n}\n\ntype WidgetContext = Record<string, unknown> & {\n /**\n * Set when the host (e.g. message detail page) provides the current user's\n * feature grants. The reassignment editor is hidden when\n * `communication_channels.assign` is not present. Wildcard grants\n * (`*` and `communication_channels.*`) are honored too.\n */\n userFeatures?: string[]\n}\n\ntype UserOption = { id: string; label: string }\n\nconst FEATURE_GATE = 'communication_channels.assign'\nconst CHANNEL_INFO_MUTATION_CONTEXT_ID = 'communication-channels-info-panel'\n// Radix Select reserves '' for \"no selection\"; use a sentinel for Unassigned.\nconst UNASSIGNED_VALUE = '__unassigned__'\n\ntype ChannelInfoMutationContext = {\n formId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n}\n\nexport default function ChannelInfoPanelWidget({\n data,\n context,\n}: InjectionWidgetComponentProps<WidgetContext, MessageWithChannelContext>) {\n const t = useT()\n const channel = data?._channel ?? null\n const contact = data?._channelContact ?? null\n const { runMutation, retryLastMutation } = useGuardedMutation<ChannelInfoMutationContext>({\n contextId: CHANNEL_INFO_MUTATION_CONTEXT_ID,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n const canReassign = hasFeature(context?.userFeatures ?? [], FEATURE_GATE)\n\n const [assignedUserId, setAssignedUserId] = React.useState<string | null>(\n contact?.assignedUserId ?? null,\n )\n const [savingAssignee, setSavingAssignee] = React.useState(false)\n const [users, setUsers] = React.useState<UserOption[]>([])\n const [usersLoaded, setUsersLoaded] = React.useState(false)\n\n React.useEffect(\n () => setAssignedUserId(contact?.assignedUserId ?? null),\n [contact?.assignedUserId],\n )\n\n const loadUsers = React.useCallback(async () => {\n if (usersLoaded || !canReassign) return\n const response = await apiCall<{\n items?: Array<{ id: string; email?: string | null; name?: string | null }>\n }>('/api/auth/users?page=1&pageSize=50', {\n // Opportunistic dropdown-options fetch: a user may hold\n // `communication_channels.assign` without `auth.users.list`. Suppress the\n // global 403/401 redirect + forbidden flash so the page degrades to an\n // empty assignee list instead of bouncing the whole browser to /login.\n headers: { 'x-om-forbidden-redirect': '0', 'x-om-unauthorized-redirect': '0' },\n }).catch(() => null)\n if (!response || !response.ok) {\n setUsersLoaded(true)\n return\n }\n const items = (response.result?.items ?? []).flatMap<UserOption>((u) => {\n if (!u?.id) return []\n const label =\n (typeof u.name === 'string' && u.name.trim().length > 0 && u.name.trim()) ||\n (typeof u.email === 'string' && u.email.trim().length > 0 && u.email.trim()) ||\n u.id\n return [{ id: u.id, label }]\n })\n setUsers(items)\n setUsersLoaded(true)\n }, [canReassign, usersLoaded])\n\n const reassign = React.useCallback(\n async (nextAssignedUserId: string | null) => {\n const threadId = data?.threadId\n if (!threadId) {\n flash(\n t(\n 'communication_channels.infoPanel.noThread',\n 'This message is not on a thread; reassignment unavailable.',\n ),\n 'error',\n )\n return\n }\n setSavingAssignee(true)\n try {\n const response = await runMutation({\n operation: () => apiCall<{ assignedUserId: string | null }>(\n `/api/communication_channels/threads/${encodeURIComponent(threadId)}/assign`,\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ assignedUserId: nextAssignedUserId }),\n },\n ),\n context: {\n formId: CHANNEL_INFO_MUTATION_CONTEXT_ID,\n resourceKind: 'communication_channels.thread',\n resourceId: threadId,\n retryLastMutation,\n },\n mutationPayload: { assignedUserId: nextAssignedUserId },\n })\n if (!response.ok) {\n const body = response.result as { error?: string } | undefined\n flash(\n body?.error ??\n t('communication_channels.infoPanel.reassignError', 'Reassignment failed'),\n 'error',\n )\n return\n }\n setAssignedUserId(nextAssignedUserId)\n flash(\n t('communication_channels.infoPanel.reassignSuccess', 'Conversation reassigned.'),\n 'success',\n )\n } catch (err) {\n flash(\n err instanceof Error\n ? err.message\n : t('communication_channels.infoPanel.reassignError', 'Reassignment failed'),\n 'error',\n )\n } finally {\n setSavingAssignee(false)\n }\n },\n [data?.threadId, retryLastMutation, runMutation, t],\n )\n\n if (!channel) return null\n\n return (\n <aside\n className=\"rounded-md border bg-card p-4 text-sm\"\n aria-label={t('communication_channels.infoPanel.aria', 'Channel info')}\n >\n <header className=\"mb-2 text-overline text-muted-foreground\">\n {t('communication_channels.infoPanel.title', 'Channel info')}\n </header>\n <dl className=\"grid grid-cols-2 gap-1 text-xs\">\n <dt className=\"text-muted-foreground\">\n {t('communication_channels.infoPanel.provider', 'Provider')}\n </dt>\n <dd>{channel.providerKey}</dd>\n\n <dt className=\"text-muted-foreground\">\n {t('communication_channels.infoPanel.type', 'Type')}\n </dt>\n <dd>{channel.channelType}</dd>\n\n <dt className=\"text-muted-foreground\">\n {t('communication_channels.infoPanel.direction', 'Direction')}\n </dt>\n <dd>{channel.direction}</dd>\n\n {channel.deliveryStatus ? (\n <>\n <dt className=\"text-muted-foreground\">\n {t('communication_channels.infoPanel.status', 'Status')}\n </dt>\n <dd>{channel.deliveryStatus}</dd>\n </>\n ) : null}\n\n {contact?.contactPersonId ? (\n <>\n <dt className=\"text-muted-foreground\">\n {t('communication_channels.infoPanel.contactPerson', 'CRM contact')}\n </dt>\n <dd className=\"truncate\" title={contact.contactPersonId}>\n {contact.contactPersonId}\n </dd>\n </>\n ) : null}\n\n {contact?.subject ? (\n <>\n <dt className=\"text-muted-foreground\">\n {t('communication_channels.infoPanel.subject', 'Subject')}\n </dt>\n <dd className=\"col-span-2 truncate\" title={contact.subject}>\n {contact.subject}\n </dd>\n </>\n ) : null}\n\n <dt className=\"text-muted-foreground\">\n {t('communication_channels.infoPanel.assignedTo', 'Assigned to')}\n </dt>\n <dd className=\"col-span-1\">\n {canReassign ? (\n <Select\n value={assignedUserId ?? UNASSIGNED_VALUE}\n onValueChange={(value) =>\n void reassign(value === UNASSIGNED_VALUE ? null : value)\n }\n onOpenChange={(isOpen) => {\n if (isOpen) void loadUsers()\n }}\n disabled={savingAssignee || !data?.threadId}\n >\n <SelectTrigger\n size=\"xs\"\n aria-label={t('communication_channels.infoPanel.assignedTo', 'Assigned to')}\n >\n <SelectValue\n placeholder={t('communication_channels.infoPanel.unassigned', 'Unassigned')}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={UNASSIGNED_VALUE}>\n {t('communication_channels.infoPanel.unassigned', 'Unassigned')}\n </SelectItem>\n {assignedUserId && !users.some((u) => u.id === assignedUserId) ? (\n <SelectItem value={assignedUserId}>{assignedUserId}</SelectItem>\n ) : null}\n {users.map((user) => (\n <SelectItem key={user.id} value={user.id}>\n {user.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : (\n <span className=\"truncate\" title={assignedUserId ?? ''}>\n {assignedUserId ?? t('communication_channels.infoPanel.unassigned', 'Unassigned')}\n </span>\n )}\n </dd>\n </dl>\n </aside>\n )\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,17 @@
1
+ import ChannelInfoPanelWidget from "./widget.client.js";
2
+ const widget = {
3
+ metadata: {
4
+ id: "communication_channels.injection.channel-info-panel",
5
+ title: "Channel info panel",
6
+ description: "Sidebar panel showing channel + contact metadata for a channel-linked message.",
7
+ features: ["communication_channels.view"],
8
+ priority: 80,
9
+ enabled: true
10
+ },
11
+ Widget: ChannelInfoPanelWidget
12
+ };
13
+ var widget_default = widget;
14
+ export {
15
+ widget_default as default
16
+ };
17
+ //# sourceMappingURL=widget.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/communication_channels/widgets/injection/channel-info-panel/widget.ts"],
4
+ "sourcesContent": ["import type { InjectionWidgetModule } from '@open-mercato/shared/modules/widgets/injection'\nimport ChannelInfoPanelWidget from './widget.client'\n\n/**\n * Channel info panel \u2014 renders a short summary of channel context for a message\n * in the detail sidebar (`detail:messages:message:sidebar`).\n *\n * Reads `_channel` + `_channelContact` enrichments. Shows provider, channel\n * type, direction + delivery status, and (when matched) the linked CRM person id.\n */\nconst widget: InjectionWidgetModule<Record<string, unknown>, Record<string, unknown>> = {\n metadata: {\n id: 'communication_channels.injection.channel-info-panel',\n title: 'Channel info panel',\n description:\n 'Sidebar panel showing channel + contact metadata for a channel-linked message.',\n features: ['communication_channels.view'],\n priority: 80,\n enabled: true,\n },\n Widget: ChannelInfoPanelWidget,\n}\n\nexport default widget\n"],
5
+ "mappings": "AACA,OAAO,4BAA4B;AASnC,MAAM,SAAkF;AAAA,EACtF,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,aACE;AAAA,IACF,UAAU,CAAC,6BAA6B;AAAA,IACxC,UAAU;AAAA,IACV,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AACV;AAEA,IAAO,iBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,44 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
4
+ import { sanitizeChannelHtml } from "../../../lib/sanitize-channel-html.js";
5
+ function ChannelPayloadRendererWidget({
6
+ data
7
+ }) {
8
+ const t = useT();
9
+ const payload = data?._channelPayload ?? null;
10
+ if (!payload || !payload.channelContentType) return null;
11
+ const { channelContentType, channelPayload } = payload;
12
+ if (channelContentType.startsWith("email/") && typeof channelPayload?.html === "string") {
13
+ const sanitized = sanitizeChannelHtml(channelPayload.html);
14
+ return /* @__PURE__ */ jsx(
15
+ "section",
16
+ {
17
+ className: "rounded-md border bg-card p-4 text-sm",
18
+ "aria-label": t(
19
+ "communication_channels.channelPayload.email.aria",
20
+ "Channel payload \u2014 email"
21
+ ),
22
+ children: /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: sanitized } })
23
+ }
24
+ );
25
+ }
26
+ return /* @__PURE__ */ jsxs(
27
+ "section",
28
+ {
29
+ className: "rounded-md border bg-muted p-4 text-xs",
30
+ "aria-label": t("communication_channels.channelPayload.aria", "Channel payload"),
31
+ children: [
32
+ /* @__PURE__ */ jsx("header", { className: "mb-2 text-overline text-muted-foreground", children: t(
33
+ `communication_channels.channelPayload.types.${channelContentType}`,
34
+ channelContentType
35
+ ) }),
36
+ /* @__PURE__ */ jsx("pre", { className: "overflow-auto whitespace-pre-wrap break-words", children: JSON.stringify(channelPayload, null, 2) })
37
+ ]
38
+ }
39
+ );
40
+ }
41
+ export {
42
+ ChannelPayloadRendererWidget as default
43
+ };
44
+ //# sourceMappingURL=widget.client.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/communication_channels/widgets/injection/channel-payload-renderer/widget.client.tsx"],
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { sanitizeChannelHtml } from '../../../lib/sanitize-channel-html'\n\ntype ChannelPayloadEnrichment = {\n channelContentType: string | null\n channelPayload: Record<string, unknown> | null\n interactiveState: Record<string, unknown> | null\n channelMetadata: Record<string, unknown> | null\n}\n\ntype MessageWithPayload = Record<string, unknown> & {\n id?: string\n _channelPayload?: ChannelPayloadEnrichment | null\n}\n\nexport default function ChannelPayloadRendererWidget({\n data,\n}: InjectionWidgetComponentProps<Record<string, unknown>, MessageWithPayload>) {\n const t = useT()\n const payload = data?._channelPayload ?? null\n if (!payload || !payload.channelContentType) return null\n\n const { channelContentType, channelPayload } = payload\n\n // Email / HTML \u2014 sanitize, then render.\n if (channelContentType.startsWith('email/') && typeof channelPayload?.html === 'string') {\n const sanitized = sanitizeChannelHtml(channelPayload.html as string)\n return (\n <section\n className=\"rounded-md border bg-card p-4 text-sm\"\n aria-label={t(\n 'communication_channels.channelPayload.email.aria',\n 'Channel payload \u2014 email',\n )}\n >\n <div dangerouslySetInnerHTML={{ __html: sanitized }} />\n </section>\n )\n }\n\n // Provider-specific payloads (Slack Block Kit, WhatsApp interactive) \u2014\n // hub-level fallback shows raw JSON; provider packages override this widget.\n return (\n <section\n className=\"rounded-md border bg-muted p-4 text-xs\"\n aria-label={t('communication_channels.channelPayload.aria', 'Channel payload')}\n >\n <header className=\"mb-2 text-overline text-muted-foreground\">\n {t(\n `communication_channels.channelPayload.types.${channelContentType}`,\n channelContentType,\n )}\n </header>\n <pre className=\"overflow-auto whitespace-pre-wrap break-words\">\n {JSON.stringify(channelPayload, null, 2)}\n </pre>\n </section>\n )\n}\n"],
5
+ "mappings": ";AAuCQ,cAQJ,YARI;AAnCR,SAAS,YAAY;AACrB,SAAS,2BAA2B;AAcrB,SAAR,6BAA8C;AAAA,EACnD;AACF,GAA+E;AAC7E,QAAM,IAAI,KAAK;AACf,QAAM,UAAU,MAAM,mBAAmB;AACzC,MAAI,CAAC,WAAW,CAAC,QAAQ,mBAAoB,QAAO;AAEpD,QAAM,EAAE,oBAAoB,eAAe,IAAI;AAG/C,MAAI,mBAAmB,WAAW,QAAQ,KAAK,OAAO,gBAAgB,SAAS,UAAU;AACvF,UAAM,YAAY,oBAAoB,eAAe,IAAc;AACnE,WACE;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,cAAY;AAAA,UACV;AAAA,UACA;AAAA,QACF;AAAA,QAEA,8BAAC,SAAI,yBAAyB,EAAE,QAAQ,UAAU,GAAG;AAAA;AAAA,IACvD;AAAA,EAEJ;AAIA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,cAAY,EAAE,8CAA8C,iBAAiB;AAAA,MAE7E;AAAA,4BAAC,YAAO,WAAU,4CACf;AAAA,UACC,+CAA+C,kBAAkB;AAAA,UACjE;AAAA,QACF,GACF;AAAA,QACA,oBAAC,SAAI,WAAU,iDACZ,eAAK,UAAU,gBAAgB,MAAM,CAAC,GACzC;AAAA;AAAA;AAAA,EACF;AAEJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,17 @@
1
+ import ChannelPayloadRendererWidget from "./widget.client.js";
2
+ const widget = {
3
+ metadata: {
4
+ id: "communication_channels.injection.channel-payload-renderer",
5
+ title: "Channel payload renderer",
6
+ description: "Renders channel-native rich payload (Block Kit, interactive, MIME) below the message body in the detail view. Generic fallback; provider packages can replace it for richer rendering.",
7
+ features: ["communication_channels.view"],
8
+ priority: 100,
9
+ enabled: true
10
+ },
11
+ Widget: ChannelPayloadRendererWidget
12
+ };
13
+ var widget_default = widget;
14
+ export {
15
+ widget_default as default
16
+ };
17
+ //# sourceMappingURL=widget.js.map