@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,50 @@
1
+ import { Migration } from "@mikro-orm/migrations";
2
+ class Migration20260526134719_communication_channels extends Migration {
3
+ up() {
4
+ this.addSql(`create table "channel_thread_mappings" ("id" uuid not null default gen_random_uuid(), "external_conversation_id" uuid not null, "message_thread_id" uuid not null, "channel_id" uuid not null, "provider_key" text not null, "external_thread_ref" text not null, "assigned_user_id" uuid null, "tenant_id" uuid not null, "organization_id" uuid null, "created_at" timestamptz not null, "updated_at" timestamptz not null, primary key ("id"));`);
5
+ this.addSql(`create index "channel_thread_mappings_thread_idx" on "channel_thread_mappings" ("message_thread_id", "tenant_id");`);
6
+ this.addSql(`create index "channel_thread_mappings_ext_conv_idx" on "channel_thread_mappings" ("external_conversation_id", "tenant_id");`);
7
+ this.addSql(`alter table "channel_thread_mappings" add constraint "channel_thread_mappings_ext_conv_uq" unique ("external_conversation_id", "tenant_id");`);
8
+ this.addSql(`create table "communication_channels" ("id" uuid not null default gen_random_uuid(), "provider_key" text not null, "channel_type" text not null, "display_name" text not null, "external_identifier" text null, "credentials_ref" uuid null, "capabilities" jsonb null, "is_active" boolean not null default true, "user_id" uuid null, "is_primary" boolean not null default false, "poll_interval_seconds" int null, "last_polled_at" timestamptz null, "status" text not null default 'connected', "last_error" text null, "channel_state" jsonb null, "tenant_id" uuid not null, "organization_id" uuid null, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, primary key ("id"));`);
9
+ this.addSql(`create index "communication_channels_tenant_type_active_idx" on "communication_channels" ("tenant_id", "channel_type", "is_active");`);
10
+ this.addSql(`create index "communication_channels_tenant_provider_idx" on "communication_channels" ("tenant_id", "provider_key");`);
11
+ this.addSql(`create unique index "communication_channels_one_primary_per_user_uq" on "communication_channels" ("user_id") where "is_primary" and "user_id" is not null and "deleted_at" is null;`);
12
+ this.addSql(`create index "communication_channels_poll_due_idx" on "communication_channels" ("is_active", "last_polled_at") where "deleted_at" is null;`);
13
+ this.addSql(`create index "communication_channels_user_lookup_idx" on "communication_channels" ("user_id", "channel_type", "deleted_at");`);
14
+ this.addSql(`create table "external_conversations" ("id" uuid not null default gen_random_uuid(), "channel_id" uuid not null, "external_conversation_id" text not null, "subject" text null, "contact_person_id" uuid null, "assigned_user_id" uuid null, "last_message_at" timestamptz null, "tenant_id" uuid not null, "organization_id" uuid null, "created_at" timestamptz not null, "updated_at" timestamptz not null, primary key ("id"));`);
15
+ this.addSql(`create index "external_conversations_assigned_user_idx" on "external_conversations" ("assigned_user_id");`);
16
+ this.addSql(`create index "external_conversations_contact_person_idx" on "external_conversations" ("contact_person_id");`);
17
+ this.addSql(`create index "external_conversations_channel_idx" on "external_conversations" ("channel_id", "external_conversation_id");`);
18
+ this.addSql(`alter table "external_conversations" add constraint "external_conversations_channel_external_uq" unique ("channel_id", "external_conversation_id");`);
19
+ this.addSql(`create table "external_messages" ("id" uuid not null default gen_random_uuid(), "channel_id" uuid not null, "conversation_id" uuid not null, "external_message_id" text not null, "direction" text not null, "sender_identifier" text null, "sender_display_name" text null, "provider_timestamp" timestamptz null, "tenant_id" uuid not null, "organization_id" uuid null, "created_at" timestamptz not null, primary key ("id"));`);
20
+ this.addSql(`create index "external_messages_channel_external_idx" on "external_messages" ("channel_id", "external_message_id");`);
21
+ this.addSql(`create index "external_messages_conversation_idx" on "external_messages" ("conversation_id");`);
22
+ this.addSql(`alter table "external_messages" add constraint "external_messages_channel_external_uq" unique ("channel_id", "external_message_id");`);
23
+ this.addSql(`create table "message_channel_links" ("id" uuid not null default gen_random_uuid(), "message_id" uuid not null, "external_conversation_id" uuid not null, "external_message_id" uuid null, "provider_key" text not null, "channel_type" text not null, "direction" text not null, "delivery_status" text not null default 'pending', "channel_payload" jsonb null, "channel_content_type" text null, "interactive_state" jsonb null, "channel_metadata" jsonb null, "tenant_id" uuid not null, "organization_id" uuid null, "created_at" timestamptz not null, primary key ("id"));`);
24
+ this.addSql(`create index "message_channel_links_ext_msg_idx" on "message_channel_links" ("external_message_id");`);
25
+ this.addSql(`create index "message_channel_links_ext_conv_idx" on "message_channel_links" ("external_conversation_id");`);
26
+ this.addSql(`create index "message_channel_links_message_idx" on "message_channel_links" ("message_id");`);
27
+ this.addSql(`alter table "message_channel_links" add constraint "message_channel_links_message_uq" unique ("message_id");`);
28
+ this.addSql(`create table "message_reactions" ("id" uuid not null default gen_random_uuid(), "message_id" uuid not null, "emoji" text not null, "reacted_by_user_id" uuid null, "reacted_by_external_id" text null, "reacted_by_display_name" text null, "provider_key" text null, "external_reaction_id" text null, "tenant_id" uuid not null, "organization_id" uuid null, "created_at" timestamptz not null, primary key ("id"));`);
29
+ this.addSql(`alter table "message_reactions" add constraint "message_reactions_exactly_one_actor_chk" check (("reacted_by_user_id" is null) <> ("reacted_by_external_id" is null));`);
30
+ this.addSql(`create index "message_reactions_message_emoji_idx" on "message_reactions" ("message_id", "emoji");`);
31
+ this.addSql(`create index "message_reactions_message_idx" on "message_reactions" ("message_id");`);
32
+ this.addSql(`create unique index "message_reactions_external_actor_uq" on "message_reactions" ("tenant_id", "message_id", "emoji", "reacted_by_external_id") where "reacted_by_external_id" is not null;`);
33
+ this.addSql(`create unique index "message_reactions_internal_actor_uq" on "message_reactions" ("tenant_id", "message_id", "emoji", "reacted_by_user_id") where "reacted_by_user_id" is not null;`);
34
+ }
35
+ down() {
36
+ this.addSql(`drop table if exists "message_reactions";`);
37
+ this.addSql(`drop table if exists "message_channel_links";`);
38
+ this.addSql(`drop table if exists "external_messages";`);
39
+ this.addSql(`drop table if exists "external_conversations";`);
40
+ this.addSql(`drop index if exists "communication_channels_user_lookup_idx";`);
41
+ this.addSql(`drop index if exists "communication_channels_poll_due_idx";`);
42
+ this.addSql(`drop index if exists "communication_channels_one_primary_per_user_uq";`);
43
+ this.addSql(`drop table if exists "communication_channels";`);
44
+ this.addSql(`drop table if exists "channel_thread_mappings";`);
45
+ }
46
+ }
47
+ export {
48
+ Migration20260526134719_communication_channels
49
+ };
50
+ //# sourceMappingURL=Migration20260526134719_communication_channels.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/communication_channels/migrations/Migration20260526134719_communication_channels.ts"],
4
+ "sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260526134719_communication_channels extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`create table \"channel_thread_mappings\" (\"id\" uuid not null default gen_random_uuid(), \"external_conversation_id\" uuid not null, \"message_thread_id\" uuid not null, \"channel_id\" uuid not null, \"provider_key\" text not null, \"external_thread_ref\" text not null, \"assigned_user_id\" uuid null, \"tenant_id\" uuid not null, \"organization_id\" uuid null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, primary key (\"id\"));`);\n this.addSql(`create index \"channel_thread_mappings_thread_idx\" on \"channel_thread_mappings\" (\"message_thread_id\", \"tenant_id\");`);\n this.addSql(`create index \"channel_thread_mappings_ext_conv_idx\" on \"channel_thread_mappings\" (\"external_conversation_id\", \"tenant_id\");`);\n this.addSql(`alter table \"channel_thread_mappings\" add constraint \"channel_thread_mappings_ext_conv_uq\" unique (\"external_conversation_id\", \"tenant_id\");`);\n\n this.addSql(`create table \"communication_channels\" (\"id\" uuid not null default gen_random_uuid(), \"provider_key\" text not null, \"channel_type\" text not null, \"display_name\" text not null, \"external_identifier\" text null, \"credentials_ref\" uuid null, \"capabilities\" jsonb null, \"is_active\" boolean not null default true, \"user_id\" uuid null, \"is_primary\" boolean not null default false, \"poll_interval_seconds\" int null, \"last_polled_at\" timestamptz null, \"status\" text not null default 'connected', \"last_error\" text null, \"channel_state\" jsonb null, \"tenant_id\" uuid not null, \"organization_id\" uuid null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, \"deleted_at\" timestamptz null, primary key (\"id\"));`);\n this.addSql(`create index \"communication_channels_tenant_type_active_idx\" on \"communication_channels\" (\"tenant_id\", \"channel_type\", \"is_active\");`);\n this.addSql(`create index \"communication_channels_tenant_provider_idx\" on \"communication_channels\" (\"tenant_id\", \"provider_key\");`);\n this.addSql(`create unique index \"communication_channels_one_primary_per_user_uq\" on \"communication_channels\" (\"user_id\") where \"is_primary\" and \"user_id\" is not null and \"deleted_at\" is null;`);\n this.addSql(`create index \"communication_channels_poll_due_idx\" on \"communication_channels\" (\"is_active\", \"last_polled_at\") where \"deleted_at\" is null;`);\n this.addSql(`create index \"communication_channels_user_lookup_idx\" on \"communication_channels\" (\"user_id\", \"channel_type\", \"deleted_at\");`);\n\n this.addSql(`create table \"external_conversations\" (\"id\" uuid not null default gen_random_uuid(), \"channel_id\" uuid not null, \"external_conversation_id\" text not null, \"subject\" text null, \"contact_person_id\" uuid null, \"assigned_user_id\" uuid null, \"last_message_at\" timestamptz null, \"tenant_id\" uuid not null, \"organization_id\" uuid null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, primary key (\"id\"));`);\n this.addSql(`create index \"external_conversations_assigned_user_idx\" on \"external_conversations\" (\"assigned_user_id\");`);\n this.addSql(`create index \"external_conversations_contact_person_idx\" on \"external_conversations\" (\"contact_person_id\");`);\n this.addSql(`create index \"external_conversations_channel_idx\" on \"external_conversations\" (\"channel_id\", \"external_conversation_id\");`);\n this.addSql(`alter table \"external_conversations\" add constraint \"external_conversations_channel_external_uq\" unique (\"channel_id\", \"external_conversation_id\");`);\n\n this.addSql(`create table \"external_messages\" (\"id\" uuid not null default gen_random_uuid(), \"channel_id\" uuid not null, \"conversation_id\" uuid not null, \"external_message_id\" text not null, \"direction\" text not null, \"sender_identifier\" text null, \"sender_display_name\" text null, \"provider_timestamp\" timestamptz null, \"tenant_id\" uuid not null, \"organization_id\" uuid null, \"created_at\" timestamptz not null, primary key (\"id\"));`);\n this.addSql(`create index \"external_messages_channel_external_idx\" on \"external_messages\" (\"channel_id\", \"external_message_id\");`);\n this.addSql(`create index \"external_messages_conversation_idx\" on \"external_messages\" (\"conversation_id\");`);\n this.addSql(`alter table \"external_messages\" add constraint \"external_messages_channel_external_uq\" unique (\"channel_id\", \"external_message_id\");`);\n\n this.addSql(`create table \"message_channel_links\" (\"id\" uuid not null default gen_random_uuid(), \"message_id\" uuid not null, \"external_conversation_id\" uuid not null, \"external_message_id\" uuid null, \"provider_key\" text not null, \"channel_type\" text not null, \"direction\" text not null, \"delivery_status\" text not null default 'pending', \"channel_payload\" jsonb null, \"channel_content_type\" text null, \"interactive_state\" jsonb null, \"channel_metadata\" jsonb null, \"tenant_id\" uuid not null, \"organization_id\" uuid null, \"created_at\" timestamptz not null, primary key (\"id\"));`);\n this.addSql(`create index \"message_channel_links_ext_msg_idx\" on \"message_channel_links\" (\"external_message_id\");`);\n this.addSql(`create index \"message_channel_links_ext_conv_idx\" on \"message_channel_links\" (\"external_conversation_id\");`);\n this.addSql(`create index \"message_channel_links_message_idx\" on \"message_channel_links\" (\"message_id\");`);\n this.addSql(`alter table \"message_channel_links\" add constraint \"message_channel_links_message_uq\" unique (\"message_id\");`);\n\n this.addSql(`create table \"message_reactions\" (\"id\" uuid not null default gen_random_uuid(), \"message_id\" uuid not null, \"emoji\" text not null, \"reacted_by_user_id\" uuid null, \"reacted_by_external_id\" text null, \"reacted_by_display_name\" text null, \"provider_key\" text null, \"external_reaction_id\" text null, \"tenant_id\" uuid not null, \"organization_id\" uuid null, \"created_at\" timestamptz not null, primary key (\"id\"));`);\n this.addSql(`alter table \"message_reactions\" add constraint \"message_reactions_exactly_one_actor_chk\" check ((\"reacted_by_user_id\" is null) <> (\"reacted_by_external_id\" is null));`);\n this.addSql(`create index \"message_reactions_message_emoji_idx\" on \"message_reactions\" (\"message_id\", \"emoji\");`);\n this.addSql(`create index \"message_reactions_message_idx\" on \"message_reactions\" (\"message_id\");`);\n this.addSql(`create unique index \"message_reactions_external_actor_uq\" on \"message_reactions\" (\"tenant_id\", \"message_id\", \"emoji\", \"reacted_by_external_id\") where \"reacted_by_external_id\" is not null;`);\n this.addSql(`create unique index \"message_reactions_internal_actor_uq\" on \"message_reactions\" (\"tenant_id\", \"message_id\", \"emoji\", \"reacted_by_user_id\") where \"reacted_by_user_id\" is not null;`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`drop table if exists \"message_reactions\";`);\n this.addSql(`drop table if exists \"message_channel_links\";`);\n this.addSql(`drop table if exists \"external_messages\";`);\n this.addSql(`drop table if exists \"external_conversations\";`);\n this.addSql(`drop index if exists \"communication_channels_user_lookup_idx\";`);\n this.addSql(`drop index if exists \"communication_channels_poll_due_idx\";`);\n this.addSql(`drop index if exists \"communication_channels_one_primary_per_user_uq\";`);\n this.addSql(`drop table if exists \"communication_channels\";`);\n this.addSql(`drop table if exists \"channel_thread_mappings\";`);\n }\n\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,uDAAuD,UAAU;AAAA,EAEnE,KAA2B;AAClC,SAAK,OAAO,obAAob;AAChc,SAAK,OAAO,oHAAoH;AAChI,SAAK,OAAO,6HAA6H;AACzI,SAAK,OAAO,8IAA8I;AAE1J,SAAK,OAAO,6sBAA6sB;AACztB,SAAK,OAAO,sIAAsI;AAClJ,SAAK,OAAO,sHAAsH;AAClI,SAAK,OAAO,qLAAqL;AACjM,SAAK,OAAO,4IAA4I;AACxJ,SAAK,OAAO,8HAA8H;AAE1I,SAAK,OAAO,qaAAqa;AACjb,SAAK,OAAO,2GAA2G;AACvH,SAAK,OAAO,6GAA6G;AACzH,SAAK,OAAO,2HAA2H;AACvI,SAAK,OAAO,qJAAqJ;AAEjK,SAAK,OAAO,qaAAqa;AACjb,SAAK,OAAO,qHAAqH;AACjI,SAAK,OAAO,+FAA+F;AAC3G,SAAK,OAAO,sIAAsI;AAElJ,SAAK,OAAO,qjBAAqjB;AACjkB,SAAK,OAAO,sGAAsG;AAClH,SAAK,OAAO,4GAA4G;AACxH,SAAK,OAAO,6FAA6F;AACzG,SAAK,OAAO,8GAA8G;AAE1H,SAAK,OAAO,yZAAyZ;AACra,SAAK,OAAO,wKAAwK;AACpL,SAAK,OAAO,oGAAoG;AAChH,SAAK,OAAO,qFAAqF;AACjG,SAAK,OAAO,6LAA6L;AACzM,SAAK,OAAO,qLAAqL;AAAA,EACnM;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,2CAA2C;AACvD,SAAK,OAAO,+CAA+C;AAC3D,SAAK,OAAO,2CAA2C;AACvD,SAAK,OAAO,gDAAgD;AAC5D,SAAK,OAAO,gEAAgE;AAC5E,SAAK,OAAO,6DAA6D;AACzE,SAAK,OAAO,wEAAwE;AACpF,SAAK,OAAO,gDAAgD;AAC5D,SAAK,OAAO,iDAAiD;AAAA,EAC/D;AAEF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,19 @@
1
+ import { Migration } from "@mikro-orm/migrations";
2
+ class Migration20260527195446_communication_channels extends Migration {
3
+ up() {
4
+ this.addSql(`create table "channel_ingest_dead_letters" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid null, "channel_id" uuid not null, "provider_key" text not null, "external_uid" text null, "external_message_id" text null, "error_class" text not null, "error_message" text not null, "raw_body" text null, "created_at" timestamptz not null, primary key ("id"));`);
5
+ this.addSql(`create index "channel_ingest_dead_letters_created_idx" on "channel_ingest_dead_letters" ("tenant_id", "created_at");`);
6
+ this.addSql(`create index "channel_ingest_dead_letters_channel_idx" on "channel_ingest_dead_letters" ("channel_id", "tenant_id");`);
7
+ this.addSql(`create table "channel_thread_tokens" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid null, "message_thread_id" uuid not null, "token" text not null, "created_at" timestamptz not null, "last_seen_at" timestamptz null, primary key ("id"));`);
8
+ this.addSql(`create index "channel_thread_tokens_thread_idx" on "channel_thread_tokens" ("message_thread_id", "tenant_id");`);
9
+ this.addSql(`alter table "channel_thread_tokens" add constraint "channel_thread_tokens_token_uq" unique ("tenant_id", "token");`);
10
+ }
11
+ down() {
12
+ this.addSql(`drop table if exists "channel_ingest_dead_letters";`);
13
+ this.addSql(`drop table if exists "channel_thread_tokens";`);
14
+ }
15
+ }
16
+ export {
17
+ Migration20260527195446_communication_channels
18
+ };
19
+ //# sourceMappingURL=Migration20260527195446_communication_channels.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/communication_channels/migrations/Migration20260527195446_communication_channels.ts"],
4
+ "sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260527195446_communication_channels extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`create table \"channel_ingest_dead_letters\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"organization_id\" uuid null, \"channel_id\" uuid not null, \"provider_key\" text not null, \"external_uid\" text null, \"external_message_id\" text null, \"error_class\" text not null, \"error_message\" text not null, \"raw_body\" text null, \"created_at\" timestamptz not null, primary key (\"id\"));`);\n this.addSql(`create index \"channel_ingest_dead_letters_created_idx\" on \"channel_ingest_dead_letters\" (\"tenant_id\", \"created_at\");`);\n this.addSql(`create index \"channel_ingest_dead_letters_channel_idx\" on \"channel_ingest_dead_letters\" (\"channel_id\", \"tenant_id\");`);\n\n this.addSql(`create table \"channel_thread_tokens\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"organization_id\" uuid null, \"message_thread_id\" uuid not null, \"token\" text not null, \"created_at\" timestamptz not null, \"last_seen_at\" timestamptz null, primary key (\"id\"));`);\n this.addSql(`create index \"channel_thread_tokens_thread_idx\" on \"channel_thread_tokens\" (\"message_thread_id\", \"tenant_id\");`);\n this.addSql(`alter table \"channel_thread_tokens\" add constraint \"channel_thread_tokens_token_uq\" unique (\"tenant_id\", \"token\");`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`drop table if exists \"channel_ingest_dead_letters\";`);\n this.addSql(`drop table if exists \"channel_thread_tokens\";`);\n }\n\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,uDAAuD,UAAU;AAAA,EAEnE,KAA2B;AAClC,SAAK,OAAO,kZAAkZ;AAC9Z,SAAK,OAAO,sHAAsH;AAClI,SAAK,OAAO,sHAAsH;AAElI,SAAK,OAAO,gSAAgS;AAC5S,SAAK,OAAO,gHAAgH;AAC5H,SAAK,OAAO,oHAAoH;AAAA,EAClI;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,qDAAqD;AACjE,SAAK,OAAO,+CAA+C;AAAA,EAC7D;AAEF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,13 @@
1
+ import { Migration } from "@mikro-orm/migrations";
2
+ class Migration20260529231848_communication_channels extends Migration {
3
+ up() {
4
+ this.addSql(`create index "communication_channels_provider_external_idx" on "communication_channels" ("provider_key", "external_identifier") where "deleted_at" is null;`);
5
+ }
6
+ down() {
7
+ this.addSql(`drop index "communication_channels_provider_external_idx";`);
8
+ }
9
+ }
10
+ export {
11
+ Migration20260529231848_communication_channels
12
+ };
13
+ //# sourceMappingURL=Migration20260529231848_communication_channels.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/communication_channels/migrations/Migration20260529231848_communication_channels.ts"],
4
+ "sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260529231848_communication_channels extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`create index \"communication_channels_provider_external_idx\" on \"communication_channels\" (\"provider_key\", \"external_identifier\") where \"deleted_at\" is null;`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`drop index \"communication_channels_provider_external_idx\";`);\n }\n\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,uDAAuD,UAAU;AAAA,EAEnE,KAA2B;AAClC,SAAK,OAAO,6JAA6J;AAAA,EAC3K;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,4DAA4D;AAAA,EAC1E;AAEF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,17 @@
1
+ import { Migration } from "@mikro-orm/migrations";
2
+ class Migration20260531120000_communication_channels extends Migration {
3
+ up() {
4
+ this.addSql(`drop index if exists "channel_thread_tokens_thread_idx";`);
5
+ this.addSql(`alter table "channel_thread_tokens" add constraint "channel_thread_tokens_thread_uq" unique ("tenant_id", "message_thread_id");`);
6
+ this.addSql(`create unique index "communication_channels_user_provider_external_uq" on "communication_channels" ("tenant_id", "user_id", "provider_key", "external_identifier") where "deleted_at" is null and "user_id" is not null and "external_identifier" is not null;`);
7
+ }
8
+ down() {
9
+ this.addSql(`drop index if exists "communication_channels_user_provider_external_uq";`);
10
+ this.addSql(`alter table "channel_thread_tokens" drop constraint if exists "channel_thread_tokens_thread_uq";`);
11
+ this.addSql(`create index "channel_thread_tokens_thread_idx" on "channel_thread_tokens" ("message_thread_id", "tenant_id");`);
12
+ }
13
+ }
14
+ export {
15
+ Migration20260531120000_communication_channels
16
+ };
17
+ //# sourceMappingURL=Migration20260531120000_communication_channels.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/communication_channels/migrations/Migration20260531120000_communication_channels.ts"],
4
+ "sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260531120000_communication_channels extends Migration {\n\n override up(): void | Promise<void> {\n // Enforce one thread token per (tenant, message_thread_id). Replaces the\n // earlier non-unique `channel_thread_tokens_thread_idx` so `getOrCreateThreadToken`\n // is idempotent under concurrency (insert-on-conflict). The new unique index\n // also serves the `WHERE tenant_id = ? AND message_thread_id = ?` lookup.\n this.addSql(`drop index if exists \"channel_thread_tokens_thread_idx\";`);\n this.addSql(`alter table \"channel_thread_tokens\" add constraint \"channel_thread_tokens_thread_uq\" unique (\"tenant_id\", \"message_thread_id\");`);\n // Enforce one channel per (tenant, user, provider, mailbox) so a reconnect\n // heals the existing row instead of inserting a duplicate. Partial: tenant-wide\n // (null user_id) and identifier-less channels are exempt.\n this.addSql(`create unique index \"communication_channels_user_provider_external_uq\" on \"communication_channels\" (\"tenant_id\", \"user_id\", \"provider_key\", \"external_identifier\") where \"deleted_at\" is null and \"user_id\" is not null and \"external_identifier\" is not null;`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`drop index if exists \"communication_channels_user_provider_external_uq\";`);\n this.addSql(`alter table \"channel_thread_tokens\" drop constraint if exists \"channel_thread_tokens_thread_uq\";`);\n this.addSql(`create index \"channel_thread_tokens_thread_idx\" on \"channel_thread_tokens\" (\"message_thread_id\", \"tenant_id\");`);\n }\n\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,uDAAuD,UAAU;AAAA,EAEnE,KAA2B;AAKlC,SAAK,OAAO,0DAA0D;AACtE,SAAK,OAAO,iIAAiI;AAI7I,SAAK,OAAO,gQAAgQ;AAAA,EAC9Q;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,0EAA0E;AACtF,SAAK,OAAO,kGAAkG;AAC9G,SAAK,OAAO,gHAAgH;AAAA,EAC9H;AAEF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,51 @@
1
+ "use client";
2
+ import { MessageReceivedRenderer } from "./widgets/notifications/MessageReceivedRenderer.js";
3
+ import { ChannelRequiresReauthRenderer } from "./widgets/notifications/ChannelRequiresReauthRenderer.js";
4
+ const communicationChannelsNotificationTypes = [
5
+ {
6
+ type: "communication_channels.message.received",
7
+ module: "communication_channels",
8
+ titleKey: "communication_channels.notifications.message_received.title",
9
+ bodyKey: "communication_channels.notifications.message_received.body",
10
+ icon: "message-circle",
11
+ severity: "info",
12
+ actions: [
13
+ {
14
+ id: "view",
15
+ labelKey: "common.view",
16
+ variant: "outline",
17
+ href: "/backend/messages/{sourceEntityId}",
18
+ icon: "external-link"
19
+ }
20
+ ],
21
+ linkHref: "/backend/messages/{sourceEntityId}",
22
+ Renderer: MessageReceivedRenderer,
23
+ expiresAfterHours: 168
24
+ },
25
+ {
26
+ type: "communication_channels.channel.requires_reauth",
27
+ module: "communication_channels",
28
+ titleKey: "communication_channels.notifications.channel_requires_reauth.title",
29
+ bodyKey: "communication_channels.notifications.channel_requires_reauth.body",
30
+ icon: "alert-triangle",
31
+ severity: "warning",
32
+ actions: [
33
+ {
34
+ id: "reconnect",
35
+ labelKey: "communication_channels.notifications.channel_requires_reauth.reconnect",
36
+ variant: "outline",
37
+ href: "/backend/profile/communication-channels?reconnect={sourceEntityId}",
38
+ icon: "refresh-cw"
39
+ }
40
+ ],
41
+ linkHref: "/backend/profile/communication-channels?reconnect={sourceEntityId}",
42
+ Renderer: ChannelRequiresReauthRenderer,
43
+ expiresAfterHours: 720
44
+ }
45
+ ];
46
+ var notifications_client_default = communicationChannelsNotificationTypes;
47
+ export {
48
+ communicationChannelsNotificationTypes,
49
+ notifications_client_default as default
50
+ };
51
+ //# sourceMappingURL=notifications.client.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/modules/communication_channels/notifications.client.ts"],
4
+ "sourcesContent": ["'use client'\n\nimport type { NotificationTypeDefinition } from '@open-mercato/shared/modules/notifications/types'\nimport { MessageReceivedRenderer } from './widgets/notifications/MessageReceivedRenderer'\nimport { ChannelRequiresReauthRenderer } from './widgets/notifications/ChannelRequiresReauthRenderer'\n\nexport const communicationChannelsNotificationTypes: NotificationTypeDefinition[] = [\n {\n type: 'communication_channels.message.received',\n module: 'communication_channels',\n titleKey: 'communication_channels.notifications.message_received.title',\n bodyKey: 'communication_channels.notifications.message_received.body',\n icon: 'message-circle',\n severity: 'info',\n actions: [\n {\n id: 'view',\n labelKey: 'common.view',\n variant: 'outline',\n href: '/backend/messages/{sourceEntityId}',\n icon: 'external-link',\n },\n ],\n linkHref: '/backend/messages/{sourceEntityId}',\n Renderer: MessageReceivedRenderer,\n expiresAfterHours: 168,\n },\n {\n type: 'communication_channels.channel.requires_reauth',\n module: 'communication_channels',\n titleKey: 'communication_channels.notifications.channel_requires_reauth.title',\n bodyKey: 'communication_channels.notifications.channel_requires_reauth.body',\n icon: 'alert-triangle',\n severity: 'warning',\n actions: [\n {\n id: 'reconnect',\n labelKey: 'communication_channels.notifications.channel_requires_reauth.reconnect',\n variant: 'outline',\n href: '/backend/profile/communication-channels?reconnect={sourceEntityId}',\n icon: 'refresh-cw',\n },\n ],\n linkHref: '/backend/profile/communication-channels?reconnect={sourceEntityId}',\n Renderer: ChannelRequiresReauthRenderer,\n expiresAfterHours: 720,\n },\n]\n\nexport default communicationChannelsNotificationTypes\n"],
5
+ "mappings": ";AAGA,SAAS,+BAA+B;AACxC,SAAS,qCAAqC;AAEvC,MAAM,yCAAuE;AAAA,EAClF;AAAA,IACE,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,SAAS;AAAA,IACT,MAAM;AAAA,IACN,UAAU;AAAA,IACV,SAAS;AAAA,MACP;AAAA,QACE,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,SAAS;AAAA,QACT,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,UAAU;AAAA,IACV,UAAU;AAAA,IACV,mBAAmB;AAAA,EACrB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,SAAS;AAAA,IACT,MAAM;AAAA,IACN,UAAU;AAAA,IACV,SAAS;AAAA,MACP;AAAA,QACE,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,SAAS;AAAA,QACT,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,UAAU;AAAA,IACV,UAAU;AAAA,IACV,mBAAmB;AAAA,EACrB;AACF;AAEA,IAAO,+BAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,53 @@
1
+ const CHANNEL_REQUIRES_REAUTH_EVENT = "om:communication_channels:channel-requires-reauth";
2
+ const MESSAGE_RECEIVED_EVENT = "om:communication_channels:message-received";
3
+ const notificationHandlers = [
4
+ {
5
+ id: "communication_channels.channel-requires-reauth-toast",
6
+ notificationType: "communication_channels.channel.requires_reauth",
7
+ features: ["communication_channels.connect_user_channel"],
8
+ priority: 110,
9
+ handle(notification, context) {
10
+ context.toast({
11
+ title: notification.title,
12
+ body: notification.body ?? void 0,
13
+ severity: "warning",
14
+ action: {
15
+ label: context.t?.(
16
+ "communication_channels.notifications.channel_requires_reauth.reconnect",
17
+ "Reconnect"
18
+ ) ?? "Reconnect",
19
+ onClick: () => {
20
+ const channelId = notification.sourceEntityId;
21
+ const target = channelId ? `/backend/profile/communication-channels?reconnect=${encodeURIComponent(channelId)}` : "/backend/profile/communication-channels";
22
+ context.navigate(target);
23
+ }
24
+ }
25
+ });
26
+ context.emitEvent(CHANNEL_REQUIRES_REAUTH_EVENT, {
27
+ notificationId: notification.id,
28
+ channelId: notification.sourceEntityId ?? null
29
+ });
30
+ context.refreshNotifications();
31
+ }
32
+ },
33
+ {
34
+ id: "communication_channels.message-received-event",
35
+ notificationType: "communication_channels.message.received",
36
+ features: ["communication_channels.view"],
37
+ priority: 100,
38
+ handle(notification, context) {
39
+ context.emitEvent(MESSAGE_RECEIVED_EVENT, {
40
+ notificationId: notification.id,
41
+ messageId: notification.sourceEntityId ?? null
42
+ });
43
+ }
44
+ }
45
+ ];
46
+ var notifications_handlers_default = notificationHandlers;
47
+ export {
48
+ CHANNEL_REQUIRES_REAUTH_EVENT,
49
+ MESSAGE_RECEIVED_EVENT,
50
+ notifications_handlers_default as default,
51
+ notificationHandlers
52
+ };
53
+ //# sourceMappingURL=notifications.handlers.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/modules/communication_channels/notifications.handlers.ts"],
4
+ "sourcesContent": ["import type { NotificationHandler } from '@open-mercato/shared/modules/notifications/handler'\n\n/**\n * Reactive notification handlers for the Communications Hub (Phase 4 of the\n * email integration spec).\n *\n * These handlers fire on the browser when the matching notification arrives via\n * the notifications stream. They run in addition to (not instead of) the static\n * UI surfaces:\n *\n * - The notification appears in the user's bell dropdown via\n * `notifications.client.ts` renderers (already wired in slice 2a).\n * - The dropdown's primary action navigates to the reconnect URL.\n *\n * What the handlers add:\n * - **Toast**: surfaces the message even when the user isn't looking at the\n * bell. The reauth toast is the highest-signal interruption \u2014 without\n * reauth the channel goes silent.\n * - **Event emit**: lets the profile page / channel admin DataTable hook in\n * via `useAppEvent(...)` (DOM Event Bridge) so they auto-refresh when the\n * state flips without requiring a manual reload.\n * - **Refresh notifications**: keeps the bell badge accurate.\n *\n * Custom event names emitted here on the DOM Event Bridge. They are published\n * for any page that opts in via `useAppEvent(...)`; no surface subscribes to\n * them today (the unified inbox auto-refreshes from the `messages.message.*`\n * bridge, and the reconnect flow is driven by the bell notification + its\n * reconnect action). Kept as forward-compatible hooks for future\n * row-highlight / refetch UX.\n */\n\nexport const CHANNEL_REQUIRES_REAUTH_EVENT = 'om:communication_channels:channel-requires-reauth'\nexport const MESSAGE_RECEIVED_EVENT = 'om:communication_channels:message-received'\n\nexport const notificationHandlers: NotificationHandler[] = [\n {\n id: 'communication_channels.channel-requires-reauth-toast',\n notificationType: 'communication_channels.channel.requires_reauth',\n features: ['communication_channels.connect_user_channel'],\n priority: 110,\n handle(notification, context) {\n context.toast({\n title: notification.title,\n body: notification.body ?? undefined,\n severity: 'warning',\n action: {\n label:\n context.t?.(\n 'communication_channels.notifications.channel_requires_reauth.reconnect',\n 'Reconnect',\n ) ?? 'Reconnect',\n onClick: () => {\n const channelId = notification.sourceEntityId\n const target = channelId\n ? `/backend/profile/communication-channels?reconnect=${encodeURIComponent(channelId)}`\n : '/backend/profile/communication-channels'\n context.navigate(target)\n },\n },\n })\n context.emitEvent(CHANNEL_REQUIRES_REAUTH_EVENT, {\n notificationId: notification.id,\n channelId: notification.sourceEntityId ?? null,\n })\n context.refreshNotifications()\n },\n },\n {\n id: 'communication_channels.message-received-event',\n notificationType: 'communication_channels.message.received',\n features: ['communication_channels.view'],\n priority: 100,\n handle(notification, context) {\n // Inbox refresh is the only side effect \u2014 the user's bell dropdown already\n // shows the notification entry. A toast here would be noisy because the\n // bell badge increments anyway, and inbound email lands in the unified\n // inbox where the user expects it.\n context.emitEvent(MESSAGE_RECEIVED_EVENT, {\n notificationId: notification.id,\n messageId: notification.sourceEntityId ?? null,\n })\n },\n },\n]\n\nexport default notificationHandlers\n"],
5
+ "mappings": "AA+BO,MAAM,gCAAgC;AACtC,MAAM,yBAAyB;AAE/B,MAAM,uBAA8C;AAAA,EACzD;AAAA,IACE,IAAI;AAAA,IACJ,kBAAkB;AAAA,IAClB,UAAU,CAAC,6CAA6C;AAAA,IACxD,UAAU;AAAA,IACV,OAAO,cAAc,SAAS;AAC5B,cAAQ,MAAM;AAAA,QACZ,OAAO,aAAa;AAAA,QACpB,MAAM,aAAa,QAAQ;AAAA,QAC3B,UAAU;AAAA,QACV,QAAQ;AAAA,UACN,OACE,QAAQ;AAAA,YACN;AAAA,YACA;AAAA,UACF,KAAK;AAAA,UACP,SAAS,MAAM;AACb,kBAAM,YAAY,aAAa;AAC/B,kBAAM,SAAS,YACX,qDAAqD,mBAAmB,SAAS,CAAC,KAClF;AACJ,oBAAQ,SAAS,MAAM;AAAA,UACzB;AAAA,QACF;AAAA,MACF,CAAC;AACD,cAAQ,UAAU,+BAA+B;AAAA,QAC/C,gBAAgB,aAAa;AAAA,QAC7B,WAAW,aAAa,kBAAkB;AAAA,MAC5C,CAAC;AACD,cAAQ,qBAAqB;AAAA,IAC/B;AAAA,EACF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,kBAAkB;AAAA,IAClB,UAAU,CAAC,6BAA6B;AAAA,IACxC,UAAU;AAAA,IACV,OAAO,cAAc,SAAS;AAK5B,cAAQ,UAAU,wBAAwB;AAAA,QACxC,gBAAgB,aAAa;AAAA,QAC7B,WAAW,aAAa,kBAAkB;AAAA,MAC5C,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,IAAO,iCAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,56 @@
1
+ const notificationTypes = [
2
+ {
3
+ type: "communication_channels.message.received",
4
+ module: "communication_channels",
5
+ titleKey: "communication_channels.notifications.message_received.title",
6
+ bodyKey: "communication_channels.notifications.message_received.body",
7
+ icon: "message-circle",
8
+ severity: "info",
9
+ actions: [
10
+ {
11
+ id: "view",
12
+ labelKey: "common.view",
13
+ variant: "outline",
14
+ href: "/backend/messages/{sourceEntityId}",
15
+ icon: "external-link"
16
+ }
17
+ ],
18
+ linkHref: "/backend/messages/{sourceEntityId}",
19
+ expiresAfterHours: 168
20
+ // 7 days
21
+ },
22
+ {
23
+ /**
24
+ * Channel-agnostic notification raised when an adapter loses authorization
25
+ * (OAuth refresh token revoked, IMAP/SMTP password rotated, WhatsApp token expired).
26
+ * Persisted by the `channel-requires-reauth-notification` subscriber in
27
+ * response to the `communication_channels.channel.requires_reauth` event
28
+ * (emitted by the poll worker and outbound delivery). Consumed by the email
29
+ * integration spec's reconnect flow.
30
+ */
31
+ type: "communication_channels.channel.requires_reauth",
32
+ module: "communication_channels",
33
+ titleKey: "communication_channels.notifications.channel_requires_reauth.title",
34
+ bodyKey: "communication_channels.notifications.channel_requires_reauth.body",
35
+ icon: "alert-triangle",
36
+ severity: "warning",
37
+ actions: [
38
+ {
39
+ id: "reconnect",
40
+ labelKey: "communication_channels.notifications.channel_requires_reauth.reconnect",
41
+ variant: "outline",
42
+ href: "/backend/profile/communication-channels?reconnect={sourceEntityId}",
43
+ icon: "refresh-cw"
44
+ }
45
+ ],
46
+ linkHref: "/backend/profile/communication-channels?reconnect={sourceEntityId}",
47
+ expiresAfterHours: 720
48
+ // 30 days — auth issues should be addressed promptly
49
+ }
50
+ ];
51
+ var notifications_default = notificationTypes;
52
+ export {
53
+ notifications_default as default,
54
+ notificationTypes
55
+ };
56
+ //# sourceMappingURL=notifications.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/modules/communication_channels/notifications.ts"],
4
+ "sourcesContent": ["import type { NotificationTypeDefinition } from '@open-mercato/shared/modules/notifications/types'\n\nexport const notificationTypes: NotificationTypeDefinition[] = [\n {\n type: 'communication_channels.message.received',\n module: 'communication_channels',\n titleKey: 'communication_channels.notifications.message_received.title',\n bodyKey: 'communication_channels.notifications.message_received.body',\n icon: 'message-circle',\n severity: 'info',\n actions: [\n {\n id: 'view',\n labelKey: 'common.view',\n variant: 'outline',\n href: '/backend/messages/{sourceEntityId}',\n icon: 'external-link',\n },\n ],\n linkHref: '/backend/messages/{sourceEntityId}',\n expiresAfterHours: 168, // 7 days\n },\n {\n /**\n * Channel-agnostic notification raised when an adapter loses authorization\n * (OAuth refresh token revoked, IMAP/SMTP password rotated, WhatsApp token expired).\n * Persisted by the `channel-requires-reauth-notification` subscriber in\n * response to the `communication_channels.channel.requires_reauth` event\n * (emitted by the poll worker and outbound delivery). Consumed by the email\n * integration spec's reconnect flow.\n */\n type: 'communication_channels.channel.requires_reauth',\n module: 'communication_channels',\n titleKey: 'communication_channels.notifications.channel_requires_reauth.title',\n bodyKey: 'communication_channels.notifications.channel_requires_reauth.body',\n icon: 'alert-triangle',\n severity: 'warning',\n actions: [\n {\n id: 'reconnect',\n labelKey: 'communication_channels.notifications.channel_requires_reauth.reconnect',\n variant: 'outline',\n href: '/backend/profile/communication-channels?reconnect={sourceEntityId}',\n icon: 'refresh-cw',\n },\n ],\n linkHref: '/backend/profile/communication-channels?reconnect={sourceEntityId}',\n expiresAfterHours: 720, // 30 days \u2014 auth issues should be addressed promptly\n },\n]\n\nexport default notificationTypes\n"],
5
+ "mappings": "AAEO,MAAM,oBAAkD;AAAA,EAC7D;AAAA,IACE,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,SAAS;AAAA,IACT,MAAM;AAAA,IACN,UAAU;AAAA,IACV,SAAS;AAAA,MACP;AAAA,QACE,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,SAAS;AAAA,QACT,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,UAAU;AAAA,IACV,mBAAmB;AAAA;AAAA,EACrB;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASE,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,SAAS;AAAA,IACT,MAAM;AAAA,IACN,UAAU;AAAA,IACV,SAAS;AAAA,MACP;AAAA,QACE,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,SAAS;AAAA,QACT,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,UAAU;AAAA,IACV,mBAAmB;AAAA;AAAA,EACrB;AACF;AAEA,IAAO,wBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,105 @@
1
+ import { createHash } from "node:crypto";
2
+ import { COMMUNICATION_CHANNELS_QUEUES } from "./lib/queue.js";
3
+ const POLL_TICK_INTERVAL_SECONDS = Math.max(
4
+ 10,
5
+ Number.parseInt(process.env.OM_HUB_POLL_SCHEDULER_TICK_SECONDS ?? "60", 10) || 60
6
+ );
7
+ function stableScheduleUuid(stableKey) {
8
+ const hex = createHash("sha256").update(stableKey).digest("hex");
9
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
10
+ }
11
+ function stablePollTickScheduleId(organizationId) {
12
+ return stableScheduleUuid(`communication_channels:poll-tick:${organizationId}`);
13
+ }
14
+ const setup = {
15
+ defaultRoleFeatures: {
16
+ superadmin: [
17
+ "communication_channels.view",
18
+ "communication_channels.manage",
19
+ "communication_channels.react",
20
+ "communication_channels.assign",
21
+ "communication_channels.connect_user_channel",
22
+ "communication_channels.admin",
23
+ "communication_channels.channel.import_history",
24
+ "communication_channels.channel.push.manage"
25
+ ],
26
+ admin: [
27
+ "communication_channels.view",
28
+ "communication_channels.manage",
29
+ "communication_channels.react",
30
+ "communication_channels.assign",
31
+ "communication_channels.connect_user_channel",
32
+ "communication_channels.admin",
33
+ "communication_channels.channel.import_history",
34
+ "communication_channels.channel.push.manage"
35
+ ],
36
+ manager: [
37
+ "communication_channels.view",
38
+ "communication_channels.manage",
39
+ "communication_channels.react",
40
+ "communication_channels.assign",
41
+ "communication_channels.connect_user_channel"
42
+ ],
43
+ employee: [
44
+ "communication_channels.view",
45
+ "communication_channels.react",
46
+ "communication_channels.connect_user_channel"
47
+ ]
48
+ },
49
+ async seedDefaults({ container, organizationId, tenantId }) {
50
+ const cradle = container;
51
+ if (typeof cradle.hasRegistration !== "function" || !cradle.hasRegistration("schedulerService")) {
52
+ return;
53
+ }
54
+ const schedulerService = container.resolve("schedulerService");
55
+ try {
56
+ await schedulerService.register({
57
+ id: stablePollTickScheduleId(organizationId),
58
+ name: "Communication channels poll tick",
59
+ description: `Enumerates active polling channels every ${POLL_TICK_INTERVAL_SECONDS}s and enqueues per-channel poll jobs.`,
60
+ scopeType: "organization",
61
+ organizationId,
62
+ tenantId,
63
+ scheduleType: "interval",
64
+ scheduleValue: `${POLL_TICK_INTERVAL_SECONDS}s`,
65
+ timezone: "UTC",
66
+ targetType: "queue",
67
+ targetQueue: COMMUNICATION_CHANNELS_QUEUES.pollTick,
68
+ targetPayload: {
69
+ scope: { tenantId, organizationId }
70
+ },
71
+ sourceType: "module",
72
+ sourceModule: "communication_channels",
73
+ isEnabled: true
74
+ });
75
+ await schedulerService.register({
76
+ id: stableScheduleUuid(`communication_channels:gmail-renew-watch:${organizationId}`),
77
+ name: "Gmail watch renewal",
78
+ description: "Daily 04:00 UTC. Re-issues gmail.users.watch for channels within OM_PUSH_RENEWAL_GMAIL_LEAD_HOURS of expiry.",
79
+ scopeType: "organization",
80
+ organizationId,
81
+ tenantId,
82
+ scheduleType: "cron",
83
+ scheduleValue: "0 4 * * *",
84
+ timezone: "UTC",
85
+ targetType: "queue",
86
+ targetQueue: COMMUNICATION_CHANNELS_QUEUES.gmailRenewWatch,
87
+ targetPayload: { scope: { tenantId, organizationId } },
88
+ sourceType: "module",
89
+ sourceModule: "communication_channels",
90
+ isEnabled: true
91
+ });
92
+ } catch (error) {
93
+ console.warn(
94
+ "[communication_channels] Failed to register module schedules:",
95
+ error instanceof Error ? error.message : error
96
+ );
97
+ }
98
+ }
99
+ };
100
+ var setup_default = setup;
101
+ export {
102
+ setup_default as default,
103
+ setup
104
+ };
105
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/modules/communication_channels/setup.ts"],
4
+ "sourcesContent": ["import { createHash } from 'node:crypto'\nimport type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'\nimport { COMMUNICATION_CHANNELS_QUEUES } from './lib/queue'\n\ntype SchedulerServiceLike = {\n register: (registration: {\n id: string\n name: string\n scopeType: 'system' | 'organization' | 'tenant'\n organizationId?: string\n tenantId?: string\n scheduleType: 'cron' | 'interval'\n scheduleValue: string\n timezone?: string\n targetType: 'queue' | 'command'\n targetQueue?: string\n targetPayload?: unknown\n sourceType?: 'user' | 'module'\n sourceModule?: string\n isEnabled?: boolean\n description?: string\n }) => Promise<void>\n}\n\n/**\n * Tick interval in seconds. Default 60s per email integration spec\n * \u00A7 Hub Deltas \u2192 Delta 6 (scheduler mechanism).\n */\nconst POLL_TICK_INTERVAL_SECONDS = Math.max(\n 10,\n Number.parseInt(process.env.OM_HUB_POLL_SCHEDULER_TICK_SECONDS ?? '60', 10) || 60,\n)\n\n/**\n * `scheduled_jobs.id` is a uuid column, so a module-owned schedule's stable\n * registration key must be hashed into a uuid rather than used verbatim \u2014 this\n * keeps `schedulerService.register()` an idempotent upsert across re-runs of\n * seedDefaults instead of trying to insert a raw string into the uuid PK.\n */\nfunction stableScheduleUuid(stableKey: string): string {\n const hex = createHash('sha256').update(stableKey).digest('hex')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`\n}\n\nfunction stablePollTickScheduleId(organizationId: string): string {\n return stableScheduleUuid(`communication_channels:poll-tick:${organizationId}`)\n}\n\nexport const setup: ModuleSetupConfig = {\n defaultRoleFeatures: {\n superadmin: [\n 'communication_channels.view',\n 'communication_channels.manage',\n 'communication_channels.react',\n 'communication_channels.assign',\n 'communication_channels.connect_user_channel',\n 'communication_channels.admin',\n 'communication_channels.channel.import_history',\n 'communication_channels.channel.push.manage',\n ],\n admin: [\n 'communication_channels.view',\n 'communication_channels.manage',\n 'communication_channels.react',\n 'communication_channels.assign',\n 'communication_channels.connect_user_channel',\n 'communication_channels.admin',\n 'communication_channels.channel.import_history',\n 'communication_channels.channel.push.manage',\n ],\n manager: [\n 'communication_channels.view',\n 'communication_channels.manage',\n 'communication_channels.react',\n 'communication_channels.assign',\n 'communication_channels.connect_user_channel',\n ],\n employee: [\n 'communication_channels.view',\n 'communication_channels.react',\n 'communication_channels.connect_user_channel',\n ],\n },\n\n async seedDefaults({ container, organizationId, tenantId }) {\n /**\n * Register the per-channel polling tick with `@open-mercato/scheduler`.\n *\n * Per email integration spec \u00A7 Hub Deltas \u2192 Delta 6: every\n * `POLL_TICK_INTERVAL_SECONDS` (default 60s), enqueue a single\n * `communication-channels-poll-tick` job that enumerates due channels and\n * fans out to the `communication-channels-poll` queue.\n *\n * The registration is per-organization (one tick row per org/tenant pair)\n * so multi-tenant deploys schedule independently. Skipped silently when the\n * scheduler module isn't enabled \u2014 keeps the hub usable in scheduler-less\n * test harnesses.\n */\n const cradle = container as { hasRegistration?: (name: string) => boolean }\n if (typeof cradle.hasRegistration !== 'function' || !cradle.hasRegistration('schedulerService')) {\n return\n }\n const schedulerService = container.resolve('schedulerService') as SchedulerServiceLike\n // Best-effort: a scheduler failure must not abort tenant initialization for\n // every other module (mirrors the ai_assistant setup pattern). The schedule\n // ids are deterministic uuids so re-runs upsert idempotently.\n try {\n await schedulerService.register({\n id: stablePollTickScheduleId(organizationId),\n name: 'Communication channels poll tick',\n description:\n `Enumerates active polling channels every ${POLL_TICK_INTERVAL_SECONDS}s and enqueues per-channel poll jobs.`,\n scopeType: 'organization',\n organizationId,\n tenantId,\n scheduleType: 'interval',\n scheduleValue: `${POLL_TICK_INTERVAL_SECONDS}s`,\n timezone: 'UTC',\n targetType: 'queue',\n targetQueue: COMMUNICATION_CHANNELS_QUEUES.pollTick,\n targetPayload: {\n scope: { tenantId, organizationId },\n },\n sourceType: 'module',\n sourceModule: 'communication_channels',\n isEnabled: true,\n })\n\n // Spec C \u00A7 Phase C4 \u2014 Gmail watch renewal cron, per-org so multi-tenant\n // deploys schedule independently.\n await schedulerService.register({\n id: stableScheduleUuid(`communication_channels:gmail-renew-watch:${organizationId}`),\n name: 'Gmail watch renewal',\n description:\n 'Daily 04:00 UTC. Re-issues gmail.users.watch for channels within OM_PUSH_RENEWAL_GMAIL_LEAD_HOURS of expiry.',\n scopeType: 'organization',\n organizationId,\n tenantId,\n scheduleType: 'cron',\n scheduleValue: '0 4 * * *',\n timezone: 'UTC',\n targetType: 'queue',\n targetQueue: COMMUNICATION_CHANNELS_QUEUES.gmailRenewWatch,\n targetPayload: { scope: { tenantId, organizationId } },\n sourceType: 'module',\n sourceModule: 'communication_channels',\n isEnabled: true,\n })\n } catch (error) {\n console.warn(\n '[communication_channels] Failed to register module schedules:',\n error instanceof Error ? error.message : error,\n )\n }\n },\n}\n\nexport default setup\n"],
5
+ "mappings": "AAAA,SAAS,kBAAkB;AAE3B,SAAS,qCAAqC;AA0B9C,MAAM,6BAA6B,KAAK;AAAA,EACtC;AAAA,EACA,OAAO,SAAS,QAAQ,IAAI,sCAAsC,MAAM,EAAE,KAAK;AACjF;AAQA,SAAS,mBAAmB,WAA2B;AACrD,QAAM,MAAM,WAAW,QAAQ,EAAE,OAAO,SAAS,EAAE,OAAO,KAAK;AAC/D,SAAO,GAAG,IAAI,MAAM,GAAG,CAAC,CAAC,IAAI,IAAI,MAAM,GAAG,EAAE,CAAC,IAAI,IAAI,MAAM,IAAI,EAAE,CAAC,IAAI,IAAI,MAAM,IAAI,EAAE,CAAC,IAAI,IAAI,MAAM,IAAI,EAAE,CAAC;AAC9G;AAEA,SAAS,yBAAyB,gBAAgC;AAChE,SAAO,mBAAmB,oCAAoC,cAAc,EAAE;AAChF;AAEO,MAAM,QAA2B;AAAA,EACtC,qBAAqB;AAAA,IACnB,YAAY;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,EAAE,WAAW,gBAAgB,SAAS,GAAG;AAc1D,UAAM,SAAS;AACf,QAAI,OAAO,OAAO,oBAAoB,cAAc,CAAC,OAAO,gBAAgB,kBAAkB,GAAG;AAC/F;AAAA,IACF;AACA,UAAM,mBAAmB,UAAU,QAAQ,kBAAkB;AAI7D,QAAI;AACF,YAAM,iBAAiB,SAAS;AAAA,QAC9B,IAAI,yBAAyB,cAAc;AAAA,QAC3C,MAAM;AAAA,QACN,aACE,4CAA4C,0BAA0B;AAAA,QACxE,WAAW;AAAA,QACX;AAAA,QACA;AAAA,QACA,cAAc;AAAA,QACd,eAAe,GAAG,0BAA0B;AAAA,QAC5C,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,aAAa,8BAA8B;AAAA,QAC3C,eAAe;AAAA,UACb,OAAO,EAAE,UAAU,eAAe;AAAA,QACpC;AAAA,QACA,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,WAAW;AAAA,MACb,CAAC;AAID,YAAM,iBAAiB,SAAS;AAAA,QAC9B,IAAI,mBAAmB,4CAA4C,cAAc,EAAE;AAAA,QACnF,MAAM;AAAA,QACN,aACE;AAAA,QACF,WAAW;AAAA,QACX;AAAA,QACA;AAAA,QACA,cAAc;AAAA,QACd,eAAe;AAAA,QACf,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,aAAa,8BAA8B;AAAA,QAC3C,eAAe,EAAE,OAAO,EAAE,UAAU,eAAe,EAAE;AAAA,QACrD,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,WAAW;AAAA,MACb,CAAC;AAAA,IACH,SAAS,OAAO;AACd,cAAQ;AAAA,QACN;AAAA,QACA,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,gBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,71 @@
1
+ import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
2
+ import { CommunicationChannel } from "../data/entities.js";
3
+ import { notificationTypes } from "../notifications.js";
4
+ import {
5
+ buildNotificationFromType,
6
+ buildFeatureNotificationFromType
7
+ } from "../../notifications/lib/notificationBuilder.js";
8
+ import { resolveNotificationService } from "../../notifications/lib/notificationService.js";
9
+ const metadata = {
10
+ event: "communication_channels.channel.requires_reauth",
11
+ persistent: true,
12
+ id: "communication_channels:channel-requires-reauth-notification"
13
+ };
14
+ const NOTIFICATION_TYPE = "communication_channels.channel.requires_reauth";
15
+ const MANAGE_FEATURE = "communication_channels.manage";
16
+ function resolveFromCtx(ctx, name) {
17
+ if (typeof ctx?.resolve === "function") return ctx.resolve(name);
18
+ if (ctx?.container && typeof ctx.container.resolve === "function") {
19
+ return ctx.container.resolve(name);
20
+ }
21
+ throw new Error(
22
+ `channel-requires-reauth-notification: subscriber context has no resolver (looking for '${name}')`
23
+ );
24
+ }
25
+ async function handler(payload, ctx) {
26
+ if (!payload?.channelId || !payload.tenantId) {
27
+ return;
28
+ }
29
+ const typeDef = notificationTypes.find((type) => type.type === NOTIFICATION_TYPE);
30
+ if (!typeDef) return;
31
+ const scope = {
32
+ tenantId: payload.tenantId,
33
+ organizationId: payload.organizationId ?? null
34
+ };
35
+ const em = resolveFromCtx(ctx, "em").fork();
36
+ const channel = await findOneWithDecryption(
37
+ em,
38
+ CommunicationChannel,
39
+ {
40
+ id: payload.channelId,
41
+ tenantId: payload.tenantId,
42
+ organizationId: payload.organizationId ?? null,
43
+ deletedAt: null
44
+ },
45
+ void 0,
46
+ scope
47
+ );
48
+ if (!channel) return;
49
+ const notificationService = resolveNotificationService(ctx);
50
+ const common = {
51
+ sourceEntityType: "communication_channel",
52
+ sourceEntityId: payload.channelId,
53
+ groupKey: payload.channelId
54
+ };
55
+ if (channel.userId) {
56
+ await notificationService.create(
57
+ buildNotificationFromType(typeDef, { ...common, recipientUserId: channel.userId }),
58
+ scope
59
+ );
60
+ return;
61
+ }
62
+ await notificationService.createForFeature(
63
+ buildFeatureNotificationFromType(typeDef, { ...common, requiredFeature: MANAGE_FEATURE }),
64
+ scope
65
+ );
66
+ }
67
+ export {
68
+ handler as default,
69
+ metadata
70
+ };
71
+ //# sourceMappingURL=channel-requires-reauth-notification.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/communication_channels/subscribers/channel-requires-reauth-notification.ts"],
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CommunicationChannel } from '../data/entities'\nimport { notificationTypes } from '../notifications'\nimport {\n buildNotificationFromType,\n buildFeatureNotificationFromType,\n} from '../../notifications/lib/notificationBuilder'\nimport { resolveNotificationService } from '../../notifications/lib/notificationService'\n\n/**\n * Subscriber: re-authentication notification.\n *\n * Listens to `communication_channels.channel.requires_reauth` (emitted by the\n * poll worker and outbound delivery when an\n * adapter loses authorization) and raises the in-app\n * `communication_channels.channel.requires_reauth` notification so the affected\n * user sees a bell entry + reconnect CTA and the reactive toast handler\n * (`notifications.handlers.ts`) fires. This is the producer half of the\n * notification contract declared in `notifications.ts` /\n * `notifications.client.ts` \u2014 without it the notification is never persisted.\n *\n * Recipient: per-user channels notify the channel owner (`channel.userId`) \u2014 the\n * only person who can complete their own OAuth/credential reconnect. Tenant-wide\n * (shared) channels have no owner, so operators holding\n * `communication_channels.manage` are notified instead.\n *\n * Idempotency: `groupKey = channelId` collapses repeated reauth events for the\n * same channel onto one notification (the notification service dedupes by\n * tenant/org/recipient/type/groupKey under an advisory lock), so a flapping\n * channel or a subscriber retry never spams the bell.\n */\nexport const metadata = {\n event: 'communication_channels.channel.requires_reauth',\n persistent: true,\n id: 'communication_channels:channel-requires-reauth-notification',\n}\n\nconst NOTIFICATION_TYPE = 'communication_channels.channel.requires_reauth'\nconst MANAGE_FEATURE = 'communication_channels.manage'\n\ntype RequiresReauthPayload = {\n channelId?: string\n providerKey?: string\n channelType?: string\n reason?: string\n tenantId?: string\n organizationId?: string | null\n}\n\ntype SubscriberContext = {\n resolve: <T = unknown>(name: string) => T\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(\n `channel-requires-reauth-notification: subscriber context has no resolver (looking for '${name}')`,\n )\n}\n\nexport default async function handler(\n payload: RequiresReauthPayload,\n ctx: SubscriberContext,\n): Promise<void> {\n if (!payload?.channelId || !payload.tenantId) {\n return\n }\n\n const typeDef = notificationTypes.find((type) => type.type === NOTIFICATION_TYPE)\n if (!typeDef) return\n\n const scope = {\n tenantId: payload.tenantId,\n organizationId: payload.organizationId ?? null,\n }\n\n const em = resolveFromCtx<EntityManager>(ctx, 'em').fork()\n const channel = await findOneWithDecryption(\n em,\n CommunicationChannel,\n {\n id: payload.channelId,\n tenantId: payload.tenantId,\n organizationId: payload.organizationId ?? null,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n if (!channel) return\n\n const notificationService = resolveNotificationService(ctx)\n const common = {\n sourceEntityType: 'communication_channel',\n sourceEntityId: payload.channelId,\n groupKey: payload.channelId,\n }\n\n if (channel.userId) {\n await notificationService.create(\n buildNotificationFromType(typeDef, { ...common, recipientUserId: channel.userId }),\n scope,\n )\n return\n }\n\n // Tenant-wide (shared) channel \u2014 no single owner. Notify operators who can\n // reconnect it on behalf of the tenant.\n await notificationService.createForFeature(\n buildFeatureNotificationFromType(typeDef, { ...common, requiredFeature: MANAGE_FEATURE }),\n scope,\n )\n}\n"],
5
+ "mappings": "AACA,SAAS,6BAA6B;AACtC,SAAS,4BAA4B;AACrC,SAAS,yBAAyB;AAClC;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,kCAAkC;AAwBpC,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,MAAM,oBAAoB;AAC1B,MAAM,iBAAiB;AAgBvB,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;AAAA,IACR,0FAA0F,IAAI;AAAA,EAChG;AACF;AAEA,eAAO,QACL,SACA,KACe;AACf,MAAI,CAAC,SAAS,aAAa,CAAC,QAAQ,UAAU;AAC5C;AAAA,EACF;AAEA,QAAM,UAAU,kBAAkB,KAAK,CAAC,SAAS,KAAK,SAAS,iBAAiB;AAChF,MAAI,CAAC,QAAS;AAEd,QAAM,QAAQ;AAAA,IACZ,UAAU,QAAQ;AAAA,IAClB,gBAAgB,QAAQ,kBAAkB;AAAA,EAC5C;AAEA,QAAM,KAAK,eAA8B,KAAK,IAAI,EAAE,KAAK;AACzD,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;AAEd,QAAM,sBAAsB,2BAA2B,GAAG;AAC1D,QAAM,SAAS;AAAA,IACb,kBAAkB;AAAA,IAClB,gBAAgB,QAAQ;AAAA,IACxB,UAAU,QAAQ;AAAA,EACpB;AAEA,MAAI,QAAQ,QAAQ;AAClB,UAAM,oBAAoB;AAAA,MACxB,0BAA0B,SAAS,EAAE,GAAG,QAAQ,iBAAiB,QAAQ,OAAO,CAAC;AAAA,MACjF;AAAA,IACF;AACA;AAAA,EACF;AAIA,QAAM,oBAAoB;AAAA,IACxB,iCAAiC,SAAS,EAAE,GAAG,QAAQ,iBAAiB,eAAe,CAAC;AAAA,IACxF;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }