@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
@@ -40,6 +40,13 @@ function diffDays(from: Date, to: Date): number {
40
40
  return Math.floor((to.getTime() - from.getTime()) / DAY_MS)
41
41
  }
42
42
 
43
+ /** Coerce an unknown value to a non-empty string array, or null when absent/empty. */
44
+ function stringArrayOrNull(value: unknown): string[] | null {
45
+ if (!Array.isArray(value)) return null
46
+ const strings = value.filter((entry): entry is string => typeof entry === 'string')
47
+ return strings.length > 0 ? strings : null
48
+ }
49
+
43
50
  async function fetchOpenInteractionCounts(
44
51
  db: CustomerKysely,
45
52
  dealIds: Set<string>,
@@ -207,4 +214,248 @@ const dealPipelineEnricher: ResponseEnricher<DealRecord> = {
207
214
  },
208
215
  }
209
216
 
210
- export const enrichers: ResponseEnricher[] = [dealPipelineEnricher]
217
+ type PersonRecord = Record<string, unknown> & { id: string }
218
+
219
+ /**
220
+ * Adds `_privateEmailCount` to each Person — the number of that person's PRIVATE
221
+ * email interactions authored by OTHER users (private emails the current viewer
222
+ * cannot see). Backs the documented "count of teammates' private emails" badge
223
+ * (see `apps/docs/docs/user-guide/customers-email.mdx`): a viewer learns an
224
+ * exchange exists without seeing its content. The count-badge UI is a pending
225
+ * follow-up; the field is populated here so the consumer can be wired without a
226
+ * second pass. Owner/tenant scoped and fail-safe to 0 — never leaks content.
227
+ */
228
+ export const privateEmailCountEnricher: ResponseEnricher<
229
+ PersonRecord,
230
+ { _privateEmailCount?: number }
231
+ > = {
232
+ id: 'customers.private-email-count',
233
+ targetEntity: 'customers.person',
234
+ features: ['customers.people.view'],
235
+ priority: 30,
236
+ timeout: 1500,
237
+ fallback: { _privateEmailCount: 0 },
238
+ critical: false,
239
+
240
+ async enrichOne(record, context) {
241
+ const enriched = await this.enrichMany!([record], context)
242
+ return enriched[0]
243
+ },
244
+
245
+ async enrichMany(records, context: EnricherContext) {
246
+ if (records.length === 0) return records
247
+
248
+ const db = resolveKyselyClient(context.em)
249
+ if (!db) {
250
+ return records.map((record) => ({ ...record, _privateEmailCount: 0 }))
251
+ }
252
+
253
+ const userId = context.userId
254
+ // Fail-safe to 0 when there is no real authoring user to exclude. An API-key
255
+ // principal (`auth.sub = "api_key:<id>"`) is not a person, so the
256
+ // `author_user_id != userId` exclusion below would match nothing and count
257
+ // every private email — short-circuit it here.
258
+ if (!userId || userId.startsWith('api_key:')) {
259
+ return records.map((record) => ({ ...record, _privateEmailCount: 0 }))
260
+ }
261
+
262
+ const personIds = records
263
+ .map((r) => r.id)
264
+ .filter((id): id is string => typeof id === 'string' && id.length > 0)
265
+
266
+ if (personIds.length === 0) {
267
+ return records.map((record) => ({ ...record, _privateEmailCount: 0 }))
268
+ }
269
+
270
+ const rows = await (db as CustomerKysely)
271
+ .selectFrom('customer_interactions')
272
+ .select(['entity_id'])
273
+ .select((eb) => eb.fn.countAll().as('count'))
274
+ .where('tenant_id', '=', context.tenantId)
275
+ .where('organization_id', '=', context.organizationId)
276
+ .where('interaction_type', '=', 'email')
277
+ .where('visibility', '=', 'private')
278
+ .where('deleted_at', 'is', null)
279
+ .where('entity_id', 'in', personIds)
280
+ .where('author_user_id', '!=', userId)
281
+ .groupBy('entity_id')
282
+ .execute()
283
+
284
+ const countMap = new Map<string, number>()
285
+ for (const row of rows) {
286
+ const personId = typeof row.entity_id === 'string' ? row.entity_id : null
287
+ if (!personId) continue
288
+ const count = typeof row.count === 'number' ? row.count : Number(row.count)
289
+ if (Number.isFinite(count)) countMap.set(personId, count)
290
+ }
291
+
292
+ return records.map((record) => ({
293
+ ...record,
294
+ _privateEmailCount: countMap.get(record.id) ?? 0,
295
+ }))
296
+ },
297
+ }
298
+
299
+ type InteractionRecord = Record<string, unknown> & {
300
+ id: string
301
+ interactionType?: string | null
302
+ externalMessageId?: string | null
303
+ }
304
+
305
+ type EmailIntegrationFields = {
306
+ externalMessageId?: string | null
307
+ rfcMessageId?: string | null
308
+ fromAddress?: string | null
309
+ toAddresses?: string[] | null
310
+ ccAddresses?: string[] | null
311
+ subject?: string | null
312
+ inReplyTo?: string | null
313
+ references?: string[] | null
314
+ /** Current visibility of the interaction row, for the private/shared toggle. */
315
+ currentVisibility?: 'private' | 'shared' | null
316
+ /** True when the interaction's author is the requesting user — gates the toggle. */
317
+ isAuthor?: boolean
318
+ }
319
+
320
+ /**
321
+ * Enriches email-type customer interactions with MessageChannelLink metadata
322
+ * so the ActivityCard widget can render Reply/Forward/visibility-toggle actions.
323
+ *
324
+ * For each interaction row where `interactionType === 'email'` and
325
+ * `externalMessageId` is set (the MessageChannelLink UUID), the enricher fetches
326
+ * the corresponding `MessageChannelLink` row and populates
327
+ * `_integrations.email.*` from its `channel_metadata` column.
328
+ *
329
+ * Non-email rows and rows without an externalMessageId pass through unchanged.
330
+ * Fail-safe: if the Kysely client is unavailable or the lookup fails, the records
331
+ * are returned unmodified so the activity timeline still renders (without email
332
+ * card actions).
333
+ */
334
+ export const interactionEmailCardEnricher: ResponseEnricher<
335
+ InteractionRecord,
336
+ { _integrations?: { email?: EmailIntegrationFields } }
337
+ > = {
338
+ id: 'customers.interaction-email-card',
339
+ // Must match the entity ID passed to applyResponseEnrichers in the interactions
340
+ // GET route (api/interactions/route.ts line 539): 'customers.interaction'.
341
+ targetEntity: 'customers.interaction',
342
+ features: ['customers.interactions.view'],
343
+ priority: 25,
344
+ timeout: 1500,
345
+ fallback: {},
346
+ critical: false,
347
+
348
+ async enrichOne(record, ctx) {
349
+ const results = await this.enrichMany!([record], ctx)
350
+ return results[0]
351
+ },
352
+
353
+ async enrichMany(records, ctx) {
354
+ if (records.length === 0) return records
355
+
356
+ // Fast path: skip the DB round-trip when no email rows with a link are present.
357
+ const emailRecords = records.filter(
358
+ (r) =>
359
+ r.interactionType === 'email' &&
360
+ typeof r.externalMessageId === 'string' &&
361
+ r.externalMessageId.length > 0,
362
+ )
363
+ if (emailRecords.length === 0) return records
364
+
365
+ const linkIds = Array.from(
366
+ new Set(emailRecords.map((r) => r.externalMessageId as string)),
367
+ )
368
+
369
+ // message_channel_links is owned by communication_channels; its read-only
370
+ // shape is declared in CustomerKyselyDb so this stays type-safe without
371
+ // cross-module coupling. Mirrors privateEmailCountEnricher.
372
+ const kysely = resolveKyselyClient(ctx.em)
373
+ if (!kysely) {
374
+ // Fail-safe: Kysely unavailable (test stubs, unusual driver wrappers).
375
+ return records
376
+ }
377
+
378
+ let linkRows: Array<{ id: string; channel_metadata: unknown }>
379
+ try {
380
+ linkRows = await kysely
381
+ .selectFrom('message_channel_links')
382
+ .select(['id', 'channel_metadata'])
383
+ .where('tenant_id', '=', ctx.tenantId)
384
+ // Defense-in-depth org scope. `id IN linkIds` already binds the lookup
385
+ // to this org's interactions, and `message_channel_links.organization_id`
386
+ // is nullable, so we tolerate NULL to avoid dropping legitimate links.
387
+ .where((eb) =>
388
+ eb.or([
389
+ eb('organization_id', '=', ctx.organizationId),
390
+ eb('organization_id', 'is', null),
391
+ ]),
392
+ )
393
+ .where('id', 'in', linkIds)
394
+ .execute()
395
+ } catch {
396
+ // Fail-safe: unexpected DB error (missing table in test env, schema drift).
397
+ return records
398
+ }
399
+
400
+ const byLinkId = new Map<string, EmailIntegrationFields>()
401
+ for (const row of linkRows) {
402
+ const meta = (row.channel_metadata ?? {}) as Record<string, unknown>
403
+ const fields: EmailIntegrationFields = {
404
+ externalMessageId: row.id,
405
+ rfcMessageId: typeof meta.messageId === 'string' ? meta.messageId : null,
406
+ fromAddress: typeof meta.from === 'string' ? meta.from : null,
407
+ toAddresses: stringArrayOrNull(meta.to),
408
+ ccAddresses: stringArrayOrNull(meta.cc),
409
+ // bcc is intentionally NOT surfaced: BCC recipients are blind by design,
410
+ // so exposing them to every teammate who can view a shared email would
411
+ // leak the blind-copy list. Keep it out of the enriched response.
412
+ subject: typeof meta.subject === 'string' ? meta.subject : null,
413
+ inReplyTo: typeof meta.inReplyTo === 'string' ? meta.inReplyTo : null,
414
+ references: stringArrayOrNull(meta.references),
415
+ }
416
+ byLinkId.set(row.id, fields)
417
+ }
418
+
419
+ const currentUserId = ctx.userId
420
+
421
+ return records.map((r) => {
422
+ if (
423
+ r.interactionType !== 'email' ||
424
+ typeof r.externalMessageId !== 'string' ||
425
+ r.externalMessageId.length === 0
426
+ ) {
427
+ return r
428
+ }
429
+ const fields = byLinkId.get(r.externalMessageId)
430
+ if (!fields) return r
431
+ const visibility =
432
+ r.visibility === 'private' || r.visibility === 'shared' ? r.visibility : null
433
+ const authorUserId = typeof r.authorUserId === 'string' ? r.authorUserId : null
434
+ const isAuthor = Boolean(currentUserId && authorUserId && authorUserId === currentUserId)
435
+ // Fail-closed (defense-in-depth): never surface another user's PRIVATE
436
+ // email metadata (subject/from/to/references), even if a consumer forgot
437
+ // to apply the visibility filter upstream. v1 is strict owner-only (no
438
+ // admin bypass — `customers.email.view_private` is inert until v2), so a
439
+ // private row is enriched only for its author. The normal read paths
440
+ // already drop these rows; this keeps the globally-registered enricher
441
+ // safe-by-construction for any future consumer that opts into it.
442
+ if (visibility === 'private' && !isAuthor) {
443
+ return r
444
+ }
445
+ const existingIntegrations = (r._integrations ?? {}) as Record<string, unknown>
446
+ return {
447
+ ...r,
448
+ _integrations: {
449
+ ...existingIntegrations,
450
+ email: {
451
+ ...fields,
452
+ currentVisibility: visibility,
453
+ isAuthor,
454
+ },
455
+ },
456
+ }
457
+ })
458
+ },
459
+ }
460
+
461
+ export const enrichers: ResponseEnricher[] = [dealPipelineEnricher, privateEmailCountEnricher, interactionEmailCardEnricher]
@@ -542,8 +542,23 @@ export class CustomerActivity {
542
542
  name: 'customer_interactions_type_idx',
543
543
  properties: ['tenantId', 'organizationId', 'interactionType'],
544
544
  })
545
+ @Index({
546
+ name: 'customer_interactions_external_msg_idx',
547
+ expression:
548
+ `create index "customer_interactions_external_msg_idx" on "customer_interactions" ("external_message_id") where "external_message_id" is not null`,
549
+ })
550
+ @Index({
551
+ name: 'customer_interactions_email_dedupe_uq',
552
+ expression:
553
+ `create unique index "customer_interactions_email_dedupe_uq" on "customer_interactions" ("entity_id", "external_message_id") where "external_message_id" is not null and "deleted_at" is null`,
554
+ })
555
+ @Index({
556
+ name: 'customer_interactions_email_visibility_idx',
557
+ expression:
558
+ `create index "customer_interactions_email_visibility_idx" on "customer_interactions" ("entity_id", "interaction_type", "visibility", "author_user_id") where "interaction_type" = 'email' and "deleted_at" is null`,
559
+ })
545
560
  export class CustomerInteraction {
546
- [OptionalProps]?: 'status' | 'pinned' | 'createdAt' | 'updatedAt' | 'deletedAt' | 'durationMinutes' | 'location' | 'allDay' | 'recurrenceRule' | 'recurrenceEnd' | 'participants' | 'reminderMinutes' | 'visibility' | 'linkedEntities' | 'guestPermissions'
561
+ [OptionalProps]?: 'status' | 'pinned' | 'createdAt' | 'updatedAt' | 'deletedAt' | 'durationMinutes' | 'location' | 'allDay' | 'recurrenceRule' | 'recurrenceEnd' | 'participants' | 'reminderMinutes' | 'visibility' | 'linkedEntities' | 'guestPermissions' | 'externalMessageId' | 'channelProviderKey'
547
562
 
548
563
  @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })
549
564
  id!: string
@@ -563,6 +578,24 @@ export class CustomerInteraction {
563
578
  @Property({ name: 'body', type: 'text', nullable: true })
564
579
  body?: string | null
565
580
 
581
+ /**
582
+ * UUID pointing at `communication_channels.message_channel_link.id`.
583
+ * Set only for rows where `interactionType === 'email'`.
584
+ *
585
+ * The cross-module link is declared in `data/extensions.ts` rather than as
586
+ * a raw FK (root AGENTS.md: no direct ORM relationships between modules).
587
+ */
588
+ @Property({ name: 'external_message_id', type: 'uuid', nullable: true })
589
+ externalMessageId?: string | null
590
+
591
+ /**
592
+ * Denormalized provider key from `MessageChannelLink.providerKey`. Common
593
+ * values today: 'gmail', 'imap'. Stored as open text so future
594
+ * providers (e.g. 'slack', 'whatsapp') can register without a schema change.
595
+ */
596
+ @Property({ name: 'channel_provider_key', type: 'text', nullable: true })
597
+ channelProviderKey?: string | null
598
+
566
599
  @Property({ name: 'status', type: 'text', default: 'planned' })
567
600
  status: string = 'planned'
568
601
 
@@ -614,6 +647,18 @@ export class CustomerInteraction {
614
647
  @Property({ name: 'reminder_minutes', type: 'int', nullable: true })
615
648
  reminderMinutes?: number | null
616
649
 
650
+ /**
651
+ * Visibility flag, shared across interaction types but with a per-type
652
+ * value space:
653
+ * - Email rows (interactionType='email'): 'private' | 'shared'.
654
+ * Filtered by `lib/visibilityFilter.ts` so private emails are only
655
+ * visible only to the channel-owner author (v1 strict owner-only; no admin bypass).
656
+ * - Activity rows (call/meeting/task): 'team' | 'public'. Surfaced via
657
+ * the ScheduleActivityDialog footer.
658
+ * Stored as plain text to keep the column reusable for future visibility
659
+ * vocabularies; the application enforces the per-type vocabulary at the
660
+ * boundary (API routes, subscribers).
661
+ */
617
662
  @Property({ name: 'visibility', type: 'text', nullable: true })
618
663
  visibility?: string | null
619
664
 
@@ -0,0 +1,26 @@
1
+ import type { EntityExtension } from '@open-mercato/shared/modules/entities'
2
+
3
+ /**
4
+ * Cross-module entity links declared by the customers module.
5
+ *
6
+ * Per root AGENTS.md, modules do NOT form direct ORM relationships across
7
+ * boundaries. Instead, plain UUID columns reference IDs in other modules and
8
+ * the link is declared here so the data engine + UI tooling can traverse.
9
+ *
10
+ * Canonical EntityExtension shape from `@open-mercato/shared/modules/entities`:
11
+ * `{ base, extension, join: { baseKey, extensionKey }, cardinality?, required?, description? }`
12
+ */
13
+
14
+ const entityExtensions: EntityExtension[] = [
15
+ {
16
+ base: 'customers:customer_interaction',
17
+ extension: 'communication_channels:message_channel_link',
18
+ join: { baseKey: 'external_message_id', extensionKey: 'id' },
19
+ cardinality: 'many-to-one',
20
+ description:
21
+ 'Links an email CustomerInteraction to the MessageChannelLink that tracks its external channel metadata',
22
+ },
23
+ ]
24
+
25
+ export const extensions = entityExtensions
26
+ export default entityExtensions
@@ -40,6 +40,17 @@ export const defaultEncryptionMaps: ModuleEncryptionMap[] = [
40
40
  { field: 'body' },
41
41
  ],
42
42
  },
43
+ {
44
+ // Interactions carry call/meeting notes and, for interactionType='email',
45
+ // the email subject (title) and body — sensitive PII. Encrypt at rest like
46
+ // the sibling customer_activity. Read paths use findWithDecryption; the
47
+ // interactions list route decrypts title/body for the returned page.
48
+ entityId: 'customers:customer_interaction',
49
+ fields: [
50
+ { field: 'title' },
51
+ { field: 'body' },
52
+ ],
53
+ },
43
54
  {
44
55
  entityId: 'customers:customer_comment',
45
56
  fields: [{ field: 'body' }],
@@ -78,6 +78,10 @@ const events = [
78
78
  { id: 'customers.person_company_link.created', label: 'Person Linked To Company', entity: 'person_company_link', category: 'crud', clientBroadcast: true },
79
79
  { id: 'customers.person_company_link.updated', label: 'Person-Company Link Updated', entity: 'person_company_link', category: 'crud', clientBroadcast: true },
80
80
  { id: 'customers.person_company_link.deleted', label: 'Person Unlinked From Company', entity: 'person_company_link', category: 'crud', clientBroadcast: true },
81
+
82
+ // ── Email integration (2026-05-27) ────────────────────────────────────────
83
+ { id: 'customers.email.linked', label: 'Email Linked To Person', entity: 'email_link', category: 'lifecycle', clientBroadcast: true },
84
+ { id: 'customers.email.visibility_changed', label: 'Email Visibility Changed', entity: 'email_link', category: 'lifecycle', clientBroadcast: true },
81
85
  ] as const
82
86
 
83
87
  export const eventsConfig = createModuleEvents({
@@ -1211,6 +1211,46 @@
1211
1211
  "customers.dictionaryEntries.create": "Kunden-Wörterbucheintrag hinzufügen",
1212
1212
  "customers.dictionaryEntries.delete": "Kunden-Wörterbucheintrag löschen",
1213
1213
  "customers.dictionaryEntries.update": "Kunden-Wörterbucheintrag aktualisieren",
1214
+ "customers.email.compose.addCc": "+ Cc",
1215
+ "customers.email.compose.addCc.ariaLabel": "Cc-Empfänger hinzufügen",
1216
+ "customers.email.compose.body": "Nachricht",
1217
+ "customers.email.compose.bodyPlaceholder": "Schreiben Sie Ihre Nachricht...",
1218
+ "customers.email.compose.button": "E-Mail senden",
1219
+ "customers.email.compose.cancel": "Abbrechen",
1220
+ "customers.email.compose.cc": "Cc",
1221
+ "customers.email.compose.ccPlaceholder": "cc@example.com",
1222
+ "customers.email.compose.noChannel.cta": "Postfach verbinden",
1223
+ "customers.email.compose.replyTitle": "Antworten",
1224
+ "customers.email.compose.selectChannel": "Konto auswählen",
1225
+ "customers.email.compose.send": "Senden",
1226
+ "customers.email.compose.sendAs": "Senden als",
1227
+ "customers.email.compose.sending": "Wird gesendet...",
1228
+ "customers.email.compose.sent": "E-Mail gesendet",
1229
+ "customers.email.compose.subject": "Betreff",
1230
+ "customers.email.compose.subjectPlaceholder": "E-Mail-Betreff",
1231
+ "customers.email.compose.title": "E-Mail verfassen",
1232
+ "customers.email.compose.to": "An",
1233
+ "customers.email.compose.toPlaceholder": "empfaenger@example.com",
1234
+ "customers.email.compose.visibility": "Sichtbarkeit",
1235
+ "customers.email.compose.visibilityPrivate": "Nur für mich",
1236
+ "customers.email.compose.visibilityShared": "Für Teammitglieder sichtbar",
1237
+ "customers.email.errors.deliveryFailed": "Zustellung fehlgeschlagen – nicht gesendet",
1238
+ "customers.email.errors.flipFailed": "Aktualisierung der Sichtbarkeit fehlgeschlagen",
1239
+ "customers.email.errors.sendFailed": "Senden fehlgeschlagen",
1240
+ "customers.email.sync.button": "Synchronisieren",
1241
+ "customers.email.sync.failed": "Postfach konnte nicht synchronisiert werden",
1242
+ "customers.email.sync.success": "Synchronisierung ausgelöst — neue Antworten erscheinen in wenigen Sekunden.",
1243
+ "customers.email.sync.syncing": "Wird synchronisiert...",
1244
+ "customers.email.sync.tooltip": "Prüfen Sie Ihr Postfach auf neue Antworten",
1245
+ "customers.email.threads.loadFailed": "E-Mails konnten nicht geladen werden",
1246
+ "customers.email.timeline.actionsAria": "E-Mail-Aktionen",
1247
+ "customers.email.timeline.forward": "Weiterleiten",
1248
+ "customers.email.timeline.reply": "Antworten",
1249
+ "customers.email.timeline.replyAll": "Allen antworten",
1250
+ "customers.email.visibility.flipToPrivate.label": "Privat machen",
1251
+ "customers.email.visibility.flipToPrivate.success": "E-Mail als privat festgelegt",
1252
+ "customers.email.visibility.flipToShared.label": "Mit Teammitgliedern teilen",
1253
+ "customers.email.visibility.flipToShared.success": "E-Mail mit Teammitgliedern geteilt",
1214
1254
  "customers.errors.access_denied": "Zugriff verweigert",
1215
1255
  "customers.errors.activity_required": "Aktivitäts-ID ist erforderlich",
1216
1256
  "customers.errors.address_required": "Adressen-ID ist erforderlich",
@@ -1770,6 +1810,7 @@
1770
1810
  "customers.people.detail.tabs.changelog": "Änderungsprotokoll",
1771
1811
  "customers.people.detail.tabs.companies": "Companies",
1772
1812
  "customers.people.detail.tabs.deals": "Geschäfte",
1813
+ "customers.people.detail.tabs.emails": "E-Mails",
1773
1814
  "customers.people.detail.tabs.files": "Files",
1774
1815
  "customers.people.detail.tabs.label": "Bereiche der Personendetails",
1775
1816
  "customers.people.detail.tabs.notes": "Notizen",
@@ -1211,6 +1211,46 @@
1211
1211
  "customers.dictionaryEntries.create": "Add customer dictionary entry",
1212
1212
  "customers.dictionaryEntries.delete": "Delete customer dictionary entry",
1213
1213
  "customers.dictionaryEntries.update": "Update customer dictionary entry",
1214
+ "customers.email.compose.addCc": "+ Cc",
1215
+ "customers.email.compose.addCc.ariaLabel": "Add Cc recipients",
1216
+ "customers.email.compose.body": "Body",
1217
+ "customers.email.compose.bodyPlaceholder": "Write your message...",
1218
+ "customers.email.compose.button": "Send email",
1219
+ "customers.email.compose.cancel": "Cancel",
1220
+ "customers.email.compose.cc": "Cc",
1221
+ "customers.email.compose.ccPlaceholder": "cc@example.com",
1222
+ "customers.email.compose.noChannel.cta": "Connect your mailbox",
1223
+ "customers.email.compose.replyTitle": "Reply",
1224
+ "customers.email.compose.selectChannel": "Select account",
1225
+ "customers.email.compose.send": "Send",
1226
+ "customers.email.compose.sendAs": "Send as",
1227
+ "customers.email.compose.sending": "Sending...",
1228
+ "customers.email.compose.sent": "Email sent",
1229
+ "customers.email.compose.subject": "Subject",
1230
+ "customers.email.compose.subjectPlaceholder": "Email subject",
1231
+ "customers.email.compose.title": "Compose email",
1232
+ "customers.email.compose.to": "To",
1233
+ "customers.email.compose.toPlaceholder": "recipient@example.com",
1234
+ "customers.email.compose.visibility": "Visibility",
1235
+ "customers.email.compose.visibilityPrivate": "Private to me",
1236
+ "customers.email.compose.visibilityShared": "Visible to teammates",
1237
+ "customers.email.errors.deliveryFailed": "Delivery failed — not sent",
1238
+ "customers.email.errors.flipFailed": "Visibility update failed",
1239
+ "customers.email.errors.sendFailed": "Send failed",
1240
+ "customers.email.sync.button": "Sync",
1241
+ "customers.email.sync.failed": "Failed to sync mailbox",
1242
+ "customers.email.sync.success": "Sync triggered — new replies will appear in a few seconds.",
1243
+ "customers.email.sync.syncing": "Syncing...",
1244
+ "customers.email.sync.tooltip": "Check your mailbox for new replies",
1245
+ "customers.email.threads.loadFailed": "Failed to load emails",
1246
+ "customers.email.timeline.actionsAria": "Email actions",
1247
+ "customers.email.timeline.forward": "Forward",
1248
+ "customers.email.timeline.reply": "Reply",
1249
+ "customers.email.timeline.replyAll": "Reply all",
1250
+ "customers.email.visibility.flipToPrivate.label": "Make private",
1251
+ "customers.email.visibility.flipToPrivate.success": "Email made private",
1252
+ "customers.email.visibility.flipToShared.label": "Share with teammates",
1253
+ "customers.email.visibility.flipToShared.success": "Email shared with teammates",
1214
1254
  "customers.errors.access_denied": "Access denied",
1215
1255
  "customers.errors.activity_required": "Activity id is required",
1216
1256
  "customers.errors.address_required": "Address id is required",
@@ -1770,6 +1810,7 @@
1770
1810
  "customers.people.detail.tabs.changelog": "Change log",
1771
1811
  "customers.people.detail.tabs.companies": "Companies",
1772
1812
  "customers.people.detail.tabs.deals": "Deals",
1813
+ "customers.people.detail.tabs.emails": "Emails",
1773
1814
  "customers.people.detail.tabs.files": "Files",
1774
1815
  "customers.people.detail.tabs.label": "Person detail sections",
1775
1816
  "customers.people.detail.tabs.notes": "Notes",
@@ -1211,6 +1211,46 @@
1211
1211
  "customers.dictionaryEntries.create": "Agregar entrada de diccionario de clientes",
1212
1212
  "customers.dictionaryEntries.delete": "Eliminar entrada de diccionario de clientes",
1213
1213
  "customers.dictionaryEntries.update": "Actualizar entrada de diccionario de clientes",
1214
+ "customers.email.compose.addCc": "+ Cc",
1215
+ "customers.email.compose.addCc.ariaLabel": "Añadir destinatarios en Cc",
1216
+ "customers.email.compose.body": "Mensaje",
1217
+ "customers.email.compose.bodyPlaceholder": "Escribe tu mensaje...",
1218
+ "customers.email.compose.button": "Enviar correo",
1219
+ "customers.email.compose.cancel": "Cancelar",
1220
+ "customers.email.compose.cc": "Cc",
1221
+ "customers.email.compose.ccPlaceholder": "cc@example.com",
1222
+ "customers.email.compose.noChannel.cta": "Conecta tu buzón",
1223
+ "customers.email.compose.replyTitle": "Responder",
1224
+ "customers.email.compose.selectChannel": "Seleccionar cuenta",
1225
+ "customers.email.compose.send": "Enviar",
1226
+ "customers.email.compose.sendAs": "Enviar como",
1227
+ "customers.email.compose.sending": "Enviando...",
1228
+ "customers.email.compose.sent": "Correo enviado",
1229
+ "customers.email.compose.subject": "Asunto",
1230
+ "customers.email.compose.subjectPlaceholder": "Asunto del correo",
1231
+ "customers.email.compose.title": "Redactar correo",
1232
+ "customers.email.compose.to": "Para",
1233
+ "customers.email.compose.toPlaceholder": "destinatario@example.com",
1234
+ "customers.email.compose.visibility": "Visibilidad",
1235
+ "customers.email.compose.visibilityPrivate": "Privado para mí",
1236
+ "customers.email.compose.visibilityShared": "Visible para el equipo",
1237
+ "customers.email.errors.deliveryFailed": "Error de entrega: no enviado",
1238
+ "customers.email.errors.flipFailed": "Error al actualizar la visibilidad",
1239
+ "customers.email.errors.sendFailed": "Error al enviar",
1240
+ "customers.email.sync.button": "Sincronizar",
1241
+ "customers.email.sync.failed": "No se pudo sincronizar el buzón",
1242
+ "customers.email.sync.success": "Sincronización iniciada — las nuevas respuestas aparecerán en unos segundos.",
1243
+ "customers.email.sync.syncing": "Sincronizando...",
1244
+ "customers.email.sync.tooltip": "Revisa tu buzón en busca de nuevas respuestas",
1245
+ "customers.email.threads.loadFailed": "No se pudieron cargar los correos",
1246
+ "customers.email.timeline.actionsAria": "Acciones de correo",
1247
+ "customers.email.timeline.forward": "Reenviar",
1248
+ "customers.email.timeline.reply": "Responder",
1249
+ "customers.email.timeline.replyAll": "Responder a todos",
1250
+ "customers.email.visibility.flipToPrivate.label": "Hacer privado",
1251
+ "customers.email.visibility.flipToPrivate.success": "Correo marcado como privado",
1252
+ "customers.email.visibility.flipToShared.label": "Compartir con el equipo",
1253
+ "customers.email.visibility.flipToShared.success": "Correo compartido con el equipo",
1214
1254
  "customers.errors.access_denied": "Acceso denegado",
1215
1255
  "customers.errors.activity_required": "Se requiere el ID de la actividad",
1216
1256
  "customers.errors.address_required": "Se requiere el ID de la dirección",
@@ -1770,6 +1810,7 @@
1770
1810
  "customers.people.detail.tabs.changelog": "Registro de cambios",
1771
1811
  "customers.people.detail.tabs.companies": "Companies",
1772
1812
  "customers.people.detail.tabs.deals": "Oportunidades",
1813
+ "customers.people.detail.tabs.emails": "Correos",
1773
1814
  "customers.people.detail.tabs.files": "Files",
1774
1815
  "customers.people.detail.tabs.label": "Secciones de detalles de la persona",
1775
1816
  "customers.people.detail.tabs.notes": "Notas",
@@ -1211,6 +1211,46 @@
1211
1211
  "customers.dictionaryEntries.create": "Dodaj wpis słownika klienta",
1212
1212
  "customers.dictionaryEntries.delete": "Usuń wpis słownika klienta",
1213
1213
  "customers.dictionaryEntries.update": "Zaktualizuj wpis słownika klienta",
1214
+ "customers.email.compose.addCc": "+ Dw",
1215
+ "customers.email.compose.addCc.ariaLabel": "Dodaj odbiorców Dw",
1216
+ "customers.email.compose.body": "Treść",
1217
+ "customers.email.compose.bodyPlaceholder": "Wpisz treść wiadomości...",
1218
+ "customers.email.compose.button": "Wyślij e-mail",
1219
+ "customers.email.compose.cancel": "Anuluj",
1220
+ "customers.email.compose.cc": "Dw",
1221
+ "customers.email.compose.ccPlaceholder": "dw@example.com",
1222
+ "customers.email.compose.noChannel.cta": "Połącz skrzynkę pocztową",
1223
+ "customers.email.compose.replyTitle": "Odpowiedz",
1224
+ "customers.email.compose.selectChannel": "Wybierz konto",
1225
+ "customers.email.compose.send": "Wyślij",
1226
+ "customers.email.compose.sendAs": "Wyślij jako",
1227
+ "customers.email.compose.sending": "Wysyłanie...",
1228
+ "customers.email.compose.sent": "Wiadomość wysłana",
1229
+ "customers.email.compose.subject": "Temat",
1230
+ "customers.email.compose.subjectPlaceholder": "Temat wiadomości",
1231
+ "customers.email.compose.title": "Napisz e-mail",
1232
+ "customers.email.compose.to": "Do",
1233
+ "customers.email.compose.toPlaceholder": "odbiorca@example.com",
1234
+ "customers.email.compose.visibility": "Widoczność",
1235
+ "customers.email.compose.visibilityPrivate": "Tylko dla mnie",
1236
+ "customers.email.compose.visibilityShared": "Widoczne dla zespołu",
1237
+ "customers.email.errors.deliveryFailed": "Dostarczanie nie powiodło się – nie wysłano",
1238
+ "customers.email.errors.flipFailed": "Aktualizacja widoczności nieudana",
1239
+ "customers.email.errors.sendFailed": "Wysyłanie nieudane",
1240
+ "customers.email.sync.button": "Synchronizuj",
1241
+ "customers.email.sync.failed": "Nie udało się zsynchronizować skrzynki",
1242
+ "customers.email.sync.success": "Synchronizacja uruchomiona — nowe odpowiedzi pojawią się za kilka sekund.",
1243
+ "customers.email.sync.syncing": "Synchronizuję...",
1244
+ "customers.email.sync.tooltip": "Sprawdź skrzynkę pocztową w poszukiwaniu nowych odpowiedzi",
1245
+ "customers.email.threads.loadFailed": "Nie udało się wczytać e-maili",
1246
+ "customers.email.timeline.actionsAria": "Akcje e-maila",
1247
+ "customers.email.timeline.forward": "Przekaż dalej",
1248
+ "customers.email.timeline.reply": "Odpowiedz",
1249
+ "customers.email.timeline.replyAll": "Odpowiedz wszystkim",
1250
+ "customers.email.visibility.flipToPrivate.label": "Ustaw jako prywatne",
1251
+ "customers.email.visibility.flipToPrivate.success": "E-mail ustawiony jako prywatny",
1252
+ "customers.email.visibility.flipToShared.label": "Udostępnij zespołowi",
1253
+ "customers.email.visibility.flipToShared.success": "E-mail udostępniony zespołowi",
1214
1254
  "customers.errors.access_denied": "Dostęp zabroniony",
1215
1255
  "customers.errors.activity_required": "Wymagany identyfikator aktywności",
1216
1256
  "customers.errors.address_required": "Wymagany identyfikator adresu",
@@ -1770,6 +1810,7 @@
1770
1810
  "customers.people.detail.tabs.changelog": "Dziennik zmian",
1771
1811
  "customers.people.detail.tabs.companies": "Companies",
1772
1812
  "customers.people.detail.tabs.deals": "Szanse",
1813
+ "customers.people.detail.tabs.emails": "E-maile",
1773
1814
  "customers.people.detail.tabs.files": "Pliki",
1774
1815
  "customers.people.detail.tabs.label": "Sekcje szczegółów osoby",
1775
1816
  "customers.people.detail.tabs.notes": "Notatki",