@open-mercato/core 0.7.0 → 0.7.1-develop.7102.1.b41f7e3e51

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 (847) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/helpers/integration/api.js +13 -1
  3. package/dist/helpers/integration/api.js.map +2 -2
  4. package/dist/helpers/integration/communicationChannelsFixtures.js +19 -0
  5. package/dist/helpers/integration/communicationChannelsFixtures.js.map +2 -2
  6. package/dist/modules/api_keys/api/keys/route.js +1 -1
  7. package/dist/modules/api_keys/api/keys/route.js.map +2 -2
  8. package/dist/modules/api_keys/backend/api-keys/page.js +3 -1
  9. package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
  10. package/dist/modules/api_keys/di.js +9 -0
  11. package/dist/modules/api_keys/di.js.map +7 -0
  12. package/dist/modules/api_keys/services/principalService.js +31 -0
  13. package/dist/modules/api_keys/services/principalService.js.map +7 -0
  14. package/dist/modules/attachments/api/route.js +2 -2
  15. package/dist/modules/attachments/api/route.js.map +2 -2
  16. package/dist/modules/attachments/components/AttachmentLibrary.js +2 -0
  17. package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
  18. package/dist/modules/attachments/di.js +11 -1
  19. package/dist/modules/attachments/di.js.map +2 -2
  20. package/dist/modules/attachments/index.js.map +1 -1
  21. package/dist/modules/attachments/lib/attachment-service.js +313 -0
  22. package/dist/modules/attachments/lib/attachment-service.js.map +7 -0
  23. package/dist/modules/attachments/lib/scoped-upload-service.js +15 -2
  24. package/dist/modules/attachments/lib/scoped-upload-service.js.map +2 -2
  25. package/dist/modules/attachments/lib/upload-limits.js +6 -2
  26. package/dist/modules/attachments/lib/upload-limits.js.map +2 -2
  27. package/dist/modules/audit_logs/backend/audit-logs/page.js +6 -0
  28. package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
  29. package/dist/modules/audit_logs/lib/display-helpers.js +19 -11
  30. package/dist/modules/audit_logs/lib/display-helpers.js.map +2 -2
  31. package/dist/modules/audit_logs/services/actionLogService.js +57 -12
  32. package/dist/modules/audit_logs/services/actionLogService.js.map +3 -3
  33. package/dist/modules/auth/acl.js +30 -5
  34. package/dist/modules/auth/acl.js.map +2 -2
  35. package/dist/modules/auth/api/feature-check.js +8 -2
  36. package/dist/modules/auth/api/feature-check.js.map +2 -2
  37. package/dist/modules/auth/api/login.js +4 -1
  38. package/dist/modules/auth/api/login.js.map +2 -2
  39. package/dist/modules/auth/api/reset/validate.js +55 -0
  40. package/dist/modules/auth/api/reset/validate.js.map +7 -0
  41. package/dist/modules/auth/api/roles/acl/route.js +28 -33
  42. package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
  43. package/dist/modules/auth/api/session/refresh.js +25 -1
  44. package/dist/modules/auth/api/session/refresh.js.map +2 -2
  45. package/dist/modules/auth/api/users/acl/route.js +96 -51
  46. package/dist/modules/auth/api/users/acl/route.js.map +2 -2
  47. package/dist/modules/auth/api/users/route.js +13 -5
  48. package/dist/modules/auth/api/users/route.js.map +2 -2
  49. package/dist/modules/auth/backend/roles/[id]/edit/page.meta.js +5 -1
  50. package/dist/modules/auth/backend/roles/[id]/edit/page.meta.js.map +2 -2
  51. package/dist/modules/auth/backend/roles/page.js +3 -1
  52. package/dist/modules/auth/backend/roles/page.js.map +2 -2
  53. package/dist/modules/auth/backend/users/[id]/edit/page.meta.js +5 -1
  54. package/dist/modules/auth/backend/users/[id]/edit/page.meta.js.map +2 -2
  55. package/dist/modules/auth/backend/users/page.js +2 -1
  56. package/dist/modules/auth/backend/users/page.js.map +2 -2
  57. package/dist/modules/auth/commands/acl.js +254 -0
  58. package/dist/modules/auth/commands/acl.js.map +7 -0
  59. package/dist/modules/auth/components/AclEditor.js +39 -30
  60. package/dist/modules/auth/components/AclEditor.js.map +2 -2
  61. package/dist/modules/auth/data/entities.js.map +2 -2
  62. package/dist/modules/auth/data/validators.js +5 -1
  63. package/dist/modules/auth/data/validators.js.map +2 -2
  64. package/dist/modules/auth/di.js +35 -9
  65. package/dist/modules/auth/di.js.map +2 -2
  66. package/dist/modules/auth/frontend/reset/[token]/page.js +46 -0
  67. package/dist/modules/auth/frontend/reset/[token]/page.js.map +2 -2
  68. package/dist/modules/auth/lib/grantChecks.js.map +2 -2
  69. package/dist/modules/auth/lib/userIdFilter.js +16 -0
  70. package/dist/modules/auth/lib/userIdFilter.js.map +7 -0
  71. package/dist/modules/auth/services/authService.js +16 -2
  72. package/dist/modules/auth/services/authService.js.map +2 -2
  73. package/dist/modules/auth/services/principalService.js +200 -0
  74. package/dist/modules/auth/services/principalService.js.map +7 -0
  75. package/dist/modules/auth/services/rbacService.js +67 -24
  76. package/dist/modules/auth/services/rbacService.js.map +3 -3
  77. package/dist/modules/auth/services/roleOrganizationScope.js +41 -0
  78. package/dist/modules/auth/services/roleOrganizationScope.js.map +7 -0
  79. package/dist/modules/business_rules/backend/logs/page.js +3 -1
  80. package/dist/modules/business_rules/backend/logs/page.js.map +2 -2
  81. package/dist/modules/business_rules/backend/rules/page.js +3 -1
  82. package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
  83. package/dist/modules/business_rules/backend/sets/page.js +3 -1
  84. package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
  85. package/dist/modules/business_rules/lib/expression-evaluator.js +9 -9
  86. package/dist/modules/business_rules/lib/expression-evaluator.js.map +2 -2
  87. package/dist/modules/business_rules/lib/rule-evaluator.js +10 -9
  88. package/dist/modules/business_rules/lib/rule-evaluator.js.map +2 -2
  89. package/dist/modules/catalog/ai-agents.js +1 -1
  90. package/dist/modules/catalog/ai-agents.js.map +1 -1
  91. package/dist/modules/catalog/ai-tools/merchandising-pack.js +2 -2
  92. package/dist/modules/catalog/ai-tools/merchandising-pack.js.map +2 -2
  93. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +5 -2
  94. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +2 -2
  95. package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -0
  96. package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
  97. package/dist/modules/catalog/components/products/ProductsDataTable.js +7 -1
  98. package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
  99. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js +2 -0
  100. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js.map +2 -2
  101. package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js +9 -1
  102. package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js.map +2 -2
  103. package/dist/modules/communication_channels/api/post/test-seed/route.js +95 -10
  104. package/dist/modules/communication_channels/api/post/test-seed/route.js.map +2 -2
  105. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js +3 -0
  106. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +2 -2
  107. package/dist/modules/communication_channels/commands/ingest-inbound-message.js +14 -1
  108. package/dist/modules/communication_channels/commands/ingest-inbound-message.js.map +2 -2
  109. package/dist/modules/communication_channels/di.js +7 -1
  110. package/dist/modules/communication_channels/di.js.map +2 -2
  111. package/dist/modules/communication_channels/lib/email-capabilities.js +4 -1
  112. package/dist/modules/communication_channels/lib/email-capabilities.js.map +2 -2
  113. package/dist/modules/communication_channels/lib/outbound-recipient.js +33 -0
  114. package/dist/modules/communication_channels/lib/outbound-recipient.js.map +7 -0
  115. package/dist/modules/communication_channels/lib/resolve-channel-type.js +51 -0
  116. package/dist/modules/communication_channels/lib/resolve-channel-type.js.map +7 -0
  117. package/dist/modules/communication_channels/lib/test-seed.js +41 -2
  118. package/dist/modules/communication_channels/lib/test-seed.js.map +2 -2
  119. package/dist/modules/configs/lib/system-status.js +9 -0
  120. package/dist/modules/configs/lib/system-status.js.map +2 -2
  121. package/dist/modules/currencies/backend/currencies/page.js +3 -1
  122. package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
  123. package/dist/modules/currencies/backend/exchange-rates/page.js +3 -1
  124. package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
  125. package/dist/modules/currencies/services/rateFetchingService.js +6 -1
  126. package/dist/modules/currencies/services/rateFetchingService.js.map +2 -2
  127. package/dist/modules/customer_accounts/api/admin/domain-mappings.js +9 -0
  128. package/dist/modules/customer_accounts/api/admin/domain-mappings.js.map +2 -2
  129. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +3 -1
  130. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
  131. package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js +3 -1
  132. package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js.map +2 -2
  133. package/dist/modules/customer_accounts/services/domainMappingService.js +10 -0
  134. package/dist/modules/customer_accounts/services/domainMappingService.js.map +2 -2
  135. package/dist/modules/customers/ai-tools/companies-pack.js +4 -1
  136. package/dist/modules/customers/ai-tools/companies-pack.js.map +2 -2
  137. package/dist/modules/customers/ai-tools/deal-analyzer-pack.js +13 -2
  138. package/dist/modules/customers/ai-tools/deal-analyzer-pack.js.map +2 -2
  139. package/dist/modules/customers/ai-tools/deals-pack.js +52 -6
  140. package/dist/modules/customers/ai-tools/deals-pack.js.map +2 -2
  141. package/dist/modules/customers/ai-tools/people-pack.js +4 -1
  142. package/dist/modules/customers/ai-tools/people-pack.js.map +2 -2
  143. package/dist/modules/customers/api/activities/route.js +48 -6
  144. package/dist/modules/customers/api/activities/route.js.map +2 -2
  145. package/dist/modules/customers/api/companies/[id]/people/route.js +20 -64
  146. package/dist/modules/customers/api/companies/[id]/people/route.js.map +2 -2
  147. package/dist/modules/customers/api/companies/[id]/route.js +17 -94
  148. package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
  149. package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js +8 -5
  150. package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js.map +2 -2
  151. package/dist/modules/customers/api/deals/[id]/companies/route.js +1 -1
  152. package/dist/modules/customers/api/deals/[id]/companies/route.js.map +2 -2
  153. package/dist/modules/customers/api/deals/[id]/people/route.js +1 -1
  154. package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
  155. package/dist/modules/customers/api/deals/[id]/route.js +8 -25
  156. package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
  157. package/dist/modules/customers/api/deals/[id]/stats/route.js +3 -22
  158. package/dist/modules/customers/api/deals/[id]/stats/route.js.map +2 -2
  159. package/dist/modules/customers/api/deals/aggregate/route.js +11 -4
  160. package/dist/modules/customers/api/deals/aggregate/route.js.map +2 -2
  161. package/dist/modules/customers/api/deals/map/route.js +2 -1
  162. package/dist/modules/customers/api/deals/map/route.js.map +2 -2
  163. package/dist/modules/customers/api/deals/route.js +38 -1
  164. package/dist/modules/customers/api/deals/route.js.map +2 -2
  165. package/dist/modules/customers/api/entity-roles-factory.js +4 -4
  166. package/dist/modules/customers/api/entity-roles-factory.js.map +2 -2
  167. package/dist/modules/customers/api/interactions/route.js +3 -1
  168. package/dist/modules/customers/api/interactions/route.js.map +2 -2
  169. package/dist/modules/customers/api/interactions/tasks/route.js +27 -4
  170. package/dist/modules/customers/api/interactions/tasks/route.js.map +2 -2
  171. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +4 -3
  172. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js.map +2 -2
  173. package/dist/modules/customers/api/people/[id]/companies/context.js +1 -1
  174. package/dist/modules/customers/api/people/[id]/companies/context.js.map +2 -2
  175. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +1 -1
  176. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +2 -2
  177. package/dist/modules/customers/api/people/[id]/route.js +11 -10
  178. package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
  179. package/dist/modules/customers/api/people/check-phone/route.js +51 -9
  180. package/dist/modules/customers/api/people/check-phone/route.js.map +2 -2
  181. package/dist/modules/customers/api/todos/route.js +30 -5
  182. package/dist/modules/customers/api/todos/route.js.map +2 -2
  183. package/dist/modules/customers/backend/customers/companies/page.js +4 -2
  184. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  185. package/dist/modules/customers/backend/customers/deals/[id]/page.js +6 -1
  186. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  187. package/dist/modules/customers/backend/customers/deals/page.js +5 -2
  188. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  189. package/dist/modules/customers/backend/customers/deals/pipeline/components/Lane.js +4 -13
  190. package/dist/modules/customers/backend/customers/deals/pipeline/components/Lane.js.map +2 -2
  191. package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js +85 -14
  192. package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js.map +2 -2
  193. package/dist/modules/customers/backend/customers/deals/pipeline/components/toneClasses.js +18 -0
  194. package/dist/modules/customers/backend/customers/deals/pipeline/components/toneClasses.js.map +7 -0
  195. package/dist/modules/customers/backend/customers/people/page.js +4 -2
  196. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  197. package/dist/modules/customers/backend/hooks/useEmailDuplicateCheck.js +9 -3
  198. package/dist/modules/customers/backend/hooks/useEmailDuplicateCheck.js.map +2 -2
  199. package/dist/modules/customers/commands/deals.js +21 -34
  200. package/dist/modules/customers/commands/deals.js.map +2 -2
  201. package/dist/modules/customers/commands/interactions.js.map +1 -1
  202. package/dist/modules/customers/commands/personCompanyLinks.js +131 -2
  203. package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
  204. package/dist/modules/customers/components/CustomerTodosTable.js +1 -0
  205. package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
  206. package/dist/modules/customers/components/DealsKpiStrip.js +7 -6
  207. package/dist/modules/customers/components/DealsKpiStrip.js.map +2 -2
  208. package/dist/modules/customers/components/calendar/AgendaList.js +2 -2
  209. package/dist/modules/customers/components/calendar/AgendaList.js.map +2 -2
  210. package/dist/modules/customers/components/calendar/CalendarEventEditor.js +1 -1
  211. package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +2 -2
  212. package/dist/modules/customers/components/calendar/CalendarScreen.js +1 -1
  213. package/dist/modules/customers/components/calendar/CalendarScreen.js.map +2 -2
  214. package/dist/modules/customers/components/calendar/CalendarSettingsModal.js +1 -1
  215. package/dist/modules/customers/components/calendar/CalendarSettingsModal.js.map +2 -2
  216. package/dist/modules/customers/components/calendar/EventBlock.js +1 -1
  217. package/dist/modules/customers/components/calendar/EventBlock.js.map +2 -2
  218. package/dist/modules/customers/components/calendar/EventPeekPopover.js +3 -2
  219. package/dist/modules/customers/components/calendar/EventPeekPopover.js.map +2 -2
  220. package/dist/modules/customers/components/calendar/editor/PeopleField.js +40 -5
  221. package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
  222. package/dist/modules/customers/components/calendar/editor/hooks.js +2 -1
  223. package/dist/modules/customers/components/calendar/editor/hooks.js.map +2 -2
  224. package/dist/modules/customers/components/calendar/types.js +1 -1
  225. package/dist/modules/customers/components/calendar/types.js.map +2 -2
  226. package/dist/modules/customers/components/detail/CompanyKpiBar.js +5 -4
  227. package/dist/modules/customers/components/detail/CompanyKpiBar.js.map +2 -2
  228. package/dist/modules/customers/components/detail/CompanyPeopleSection.js +3 -1
  229. package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
  230. package/dist/modules/customers/components/detail/DealForm.js +19 -7
  231. package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
  232. package/dist/modules/customers/components/detail/DealsSection.js +6 -5
  233. package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
  234. package/dist/modules/customers/components/detail/EntityTagsDialog.js +35 -11
  235. package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
  236. package/dist/modules/customers/components/detail/PersonCompaniesSection.js +3 -1
  237. package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
  238. package/dist/modules/customers/components/detail/hooks/usePersonTasks.js +19 -13
  239. package/dist/modules/customers/components/detail/hooks/usePersonTasks.js.map +2 -2
  240. package/dist/modules/customers/components/detail/schedule/ParticipantsField.js +4 -4
  241. package/dist/modules/customers/components/detail/schedule/ParticipantsField.js.map +2 -2
  242. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +3 -3
  243. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
  244. package/dist/modules/customers/components/detail/utils.js +5 -5
  245. package/dist/modules/customers/components/detail/utils.js.map +2 -2
  246. package/dist/modules/customers/data/entities.js.map +1 -1
  247. package/dist/modules/customers/data/validators.js +32 -3
  248. package/dist/modules/customers/data/validators.js.map +2 -2
  249. package/dist/modules/customers/events.js +5 -0
  250. package/dist/modules/customers/events.js.map +2 -2
  251. package/dist/modules/customers/lib/calendar/conflicts.js +8 -2
  252. package/dist/modules/customers/lib/calendar/conflicts.js.map +2 -2
  253. package/dist/modules/customers/lib/calendar/editorPayload.js +3 -2
  254. package/dist/modules/customers/lib/calendar/editorPayload.js.map +2 -2
  255. package/dist/modules/customers/lib/calendar/mapItem.js +8 -3
  256. package/dist/modules/customers/lib/calendar/mapItem.js.map +2 -2
  257. package/dist/modules/customers/lib/calendar/participantIdentity.js +9 -0
  258. package/dist/modules/customers/lib/calendar/participantIdentity.js.map +7 -0
  259. package/dist/modules/customers/lib/closureStage.js +45 -0
  260. package/dist/modules/customers/lib/closureStage.js.map +7 -0
  261. package/dist/modules/customers/lib/dealStatus.js +30 -0
  262. package/dist/modules/customers/lib/dealStatus.js.map +2 -2
  263. package/dist/modules/customers/lib/detailReadAccess.js +12 -0
  264. package/dist/modules/customers/lib/detailReadAccess.js.map +7 -0
  265. package/dist/modules/customers/lib/findPeopleByAddresses.js +1 -0
  266. package/dist/modules/customers/lib/findPeopleByAddresses.js.map +2 -2
  267. package/dist/modules/customers/lib/personCompanies.js +100 -2
  268. package/dist/modules/customers/lib/personCompanies.js.map +2 -2
  269. package/dist/modules/customers/lib/todoCompatibility.js +12 -0
  270. package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
  271. package/dist/modules/dashboards/lib/widgetScope.js +6 -1
  272. package/dist/modules/dashboards/lib/widgetScope.js.map +2 -2
  273. package/dist/modules/data_sync/backend/data-sync/page.js +3 -1
  274. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  275. package/dist/modules/data_sync/lib/abandoned-run.js +19 -0
  276. package/dist/modules/data_sync/lib/abandoned-run.js.map +7 -0
  277. package/dist/modules/data_sync/lib/sync-engine.js +72 -6
  278. package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
  279. package/dist/modules/data_sync/workers/sync-export.js +5 -1
  280. package/dist/modules/data_sync/workers/sync-export.js.map +2 -2
  281. package/dist/modules/data_sync/workers/sync-import.js +5 -1
  282. package/dist/modules/data_sync/workers/sync-import.js.map +2 -2
  283. package/dist/modules/devices/acl.js +9 -1
  284. package/dist/modules/devices/acl.js.map +2 -2
  285. package/dist/modules/devices/api/admin/devices/[id]/route.js +5 -32
  286. package/dist/modules/devices/api/admin/devices/[id]/route.js.map +2 -2
  287. package/dist/modules/devices/api/admin/devices/route.js +14 -1
  288. package/dist/modules/devices/api/admin/devices/route.js.map +2 -2
  289. package/dist/modules/devices/api/deviceList.js +99 -12
  290. package/dist/modules/devices/api/deviceList.js.map +2 -2
  291. package/dist/modules/devices/api/deviceSerialization.js +46 -0
  292. package/dist/modules/devices/api/deviceSerialization.js.map +7 -0
  293. package/dist/modules/devices/api/openapi.js +3 -1
  294. package/dist/modules/devices/api/openapi.js.map +2 -2
  295. package/dist/modules/devices/api/route.js +9 -1
  296. package/dist/modules/devices/api/route.js.map +2 -2
  297. package/dist/modules/devices/backend/devices/[id]/page.js +10 -26
  298. package/dist/modules/devices/backend/devices/[id]/page.js.map +2 -2
  299. package/dist/modules/devices/backend/devices/create/page.js +17 -1
  300. package/dist/modules/devices/backend/devices/create/page.js.map +2 -2
  301. package/dist/modules/devices/backend/devices/page.js +28 -34
  302. package/dist/modules/devices/backend/devices/page.js.map +2 -2
  303. package/dist/modules/devices/backend/devices/useDeviceUserLabels.js +34 -0
  304. package/dist/modules/devices/backend/devices/useDeviceUserLabels.js.map +7 -0
  305. package/dist/modules/devices/backend/devices/userOptions.js +52 -0
  306. package/dist/modules/devices/backend/devices/userOptions.js.map +7 -0
  307. package/dist/modules/devices/setup.js +6 -2
  308. package/dist/modules/devices/setup.js.map +2 -2
  309. package/dist/modules/directory/backend/directory/organizations/page.js +2 -1
  310. package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
  311. package/dist/modules/directory/backend/directory/tenants/page.js +2 -1
  312. package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
  313. package/dist/modules/directory/di.js +9 -0
  314. package/dist/modules/directory/di.js.map +2 -2
  315. package/dist/modules/directory/services/organizationHierarchyService.js +29 -0
  316. package/dist/modules/directory/services/organizationHierarchyService.js.map +7 -0
  317. package/dist/modules/directory/services/organizationScopeService.js +56 -0
  318. package/dist/modules/directory/services/organizationScopeService.js.map +7 -0
  319. package/dist/modules/directory/utils/organizationScope.js.map +2 -2
  320. package/dist/modules/entities/api/records.js +4 -2
  321. package/dist/modules/entities/api/records.js.map +2 -2
  322. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +3 -1
  323. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
  324. package/dist/modules/eudr/api/plots/route.js +5 -1
  325. package/dist/modules/eudr/api/plots/route.js.map +2 -2
  326. package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js +3 -0
  327. package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js.map +2 -2
  328. package/dist/modules/eudr/backend/eudr/plots/page.js +3 -0
  329. package/dist/modules/eudr/backend/eudr/plots/page.js.map +2 -2
  330. package/dist/modules/eudr/backend/eudr/product-mappings/page.js +3 -0
  331. package/dist/modules/eudr/backend/eudr/product-mappings/page.js.map +2 -2
  332. package/dist/modules/eudr/backend/eudr/risk-assessments/page.js +3 -0
  333. package/dist/modules/eudr/backend/eudr/risk-assessments/page.js.map +2 -2
  334. package/dist/modules/eudr/backend/eudr/statements/page.js +3 -0
  335. package/dist/modules/eudr/backend/eudr/statements/page.js.map +2 -2
  336. package/dist/modules/eudr/commands/statements.js +0 -3
  337. package/dist/modules/eudr/commands/statements.js.map +2 -2
  338. package/dist/modules/eudr/data/validators.js +4 -1
  339. package/dist/modules/eudr/data/validators.js.map +2 -2
  340. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +1 -0
  341. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
  342. package/dist/modules/feature_toggles/components/OverridesTable.js +1 -0
  343. package/dist/modules/feature_toggles/components/OverridesTable.js.map +2 -2
  344. package/dist/modules/feature_toggles/defaults.json +0 -8
  345. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js +3 -0
  346. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js.map +2 -2
  347. package/dist/modules/inbox_ops/backend/inbox-ops/page.js +3 -0
  348. package/dist/modules/inbox_ops/backend/inbox-ops/page.js.map +2 -2
  349. package/dist/modules/inbox_ops/lib/htmlToPlainText.js +1 -12
  350. package/dist/modules/inbox_ops/lib/htmlToPlainText.js.map +2 -2
  351. package/dist/modules/integrations/api/[id]/credentials/route.js +6 -1
  352. package/dist/modules/integrations/api/[id]/credentials/route.js.map +2 -2
  353. package/dist/modules/integrations/backend/integrations/[id]/page.js +38 -29
  354. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  355. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +36 -9
  356. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
  357. package/dist/modules/integrations/backend/integrations/credential-secret-fields.js +55 -0
  358. package/dist/modules/integrations/backend/integrations/credential-secret-fields.js.map +7 -0
  359. package/dist/modules/integrations/data/validators.js +11 -3
  360. package/dist/modules/integrations/data/validators.js.map +2 -2
  361. package/dist/modules/integrations/lib/credentials-masking.js +6 -2
  362. package/dist/modules/integrations/lib/credentials-masking.js.map +2 -2
  363. package/dist/modules/messages/api/[id]/route.js +29 -1
  364. package/dist/modules/messages/api/[id]/route.js.map +2 -2
  365. package/dist/modules/messages/api/openapi.js +17 -2
  366. package/dist/modules/messages/api/openapi.js.map +2 -2
  367. package/dist/modules/messages/api/route.js +17 -2
  368. package/dist/modules/messages/api/route.js.map +2 -2
  369. package/dist/modules/messages/components/MessagesInboxPageClient.js +7 -14
  370. package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
  371. package/dist/modules/messages/components/inboxFilters.js +15 -0
  372. package/dist/modules/messages/components/inboxFilters.js.map +2 -2
  373. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js +11 -1
  374. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js.map +2 -2
  375. package/dist/modules/messages/components/message-detail/panels/MessageHeader.js +3 -1
  376. package/dist/modules/messages/components/message-detail/panels/MessageHeader.js.map +2 -2
  377. package/dist/modules/messages/components/message-detail/panels/thread-panel.js +2 -1
  378. package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +2 -2
  379. package/dist/modules/messages/components/messageListLabels.js +14 -2
  380. package/dist/modules/messages/components/messageListLabels.js.map +2 -2
  381. package/dist/modules/messages/data/validators.js +18 -4
  382. package/dist/modules/messages/data/validators.js.map +2 -2
  383. package/dist/modules/messages/lib/channel-sender-identity.js +26 -0
  384. package/dist/modules/messages/lib/channel-sender-identity.js.map +7 -0
  385. package/dist/modules/messages/lib/composeSourceChannelType.js +41 -0
  386. package/dist/modules/messages/lib/composeSourceChannelType.js.map +7 -0
  387. package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +4 -6
  388. package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +2 -2
  389. package/dist/modules/payment_gateways/backend/payment-gateways/page.js +3 -1
  390. package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
  391. package/dist/modules/payment_gateways/lib/webhook-processor.js +7 -0
  392. package/dist/modules/payment_gateways/lib/webhook-processor.js.map +2 -2
  393. package/dist/modules/planner/backend/planner/availability-rulesets/page.js +3 -0
  394. package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
  395. package/dist/modules/push_notifications/backend/push_notifications/page.js +3 -1
  396. package/dist/modules/push_notifications/backend/push_notifications/page.js.map +2 -2
  397. package/dist/modules/push_notifications/backend/push_notifications/send/page.js +1 -1
  398. package/dist/modules/push_notifications/backend/push_notifications/send/page.js.map +2 -2
  399. package/dist/modules/query_index/lib/engine.js +150 -51
  400. package/dist/modules/query_index/lib/engine.js.map +2 -2
  401. package/dist/modules/query_index/lib/search-entity-policy.js +14 -0
  402. package/dist/modules/query_index/lib/search-entity-policy.js.map +7 -0
  403. package/dist/modules/query_index/lib/search-tokens.js +79 -3
  404. package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
  405. package/dist/modules/resources/backend/resources/resource-types/page.js +3 -1
  406. package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
  407. package/dist/modules/resources/backend/resources/resources/page.js +3 -1
  408. package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
  409. package/dist/modules/sales/backend/sales/channels/offers/page.js +3 -0
  410. package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
  411. package/dist/modules/sales/backend/sales/channels/page.js +3 -0
  412. package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
  413. package/dist/modules/sales/backend/sales/documents/[id]/page.js +10 -8
  414. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  415. package/dist/modules/sales/commands/documents.js +79 -1
  416. package/dist/modules/sales/commands/documents.js.map +2 -2
  417. package/dist/modules/sales/components/PriceWithCurrency.js +7 -5
  418. package/dist/modules/sales/components/PriceWithCurrency.js.map +2 -2
  419. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +3 -0
  420. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
  421. package/dist/modules/sales/components/documents/AdjustmentsSection.js +8 -6
  422. package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
  423. package/dist/modules/sales/components/documents/ItemsSection.js +51 -22
  424. package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
  425. package/dist/modules/sales/components/documents/LineItemDialog.js +83 -18
  426. package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
  427. package/dist/modules/sales/components/documents/PaymentsSection.js +23 -9
  428. package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
  429. package/dist/modules/sales/components/documents/ReturnsSection.js +8 -6
  430. package/dist/modules/sales/components/documents/ReturnsSection.js.map +2 -2
  431. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +68 -14
  432. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  433. package/dist/modules/sales/components/documents/SalesOrderDraftLines.js +6 -5
  434. package/dist/modules/sales/components/documents/SalesOrderDraftLines.js.map +2 -2
  435. package/dist/modules/sales/components/documents/ShipmentDialog.js +5 -4
  436. package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
  437. package/dist/modules/sales/components/documents/ShipmentsSection.js +8 -6
  438. package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
  439. package/dist/modules/sales/components/documents/lineItemShipmentLock.js +54 -0
  440. package/dist/modules/sales/components/documents/lineItemShipmentLock.js.map +7 -0
  441. package/dist/modules/sales/components/documents/lineItemUtils.js +2 -2
  442. package/dist/modules/sales/components/documents/lineItemUtils.js.map +2 -2
  443. package/dist/modules/sales/data/entities.js +8 -2
  444. package/dist/modules/sales/data/entities.js.map +2 -2
  445. package/dist/modules/sales/extension-points.js +1 -0
  446. package/dist/modules/sales/extension-points.js.map +2 -2
  447. package/dist/modules/sales/lib/salesChannelsToggleSeed.js +33 -0
  448. package/dist/modules/sales/lib/salesChannelsToggleSeed.js.map +7 -0
  449. package/dist/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.js +32 -0
  450. package/dist/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.js.map +7 -0
  451. package/dist/modules/sales/setup.js +2 -0
  452. package/dist/modules/sales/setup.js.map +2 -2
  453. package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js +10 -2
  454. package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js.map +2 -2
  455. package/dist/modules/sales/widgets/injection-table.js +4 -7
  456. package/dist/modules/sales/widgets/injection-table.js.map +2 -2
  457. package/dist/modules/staff/backend/staff/leave-requests/page.js +3 -0
  458. package/dist/modules/staff/backend/staff/leave-requests/page.js.map +2 -2
  459. package/dist/modules/staff/backend/staff/my-leave-requests/page.js +3 -0
  460. package/dist/modules/staff/backend/staff/my-leave-requests/page.js.map +2 -2
  461. package/dist/modules/staff/backend/staff/team-members/page.js +3 -0
  462. package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
  463. package/dist/modules/staff/backend/staff/team-roles/page.js +3 -0
  464. package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
  465. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +3 -0
  466. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  467. package/dist/modules/staff/backend/staff/teams/page.js +3 -0
  468. package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
  469. package/dist/modules/staff/backend/staff/timesheets/page.js +29 -18
  470. package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
  471. package/dist/modules/staff/backend/staff/timesheets/projects/page.js +3 -0
  472. package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
  473. package/dist/modules/sync_excel/lib/adapters/customers.js +1 -0
  474. package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
  475. package/dist/modules/warranty_claims/api/assignees/route.js +3 -3
  476. package/dist/modules/warranty_claims/api/assignees/route.js.map +2 -2
  477. package/dist/modules/warranty_claims/api/portal/attachments/route.js +2 -2
  478. package/dist/modules/warranty_claims/api/portal/attachments/route.js.map +2 -2
  479. package/dist/modules/warranty_claims/api/portal/claims/route.js +12 -9
  480. package/dist/modules/warranty_claims/api/portal/claims/route.js.map +2 -2
  481. package/dist/modules/warranty_claims/backend/page.js +3 -0
  482. package/dist/modules/warranty_claims/backend/page.js.map +2 -2
  483. package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js +3 -0
  484. package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js.map +2 -2
  485. package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js +3 -0
  486. package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js.map +2 -2
  487. package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js +3 -0
  488. package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js.map +2 -2
  489. package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js +3 -0
  490. package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js.map +2 -2
  491. package/dist/modules/wms/api/warehouseSearch.js +21 -0
  492. package/dist/modules/wms/api/warehouseSearch.js.map +7 -0
  493. package/dist/modules/wms/api/warehouses/route.js +13 -9
  494. package/dist/modules/wms/api/warehouses/route.js.map +2 -2
  495. package/dist/modules/wms/api/zones/route.js +15 -2
  496. package/dist/modules/wms/api/zones/route.js.map +2 -2
  497. package/dist/modules/wms/commands/configuration.js +121 -9
  498. package/dist/modules/wms/commands/configuration.js.map +2 -2
  499. package/dist/modules/wms/commands/inventory-actions.js +3 -0
  500. package/dist/modules/wms/commands/inventory-actions.js.map +2 -2
  501. package/dist/modules/wms/commands/shared.js +9 -1
  502. package/dist/modules/wms/commands/shared.js.map +2 -2
  503. package/dist/modules/wms/components/backend/WarehouseEditDialog.js +158 -0
  504. package/dist/modules/wms/components/backend/WarehouseEditDialog.js.map +7 -0
  505. package/dist/modules/wms/components/backend/WmsConfigurationPage.js +76 -111
  506. package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +3 -3
  507. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +1 -0
  508. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +2 -2
  509. package/dist/modules/wms/components/backend/WmsLotsListPage.js +1 -0
  510. package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +2 -2
  511. package/dist/modules/wms/components/backend/inventoryMutationLoaders.js +27 -20
  512. package/dist/modules/wms/components/backend/inventoryMutationLoaders.js.map +2 -2
  513. package/dist/modules/wms/components/backend/warehouseFormOptions.js +66 -0
  514. package/dist/modules/wms/components/backend/warehouseFormOptions.js.map +7 -0
  515. package/dist/modules/workflows/backend/definitions/page.js +3 -1
  516. package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
  517. package/dist/modules/workflows/backend/events/page.js +3 -1
  518. package/dist/modules/workflows/backend/events/page.js.map +2 -2
  519. package/dist/modules/workflows/backend/instances/page.js +3 -1
  520. package/dist/modules/workflows/backend/instances/page.js.map +2 -2
  521. package/dist/modules/workflows/backend/tasks/page.js +3 -1
  522. package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
  523. package/dist/modules/workflows/lib/activity-executor.js +4 -0
  524. package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
  525. package/package.json +9 -10
  526. package/src/helpers/integration/api.ts +33 -1
  527. package/src/helpers/integration/communicationChannelsFixtures.ts +69 -1
  528. package/src/modules/api_keys/api/keys/route.ts +3 -1
  529. package/src/modules/api_keys/backend/api-keys/page.tsx +4 -1
  530. package/src/modules/api_keys/di.ts +7 -0
  531. package/src/modules/api_keys/services/principalService.ts +33 -0
  532. package/src/modules/attachments/AGENTS.md +15 -0
  533. package/src/modules/attachments/api/route.ts +2 -2
  534. package/src/modules/attachments/components/AttachmentLibrary.tsx +3 -0
  535. package/src/modules/attachments/di.ts +16 -0
  536. package/src/modules/attachments/i18n/de.json +5 -0
  537. package/src/modules/attachments/i18n/en.json +5 -0
  538. package/src/modules/attachments/i18n/es.json +5 -0
  539. package/src/modules/attachments/i18n/ko.json +5 -0
  540. package/src/modules/attachments/i18n/pl.json +5 -0
  541. package/src/modules/attachments/index.ts +10 -0
  542. package/src/modules/attachments/lib/attachment-service.ts +468 -0
  543. package/src/modules/attachments/lib/scoped-upload-service.ts +46 -0
  544. package/src/modules/attachments/lib/upload-limits.ts +6 -2
  545. package/src/modules/audit_logs/backend/audit-logs/page.tsx +8 -0
  546. package/src/modules/audit_logs/lib/display-helpers.tsx +42 -32
  547. package/src/modules/audit_logs/services/actionLogService.ts +74 -11
  548. package/src/modules/auth/acl.ts +30 -6
  549. package/src/modules/auth/api/feature-check.ts +10 -3
  550. package/src/modules/auth/api/login.ts +9 -1
  551. package/src/modules/auth/api/reset/validate.ts +57 -0
  552. package/src/modules/auth/api/roles/acl/route.ts +42 -39
  553. package/src/modules/auth/api/session/refresh.ts +32 -1
  554. package/src/modules/auth/api/users/acl/route.ts +177 -53
  555. package/src/modules/auth/api/users/route.ts +18 -5
  556. package/src/modules/auth/backend/roles/[id]/edit/page.meta.ts +5 -2
  557. package/src/modules/auth/backend/roles/page.tsx +4 -2
  558. package/src/modules/auth/backend/users/[id]/edit/page.meta.ts +5 -2
  559. package/src/modules/auth/backend/users/page.tsx +3 -2
  560. package/src/modules/auth/commands/acl.ts +495 -0
  561. package/src/modules/auth/components/AclEditor.tsx +63 -33
  562. package/src/modules/auth/data/entities.ts +4 -1
  563. package/src/modules/auth/data/validators.ts +5 -0
  564. package/src/modules/auth/di.ts +46 -16
  565. package/src/modules/auth/frontend/reset/[token]/page.tsx +74 -0
  566. package/src/modules/auth/i18n/de.json +389 -0
  567. package/src/modules/auth/i18n/en.json +389 -0
  568. package/src/modules/auth/i18n/es.json +389 -0
  569. package/src/modules/auth/i18n/ko.json +389 -0
  570. package/src/modules/auth/i18n/pl.json +391 -2
  571. package/src/modules/auth/lib/grantChecks.ts +6 -0
  572. package/src/modules/auth/lib/userIdFilter.ts +31 -0
  573. package/src/modules/auth/services/authService.ts +18 -2
  574. package/src/modules/auth/services/principalService.ts +266 -0
  575. package/src/modules/auth/services/rbacService.ts +110 -24
  576. package/src/modules/auth/services/roleOrganizationScope.ts +70 -0
  577. package/src/modules/business_rules/backend/logs/page.tsx +4 -1
  578. package/src/modules/business_rules/backend/rules/page.tsx +4 -1
  579. package/src/modules/business_rules/backend/sets/page.tsx +4 -1
  580. package/src/modules/business_rules/lib/expression-evaluator.ts +9 -9
  581. package/src/modules/business_rules/lib/rule-evaluator.ts +10 -9
  582. package/src/modules/catalog/ai-agents.ts +1 -1
  583. package/src/modules/catalog/ai-tools/merchandising-pack.ts +2 -2
  584. package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +12 -5
  585. package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +3 -0
  586. package/src/modules/catalog/components/products/ProductsDataTable.tsx +7 -0
  587. package/src/modules/catalog/i18n/de.json +1 -0
  588. package/src/modules/catalog/i18n/en.json +1 -0
  589. package/src/modules/catalog/i18n/es.json +1 -0
  590. package/src/modules/catalog/i18n/ko.json +1 -0
  591. package/src/modules/catalog/i18n/pl.json +1 -0
  592. package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.tsx +4 -0
  593. package/src/modules/communication_channels/api/post/channels/[id]/test-send/route.ts +17 -1
  594. package/src/modules/communication_channels/api/post/test-seed/route.ts +155 -16
  595. package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +4 -0
  596. package/src/modules/communication_channels/commands/ingest-inbound-message.ts +38 -1
  597. package/src/modules/communication_channels/di.ts +7 -0
  598. package/src/modules/communication_channels/lib/adapter.ts +14 -0
  599. package/src/modules/communication_channels/lib/email-capabilities.ts +4 -0
  600. package/src/modules/communication_channels/lib/outbound-recipient.ts +71 -0
  601. package/src/modules/communication_channels/lib/resolve-channel-type.ts +99 -0
  602. package/src/modules/communication_channels/lib/test-seed.ts +64 -4
  603. package/src/modules/configs/i18n/de.json +2 -0
  604. package/src/modules/configs/i18n/en.json +2 -0
  605. package/src/modules/configs/i18n/es.json +2 -0
  606. package/src/modules/configs/i18n/ko.json +2 -0
  607. package/src/modules/configs/i18n/pl.json +2 -0
  608. package/src/modules/configs/lib/system-status.ts +9 -0
  609. package/src/modules/currencies/AGENTS.md +3 -0
  610. package/src/modules/currencies/backend/currencies/page.tsx +4 -1
  611. package/src/modules/currencies/backend/exchange-rates/page.tsx +4 -1
  612. package/src/modules/currencies/services/README.md +45 -0
  613. package/src/modules/currencies/services/rateFetchingService.ts +6 -1
  614. package/src/modules/customer_accounts/api/admin/domain-mappings.ts +7 -0
  615. package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +4 -1
  616. package/src/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.tsx +4 -1
  617. package/src/modules/customer_accounts/services/domainMappingService.ts +10 -0
  618. package/src/modules/customers/ai-tools/companies-pack.ts +4 -1
  619. package/src/modules/customers/ai-tools/deal-analyzer-pack.ts +17 -2
  620. package/src/modules/customers/ai-tools/deals-pack.ts +66 -1
  621. package/src/modules/customers/ai-tools/people-pack.ts +4 -1
  622. package/src/modules/customers/api/activities/route.ts +45 -0
  623. package/src/modules/customers/api/companies/[id]/people/route.ts +24 -73
  624. package/src/modules/customers/api/companies/[id]/route.ts +24 -107
  625. package/src/modules/customers/api/dashboard/widgets/customer-todos/route.ts +16 -8
  626. package/src/modules/customers/api/deals/[id]/companies/route.ts +4 -1
  627. package/src/modules/customers/api/deals/[id]/people/route.ts +4 -1
  628. package/src/modules/customers/api/deals/[id]/route.ts +17 -28
  629. package/src/modules/customers/api/deals/[id]/stats/route.ts +10 -25
  630. package/src/modules/customers/api/deals/aggregate/route.ts +14 -4
  631. package/src/modules/customers/api/deals/map/route.ts +1 -0
  632. package/src/modules/customers/api/deals/route.ts +50 -1
  633. package/src/modules/customers/api/entity-roles-factory.ts +8 -4
  634. package/src/modules/customers/api/interactions/route.ts +8 -2
  635. package/src/modules/customers/api/interactions/tasks/route.ts +24 -1
  636. package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +12 -4
  637. package/src/modules/customers/api/people/[id]/companies/context.ts +4 -1
  638. package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +4 -1
  639. package/src/modules/customers/api/people/[id]/route.ts +16 -11
  640. package/src/modules/customers/api/people/check-phone/route.ts +75 -10
  641. package/src/modules/customers/api/todos/route.ts +27 -2
  642. package/src/modules/customers/backend/customers/companies/page.tsx +5 -2
  643. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +7 -2
  644. package/src/modules/customers/backend/customers/deals/page.tsx +8 -2
  645. package/src/modules/customers/backend/customers/deals/pipeline/components/Lane.tsx +5 -14
  646. package/src/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.tsx +109 -27
  647. package/src/modules/customers/backend/customers/deals/pipeline/components/toneClasses.ts +21 -0
  648. package/src/modules/customers/backend/customers/people/page.tsx +5 -2
  649. package/src/modules/customers/backend/hooks/useEmailDuplicateCheck.ts +12 -4
  650. package/src/modules/customers/commands/deals.ts +34 -59
  651. package/src/modules/customers/commands/interactions.ts +1 -1
  652. package/src/modules/customers/commands/personCompanyLinks.ts +224 -8
  653. package/src/modules/customers/components/CustomerTodosTable.tsx +2 -0
  654. package/src/modules/customers/components/DealsKpiStrip.tsx +7 -7
  655. package/src/modules/customers/components/calendar/AgendaList.tsx +3 -3
  656. package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +1 -1
  657. package/src/modules/customers/components/calendar/CalendarScreen.tsx +1 -1
  658. package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +1 -1
  659. package/src/modules/customers/components/calendar/EventBlock.tsx +2 -2
  660. package/src/modules/customers/components/calendar/EventPeekPopover.tsx +4 -2
  661. package/src/modules/customers/components/calendar/editor/PeopleField.tsx +61 -5
  662. package/src/modules/customers/components/calendar/editor/hooks.ts +7 -1
  663. package/src/modules/customers/components/calendar/types.ts +2 -2
  664. package/src/modules/customers/components/detail/CompanyKpiBar.tsx +5 -4
  665. package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +8 -1
  666. package/src/modules/customers/components/detail/DealForm.tsx +22 -2
  667. package/src/modules/customers/components/detail/DealsSection.tsx +11 -5
  668. package/src/modules/customers/components/detail/EntityTagsDialog.tsx +58 -12
  669. package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +8 -1
  670. package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +23 -14
  671. package/src/modules/customers/components/detail/schedule/ParticipantsField.tsx +5 -5
  672. package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +5 -5
  673. package/src/modules/customers/components/detail/types.ts +1 -1
  674. package/src/modules/customers/components/detail/utils.ts +15 -5
  675. package/src/modules/customers/data/entities.ts +1 -1
  676. package/src/modules/customers/data/validators.ts +50 -9
  677. package/src/modules/customers/events.ts +5 -0
  678. package/src/modules/customers/i18n/de.json +9 -1
  679. package/src/modules/customers/i18n/en.json +9 -1
  680. package/src/modules/customers/i18n/es.json +9 -1
  681. package/src/modules/customers/i18n/ko.json +9 -1
  682. package/src/modules/customers/i18n/pl.json +9 -1
  683. package/src/modules/customers/lib/calendar/conflicts.ts +10 -2
  684. package/src/modules/customers/lib/calendar/editorPayload.ts +4 -3
  685. package/src/modules/customers/lib/calendar/mapItem.ts +8 -3
  686. package/src/modules/customers/lib/calendar/participantIdentity.ts +17 -0
  687. package/src/modules/customers/lib/closureStage.ts +76 -0
  688. package/src/modules/customers/lib/dealStatus.ts +42 -0
  689. package/src/modules/customers/lib/detailReadAccess.ts +35 -0
  690. package/src/modules/customers/lib/findPeopleByAddresses.ts +8 -6
  691. package/src/modules/customers/lib/personCompanies.ts +136 -1
  692. package/src/modules/customers/lib/todoCompatibility.ts +19 -1
  693. package/src/modules/dashboards/i18n/es.json +4 -4
  694. package/src/modules/dashboards/i18n/pl.json +7 -7
  695. package/src/modules/dashboards/lib/widgetScope.ts +6 -0
  696. package/src/modules/data_sync/AGENTS.md +1 -1
  697. package/src/modules/data_sync/backend/data-sync/page.tsx +4 -1
  698. package/src/modules/data_sync/lib/abandoned-run.ts +56 -0
  699. package/src/modules/data_sync/lib/adapter.ts +36 -0
  700. package/src/modules/data_sync/lib/sync-engine.ts +113 -5
  701. package/src/modules/data_sync/workers/sync-export.ts +4 -0
  702. package/src/modules/data_sync/workers/sync-import.ts +4 -0
  703. package/src/modules/devices/AGENTS.md +20 -1
  704. package/src/modules/devices/acl.ts +9 -1
  705. package/src/modules/devices/api/admin/devices/[id]/route.ts +5 -34
  706. package/src/modules/devices/api/admin/devices/route.ts +14 -1
  707. package/src/modules/devices/api/deviceList.ts +135 -11
  708. package/src/modules/devices/api/deviceSerialization.ts +50 -0
  709. package/src/modules/devices/api/openapi.ts +9 -1
  710. package/src/modules/devices/api/route.ts +9 -1
  711. package/src/modules/devices/backend/devices/[id]/page.tsx +18 -32
  712. package/src/modules/devices/backend/devices/create/page.tsx +17 -1
  713. package/src/modules/devices/backend/devices/page.tsx +44 -45
  714. package/src/modules/devices/backend/devices/useDeviceUserLabels.ts +45 -0
  715. package/src/modules/devices/backend/devices/userOptions.ts +99 -0
  716. package/src/modules/devices/i18n/de.json +3 -2
  717. package/src/modules/devices/i18n/en.json +3 -2
  718. package/src/modules/devices/i18n/es.json +3 -2
  719. package/src/modules/devices/i18n/ko.json +3 -2
  720. package/src/modules/devices/i18n/pl.json +3 -2
  721. package/src/modules/devices/setup.ts +6 -2
  722. package/src/modules/directory/backend/directory/organizations/page.tsx +3 -1
  723. package/src/modules/directory/backend/directory/tenants/page.tsx +3 -1
  724. package/src/modules/directory/di.ts +14 -2
  725. package/src/modules/directory/services/organizationHierarchyService.ts +34 -0
  726. package/src/modules/directory/services/organizationScopeService.ts +85 -0
  727. package/src/modules/directory/utils/organizationScope.ts +4 -15
  728. package/src/modules/entities/api/records.ts +2 -0
  729. package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +4 -1
  730. package/src/modules/eudr/api/plots/route.ts +4 -0
  731. package/src/modules/eudr/backend/eudr/evidence-submissions/page.tsx +4 -0
  732. package/src/modules/eudr/backend/eudr/plots/page.tsx +4 -0
  733. package/src/modules/eudr/backend/eudr/product-mappings/page.tsx +4 -0
  734. package/src/modules/eudr/backend/eudr/risk-assessments/page.tsx +4 -0
  735. package/src/modules/eudr/backend/eudr/statements/page.tsx +4 -0
  736. package/src/modules/eudr/commands/statements.ts +0 -3
  737. package/src/modules/eudr/data/validators.ts +16 -1
  738. package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +2 -1
  739. package/src/modules/feature_toggles/components/OverridesTable.tsx +2 -1
  740. package/src/modules/feature_toggles/defaults.json +0 -8
  741. package/src/modules/inbox_ops/backend/inbox-ops/log/page.tsx +4 -0
  742. package/src/modules/inbox_ops/backend/inbox-ops/page.tsx +4 -0
  743. package/src/modules/inbox_ops/lib/htmlToPlainText.ts +1 -17
  744. package/src/modules/integrations/api/[id]/credentials/route.ts +6 -4
  745. package/src/modules/integrations/backend/integrations/[id]/page.tsx +61 -31
  746. package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +44 -9
  747. package/src/modules/integrations/backend/integrations/credential-secret-fields.ts +84 -0
  748. package/src/modules/integrations/data/validators.ts +12 -2
  749. package/src/modules/integrations/i18n/de.json +1 -0
  750. package/src/modules/integrations/i18n/en.json +1 -0
  751. package/src/modules/integrations/i18n/es.json +1 -0
  752. package/src/modules/integrations/i18n/ko.json +1 -0
  753. package/src/modules/integrations/i18n/pl.json +1 -0
  754. package/src/modules/integrations/lib/credentials-masking.ts +10 -6
  755. package/src/modules/messages/api/[id]/route.ts +55 -1
  756. package/src/modules/messages/api/openapi.ts +20 -0
  757. package/src/modules/messages/api/route.ts +31 -2
  758. package/src/modules/messages/components/MessagesInboxPageClient.tsx +9 -16
  759. package/src/modules/messages/components/inboxFilters.ts +36 -0
  760. package/src/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.ts +14 -1
  761. package/src/modules/messages/components/message-detail/panels/MessageHeader.tsx +3 -1
  762. package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +2 -1
  763. package/src/modules/messages/components/message-detail/types.ts +3 -0
  764. package/src/modules/messages/components/messageListLabels.ts +52 -3
  765. package/src/modules/messages/data/validators.ts +43 -4
  766. package/src/modules/messages/lib/channel-sender-identity.ts +55 -0
  767. package/src/modules/messages/lib/composeSourceChannelType.ts +95 -0
  768. package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +4 -6
  769. package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +4 -1
  770. package/src/modules/payment_gateways/lib/webhook-processor.ts +11 -0
  771. package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +4 -0
  772. package/src/modules/push_notifications/backend/push_notifications/page.tsx +4 -1
  773. package/src/modules/push_notifications/backend/push_notifications/send/page.tsx +4 -4
  774. package/src/modules/query_index/lib/engine.ts +249 -61
  775. package/src/modules/query_index/lib/search-entity-policy.ts +46 -0
  776. package/src/modules/query_index/lib/search-tokens.ts +135 -3
  777. package/src/modules/resources/backend/resources/resource-types/page.tsx +4 -1
  778. package/src/modules/resources/backend/resources/resources/page.tsx +4 -1
  779. package/src/modules/sales/backend/sales/channels/offers/page.tsx +4 -0
  780. package/src/modules/sales/backend/sales/channels/page.tsx +4 -0
  781. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +14 -8
  782. package/src/modules/sales/commands/documents.ts +93 -0
  783. package/src/modules/sales/components/PriceWithCurrency.tsx +17 -5
  784. package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +4 -0
  785. package/src/modules/sales/components/documents/AdjustmentsSection.tsx +6 -5
  786. package/src/modules/sales/components/documents/ItemsSection.tsx +56 -18
  787. package/src/modules/sales/components/documents/LineItemDialog.tsx +137 -20
  788. package/src/modules/sales/components/documents/PaymentsSection.tsx +20 -9
  789. package/src/modules/sales/components/documents/ReturnsSection.tsx +6 -5
  790. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +106 -14
  791. package/src/modules/sales/components/documents/SalesOrderDraftLines.tsx +6 -5
  792. package/src/modules/sales/components/documents/ShipmentDialog.tsx +5 -4
  793. package/src/modules/sales/components/documents/ShipmentsSection.tsx +6 -5
  794. package/src/modules/sales/components/documents/lineItemShipmentLock.ts +74 -0
  795. package/src/modules/sales/components/documents/lineItemUtils.ts +7 -2
  796. package/src/modules/sales/data/entities.ts +6 -0
  797. package/src/modules/sales/extension-points.ts +1 -0
  798. package/src/modules/sales/i18n/de.json +8 -0
  799. package/src/modules/sales/i18n/en.json +8 -0
  800. package/src/modules/sales/i18n/es.json +8 -0
  801. package/src/modules/sales/i18n/ko.json +8 -0
  802. package/src/modules/sales/i18n/pl.json +8 -0
  803. package/src/modules/sales/lib/salesChannelsToggleSeed.ts +42 -0
  804. package/src/modules/sales/migrations/.snapshot-open-mercato.json +60 -0
  805. package/src/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.ts +87 -0
  806. package/src/modules/sales/setup.ts +2 -0
  807. package/src/modules/sales/widgets/injection/payment-gateway-status-column/widget.ts +9 -1
  808. package/src/modules/sales/widgets/injection-table.ts +4 -7
  809. package/src/modules/staff/backend/staff/leave-requests/page.tsx +4 -0
  810. package/src/modules/staff/backend/staff/my-leave-requests/page.tsx +4 -0
  811. package/src/modules/staff/backend/staff/team-members/page.tsx +6 -0
  812. package/src/modules/staff/backend/staff/team-roles/page.tsx +4 -0
  813. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +4 -0
  814. package/src/modules/staff/backend/staff/teams/page.tsx +4 -0
  815. package/src/modules/staff/backend/staff/timesheets/page.tsx +12 -1
  816. package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +4 -0
  817. package/src/modules/sync_excel/lib/adapters/customers.ts +5 -0
  818. package/src/modules/warranty_claims/api/assignees/route.ts +3 -3
  819. package/src/modules/warranty_claims/api/portal/attachments/route.ts +2 -2
  820. package/src/modules/warranty_claims/api/portal/claims/route.ts +12 -9
  821. package/src/modules/warranty_claims/backend/page.tsx +4 -0
  822. package/src/modules/warranty_claims/backend/warranty_claims/registrations/page.tsx +4 -0
  823. package/src/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.tsx +4 -0
  824. package/src/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.tsx +4 -0
  825. package/src/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.tsx +4 -0
  826. package/src/modules/wms/api/warehouseSearch.ts +23 -0
  827. package/src/modules/wms/api/warehouses/route.ts +13 -9
  828. package/src/modules/wms/api/zones/route.ts +16 -0
  829. package/src/modules/wms/commands/configuration.ts +159 -10
  830. package/src/modules/wms/commands/inventory-actions.ts +3 -0
  831. package/src/modules/wms/commands/shared.ts +17 -0
  832. package/src/modules/wms/components/backend/WarehouseEditDialog.tsx +216 -0
  833. package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +95 -141
  834. package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +2 -0
  835. package/src/modules/wms/components/backend/WmsLotsListPage.tsx +2 -0
  836. package/src/modules/wms/components/backend/inventoryMutationLoaders.ts +36 -20
  837. package/src/modules/wms/components/backend/warehouseFormOptions.ts +72 -0
  838. package/src/modules/wms/i18n/de.json +2 -0
  839. package/src/modules/wms/i18n/en.json +2 -0
  840. package/src/modules/wms/i18n/es.json +2 -0
  841. package/src/modules/wms/i18n/ko.json +2 -0
  842. package/src/modules/wms/i18n/pl.json +2 -0
  843. package/src/modules/workflows/backend/definitions/page.tsx +4 -1
  844. package/src/modules/workflows/backend/events/page.tsx +4 -1
  845. package/src/modules/workflows/backend/instances/page.tsx +4 -1
  846. package/src/modules/workflows/backend/tasks/page.tsx +4 -1
  847. package/src/modules/workflows/lib/activity-executor.ts +9 -0
@@ -11,6 +11,7 @@ import {
11
11
  import { getChannelAdapterRegistry } from './lib/adapter-registry-singleton'
12
12
  import { ensureTestSeedAdapterRegistered } from './lib/test-seed'
13
13
  import { sendAsUser } from './lib/send-as-user'
14
+ import { resolveChannelTypeSafely } from './lib/resolve-channel-type'
14
15
 
15
16
  export function register(container: AppContainer) {
16
17
  // Test-only: register the network-free stub channel adapter when
@@ -36,5 +37,11 @@ export function register(container: AppContainer) {
36
37
  // In-process send-as-user facade. Cross-module callers (e.g. the customers
37
38
  // compose route) resolve this instead of making an HTTP self-call.
38
39
  communicationChannelsSendAsUser: asValue(sendAsUser),
40
+
41
+ // Cross-module channel-type lookup. The messages compose route resolves this
42
+ // to decide whether an external correspondent must carry an email address
43
+ // (#4975); absent module or failed lookup reads as "unknown", which the
44
+ // messages validator handles fail-closed.
45
+ communicationChannelsResolveChannelType: asValue(resolveChannelTypeSafely),
39
46
  })
40
47
  }
@@ -48,6 +48,20 @@ export interface ChannelCapabilities {
48
48
  * Optional; existing chat providers (Slack, WhatsApp) omit and are treated as `true`.
49
49
  */
50
50
  realtimePush?: boolean
51
+
52
+ /**
53
+ * Shape of the outbound recipient this provider's `sendMessage` accepts as
54
+ * `metadata.to`. Optional; when absent the hub validates recipients as email
55
+ * addresses, so every provider that predates this field keeps its exact
56
+ * behavior.
57
+ *
58
+ * Declare `'provider-native'` when recipients are provider-issued identifiers
59
+ * rather than email addresses (e.g. a Discord channel snowflake). The hub then
60
+ * applies transport-safety checks only (see `validateOutboundRecipient`) and
61
+ * the adapter owns the provider-specific format — it MUST treat the value as
62
+ * untrusted input.
63
+ */
64
+ recipientFormat?: 'email' | 'provider-native'
51
65
  }
52
66
 
53
67
  // ── Send / status / sender listing ────────────────────────────
@@ -57,4 +57,8 @@ export const baseEmailCapabilities: ChannelCapabilities = {
57
57
 
58
58
  // Polling (real-time push deferred to v2 for all email providers)
59
59
  realtimePush: false,
60
+
61
+ // Stated rather than left to the default so the email baseline reads as an
62
+ // explicit choice: outbound recipients here are addresses, not provider ids.
63
+ recipientFormat: 'email',
60
64
  }
@@ -0,0 +1,71 @@
1
+ import { z } from 'zod'
2
+ import type { ChannelCapabilities } from './adapter'
3
+
4
+ /**
5
+ * Upper bound shared by both recipient shapes. 320 is the RFC 5321 maximum for
6
+ * an email address (64 local + `@` + 255 domain); provider-native identifiers
7
+ * are far shorter, so one ceiling covers both.
8
+ */
9
+ export const MAX_OUTBOUND_RECIPIENT_LENGTH = 320
10
+
11
+ const emailRecipientSchema = z.string().email()
12
+
13
+ /**
14
+ * Characters a provider-native recipient may contain. This is an allowlist, not a
15
+ * denylist, because the recipient reaches adapters that interpolate it into a REST
16
+ * path (Discord posts to `/channels/{recipient}/messages`), and a denylist fails
17
+ * open on every character nobody thought of — percent-encoded separators
18
+ * (`%2F`, `%2e%2e%2f`) and control bytes (NUL, DEL) all walked through the
19
+ * previous `[\r\n\s/\\?#]` class. An allowlist fails closed instead: the worst
20
+ * case is a provider whose identifier alphabet needs widening, which is a
21
+ * reviewable one-line change rather than a silent path-steering primitive.
22
+ *
23
+ * The set covers every provider-native identifier shape the hub has to carry
24
+ * today — Discord snowflakes (digits), Slack-style ids (alphanumerics), and email
25
+ * addresses, since `'provider-native'` must never narrow what `'email'` accepts.
26
+ */
27
+ const PROVIDER_NATIVE_ALLOWED = /^[A-Za-z0-9._:@+-]+$/
28
+
29
+ export type OutboundRecipientCheck = { ok: true } | { ok: false; error: string }
30
+
31
+ /**
32
+ * Validate an outbound recipient against the provider's declared recipient
33
+ * shape.
34
+ *
35
+ * The hub used to hard-wire `z.string().email()` on every outbound endpoint,
36
+ * which left providers whose recipients are not email addresses with no product
37
+ * path to send at all (#4976). Validation now follows the adapter's
38
+ * `capabilities.recipientFormat`, defaulting to `'email'` so every existing
39
+ * provider keeps byte-identical behavior.
40
+ */
41
+ export function validateOutboundRecipient(
42
+ recipient: unknown,
43
+ capabilities: Pick<ChannelCapabilities, 'recipientFormat'> | null | undefined,
44
+ ): OutboundRecipientCheck {
45
+ if (typeof recipient !== 'string' || recipient.length === 0) {
46
+ return { ok: false, error: 'Recipient is required' }
47
+ }
48
+ if (recipient.length > MAX_OUTBOUND_RECIPIENT_LENGTH) {
49
+ return {
50
+ ok: false,
51
+ error: `Recipient must be at most ${MAX_OUTBOUND_RECIPIENT_LENGTH} characters`,
52
+ }
53
+ }
54
+ if (capabilities?.recipientFormat !== 'provider-native') {
55
+ return emailRecipientSchema.safeParse(recipient).success
56
+ ? { ok: true }
57
+ : { ok: false, error: 'Recipient must be a valid email address' }
58
+ }
59
+ if (!PROVIDER_NATIVE_ALLOWED.test(recipient)) {
60
+ return {
61
+ ok: false,
62
+ error: 'Recipient may only contain letters, digits, and the characters . _ : @ + -',
63
+ }
64
+ }
65
+ // `.` is allowed (email addresses need it), so traversal still has to be
66
+ // rejected explicitly even though the separators it would need are not.
67
+ if (recipient.includes('..')) {
68
+ return { ok: false, error: 'Recipient must not contain ".."' }
69
+ }
70
+ return { ok: true }
71
+ }
@@ -0,0 +1,99 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql'
2
+ import type { AppContainer } from '@open-mercato/shared/lib/di/container'
3
+ import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
4
+ import { createLogger } from '@open-mercato/shared/lib/logger'
5
+ import { CommunicationChannel, ExternalConversation, MessageChannelLink } from '../data/entities'
6
+
7
+ const logger = createLogger('communication_channels').child({ component: 'resolve-channel-type' })
8
+
9
+ export type ChannelTypeScope = {
10
+ tenantId: string
11
+ organizationId: string | null
12
+ }
13
+
14
+ export type ChannelTypeReference = {
15
+ /** `ExternalConversation.id`, as carried by a message's `sourceEntityId`. */
16
+ externalConversationId?: string | null
17
+ /** A platform `messages.message` id that may be linked to a channel. */
18
+ messageId?: string | null
19
+ }
20
+
21
+ /**
22
+ * Resolve the channel type behind a platform message or conversation (#4975).
23
+ *
24
+ * Cross-module callers (the `messages` compose route) need to know whether an
25
+ * external correspondent is reachable by email before validating a compose
26
+ * payload, but `messages` may not reach into this module's entities. They
27
+ * resolve this facade from DI instead — mirroring `communicationChannelsSendAsUser`
28
+ * — and treat a `null` result as "unknown", which the messages validator
29
+ * handles fail-closed.
30
+ *
31
+ * Always tenant/organization scoped: a reference that does not resolve inside
32
+ * the caller's scope is reported as unknown rather than looked up globally.
33
+ */
34
+ export async function resolveChannelType(
35
+ container: AppContainer,
36
+ scope: ChannelTypeScope,
37
+ reference: ChannelTypeReference,
38
+ ): Promise<string | null> {
39
+ const em = (container.resolve('em') as EntityManager).fork()
40
+ const dscope = { tenantId: scope.tenantId, organizationId: scope.organizationId ?? null }
41
+ const baseFilter = { tenantId: scope.tenantId, organizationId: scope.organizationId ?? null }
42
+
43
+ let externalConversationId = reference.externalConversationId ?? null
44
+
45
+ if (!externalConversationId && reference.messageId) {
46
+ // The message is linked to a channel directly — `MessageChannelLink` carries
47
+ // a denormalized channel type, so this is the cheapest hop when it exists.
48
+ const link = await findOneWithDecryption(
49
+ em,
50
+ MessageChannelLink,
51
+ { messageId: reference.messageId, ...baseFilter },
52
+ undefined,
53
+ dscope,
54
+ )
55
+ if (link?.channelType) return link.channelType
56
+ externalConversationId = link?.externalConversationId ?? null
57
+ }
58
+
59
+ if (!externalConversationId) return null
60
+
61
+ const conversation = await findOneWithDecryption(
62
+ em,
63
+ ExternalConversation,
64
+ { id: externalConversationId, ...baseFilter },
65
+ undefined,
66
+ dscope,
67
+ )
68
+ if (!conversation?.channelId) return null
69
+
70
+ const channel = await findOneWithDecryption(
71
+ em,
72
+ CommunicationChannel,
73
+ { id: conversation.channelId, ...baseFilter, deletedAt: null },
74
+ undefined,
75
+ dscope,
76
+ )
77
+ return channel?.channelType ?? null
78
+ }
79
+
80
+ /**
81
+ * Same contract, but never throws: a lookup failure degrades to "unknown" so a
82
+ * transient database error cannot turn into a 500 on an otherwise valid compose.
83
+ * Unknown is the safe answer — the messages validator fails closed on it.
84
+ */
85
+ export async function resolveChannelTypeSafely(
86
+ container: AppContainer,
87
+ scope: ChannelTypeScope,
88
+ reference: ChannelTypeReference,
89
+ ): Promise<string | null> {
90
+ try {
91
+ return await resolveChannelType(container, scope, reference)
92
+ } catch (err) {
93
+ logger.warn('channel type resolution failed, treating the channel as unknown', { err })
94
+ return null
95
+ }
96
+ }
97
+
98
+ /** DI service type for cross-module callers (resolve `communicationChannelsResolveChannelType`). */
99
+ export type ResolveChannelTypeService = typeof resolveChannelTypeSafely
@@ -41,6 +41,19 @@ import { hasChannelAdapter, registerChannelAdapter } from './adapter-registry-si
41
41
  /** Provider key for the network-free test stub adapter. */
42
42
  export const TEST_SEED_PROVIDER_KEY = '__test_seed__'
43
43
 
44
+ /**
45
+ * Provider key for the network-free stub adapter that stands in for a CHAT
46
+ * provider — one whose senders are identified by an opaque handle and have no
47
+ * email address at all (Discord, Slack, Telegram…).
48
+ *
49
+ * It exists because the email-shaped stub above can only ever prove the hub
50
+ * accepts email-shaped data. That is precisely how CI stayed green while every
51
+ * real inbound Discord message was rejected (#4975): the fixture invented an
52
+ * address the provider can never produce. Tests that need to prove the hub's
53
+ * non-email identity contract MUST drive this provider instead.
54
+ */
55
+ export const TEST_SEED_CHAT_PROVIDER_KEY = '__test_seed_chat__'
56
+
44
57
  /** Env flag that unlocks test-only channel seeding. Off in production. */
45
58
  export const TEST_CHANNEL_SEEDING_ENV = 'OM_ENABLE_TEST_CHANNEL_SEEDING'
46
59
 
@@ -72,8 +85,10 @@ const testSeedCapabilities: ChannelCapabilities = {
72
85
  * delivery worker reach its success path and emit `communication_channels.message.sent`.
73
86
  */
74
87
  class TestSeedChannelAdapter implements ChannelAdapter {
75
- readonly providerKey = TEST_SEED_PROVIDER_KEY
76
- readonly channelType = 'email'
88
+ // Widened to `string` rather than inferred as a literal so the chat-flavoured
89
+ // subclass below can override both with its own provider key / channel type.
90
+ readonly providerKey: string = TEST_SEED_PROVIDER_KEY
91
+ readonly channelType: string = 'email'
77
92
  readonly capabilities = testSeedCapabilities
78
93
 
79
94
  async sendMessage(input: SendMessageInput): Promise<SendMessageResult> {
@@ -121,13 +136,54 @@ class TestSeedChannelAdapter implements ChannelAdapter {
121
136
  }
122
137
  }
123
138
 
139
+ /**
140
+ * Chat-flavoured twin of {@link TestSeedChannelAdapter}: same network-free
141
+ * behaviour, but it declares a non-email `channelType`, so a channel connected
142
+ * through it is shaped like a real chat channel — including an
143
+ * `externalIdentifier` of NULL when no email-ish credential key is supplied.
144
+ */
145
+ class TestSeedChatChannelAdapter extends TestSeedChannelAdapter {
146
+ readonly providerKey: string = TEST_SEED_CHAT_PROVIDER_KEY
147
+ readonly channelType: string = 'discord'
148
+
149
+ async normalizeInbound(raw: InboundMessage): Promise<NormalizedInboundMessage> {
150
+ // Unlike the email stub, this one is reachable: the test-seed ingest action
151
+ // feeds it a chat-shaped frame so the message travels the real ingest path
152
+ // (and therefore the real compose validation) rather than a SQL shortcut.
153
+ const frame = (raw.raw ?? {}) as Record<string, unknown>
154
+ const senderIdentifier = String(frame.senderIdentifier ?? '')
155
+ if (!senderIdentifier) {
156
+ throw new Error('[internal] TestSeedChatChannelAdapter requires a senderIdentifier')
157
+ }
158
+ return {
159
+ externalMessageId: String(frame.externalMessageId ?? ''),
160
+ externalConversationId: String(frame.externalConversationId ?? ''),
161
+ senderIdentifier,
162
+ senderDisplayName:
163
+ typeof frame.senderDisplayName === 'string' ? frame.senderDisplayName : undefined,
164
+ body: typeof frame.body === 'string' ? frame.body : '',
165
+ bodyFormat: 'text',
166
+ timestamp: new Date(),
167
+ channelPayload: {},
168
+ channelContentType: 'text/plain',
169
+ channelMetadata: {},
170
+ }
171
+ }
172
+ }
173
+
124
174
  let cachedTestSeedAdapter: TestSeedChannelAdapter | null = null
175
+ let cachedTestSeedChatAdapter: TestSeedChatChannelAdapter | null = null
125
176
 
126
177
  function getTestSeedChannelAdapter(): TestSeedChannelAdapter {
127
178
  if (!cachedTestSeedAdapter) cachedTestSeedAdapter = new TestSeedChannelAdapter()
128
179
  return cachedTestSeedAdapter
129
180
  }
130
181
 
182
+ function getTestSeedChatChannelAdapter(): TestSeedChatChannelAdapter {
183
+ if (!cachedTestSeedChatAdapter) cachedTestSeedChatAdapter = new TestSeedChatChannelAdapter()
184
+ return cachedTestSeedChatAdapter
185
+ }
186
+
131
187
  /**
132
188
  * Register the test-seed adapter exactly once, but ONLY when the env flag is set.
133
189
  * Idempotent and safe to call from every container creation (`di.register`) — a
@@ -135,6 +191,10 @@ function getTestSeedChannelAdapter(): TestSeedChannelAdapter {
135
191
  */
136
192
  export function ensureTestSeedAdapterRegistered(): void {
137
193
  if (!isTestChannelSeedingEnabled()) return
138
- if (hasChannelAdapter(TEST_SEED_PROVIDER_KEY)) return
139
- registerChannelAdapter(getTestSeedChannelAdapter())
194
+ if (!hasChannelAdapter(TEST_SEED_PROVIDER_KEY)) {
195
+ registerChannelAdapter(getTestSeedChannelAdapter())
196
+ }
197
+ if (!hasChannelAdapter(TEST_SEED_CHAT_PROVIDER_KEY)) {
198
+ registerChannelAdapter(getTestSeedChatChannelAdapter())
199
+ }
140
200
  }
@@ -155,6 +155,8 @@
155
155
  "configs.systemStatus.variables.entitiesBackcompatEav.label": "Legacy-EAV-Schreibvorgänge",
156
156
  "configs.systemStatus.variables.forceQueryIndexOnPartialIndexes.description": "Query-Index-Ergebnisse auch bei unvollständiger Abdeckung bereitstellen.",
157
157
  "configs.systemStatus.variables.forceQueryIndexOnPartialIndexes.label": "Teilindex-Nutzung erzwingen",
158
+ "configs.systemStatus.variables.listCountCap.description": "Maximal gemeldete Gesamtzahl einer Liste; die Zählung stoppt an der Obergrenze und begrenzte Summen werden z. B. als „10 000+“ angezeigt. 0 deaktiviert die Begrenzung.",
159
+ "configs.systemStatus.variables.listCountCap.label": "Obergrenze für Listenzählung",
158
160
  "configs.systemStatus.variables.logLevel.description": "Fallback-Log-Level, wenn die Verbosität nicht gesetzt ist.",
159
161
  "configs.systemStatus.variables.logLevel.label": "Log-Level",
160
162
  "configs.systemStatus.variables.logVerbosity.description": "Überschreibt die strukturierte Log-Verbosität wie Debug oder Trace.",
@@ -155,6 +155,8 @@
155
155
  "configs.systemStatus.variables.entitiesBackcompatEav.label": "Legacy EAV writes",
156
156
  "configs.systemStatus.variables.forceQueryIndexOnPartialIndexes.description": "Serve query index results even when coverage is partial.",
157
157
  "configs.systemStatus.variables.forceQueryIndexOnPartialIndexes.label": "Force partial index usage",
158
+ "configs.systemStatus.variables.listCountCap.description": "Maximum reported list total; counting stops at the cap and capped totals render as e.g. “10 000+”. 0 disables capping.",
159
+ "configs.systemStatus.variables.listCountCap.label": "List count cap",
158
160
  "configs.systemStatus.variables.logLevel.description": "Fallback log level applied when verbosity is not set.",
159
161
  "configs.systemStatus.variables.logLevel.label": "Log level",
160
162
  "configs.systemStatus.variables.logVerbosity.description": "Overrides structured log verbosity such as debug or trace.",
@@ -155,6 +155,8 @@
155
155
  "configs.systemStatus.variables.entitiesBackcompatEav.label": "Escrituras EAV heredadas",
156
156
  "configs.systemStatus.variables.forceQueryIndexOnPartialIndexes.description": "Servir resultados del índice de consultas incluso cuando la cobertura es parcial.",
157
157
  "configs.systemStatus.variables.forceQueryIndexOnPartialIndexes.label": "Forzar uso de índice parcial",
158
+ "configs.systemStatus.variables.listCountCap.description": "Total máximo informado en listas; el conteo se detiene en el límite y los totales limitados se muestran p. ej. como «10 000+». 0 desactiva el límite.",
159
+ "configs.systemStatus.variables.listCountCap.label": "Límite del conteo de listas",
158
160
  "configs.systemStatus.variables.logLevel.description": "Nivel de registro de respaldo cuando la verbosidad no está configurada.",
159
161
  "configs.systemStatus.variables.logLevel.label": "Nivel de registro",
160
162
  "configs.systemStatus.variables.logVerbosity.description": "Anula la verbosidad del registro estructurado, como debug o trace.",
@@ -155,6 +155,8 @@
155
155
  "configs.systemStatus.variables.entitiesBackcompatEav.label": "레거시 EAV 쓰기",
156
156
  "configs.systemStatus.variables.forceQueryIndexOnPartialIndexes.description": "커버리지가 부분적이어도 쿼리 인덱스 결과를 제공합니다.",
157
157
  "configs.systemStatus.variables.forceQueryIndexOnPartialIndexes.label": "부분 인덱스 사용 강제",
158
+ "configs.systemStatus.variables.listCountCap.description": "목록 총계의 최대 보고 값입니다. 카운트는 상한에서 멈추며 제한된 총계는 예를 들어 “10 000+”로 표시됩니다. 0이면 상한이 비활성화됩니다.",
159
+ "configs.systemStatus.variables.listCountCap.label": "목록 카운트 상한",
158
160
  "configs.systemStatus.variables.logLevel.description": "상세 수준이 설정되지 않았을 때 적용되는 대체 로그 레벨입니다.",
159
161
  "configs.systemStatus.variables.logLevel.label": "로그 레벨",
160
162
  "configs.systemStatus.variables.logVerbosity.description": "debug나 trace와 같은 구조화된 로그 상세 수준을 재정의합니다.",
@@ -155,6 +155,8 @@
155
155
  "configs.systemStatus.variables.entitiesBackcompatEav.label": "Zapis do legacy EAV",
156
156
  "configs.systemStatus.variables.forceQueryIndexOnPartialIndexes.description": "Pozwala korzystać z wyników indeksu zapytań nawet przy częściowym pokryciu.",
157
157
  "configs.systemStatus.variables.forceQueryIndexOnPartialIndexes.label": "Wymuś użycie częściowego indeksu",
158
+ "configs.systemStatus.variables.listCountCap.description": "Maksymalna raportowana liczba wyników listy; zliczanie zatrzymuje się na limicie, a ograniczone sumy są pokazywane np. jako „10 000+”. 0 wyłącza limit.",
159
+ "configs.systemStatus.variables.listCountCap.label": "Limit licznika list",
158
160
  "configs.systemStatus.variables.logLevel.description": "Domyślny poziom logowania używany, gdy nie ustawiono szczegółowości.",
159
161
  "configs.systemStatus.variables.logLevel.label": "Poziom logowania",
160
162
  "configs.systemStatus.variables.logVerbosity.description": "Nadpisuje poziom szczegółowości logów, np. debug lub trace.",
@@ -267,6 +267,15 @@ export const SYSTEM_STATUS_VARIABLES: SystemStatusVariableDefinition[] = [
267
267
  docUrl: `${SYSTEM_STATUS_DOC_BASE}#optimize_index_coverage_stats`,
268
268
  defaultValue: 'false',
269
269
  },
270
+ {
271
+ key: 'OM_LIST_COUNT_CAP',
272
+ category: 'query_index',
273
+ kind: 'string',
274
+ labelKey: 'configs.systemStatus.variables.listCountCap.label',
275
+ descriptionKey: 'configs.systemStatus.variables.listCountCap.description',
276
+ docUrl: `${SYSTEM_STATUS_DOC_BASE}#om_list_count_cap`,
277
+ defaultValue: '10000',
278
+ },
270
279
  {
271
280
  key: 'FORCE_QUERY_INDEX_ON_PARTIAL_INDEXES',
272
281
  category: 'query_index',
@@ -9,6 +9,9 @@ Use the currencies module for multi-currency support, exchange rates, and curren
9
9
  3. **MUST record both transaction currency and base currency amounts** — dual recording is mandatory for reporting
10
10
  4. **MUST calculate realized gains/losses** on payment: `(payment rate - invoice rate) × foreign amount`
11
11
  5. **MUST keep financial postings atomic** — full transaction rollback on error
12
+ 6. **MUST NOT filter rate fetching by `isActive`** — that flag decides whether a currency can be
13
+ picked for something new, not whether it still needs a live rate. Rates are fetched for every
14
+ currency in scope that is not soft-deleted. See `services/README.md` → "Which Currencies Get Rates"
12
15
 
13
16
  ## Ask First
14
17
 
@@ -41,6 +41,7 @@ type ResponsePayload = {
41
41
  total: number
42
42
  page: number
43
43
  totalPages: number
44
+ totalIsCapped?: boolean
44
45
  }
45
46
 
46
47
  export default function CurrenciesPage() {
@@ -50,6 +51,7 @@ export default function CurrenciesPage() {
50
51
  const [page, setPage] = React.useState(1)
51
52
  const [total, setTotal] = React.useState(0)
52
53
  const [totalPages, setTotalPages] = React.useState(1)
54
+ const [totalIsCapped, setTotalIsCapped] = React.useState(false)
53
55
  const [search, setSearch] = React.useState('')
54
56
  const [filters, setFilters] = React.useState<FilterValues>({})
55
57
  const [isLoading, setIsLoading] = React.useState(true)
@@ -96,6 +98,7 @@ export default function CurrenciesPage() {
96
98
  setRows(Array.isArray(payload.items) ? payload.items : [])
97
99
  setTotal(payload.total || 0)
98
100
  setTotalPages(payload.totalPages || 1)
101
+ setTotalIsCapped(payload?.totalIsCapped === true)
99
102
  }
100
103
  } catch (error) {
101
104
  if (!cancelled) {
@@ -342,7 +345,7 @@ export default function CurrenciesPage() {
342
345
  createLabel={t('currencies.list.actions.create')}
343
346
  />
344
347
  )}
345
- pagination={{ page, pageSize: 50, total, totalPages, onPageChange: setPage }}
348
+ pagination={{ page, pageSize: 50, total, totalPages, totalIsCapped, onPageChange: setPage }}
346
349
  isLoading={isLoading}
347
350
  perspective={{ tableId: extensionPoints.hosts.currenciesTable.tableId }}
348
351
  />
@@ -42,6 +42,7 @@ type ResponsePayload = {
42
42
  total: number
43
43
  page: number
44
44
  totalPages: number
45
+ totalIsCapped?: boolean
45
46
  }
46
47
 
47
48
  export default function ExchangeRatesPage() {
@@ -51,6 +52,7 @@ export default function ExchangeRatesPage() {
51
52
  const [page, setPage] = React.useState(1)
52
53
  const [total, setTotal] = React.useState(0)
53
54
  const [totalPages, setTotalPages] = React.useState(1)
55
+ const [totalIsCapped, setTotalIsCapped] = React.useState(false)
54
56
  const [search, setSearch] = React.useState('')
55
57
  const [filters, setFilters] = React.useState<FilterValues>({})
56
58
  const [isLoading, setIsLoading] = React.useState(true)
@@ -100,6 +102,7 @@ export default function ExchangeRatesPage() {
100
102
  setRows(Array.isArray(payload.items) ? payload.items : [])
101
103
  setTotal(payload.total || 0)
102
104
  setTotalPages(payload.totalPages || 1)
105
+ setTotalIsCapped(payload?.totalIsCapped === true)
103
106
  }
104
107
  } catch (error) {
105
108
  if (!cancelled) {
@@ -332,7 +335,7 @@ export default function ExchangeRatesPage() {
332
335
  createLabel={t('exchangeRates.list.actions.create')}
333
336
  />
334
337
  )}
335
- pagination={{ page, pageSize: 50, total, totalPages, onPageChange: setPage }}
338
+ pagination={{ page, pageSize: 50, total, totalPages, totalIsCapped, onPageChange: setPage }}
336
339
  isLoading={isLoading}
337
340
  perspective={{ tableId: extensionPoints.hosts.exchangeRatesTable.tableId }}
338
341
  />
@@ -282,6 +282,51 @@ console.log(`By provider:`, result.byProvider)
282
282
  console.log(`Errors:`, result.errors)
283
283
  ```
284
284
 
285
+ ### Which Currencies Get Rates
286
+
287
+ `fetchRatesForDate` first resolves the set of currency codes worth storing rates for, then filters
288
+ every provider response against it — a rate is kept only when **both** legs of its pair are in the
289
+ set. The set is every currency in the tenant/organization scope that is not soft-deleted.
290
+
291
+ `isActive` deliberately plays no part here. That flag answers whether a currency may be **selected**
292
+ for something new (it gates `api/currencies/options`, the `?isActive` list filter and the
293
+ exchange-rate form's currency select), which says nothing about whether records already denominated
294
+ in it must stay convertible. Deactivating a currency while existing records still reference it is
295
+ the normal way to grandfather it, and those records keep needing a rate — otherwise conversions out
296
+ of the currency start failing once the stored rates fall outside the consumer's lookback window.
297
+ `ExchangeRateService` defaults to `maxDaysBack: 30`, but consumers override it — the deal-value
298
+ conversions in `customers/api/deals/{aggregate,summary}` pass `maxDaysBack: 60`, so a currency that
299
+ stopped accruing rates drops out of pipeline totals (`convertedAll: false`, no error surfaced)
300
+ roughly 60 days later.
301
+
302
+ **Soft delete is the only thing that stops a currency from accruing rates.** `deletedAt` excludes it
303
+ from the set; nothing else does, `isActive` included.
304
+
305
+ Reaching `deletedAt` takes two steps, in this order, because `deleteCurrencyCommand` refuses the
306
+ delete while the currency still has live rates — the very rates fetching keeps writing
307
+ (`storeRates` stores each one with `isActive: true`):
308
+
309
+ 1. Delete or deactivate every `exchange_rates` row whose `fromCurrencyCode` or `toCurrencyCode` is
310
+ the currency, otherwise `DELETE /api/currencies/currencies` answers
311
+ `400 Cannot delete currency XXX because it has N active exchange rate(s)`.
312
+ 2. Soft-delete the currency, with no fetch in between. Any fetch in that window — the "Fetch rates"
313
+ button, `mercato currencies fetch-rates`, or `ExchangeRateService`'s `autoFetch` (which defaults
314
+ to `true`) — recreates the rates and re-blocks the delete.
315
+
316
+ There is deliberately **no reversible way to pause rate accrual for a single currency**. An earlier
317
+ draft of this change added a `Currency.fetchRatesWhenInactive` opt-in column for exactly that and it
318
+ was dropped: an extra column to express "grandfathered but still convertible" is the state
319
+ `isActive: false` already describes, and the cost of keeping a currency in the set is bounded (see
320
+ below). Soft delete is the terminal off-switch, not a pause.
321
+
322
+ Note that both bundled providers (NBP, Raiffeisen) return `[]` outright when `PLN` is missing from
323
+ the set, so a `PLN` that fell out of it silenced the entire provider rather than just `PLN`'s own
324
+ pairs — another reason the set is not narrowed by selectability.
325
+
326
+ Keeping the set wide costs no extra provider calls: both providers fetch a full table in a single
327
+ request per date and the set is applied locally. The only cost is additional `exchange_rates` rows,
328
+ bounded by what the provider returns anyway.
329
+
285
330
  ### When to Use RateFetchingService Directly
286
331
 
287
332
  - Scheduled/batch fetching of rates
@@ -131,6 +131,12 @@ export class RateFetchingService {
131
131
  }
132
132
  }
133
133
 
134
+ /**
135
+ * Currencies whose rates are worth storing. Deliberately not filtered by `isActive`: that flag
136
+ * answers whether a currency may be picked for something new, which says nothing about whether
137
+ * records already denominated in it must stay convertible. Soft delete is what takes a currency
138
+ * out of rate fetching.
139
+ */
134
140
  private async getExistingCurrencies(scope: {
135
141
  tenantId: string
136
142
  organizationId: string
@@ -138,7 +144,6 @@ export class RateFetchingService {
138
144
  return this.em.find(Currency, {
139
145
  tenantId: scope.tenantId,
140
146
  organizationId: scope.organizationId,
141
- isActive: true,
142
147
  deletedAt: null,
143
148
  })
144
149
  }
@@ -14,6 +14,7 @@ import {
14
14
  import { registerDomainSchema } from '@open-mercato/core/modules/customer_accounts/data/validators'
15
15
  import {
16
16
  DomainMappingService,
17
+ DomainMappingOrgScopeError,
17
18
  type ResolveResult,
18
19
  } from '@open-mercato/core/modules/customer_accounts/services/domainMappingService'
19
20
  import { DomainMapping } from '@open-mercato/core/modules/customer_accounts/data/entities'
@@ -142,6 +143,12 @@ export async function POST(req: Request) {
142
143
  { status: 409 },
143
144
  )
144
145
  }
146
+ if (err instanceof DomainMappingOrgScopeError) {
147
+ return NextResponse.json(
148
+ { ok: false, error: 'Organization was not found in the current tenant.' },
149
+ { status: 400 },
150
+ )
151
+ }
145
152
  const message = err instanceof Error ? err.message : 'Failed to register domain'
146
153
  return NextResponse.json({ ok: false, error: message }, { status: 500 })
147
154
  }
@@ -34,6 +34,7 @@ type RolesResponse = {
34
34
  items?: RoleRow[]
35
35
  total?: number
36
36
  totalPages?: number
37
+ totalIsCapped?: boolean
37
38
  }
38
39
 
39
40
  export default function CustomerRolesPage() {
@@ -45,6 +46,7 @@ export default function CustomerRolesPage() {
45
46
  const [pageSize] = React.useState(50)
46
47
  const [total, setTotal] = React.useState(0)
47
48
  const [totalPages, setTotalPages] = React.useState(1)
49
+ const [totalIsCapped, setTotalIsCapped] = React.useState(false)
48
50
  const [search, setSearch] = React.useState('')
49
51
  const [isLoading, setIsLoading] = React.useState(true)
50
52
  const [reloadToken, setReloadToken] = React.useState(0)
@@ -88,6 +90,7 @@ export default function CustomerRolesPage() {
88
90
  setRows(items)
89
91
  setTotal(typeof payload?.total === 'number' ? payload.total : items.length)
90
92
  setTotalPages(typeof payload?.totalPages === 'number' ? payload.totalPages : 1)
93
+ setTotalIsCapped(payload?.totalIsCapped === true)
91
94
  } catch (err) {
92
95
  if (!cancelled) {
93
96
  const message = err instanceof Error ? err.message : t('customer_accounts.admin.roles.error.load', 'Failed to load roles')
@@ -240,7 +243,7 @@ export default function CustomerRolesPage() {
240
243
  ]}
241
244
  />
242
245
  )}
243
- pagination={{ page, pageSize, total, totalPages, onPageChange: setPage }}
246
+ pagination={{ page, pageSize, total, totalPages, totalIsCapped, onPageChange: setPage }}
244
247
  isLoading={isLoading}
245
248
  />
246
249
  </PageBody>
@@ -41,6 +41,7 @@ type UsersResponse = {
41
41
  items?: UserRow[]
42
42
  total?: number
43
43
  totalPages?: number
44
+ totalIsCapped?: boolean
44
45
  }
45
46
 
46
47
  function formatDate(value: string | null | undefined, fallback: string): string {
@@ -239,6 +240,7 @@ export function PortalUsersPageClient({ portalOrigin }: PortalUsersPageClientPro
239
240
  const [pageSize] = React.useState(50)
240
241
  const [total, setTotal] = React.useState(0)
241
242
  const [totalPages, setTotalPages] = React.useState(1)
243
+ const [totalIsCapped, setTotalIsCapped] = React.useState(false)
242
244
  const [search, setSearch] = React.useState('')
243
245
  const [filterValues, setFilterValues] = React.useState<FilterValues>({})
244
246
  const [isLoading, setIsLoading] = React.useState(true)
@@ -318,6 +320,7 @@ export function PortalUsersPageClient({ portalOrigin }: PortalUsersPageClientPro
318
320
  setRows(items)
319
321
  setTotal(typeof payload?.total === 'number' ? payload.total : items.length)
320
322
  setTotalPages(typeof payload?.totalPages === 'number' ? payload.totalPages : 1)
323
+ setTotalIsCapped(payload?.totalIsCapped === true)
321
324
  } catch (err) {
322
325
  if (!cancelled) {
323
326
  const message = err instanceof Error ? err.message : t('customer_accounts.admin.error.loadUsers', 'Failed to load customer users')
@@ -582,7 +585,7 @@ export function PortalUsersPageClient({ portalOrigin }: PortalUsersPageClientPro
582
585
  ]}
583
586
  />
584
587
  )}
585
- pagination={{ page, pageSize, total, totalPages, onPageChange: setPage }}
588
+ pagination={{ page, pageSize, total, totalPages, totalIsCapped, onPageChange: setPage }}
586
589
  isLoading={isLoading}
587
590
  />
588
591
  <CreateUserDialog