@open-mercato/core 0.7.0 → 0.7.1-develop.7103.1.41ff100d93
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.
- package/.turbo/turbo-build.log +1 -1
- package/dist/helpers/integration/api.js +13 -1
- package/dist/helpers/integration/api.js.map +2 -2
- package/dist/helpers/integration/communicationChannelsFixtures.js +19 -0
- package/dist/helpers/integration/communicationChannelsFixtures.js.map +2 -2
- package/dist/modules/api_keys/api/keys/route.js +1 -1
- package/dist/modules/api_keys/api/keys/route.js.map +2 -2
- package/dist/modules/api_keys/backend/api-keys/page.js +3 -1
- package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
- package/dist/modules/api_keys/di.js +9 -0
- package/dist/modules/api_keys/di.js.map +7 -0
- package/dist/modules/api_keys/services/principalService.js +31 -0
- package/dist/modules/api_keys/services/principalService.js.map +7 -0
- package/dist/modules/attachments/api/route.js +2 -2
- package/dist/modules/attachments/api/route.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentLibrary.js +2 -0
- package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
- package/dist/modules/attachments/di.js +11 -1
- package/dist/modules/attachments/di.js.map +2 -2
- package/dist/modules/attachments/index.js.map +1 -1
- package/dist/modules/attachments/lib/attachment-service.js +313 -0
- package/dist/modules/attachments/lib/attachment-service.js.map +7 -0
- package/dist/modules/attachments/lib/scoped-upload-service.js +15 -2
- package/dist/modules/attachments/lib/scoped-upload-service.js.map +2 -2
- package/dist/modules/attachments/lib/upload-limits.js +6 -2
- package/dist/modules/attachments/lib/upload-limits.js.map +2 -2
- package/dist/modules/audit_logs/backend/audit-logs/page.js +6 -0
- package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
- package/dist/modules/audit_logs/lib/display-helpers.js +19 -11
- package/dist/modules/audit_logs/lib/display-helpers.js.map +2 -2
- package/dist/modules/audit_logs/services/actionLogService.js +57 -12
- package/dist/modules/audit_logs/services/actionLogService.js.map +3 -3
- package/dist/modules/auth/acl.js +30 -5
- package/dist/modules/auth/acl.js.map +2 -2
- package/dist/modules/auth/api/feature-check.js +8 -2
- package/dist/modules/auth/api/feature-check.js.map +2 -2
- package/dist/modules/auth/api/login.js +4 -1
- package/dist/modules/auth/api/login.js.map +2 -2
- package/dist/modules/auth/api/reset/validate.js +55 -0
- package/dist/modules/auth/api/reset/validate.js.map +7 -0
- package/dist/modules/auth/api/roles/acl/route.js +28 -33
- package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
- package/dist/modules/auth/api/session/refresh.js +25 -1
- package/dist/modules/auth/api/session/refresh.js.map +2 -2
- package/dist/modules/auth/api/users/acl/route.js +96 -51
- package/dist/modules/auth/api/users/acl/route.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +13 -5
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/backend/roles/[id]/edit/page.meta.js +5 -1
- package/dist/modules/auth/backend/roles/[id]/edit/page.meta.js.map +2 -2
- package/dist/modules/auth/backend/roles/page.js +3 -1
- package/dist/modules/auth/backend/roles/page.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.meta.js +5 -1
- package/dist/modules/auth/backend/users/[id]/edit/page.meta.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +2 -1
- package/dist/modules/auth/backend/users/page.js.map +2 -2
- package/dist/modules/auth/commands/acl.js +254 -0
- package/dist/modules/auth/commands/acl.js.map +7 -0
- package/dist/modules/auth/components/AclEditor.js +39 -30
- package/dist/modules/auth/components/AclEditor.js.map +2 -2
- package/dist/modules/auth/data/entities.js.map +2 -2
- package/dist/modules/auth/data/validators.js +5 -1
- package/dist/modules/auth/data/validators.js.map +2 -2
- package/dist/modules/auth/di.js +35 -9
- package/dist/modules/auth/di.js.map +2 -2
- package/dist/modules/auth/frontend/reset/[token]/page.js +46 -0
- package/dist/modules/auth/frontend/reset/[token]/page.js.map +2 -2
- package/dist/modules/auth/lib/grantChecks.js.map +2 -2
- package/dist/modules/auth/lib/userIdFilter.js +16 -0
- package/dist/modules/auth/lib/userIdFilter.js.map +7 -0
- package/dist/modules/auth/services/authService.js +16 -2
- package/dist/modules/auth/services/authService.js.map +2 -2
- package/dist/modules/auth/services/principalService.js +200 -0
- package/dist/modules/auth/services/principalService.js.map +7 -0
- package/dist/modules/auth/services/rbacService.js +67 -24
- package/dist/modules/auth/services/rbacService.js.map +3 -3
- package/dist/modules/auth/services/roleOrganizationScope.js +41 -0
- package/dist/modules/auth/services/roleOrganizationScope.js.map +7 -0
- package/dist/modules/business_rules/backend/logs/page.js +3 -1
- package/dist/modules/business_rules/backend/logs/page.js.map +2 -2
- package/dist/modules/business_rules/backend/rules/page.js +3 -1
- package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/page.js +3 -1
- package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
- package/dist/modules/business_rules/lib/expression-evaluator.js +9 -9
- package/dist/modules/business_rules/lib/expression-evaluator.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-evaluator.js +10 -9
- package/dist/modules/business_rules/lib/rule-evaluator.js.map +2 -2
- package/dist/modules/catalog/ai-agents.js +1 -1
- package/dist/modules/catalog/ai-agents.js.map +1 -1
- package/dist/modules/catalog/ai-tools/merchandising-pack.js +2 -2
- package/dist/modules/catalog/ai-tools/merchandising-pack.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +5 -2
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +2 -2
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -0
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductsDataTable.js +7 -1
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js +2 -0
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js.map +2 -2
- package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js +9 -1
- package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/test-seed/route.js +95 -10
- package/dist/modules/communication_channels/api/post/test-seed/route.js.map +2 -2
- package/dist/modules/communication_channels/backend/communication_channels/channels/page.js +3 -0
- package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +2 -2
- package/dist/modules/communication_channels/commands/ingest-inbound-message.js +14 -1
- package/dist/modules/communication_channels/commands/ingest-inbound-message.js.map +2 -2
- package/dist/modules/communication_channels/di.js +7 -1
- package/dist/modules/communication_channels/di.js.map +2 -2
- package/dist/modules/communication_channels/lib/email-capabilities.js +4 -1
- package/dist/modules/communication_channels/lib/email-capabilities.js.map +2 -2
- package/dist/modules/communication_channels/lib/outbound-recipient.js +33 -0
- package/dist/modules/communication_channels/lib/outbound-recipient.js.map +7 -0
- package/dist/modules/communication_channels/lib/resolve-channel-type.js +51 -0
- package/dist/modules/communication_channels/lib/resolve-channel-type.js.map +7 -0
- package/dist/modules/communication_channels/lib/test-seed.js +41 -2
- package/dist/modules/communication_channels/lib/test-seed.js.map +2 -2
- package/dist/modules/configs/lib/system-status.js +9 -0
- package/dist/modules/configs/lib/system-status.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/page.js +3 -1
- package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js +3 -1
- package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
- package/dist/modules/currencies/services/rateFetchingService.js +6 -1
- package/dist/modules/currencies/services/rateFetchingService.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/domain-mappings.js +9 -0
- package/dist/modules/customer_accounts/api/admin/domain-mappings.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +3 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js +3 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js.map +2 -2
- package/dist/modules/customer_accounts/services/domainMappingService.js +10 -0
- package/dist/modules/customer_accounts/services/domainMappingService.js.map +2 -2
- package/dist/modules/customers/ai-tools/companies-pack.js +4 -1
- package/dist/modules/customers/ai-tools/companies-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/deal-analyzer-pack.js +13 -2
- package/dist/modules/customers/ai-tools/deal-analyzer-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/deals-pack.js +52 -6
- package/dist/modules/customers/ai-tools/deals-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/people-pack.js +4 -1
- package/dist/modules/customers/ai-tools/people-pack.js.map +2 -2
- package/dist/modules/customers/api/activities/route.js +48 -6
- package/dist/modules/customers/api/activities/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/people/route.js +20 -64
- package/dist/modules/customers/api/companies/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/route.js +17 -94
- package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js +8 -5
- package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/companies/route.js +1 -1
- package/dist/modules/customers/api/deals/[id]/companies/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/people/route.js +1 -1
- package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/route.js +8 -25
- package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/stats/route.js +3 -22
- package/dist/modules/customers/api/deals/[id]/stats/route.js.map +2 -2
- package/dist/modules/customers/api/deals/aggregate/route.js +14 -9
- package/dist/modules/customers/api/deals/aggregate/route.js.map +2 -2
- package/dist/modules/customers/api/deals/map/route.js +5 -5
- package/dist/modules/customers/api/deals/map/route.js.map +2 -2
- package/dist/modules/customers/api/deals/route.js +38 -1
- package/dist/modules/customers/api/deals/route.js.map +2 -2
- package/dist/modules/customers/api/entity-roles-factory.js +4 -4
- package/dist/modules/customers/api/entity-roles-factory.js.map +2 -2
- package/dist/modules/customers/api/interactions/route.js +3 -1
- package/dist/modules/customers/api/interactions/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/tasks/route.js +27 -4
- package/dist/modules/customers/api/interactions/tasks/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +4 -3
- package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/context.js +1 -1
- package/dist/modules/customers/api/people/[id]/companies/context.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +1 -1
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/route.js +11 -10
- package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/people/check-phone/route.js +51 -9
- package/dist/modules/customers/api/people/check-phone/route.js.map +2 -2
- package/dist/modules/customers/api/todos/route.js +30 -5
- package/dist/modules/customers/api/todos/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +4 -2
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +6 -1
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +5 -2
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/Lane.js +4 -13
- package/dist/modules/customers/backend/customers/deals/pipeline/components/Lane.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js +85 -14
- package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/toneClasses.js +18 -0
- package/dist/modules/customers/backend/customers/deals/pipeline/components/toneClasses.js.map +7 -0
- package/dist/modules/customers/backend/customers/people/page.js +4 -2
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/backend/hooks/useEmailDuplicateCheck.js +9 -3
- package/dist/modules/customers/backend/hooks/useEmailDuplicateCheck.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +21 -34
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js.map +1 -1
- package/dist/modules/customers/commands/personCompanyLinks.js +131 -2
- package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
- package/dist/modules/customers/components/CustomerTodosTable.js +1 -0
- package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
- package/dist/modules/customers/components/DealsKpiStrip.js +7 -6
- package/dist/modules/customers/components/DealsKpiStrip.js.map +2 -2
- package/dist/modules/customers/components/calendar/AgendaList.js +2 -2
- package/dist/modules/customers/components/calendar/AgendaList.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js +1 -1
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarScreen.js +1 -1
- package/dist/modules/customers/components/calendar/CalendarScreen.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js +1 -1
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js.map +2 -2
- package/dist/modules/customers/components/calendar/EventBlock.js +1 -1
- package/dist/modules/customers/components/calendar/EventBlock.js.map +2 -2
- package/dist/modules/customers/components/calendar/EventPeekPopover.js +3 -2
- package/dist/modules/customers/components/calendar/EventPeekPopover.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/PeopleField.js +40 -5
- package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/hooks.js +2 -1
- package/dist/modules/customers/components/calendar/editor/hooks.js.map +2 -2
- package/dist/modules/customers/components/calendar/types.js +1 -1
- package/dist/modules/customers/components/calendar/types.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyKpiBar.js +5 -4
- package/dist/modules/customers/components/detail/CompanyKpiBar.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js +3 -1
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
- package/dist/modules/customers/components/detail/DealForm.js +19 -7
- package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
- package/dist/modules/customers/components/detail/DealsSection.js +6 -5
- package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js +35 -11
- package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js +3 -1
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/usePersonTasks.js +19 -13
- package/dist/modules/customers/components/detail/hooks/usePersonTasks.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/ParticipantsField.js +4 -4
- package/dist/modules/customers/components/detail/schedule/ParticipantsField.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +3 -3
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
- package/dist/modules/customers/components/detail/utils.js +5 -5
- package/dist/modules/customers/components/detail/utils.js.map +2 -2
- package/dist/modules/customers/data/entities.js.map +1 -1
- package/dist/modules/customers/data/validators.js +32 -3
- package/dist/modules/customers/data/validators.js.map +2 -2
- package/dist/modules/customers/events.js +5 -0
- package/dist/modules/customers/events.js.map +2 -2
- package/dist/modules/customers/lib/calendar/conflicts.js +8 -2
- package/dist/modules/customers/lib/calendar/conflicts.js.map +2 -2
- package/dist/modules/customers/lib/calendar/editorPayload.js +3 -2
- package/dist/modules/customers/lib/calendar/editorPayload.js.map +2 -2
- package/dist/modules/customers/lib/calendar/mapItem.js +8 -3
- package/dist/modules/customers/lib/calendar/mapItem.js.map +2 -2
- package/dist/modules/customers/lib/calendar/participantIdentity.js +9 -0
- package/dist/modules/customers/lib/calendar/participantIdentity.js.map +7 -0
- package/dist/modules/customers/lib/closureStage.js +45 -0
- package/dist/modules/customers/lib/closureStage.js.map +7 -0
- package/dist/modules/customers/lib/dealStatus.js +30 -0
- package/dist/modules/customers/lib/dealStatus.js.map +2 -2
- package/dist/modules/customers/lib/detailReadAccess.js +12 -0
- package/dist/modules/customers/lib/detailReadAccess.js.map +7 -0
- package/dist/modules/customers/lib/findPeopleByAddresses.js +1 -0
- package/dist/modules/customers/lib/findPeopleByAddresses.js.map +2 -2
- package/dist/modules/customers/lib/personCompanies.js +100 -2
- package/dist/modules/customers/lib/personCompanies.js.map +2 -2
- package/dist/modules/customers/lib/todoCompatibility.js +12 -0
- package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
- package/dist/modules/dashboards/lib/widgetScope.js +6 -1
- package/dist/modules/dashboards/lib/widgetScope.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +3 -1
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/lib/abandoned-run.js +19 -0
- package/dist/modules/data_sync/lib/abandoned-run.js.map +7 -0
- package/dist/modules/data_sync/lib/sync-engine.js +72 -6
- package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
- package/dist/modules/data_sync/workers/sync-export.js +5 -1
- package/dist/modules/data_sync/workers/sync-export.js.map +2 -2
- package/dist/modules/data_sync/workers/sync-import.js +5 -1
- package/dist/modules/data_sync/workers/sync-import.js.map +2 -2
- package/dist/modules/devices/acl.js +9 -1
- package/dist/modules/devices/acl.js.map +2 -2
- package/dist/modules/devices/api/admin/devices/[id]/route.js +5 -32
- package/dist/modules/devices/api/admin/devices/[id]/route.js.map +2 -2
- package/dist/modules/devices/api/admin/devices/route.js +14 -1
- package/dist/modules/devices/api/admin/devices/route.js.map +2 -2
- package/dist/modules/devices/api/deviceList.js +99 -12
- package/dist/modules/devices/api/deviceList.js.map +2 -2
- package/dist/modules/devices/api/deviceSerialization.js +46 -0
- package/dist/modules/devices/api/deviceSerialization.js.map +7 -0
- package/dist/modules/devices/api/openapi.js +3 -1
- package/dist/modules/devices/api/openapi.js.map +2 -2
- package/dist/modules/devices/api/route.js +9 -1
- package/dist/modules/devices/api/route.js.map +2 -2
- package/dist/modules/devices/backend/devices/[id]/page.js +10 -26
- package/dist/modules/devices/backend/devices/[id]/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/create/page.js +17 -1
- package/dist/modules/devices/backend/devices/create/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/page.js +28 -34
- package/dist/modules/devices/backend/devices/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/useDeviceUserLabels.js +34 -0
- package/dist/modules/devices/backend/devices/useDeviceUserLabels.js.map +7 -0
- package/dist/modules/devices/backend/devices/userOptions.js +52 -0
- package/dist/modules/devices/backend/devices/userOptions.js.map +7 -0
- package/dist/modules/devices/setup.js +6 -2
- package/dist/modules/devices/setup.js.map +2 -2
- package/dist/modules/directory/backend/directory/organizations/page.js +2 -1
- package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/page.js +2 -1
- package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
- package/dist/modules/directory/di.js +9 -0
- package/dist/modules/directory/di.js.map +2 -2
- package/dist/modules/directory/services/organizationHierarchyService.js +29 -0
- package/dist/modules/directory/services/organizationHierarchyService.js.map +7 -0
- package/dist/modules/directory/services/organizationScopeService.js +56 -0
- package/dist/modules/directory/services/organizationScopeService.js.map +7 -0
- package/dist/modules/directory/utils/organizationScope.js.map +2 -2
- package/dist/modules/entities/api/records.js +4 -2
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +3 -1
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/eudr/api/plots/route.js +5 -1
- package/dist/modules/eudr/api/plots/route.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/plots/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/plots/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/product-mappings/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/statements/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/statements/page.js.map +2 -2
- package/dist/modules/eudr/commands/statements.js +0 -3
- package/dist/modules/eudr/commands/statements.js.map +2 -2
- package/dist/modules/eudr/data/validators.js +4 -1
- package/dist/modules/eudr/data/validators.js.map +2 -2
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +1 -0
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
- package/dist/modules/feature_toggles/components/OverridesTable.js +1 -0
- package/dist/modules/feature_toggles/components/OverridesTable.js.map +2 -2
- package/dist/modules/feature_toggles/defaults.json +0 -8
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js +3 -0
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/page.js +3 -0
- package/dist/modules/inbox_ops/backend/inbox-ops/page.js.map +2 -2
- package/dist/modules/inbox_ops/lib/htmlToPlainText.js +1 -12
- package/dist/modules/inbox_ops/lib/htmlToPlainText.js.map +2 -2
- package/dist/modules/integrations/api/[id]/credentials/route.js +6 -1
- package/dist/modules/integrations/api/[id]/credentials/route.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/[id]/page.js +38 -29
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +36 -9
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/credential-secret-fields.js +55 -0
- package/dist/modules/integrations/backend/integrations/credential-secret-fields.js.map +7 -0
- package/dist/modules/integrations/data/validators.js +11 -3
- package/dist/modules/integrations/data/validators.js.map +2 -2
- package/dist/modules/integrations/lib/credentials-masking.js +6 -2
- package/dist/modules/integrations/lib/credentials-masking.js.map +2 -2
- package/dist/modules/messages/api/[id]/route.js +29 -1
- package/dist/modules/messages/api/[id]/route.js.map +2 -2
- package/dist/modules/messages/api/openapi.js +17 -2
- package/dist/modules/messages/api/openapi.js.map +2 -2
- package/dist/modules/messages/api/route.js +17 -2
- package/dist/modules/messages/api/route.js.map +2 -2
- package/dist/modules/messages/components/MessagesInboxPageClient.js +7 -14
- package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
- package/dist/modules/messages/components/inboxFilters.js +15 -0
- package/dist/modules/messages/components/inboxFilters.js.map +2 -2
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js +11 -1
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js.map +2 -2
- package/dist/modules/messages/components/message-detail/panels/MessageHeader.js +3 -1
- package/dist/modules/messages/components/message-detail/panels/MessageHeader.js.map +2 -2
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js +2 -1
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +2 -2
- package/dist/modules/messages/components/messageListLabels.js +14 -2
- package/dist/modules/messages/components/messageListLabels.js.map +2 -2
- package/dist/modules/messages/data/validators.js +18 -4
- package/dist/modules/messages/data/validators.js.map +2 -2
- package/dist/modules/messages/lib/channel-sender-identity.js +26 -0
- package/dist/modules/messages/lib/channel-sender-identity.js.map +7 -0
- package/dist/modules/messages/lib/composeSourceChannelType.js +41 -0
- package/dist/modules/messages/lib/composeSourceChannelType.js.map +7 -0
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +4 -6
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +2 -2
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js +3 -1
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
- package/dist/modules/payment_gateways/lib/webhook-processor.js +7 -0
- package/dist/modules/payment_gateways/lib/webhook-processor.js.map +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js +3 -0
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/push_notifications/backend/push_notifications/page.js +3 -1
- package/dist/modules/push_notifications/backend/push_notifications/page.js.map +2 -2
- package/dist/modules/push_notifications/backend/push_notifications/send/page.js +1 -1
- package/dist/modules/push_notifications/backend/push_notifications/send/page.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +150 -51
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/lib/search-entity-policy.js +14 -0
- package/dist/modules/query_index/lib/search-entity-policy.js.map +7 -0
- package/dist/modules/query_index/lib/search-tokens.js +79 -3
- package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js +3 -1
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js +3 -1
- package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js +3 -0
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +3 -0
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +10 -8
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +79 -1
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/components/PriceWithCurrency.js +7 -5
- package/dist/modules/sales/components/PriceWithCurrency.js.map +2 -2
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +3 -0
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentsSection.js +8 -6
- package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +51 -22
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +83 -18
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js +23 -9
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnsSection.js +8 -6
- package/dist/modules/sales/components/documents/ReturnsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +68 -14
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesOrderDraftLines.js +6 -5
- package/dist/modules/sales/components/documents/SalesOrderDraftLines.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +5 -4
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentsSection.js +8 -6
- package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/lineItemShipmentLock.js +54 -0
- package/dist/modules/sales/components/documents/lineItemShipmentLock.js.map +7 -0
- package/dist/modules/sales/components/documents/lineItemUtils.js +2 -2
- package/dist/modules/sales/components/documents/lineItemUtils.js.map +2 -2
- package/dist/modules/sales/data/entities.js +8 -2
- package/dist/modules/sales/data/entities.js.map +2 -2
- package/dist/modules/sales/extension-points.js +1 -0
- package/dist/modules/sales/extension-points.js.map +2 -2
- package/dist/modules/sales/lib/salesChannelsToggleSeed.js +33 -0
- package/dist/modules/sales/lib/salesChannelsToggleSeed.js.map +7 -0
- package/dist/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.js +32 -0
- package/dist/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.js.map +7 -0
- package/dist/modules/sales/setup.js +2 -0
- package/dist/modules/sales/setup.js.map +2 -2
- package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js +10 -2
- package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js.map +2 -2
- package/dist/modules/sales/widgets/injection-table.js +4 -7
- package/dist/modules/sales/widgets/injection-table.js.map +2 -2
- package/dist/modules/staff/backend/staff/leave-requests/page.js +3 -0
- package/dist/modules/staff/backend/staff/leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js +3 -0
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/page.js +3 -0
- package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js +3 -0
- package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +3 -0
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js +3 -0
- package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/page.js +29 -18
- package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js +3 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
- package/dist/modules/sync_excel/lib/adapters/customers.js +1 -0
- package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
- package/dist/modules/warranty_claims/api/assignees/route.js +3 -3
- package/dist/modules/warranty_claims/api/assignees/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/attachments/route.js +2 -2
- package/dist/modules/warranty_claims/api/portal/attachments/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/route.js +12 -9
- package/dist/modules/warranty_claims/api/portal/claims/route.js.map +2 -2
- package/dist/modules/warranty_claims/backend/page.js +3 -0
- package/dist/modules/warranty_claims/backend/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js +3 -0
- package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js +3 -0
- package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js +3 -0
- package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js.map +2 -2
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js +3 -0
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js.map +2 -2
- package/dist/modules/wms/api/warehouseSearch.js +21 -0
- package/dist/modules/wms/api/warehouseSearch.js.map +7 -0
- package/dist/modules/wms/api/warehouses/route.js +13 -9
- package/dist/modules/wms/api/warehouses/route.js.map +2 -2
- package/dist/modules/wms/api/zones/route.js +15 -2
- package/dist/modules/wms/api/zones/route.js.map +2 -2
- package/dist/modules/wms/commands/configuration.js +121 -9
- package/dist/modules/wms/commands/configuration.js.map +2 -2
- package/dist/modules/wms/commands/inventory-actions.js +3 -0
- package/dist/modules/wms/commands/inventory-actions.js.map +2 -2
- package/dist/modules/wms/commands/shared.js +9 -1
- package/dist/modules/wms/commands/shared.js.map +2 -2
- package/dist/modules/wms/components/backend/WarehouseEditDialog.js +158 -0
- package/dist/modules/wms/components/backend/WarehouseEditDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js +76 -111
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +3 -3
- package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +1 -0
- package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsLotsListPage.js +1 -0
- package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +2 -2
- package/dist/modules/wms/components/backend/inventoryMutationLoaders.js +27 -20
- package/dist/modules/wms/components/backend/inventoryMutationLoaders.js.map +2 -2
- package/dist/modules/wms/components/backend/warehouseFormOptions.js +66 -0
- package/dist/modules/wms/components/backend/warehouseFormOptions.js.map +7 -0
- package/dist/modules/workflows/backend/definitions/page.js +3 -1
- package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
- package/dist/modules/workflows/backend/events/page.js +3 -1
- package/dist/modules/workflows/backend/events/page.js.map +2 -2
- package/dist/modules/workflows/backend/instances/page.js +3 -1
- package/dist/modules/workflows/backend/instances/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/page.js +3 -1
- package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
- package/dist/modules/workflows/lib/activity-executor.js +4 -0
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/package.json +9 -10
- package/src/helpers/integration/api.ts +33 -1
- package/src/helpers/integration/communicationChannelsFixtures.ts +69 -1
- package/src/modules/api_keys/api/keys/route.ts +3 -1
- package/src/modules/api_keys/backend/api-keys/page.tsx +4 -1
- package/src/modules/api_keys/di.ts +7 -0
- package/src/modules/api_keys/services/principalService.ts +33 -0
- package/src/modules/attachments/AGENTS.md +15 -0
- package/src/modules/attachments/api/route.ts +2 -2
- package/src/modules/attachments/components/AttachmentLibrary.tsx +3 -0
- package/src/modules/attachments/di.ts +16 -0
- package/src/modules/attachments/i18n/de.json +5 -0
- package/src/modules/attachments/i18n/en.json +5 -0
- package/src/modules/attachments/i18n/es.json +5 -0
- package/src/modules/attachments/i18n/ko.json +5 -0
- package/src/modules/attachments/i18n/pl.json +5 -0
- package/src/modules/attachments/index.ts +10 -0
- package/src/modules/attachments/lib/attachment-service.ts +468 -0
- package/src/modules/attachments/lib/scoped-upload-service.ts +46 -0
- package/src/modules/attachments/lib/upload-limits.ts +6 -2
- package/src/modules/audit_logs/backend/audit-logs/page.tsx +8 -0
- package/src/modules/audit_logs/lib/display-helpers.tsx +42 -32
- package/src/modules/audit_logs/services/actionLogService.ts +74 -11
- package/src/modules/auth/acl.ts +30 -6
- package/src/modules/auth/api/feature-check.ts +10 -3
- package/src/modules/auth/api/login.ts +9 -1
- package/src/modules/auth/api/reset/validate.ts +57 -0
- package/src/modules/auth/api/roles/acl/route.ts +42 -39
- package/src/modules/auth/api/session/refresh.ts +32 -1
- package/src/modules/auth/api/users/acl/route.ts +177 -53
- package/src/modules/auth/api/users/route.ts +18 -5
- package/src/modules/auth/backend/roles/[id]/edit/page.meta.ts +5 -2
- package/src/modules/auth/backend/roles/page.tsx +4 -2
- package/src/modules/auth/backend/users/[id]/edit/page.meta.ts +5 -2
- package/src/modules/auth/backend/users/page.tsx +3 -2
- package/src/modules/auth/commands/acl.ts +495 -0
- package/src/modules/auth/components/AclEditor.tsx +63 -33
- package/src/modules/auth/data/entities.ts +4 -1
- package/src/modules/auth/data/validators.ts +5 -0
- package/src/modules/auth/di.ts +46 -16
- package/src/modules/auth/frontend/reset/[token]/page.tsx +74 -0
- package/src/modules/auth/i18n/de.json +389 -0
- package/src/modules/auth/i18n/en.json +389 -0
- package/src/modules/auth/i18n/es.json +389 -0
- package/src/modules/auth/i18n/ko.json +389 -0
- package/src/modules/auth/i18n/pl.json +391 -2
- package/src/modules/auth/lib/grantChecks.ts +6 -0
- package/src/modules/auth/lib/userIdFilter.ts +31 -0
- package/src/modules/auth/services/authService.ts +18 -2
- package/src/modules/auth/services/principalService.ts +266 -0
- package/src/modules/auth/services/rbacService.ts +110 -24
- package/src/modules/auth/services/roleOrganizationScope.ts +70 -0
- package/src/modules/business_rules/backend/logs/page.tsx +4 -1
- package/src/modules/business_rules/backend/rules/page.tsx +4 -1
- package/src/modules/business_rules/backend/sets/page.tsx +4 -1
- package/src/modules/business_rules/lib/expression-evaluator.ts +9 -9
- package/src/modules/business_rules/lib/rule-evaluator.ts +10 -9
- package/src/modules/catalog/ai-agents.ts +1 -1
- package/src/modules/catalog/ai-tools/merchandising-pack.ts +2 -2
- package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +12 -5
- package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +3 -0
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +7 -0
- package/src/modules/catalog/i18n/de.json +1 -0
- package/src/modules/catalog/i18n/en.json +1 -0
- package/src/modules/catalog/i18n/es.json +1 -0
- package/src/modules/catalog/i18n/ko.json +1 -0
- package/src/modules/catalog/i18n/pl.json +1 -0
- package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.tsx +4 -0
- package/src/modules/communication_channels/api/post/channels/[id]/test-send/route.ts +17 -1
- package/src/modules/communication_channels/api/post/test-seed/route.ts +155 -16
- package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +4 -0
- package/src/modules/communication_channels/commands/ingest-inbound-message.ts +38 -1
- package/src/modules/communication_channels/di.ts +7 -0
- package/src/modules/communication_channels/lib/adapter.ts +14 -0
- package/src/modules/communication_channels/lib/email-capabilities.ts +4 -0
- package/src/modules/communication_channels/lib/outbound-recipient.ts +71 -0
- package/src/modules/communication_channels/lib/resolve-channel-type.ts +99 -0
- package/src/modules/communication_channels/lib/test-seed.ts +64 -4
- package/src/modules/configs/i18n/de.json +2 -0
- package/src/modules/configs/i18n/en.json +2 -0
- package/src/modules/configs/i18n/es.json +2 -0
- package/src/modules/configs/i18n/ko.json +2 -0
- package/src/modules/configs/i18n/pl.json +2 -0
- package/src/modules/configs/lib/system-status.ts +9 -0
- package/src/modules/currencies/AGENTS.md +3 -0
- package/src/modules/currencies/backend/currencies/page.tsx +4 -1
- package/src/modules/currencies/backend/exchange-rates/page.tsx +4 -1
- package/src/modules/currencies/services/README.md +45 -0
- package/src/modules/currencies/services/rateFetchingService.ts +6 -1
- package/src/modules/customer_accounts/api/admin/domain-mappings.ts +7 -0
- package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +4 -1
- package/src/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.tsx +4 -1
- package/src/modules/customer_accounts/services/domainMappingService.ts +10 -0
- package/src/modules/customers/ai-tools/companies-pack.ts +4 -1
- package/src/modules/customers/ai-tools/deal-analyzer-pack.ts +17 -2
- package/src/modules/customers/ai-tools/deals-pack.ts +66 -1
- package/src/modules/customers/ai-tools/people-pack.ts +4 -1
- package/src/modules/customers/api/activities/route.ts +45 -0
- package/src/modules/customers/api/companies/[id]/people/route.ts +24 -73
- package/src/modules/customers/api/companies/[id]/route.ts +24 -107
- package/src/modules/customers/api/dashboard/widgets/customer-todos/route.ts +16 -8
- package/src/modules/customers/api/deals/[id]/companies/route.ts +4 -1
- package/src/modules/customers/api/deals/[id]/people/route.ts +4 -1
- package/src/modules/customers/api/deals/[id]/route.ts +17 -28
- package/src/modules/customers/api/deals/[id]/stats/route.ts +10 -25
- package/src/modules/customers/api/deals/aggregate/route.ts +17 -9
- package/src/modules/customers/api/deals/map/route.ts +4 -4
- package/src/modules/customers/api/deals/route.ts +50 -1
- package/src/modules/customers/api/entity-roles-factory.ts +8 -4
- package/src/modules/customers/api/interactions/route.ts +8 -2
- package/src/modules/customers/api/interactions/tasks/route.ts +24 -1
- package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +12 -4
- package/src/modules/customers/api/people/[id]/companies/context.ts +4 -1
- package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +4 -1
- package/src/modules/customers/api/people/[id]/route.ts +16 -11
- package/src/modules/customers/api/people/check-phone/route.ts +75 -10
- package/src/modules/customers/api/todos/route.ts +27 -2
- package/src/modules/customers/backend/customers/companies/page.tsx +5 -2
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +7 -2
- package/src/modules/customers/backend/customers/deals/page.tsx +8 -2
- package/src/modules/customers/backend/customers/deals/pipeline/components/Lane.tsx +5 -14
- package/src/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.tsx +109 -27
- package/src/modules/customers/backend/customers/deals/pipeline/components/toneClasses.ts +21 -0
- package/src/modules/customers/backend/customers/people/page.tsx +5 -2
- package/src/modules/customers/backend/hooks/useEmailDuplicateCheck.ts +12 -4
- package/src/modules/customers/commands/deals.ts +34 -59
- package/src/modules/customers/commands/interactions.ts +1 -1
- package/src/modules/customers/commands/personCompanyLinks.ts +224 -8
- package/src/modules/customers/components/CustomerTodosTable.tsx +2 -0
- package/src/modules/customers/components/DealsKpiStrip.tsx +7 -7
- package/src/modules/customers/components/calendar/AgendaList.tsx +3 -3
- package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +1 -1
- package/src/modules/customers/components/calendar/CalendarScreen.tsx +1 -1
- package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +1 -1
- package/src/modules/customers/components/calendar/EventBlock.tsx +2 -2
- package/src/modules/customers/components/calendar/EventPeekPopover.tsx +4 -2
- package/src/modules/customers/components/calendar/editor/PeopleField.tsx +61 -5
- package/src/modules/customers/components/calendar/editor/hooks.ts +7 -1
- package/src/modules/customers/components/calendar/types.ts +2 -2
- package/src/modules/customers/components/detail/CompanyKpiBar.tsx +5 -4
- package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +8 -1
- package/src/modules/customers/components/detail/DealForm.tsx +22 -2
- package/src/modules/customers/components/detail/DealsSection.tsx +11 -5
- package/src/modules/customers/components/detail/EntityTagsDialog.tsx +58 -12
- package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +8 -1
- package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +23 -14
- package/src/modules/customers/components/detail/schedule/ParticipantsField.tsx +5 -5
- package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +5 -5
- package/src/modules/customers/components/detail/types.ts +1 -1
- package/src/modules/customers/components/detail/utils.ts +15 -5
- package/src/modules/customers/data/entities.ts +1 -1
- package/src/modules/customers/data/validators.ts +50 -9
- package/src/modules/customers/events.ts +5 -0
- package/src/modules/customers/i18n/de.json +9 -1
- package/src/modules/customers/i18n/en.json +9 -1
- package/src/modules/customers/i18n/es.json +9 -1
- package/src/modules/customers/i18n/ko.json +9 -1
- package/src/modules/customers/i18n/pl.json +9 -1
- package/src/modules/customers/lib/calendar/conflicts.ts +10 -2
- package/src/modules/customers/lib/calendar/editorPayload.ts +4 -3
- package/src/modules/customers/lib/calendar/mapItem.ts +8 -3
- package/src/modules/customers/lib/calendar/participantIdentity.ts +17 -0
- package/src/modules/customers/lib/closureStage.ts +76 -0
- package/src/modules/customers/lib/dealStatus.ts +42 -0
- package/src/modules/customers/lib/detailReadAccess.ts +35 -0
- package/src/modules/customers/lib/findPeopleByAddresses.ts +8 -6
- package/src/modules/customers/lib/personCompanies.ts +136 -1
- package/src/modules/customers/lib/todoCompatibility.ts +19 -1
- package/src/modules/dashboards/i18n/es.json +4 -4
- package/src/modules/dashboards/i18n/pl.json +7 -7
- package/src/modules/dashboards/lib/widgetScope.ts +6 -0
- package/src/modules/data_sync/AGENTS.md +1 -1
- package/src/modules/data_sync/backend/data-sync/page.tsx +4 -1
- package/src/modules/data_sync/lib/abandoned-run.ts +56 -0
- package/src/modules/data_sync/lib/adapter.ts +36 -0
- package/src/modules/data_sync/lib/sync-engine.ts +113 -5
- package/src/modules/data_sync/workers/sync-export.ts +4 -0
- package/src/modules/data_sync/workers/sync-import.ts +4 -0
- package/src/modules/devices/AGENTS.md +20 -1
- package/src/modules/devices/acl.ts +9 -1
- package/src/modules/devices/api/admin/devices/[id]/route.ts +5 -34
- package/src/modules/devices/api/admin/devices/route.ts +14 -1
- package/src/modules/devices/api/deviceList.ts +135 -11
- package/src/modules/devices/api/deviceSerialization.ts +50 -0
- package/src/modules/devices/api/openapi.ts +9 -1
- package/src/modules/devices/api/route.ts +9 -1
- package/src/modules/devices/backend/devices/[id]/page.tsx +18 -32
- package/src/modules/devices/backend/devices/create/page.tsx +17 -1
- package/src/modules/devices/backend/devices/page.tsx +44 -45
- package/src/modules/devices/backend/devices/useDeviceUserLabels.ts +45 -0
- package/src/modules/devices/backend/devices/userOptions.ts +99 -0
- package/src/modules/devices/i18n/de.json +3 -2
- package/src/modules/devices/i18n/en.json +3 -2
- package/src/modules/devices/i18n/es.json +3 -2
- package/src/modules/devices/i18n/ko.json +3 -2
- package/src/modules/devices/i18n/pl.json +3 -2
- package/src/modules/devices/setup.ts +6 -2
- package/src/modules/directory/backend/directory/organizations/page.tsx +3 -1
- package/src/modules/directory/backend/directory/tenants/page.tsx +3 -1
- package/src/modules/directory/di.ts +14 -2
- package/src/modules/directory/services/organizationHierarchyService.ts +34 -0
- package/src/modules/directory/services/organizationScopeService.ts +85 -0
- package/src/modules/directory/utils/organizationScope.ts +4 -15
- package/src/modules/entities/api/records.ts +2 -0
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +4 -1
- package/src/modules/eudr/api/plots/route.ts +4 -0
- package/src/modules/eudr/backend/eudr/evidence-submissions/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/plots/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/product-mappings/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/risk-assessments/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/statements/page.tsx +4 -0
- package/src/modules/eudr/commands/statements.ts +0 -3
- package/src/modules/eudr/data/validators.ts +16 -1
- package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +2 -1
- package/src/modules/feature_toggles/components/OverridesTable.tsx +2 -1
- package/src/modules/feature_toggles/defaults.json +0 -8
- package/src/modules/inbox_ops/backend/inbox-ops/log/page.tsx +4 -0
- package/src/modules/inbox_ops/backend/inbox-ops/page.tsx +4 -0
- package/src/modules/inbox_ops/lib/htmlToPlainText.ts +1 -17
- package/src/modules/integrations/api/[id]/credentials/route.ts +6 -4
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +61 -31
- package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +44 -9
- package/src/modules/integrations/backend/integrations/credential-secret-fields.ts +84 -0
- package/src/modules/integrations/data/validators.ts +12 -2
- package/src/modules/integrations/i18n/de.json +1 -0
- package/src/modules/integrations/i18n/en.json +1 -0
- package/src/modules/integrations/i18n/es.json +1 -0
- package/src/modules/integrations/i18n/ko.json +1 -0
- package/src/modules/integrations/i18n/pl.json +1 -0
- package/src/modules/integrations/lib/credentials-masking.ts +10 -6
- package/src/modules/messages/api/[id]/route.ts +55 -1
- package/src/modules/messages/api/openapi.ts +20 -0
- package/src/modules/messages/api/route.ts +31 -2
- package/src/modules/messages/components/MessagesInboxPageClient.tsx +9 -16
- package/src/modules/messages/components/inboxFilters.ts +36 -0
- package/src/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.ts +14 -1
- package/src/modules/messages/components/message-detail/panels/MessageHeader.tsx +3 -1
- package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +2 -1
- package/src/modules/messages/components/message-detail/types.ts +3 -0
- package/src/modules/messages/components/messageListLabels.ts +52 -3
- package/src/modules/messages/data/validators.ts +43 -4
- package/src/modules/messages/lib/channel-sender-identity.ts +55 -0
- package/src/modules/messages/lib/composeSourceChannelType.ts +95 -0
- package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +4 -6
- package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +4 -1
- package/src/modules/payment_gateways/lib/webhook-processor.ts +11 -0
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +4 -0
- package/src/modules/push_notifications/backend/push_notifications/page.tsx +4 -1
- package/src/modules/push_notifications/backend/push_notifications/send/page.tsx +4 -4
- package/src/modules/query_index/lib/engine.ts +249 -61
- package/src/modules/query_index/lib/search-entity-policy.ts +46 -0
- package/src/modules/query_index/lib/search-tokens.ts +135 -3
- package/src/modules/resources/backend/resources/resource-types/page.tsx +4 -1
- package/src/modules/resources/backend/resources/resources/page.tsx +4 -1
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +4 -0
- package/src/modules/sales/backend/sales/channels/page.tsx +4 -0
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +14 -8
- package/src/modules/sales/commands/documents.ts +93 -0
- package/src/modules/sales/components/PriceWithCurrency.tsx +17 -5
- package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +4 -0
- package/src/modules/sales/components/documents/AdjustmentsSection.tsx +6 -5
- package/src/modules/sales/components/documents/ItemsSection.tsx +56 -18
- package/src/modules/sales/components/documents/LineItemDialog.tsx +137 -20
- package/src/modules/sales/components/documents/PaymentsSection.tsx +20 -9
- package/src/modules/sales/components/documents/ReturnsSection.tsx +6 -5
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +106 -14
- package/src/modules/sales/components/documents/SalesOrderDraftLines.tsx +6 -5
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +5 -4
- package/src/modules/sales/components/documents/ShipmentsSection.tsx +6 -5
- package/src/modules/sales/components/documents/lineItemShipmentLock.ts +74 -0
- package/src/modules/sales/components/documents/lineItemUtils.ts +7 -2
- package/src/modules/sales/data/entities.ts +6 -0
- package/src/modules/sales/extension-points.ts +1 -0
- package/src/modules/sales/i18n/de.json +8 -0
- package/src/modules/sales/i18n/en.json +8 -0
- package/src/modules/sales/i18n/es.json +8 -0
- package/src/modules/sales/i18n/ko.json +8 -0
- package/src/modules/sales/i18n/pl.json +8 -0
- package/src/modules/sales/lib/salesChannelsToggleSeed.ts +42 -0
- package/src/modules/sales/migrations/.snapshot-open-mercato.json +60 -0
- package/src/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.ts +87 -0
- package/src/modules/sales/setup.ts +2 -0
- package/src/modules/sales/widgets/injection/payment-gateway-status-column/widget.ts +9 -1
- package/src/modules/sales/widgets/injection-table.ts +4 -7
- package/src/modules/staff/backend/staff/leave-requests/page.tsx +4 -0
- package/src/modules/staff/backend/staff/my-leave-requests/page.tsx +4 -0
- package/src/modules/staff/backend/staff/team-members/page.tsx +6 -0
- package/src/modules/staff/backend/staff/team-roles/page.tsx +4 -0
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +4 -0
- package/src/modules/staff/backend/staff/teams/page.tsx +4 -0
- package/src/modules/staff/backend/staff/timesheets/page.tsx +12 -1
- package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +4 -0
- package/src/modules/sync_excel/lib/adapters/customers.ts +5 -0
- package/src/modules/warranty_claims/api/assignees/route.ts +3 -3
- package/src/modules/warranty_claims/api/portal/attachments/route.ts +2 -2
- package/src/modules/warranty_claims/api/portal/claims/route.ts +12 -9
- package/src/modules/warranty_claims/backend/page.tsx +4 -0
- package/src/modules/warranty_claims/backend/warranty_claims/registrations/page.tsx +4 -0
- package/src/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.tsx +4 -0
- package/src/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.tsx +4 -0
- package/src/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.tsx +4 -0
- package/src/modules/wms/api/warehouseSearch.ts +23 -0
- package/src/modules/wms/api/warehouses/route.ts +13 -9
- package/src/modules/wms/api/zones/route.ts +16 -0
- package/src/modules/wms/commands/configuration.ts +159 -10
- package/src/modules/wms/commands/inventory-actions.ts +3 -0
- package/src/modules/wms/commands/shared.ts +17 -0
- package/src/modules/wms/components/backend/WarehouseEditDialog.tsx +216 -0
- package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +95 -141
- package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +2 -0
- package/src/modules/wms/components/backend/WmsLotsListPage.tsx +2 -0
- package/src/modules/wms/components/backend/inventoryMutationLoaders.ts +36 -20
- package/src/modules/wms/components/backend/warehouseFormOptions.ts +72 -0
- package/src/modules/wms/i18n/de.json +2 -0
- package/src/modules/wms/i18n/en.json +2 -0
- package/src/modules/wms/i18n/es.json +2 -0
- package/src/modules/wms/i18n/ko.json +2 -0
- package/src/modules/wms/i18n/pl.json +2 -0
- package/src/modules/workflows/backend/definitions/page.tsx +4 -1
- package/src/modules/workflows/backend/events/page.tsx +4 -1
- package/src/modules/workflows/backend/instances/page.tsx +4 -1
- package/src/modules/workflows/backend/tasks/page.tsx +4 -1
- package/src/modules/workflows/lib/activity-executor.ts +9 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
import {
|
|
3
3
|
attachmentIdsPayloadSchema,
|
|
4
|
+
composeMessageRequestSchema,
|
|
4
5
|
composeMessageSchema,
|
|
5
6
|
executeActionSchema,
|
|
6
7
|
forwardMessageSchema,
|
|
@@ -50,11 +51,19 @@ export const messageListItemSchema = z.object({
|
|
|
50
51
|
threadId: z.string().uuid().nullable().optional(),
|
|
51
52
|
})
|
|
52
53
|
|
|
54
|
+
export const enrichmentMetaSchema = z.object({
|
|
55
|
+
enrichedBy: z.array(z.string()),
|
|
56
|
+
enricherErrors: z.array(z.string()).optional(),
|
|
57
|
+
})
|
|
58
|
+
|
|
53
59
|
export const messageThreadItemSchema = z.object({
|
|
54
60
|
id: z.string().uuid(),
|
|
55
61
|
senderUserId: z.string().uuid(),
|
|
56
62
|
senderName: z.string().nullable().optional(),
|
|
57
63
|
senderEmail: z.string().nullable().optional(),
|
|
64
|
+
externalName: z.string().nullable().optional(),
|
|
65
|
+
externalEmail: z.string().nullable().optional(),
|
|
66
|
+
sourceEntityType: z.string().nullable().optional(),
|
|
58
67
|
body: z.string(),
|
|
59
68
|
bodyFormat: z.enum(['text', 'markdown']).optional(),
|
|
60
69
|
sentAt: z.string().nullable().optional(),
|
|
@@ -126,7 +135,17 @@ export const messageDetailResponseSchema = z.object({
|
|
|
126
135
|
isRead: z.boolean(),
|
|
127
136
|
conversationArchived: z.boolean(),
|
|
128
137
|
conversationAllUnread: z.boolean(),
|
|
138
|
+
_channel: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
139
|
+
_channelPayload: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
140
|
+
_channelContact: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
141
|
+
_reactions: z.array(z.record(z.string(), z.unknown())).optional(),
|
|
142
|
+
_meta: enrichmentMetaSchema.optional(),
|
|
129
143
|
})
|
|
144
|
+
// The detail route runs response enrichers for `messages.message`, so any
|
|
145
|
+
// module registering one may contribute further `_`-prefixed keys. Without
|
|
146
|
+
// this the generator emits `additionalProperties: false` and the published
|
|
147
|
+
// spec forbids the very fields the route returns.
|
|
148
|
+
.passthrough()
|
|
130
149
|
|
|
131
150
|
export const messageTokenDetailResponseSchema = z.object({
|
|
132
151
|
id: z.string().uuid(),
|
|
@@ -265,6 +284,7 @@ export {
|
|
|
265
284
|
messageObjectSchema,
|
|
266
285
|
messageRecipientSchema,
|
|
267
286
|
composeMessageSchema,
|
|
287
|
+
composeMessageRequestSchema,
|
|
268
288
|
listMessagesSchema,
|
|
269
289
|
forwardMessageSchema,
|
|
270
290
|
replyMessageSchema,
|
|
@@ -17,6 +17,11 @@ import { lookupHashCandidates } from '@open-mercato/shared/lib/encryption/aes'
|
|
|
17
17
|
import { User } from '../../auth/data/entities'
|
|
18
18
|
import { Message, MessageObject } from '../data/entities'
|
|
19
19
|
import { composeMessageSchema, listMessagesSchema, type ListMessagesInput } from '../data/validators'
|
|
20
|
+
import {
|
|
21
|
+
composeRequiresChannelTypeResolution,
|
|
22
|
+
composeSourceHintSchema,
|
|
23
|
+
resolveComposeSourceChannelType,
|
|
24
|
+
} from '../lib/composeSourceChannelType'
|
|
20
25
|
import { MESSAGE_ATTACHMENT_ENTITY_ID } from '../lib/constants'
|
|
21
26
|
import { getMessageType } from '../lib/message-types-registry'
|
|
22
27
|
import { validateMessageObjectsForType } from '../lib/object-validation'
|
|
@@ -27,7 +32,7 @@ import { resolveUserFeatures, runMessageMutationGuardAfterSuccess, runMessageMut
|
|
|
27
32
|
import { findMessageIdsBySearchTokens } from '../lib/searchLookup'
|
|
28
33
|
import { MessageCommandExecuteResult } from '../commands/shared'
|
|
29
34
|
import {
|
|
30
|
-
|
|
35
|
+
composeMessageRequestSchema as composeSchema,
|
|
31
36
|
composeResponseSchema,
|
|
32
37
|
listMessagesSchema as listSchema,
|
|
33
38
|
messageListItemSchema,
|
|
@@ -445,7 +450,31 @@ export async function POST(req: Request) {
|
|
|
445
450
|
const { ctx, scope } = await resolveMessageContext(req)
|
|
446
451
|
const commandBus = ctx.container.resolve('commandBus') as CommandBus
|
|
447
452
|
const body = await req.json().catch(() => ({}))
|
|
448
|
-
|
|
453
|
+
|
|
454
|
+
// #4975: whether `externalEmail` is required depends on the channel this
|
|
455
|
+
// message originates from, so the channel type has to be established BEFORE
|
|
456
|
+
// validation. It is resolved server-side from the referenced conversation or
|
|
457
|
+
// parent message and any client-sent `sourceChannelType` is dropped —
|
|
458
|
+
// otherwise a caller could waive the requirement by asserting its own type.
|
|
459
|
+
// An unresolvable source stays `undefined`, which the validator fails closed on.
|
|
460
|
+
// Only the "public, non-draft, no address" branch of the validator reads the
|
|
461
|
+
// answer, so every other compose skips the lookup instead of discarding it.
|
|
462
|
+
const sourceHint = composeRequiresChannelTypeResolution(body)
|
|
463
|
+
? composeSourceHintSchema.safeParse(body)
|
|
464
|
+
: null
|
|
465
|
+
const sourceChannelType = sourceHint?.success
|
|
466
|
+
? await resolveComposeSourceChannelType(
|
|
467
|
+
ctx.container,
|
|
468
|
+
{ tenantId: scope.tenantId, organizationId: scope.organizationId ?? null },
|
|
469
|
+
sourceHint.data,
|
|
470
|
+
)
|
|
471
|
+
: undefined
|
|
472
|
+
const { sourceChannelType: _clientSuppliedChannelType, ...clientBody } =
|
|
473
|
+
(body ?? {}) as Record<string, unknown>
|
|
474
|
+
const input = composeMessageSchema.parse({
|
|
475
|
+
...clientBody,
|
|
476
|
+
...(sourceChannelType ? { sourceChannelType } : {}),
|
|
477
|
+
})
|
|
449
478
|
|
|
450
479
|
const isPublicVisibility = input.visibility === 'public'
|
|
451
480
|
const sendViaEmail = isPublicVisibility ? true : input.sendViaEmail
|
|
@@ -24,6 +24,7 @@ import { useMessagesInboxBulkActions, type MessageFolder } from './useMessagesIn
|
|
|
24
24
|
import {
|
|
25
25
|
buildMessagesInboxFilters,
|
|
26
26
|
buildMessagesListParams,
|
|
27
|
+
buildSenderOptionsFromMessages,
|
|
27
28
|
type SenderOption,
|
|
28
29
|
} from './inboxFilters'
|
|
29
30
|
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
@@ -38,6 +39,9 @@ type MessageListItem = {
|
|
|
38
39
|
senderUserId: string
|
|
39
40
|
senderName?: string | null
|
|
40
41
|
senderEmail?: string | null
|
|
42
|
+
externalName?: string | null
|
|
43
|
+
externalEmail?: string | null
|
|
44
|
+
sourceEntityType?: string | null
|
|
41
45
|
priority: string
|
|
42
46
|
status: string
|
|
43
47
|
hasObjects: boolean
|
|
@@ -58,6 +62,7 @@ type MessageListResponse = {
|
|
|
58
62
|
page?: number
|
|
59
63
|
pageSize?: number
|
|
60
64
|
totalPages?: number
|
|
65
|
+
totalIsCapped?: boolean
|
|
61
66
|
}
|
|
62
67
|
|
|
63
68
|
type MessageTypeItem = {
|
|
@@ -138,6 +143,7 @@ export function MessagesInboxPageClient() {
|
|
|
138
143
|
page: Number(call.result?.page ?? page),
|
|
139
144
|
pageSize: Number(call.result?.pageSize ?? pageSize),
|
|
140
145
|
totalPages: Number(call.result?.totalPages ?? 0),
|
|
146
|
+
totalIsCapped: call.result?.totalIsCapped === true,
|
|
141
147
|
}
|
|
142
148
|
},
|
|
143
149
|
})
|
|
@@ -236,22 +242,7 @@ export function MessagesInboxPageClient() {
|
|
|
236
242
|
|
|
237
243
|
React.useEffect(() => {
|
|
238
244
|
const items = listQuery.data?.items ?? []
|
|
239
|
-
|
|
240
|
-
if (typeof item.senderUserId !== 'string' || item.senderUserId.trim().length === 0) return []
|
|
241
|
-
const name = typeof item.senderName === 'string' && item.senderName.trim().length > 0
|
|
242
|
-
? item.senderName.trim()
|
|
243
|
-
: null
|
|
244
|
-
const email = typeof item.senderEmail === 'string' && item.senderEmail.trim().length > 0
|
|
245
|
-
? item.senderEmail.trim()
|
|
246
|
-
: null
|
|
247
|
-
const label = name ?? email ?? item.senderUserId
|
|
248
|
-
return [{
|
|
249
|
-
value: item.senderUserId,
|
|
250
|
-
label,
|
|
251
|
-
description: email && email !== label ? email : null,
|
|
252
|
-
}]
|
|
253
|
-
})
|
|
254
|
-
mergeSenderOptions(next)
|
|
245
|
+
mergeSenderOptions(buildSenderOptionsFromMessages(items))
|
|
255
246
|
}, [listQuery.data?.items, mergeSenderOptions])
|
|
256
247
|
|
|
257
248
|
React.useEffect(() => {
|
|
@@ -361,6 +352,7 @@ export function MessagesInboxPageClient() {
|
|
|
361
352
|
|
|
362
353
|
const rows = listQuery.data?.items ?? []
|
|
363
354
|
const total = listQuery.data?.total ?? 0
|
|
355
|
+
const totalIsCapped = listQuery.data?.totalIsCapped === true
|
|
364
356
|
const totalPages = listQuery.data?.totalPages ?? 0
|
|
365
357
|
|
|
366
358
|
return (
|
|
@@ -398,6 +390,7 @@ export function MessagesInboxPageClient() {
|
|
|
398
390
|
pageSize,
|
|
399
391
|
total,
|
|
400
392
|
totalPages,
|
|
393
|
+
totalIsCapped,
|
|
401
394
|
onPageChange: setPage,
|
|
402
395
|
}}
|
|
403
396
|
actions={
|
|
@@ -8,6 +8,42 @@ export type SenderOption = {
|
|
|
8
8
|
description?: string | null
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
type SenderOptionSource = {
|
|
12
|
+
senderUserId?: string | null
|
|
13
|
+
senderName?: string | null
|
|
14
|
+
senderEmail?: string | null
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Sender-filter options derived from the rows currently in the list.
|
|
19
|
+
*
|
|
20
|
+
* The filter narrows by `senderUserId`, so a row only yields an honest option
|
|
21
|
+
* when it also carries the platform identity behind that id. Ingested external
|
|
22
|
+
* mail does not: every such message in a tenant is composed under one
|
|
23
|
+
* system-user id, so labelling that id with one external sender's name would
|
|
24
|
+
* collapse every external sender into a single option that quietly returns all
|
|
25
|
+
* of their mail. Those rows are skipped, and the directory-loaded options —
|
|
26
|
+
* which are real platform users — stand alone.
|
|
27
|
+
*/
|
|
28
|
+
export function buildSenderOptionsFromMessages(items: SenderOptionSource[]): SenderOption[] {
|
|
29
|
+
return items.flatMap((item): SenderOption[] => {
|
|
30
|
+
if (typeof item.senderUserId !== 'string' || item.senderUserId.trim().length === 0) return []
|
|
31
|
+
const name = typeof item.senderName === 'string' && item.senderName.trim().length > 0
|
|
32
|
+
? item.senderName.trim()
|
|
33
|
+
: null
|
|
34
|
+
const email = typeof item.senderEmail === 'string' && item.senderEmail.trim().length > 0
|
|
35
|
+
? item.senderEmail.trim()
|
|
36
|
+
: null
|
|
37
|
+
const label = name ?? email
|
|
38
|
+
if (!label) return []
|
|
39
|
+
return [{
|
|
40
|
+
value: item.senderUserId,
|
|
41
|
+
label,
|
|
42
|
+
description: email && email !== label ? email : null,
|
|
43
|
+
}]
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
11
47
|
export type MessagesInboxFilterContext = {
|
|
12
48
|
t: Translator
|
|
13
49
|
typeOptions: { value: string; label: string }[]
|
package/src/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.ts
CHANGED
|
@@ -4,12 +4,16 @@ import * as React from 'react'
|
|
|
4
4
|
import type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'
|
|
5
5
|
import type { MessageListItemProps } from '@open-mercato/shared/modules/messages/types'
|
|
6
6
|
import type { MessageDetail } from '../types'
|
|
7
|
+
import { getMessageParticipantLabel } from '../../messageListLabels'
|
|
7
8
|
|
|
8
9
|
export type ConversationItem = {
|
|
9
10
|
id: string
|
|
10
11
|
senderUserId: string
|
|
11
12
|
senderName?: string | null
|
|
12
13
|
senderEmail?: string | null
|
|
14
|
+
externalName?: string | null
|
|
15
|
+
externalEmail?: string | null
|
|
16
|
+
sourceEntityType?: string | null
|
|
13
17
|
body: string
|
|
14
18
|
bodyFormat?: 'text' | 'markdown'
|
|
15
19
|
sentAt?: string | null
|
|
@@ -33,6 +37,9 @@ export function useMessageDetailsConversation({
|
|
|
33
37
|
senderUserId: detail.senderUserId,
|
|
34
38
|
senderName: detail.senderName,
|
|
35
39
|
senderEmail: detail.senderEmail,
|
|
40
|
+
externalName: detail.externalName,
|
|
41
|
+
externalEmail: detail.externalEmail,
|
|
42
|
+
sourceEntityType: detail.sourceEntityType,
|
|
36
43
|
body: detail.body,
|
|
37
44
|
bodyFormat: detail.bodyFormat,
|
|
38
45
|
sentAt: detail.sentAt,
|
|
@@ -46,6 +53,9 @@ export function useMessageDetailsConversation({
|
|
|
46
53
|
senderUserId: item.senderUserId,
|
|
47
54
|
senderName: item.senderName,
|
|
48
55
|
senderEmail: item.senderEmail,
|
|
56
|
+
externalName: item.externalName,
|
|
57
|
+
externalEmail: item.externalEmail,
|
|
58
|
+
sourceEntityType: item.sourceEntityType,
|
|
49
59
|
body: item.body,
|
|
50
60
|
bodyFormat: item.bodyFormat,
|
|
51
61
|
sentAt: item.sentAt,
|
|
@@ -58,6 +68,9 @@ export function useMessageDetailsConversation({
|
|
|
58
68
|
senderUserId: detail.senderUserId,
|
|
59
69
|
senderName: detail.senderName,
|
|
60
70
|
senderEmail: detail.senderEmail,
|
|
71
|
+
externalName: detail.externalName,
|
|
72
|
+
externalEmail: detail.externalEmail,
|
|
73
|
+
sourceEntityType: detail.sourceEntityType,
|
|
61
74
|
body: detail.body,
|
|
62
75
|
bodyFormat: detail.bodyFormat,
|
|
63
76
|
sentAt: detail.sentAt,
|
|
@@ -114,7 +127,7 @@ export function useMessageDetailsConversation({
|
|
|
114
127
|
bodyFormat: item.bodyFormat ?? 'text',
|
|
115
128
|
priority: 'normal',
|
|
116
129
|
sentAt: item.sentAt ? new Date(item.sentAt) : null,
|
|
117
|
-
senderName: item
|
|
130
|
+
senderName: getMessageParticipantLabel(item),
|
|
118
131
|
hasObjects: (item.objects ?? []).length > 0,
|
|
119
132
|
objectCount: (item.objects ?? []).length,
|
|
120
133
|
hasAttachments: false,
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
} from 'lucide-react'
|
|
19
19
|
import type { MessageDetail } from '../types'
|
|
20
20
|
import { formatDateTime } from '../utils'
|
|
21
|
+
import { getMessageParticipantLabel } from '../../messageListLabels'
|
|
21
22
|
|
|
22
23
|
type MessageHeaderProps = {
|
|
23
24
|
detail: MessageDetail
|
|
@@ -40,6 +41,7 @@ export function MessageHeader(props: MessageHeaderProps) {
|
|
|
40
41
|
const t = useT()
|
|
41
42
|
const showSubject = props.showSubject !== false
|
|
42
43
|
const canReply = !props.detail.isDraft && props.detail.typeDefinition.allowReply
|
|
44
|
+
const senderLabel = getMessageParticipantLabel(props.detail)
|
|
43
45
|
const actionItems = React.useMemo(() => {
|
|
44
46
|
const items: ActionItem[] = []
|
|
45
47
|
|
|
@@ -121,7 +123,7 @@ export function MessageHeader(props: MessageHeaderProps) {
|
|
|
121
123
|
<FormHeader
|
|
122
124
|
mode="detail"
|
|
123
125
|
title={showSubject ? props.detail.subject : undefined}
|
|
124
|
-
subtitle={`${t('messages.detail.from', 'From')}: ${
|
|
126
|
+
subtitle={`${t('messages.detail.from', 'From')}: ${senderLabel}`}
|
|
125
127
|
statusBadge={<p className="text-xs text-muted-foreground">{formatDateTime(props.detail.sentAt)}</p>}
|
|
126
128
|
utilityActions={canReply ? (
|
|
127
129
|
<IconButton
|
|
@@ -6,6 +6,7 @@ import { getMessageUiComponentRegistry } from '../../utils/typeUiRegistry'
|
|
|
6
6
|
import { getMessageObjectType } from '../../../lib/message-objects-registry'
|
|
7
7
|
import type { MessageDetail, MessageDetailObject } from '../types'
|
|
8
8
|
import { formatDateTime } from '../utils'
|
|
9
|
+
import { getMessageParticipantLabel } from '../../messageListLabels'
|
|
9
10
|
|
|
10
11
|
export function MessageDetailThreadSection({ detail }: { detail: MessageDetail }) {
|
|
11
12
|
const t = useT()
|
|
@@ -20,7 +21,7 @@ export function MessageDetailThreadSection({ detail }: { detail: MessageDetail }
|
|
|
20
21
|
{(detail.thread ?? []).map((threadItem) => (
|
|
21
22
|
<article key={threadItem.id} className="rounded border p-3">
|
|
22
23
|
<p className="text-xs text-muted-foreground">
|
|
23
|
-
{(threadItem
|
|
24
|
+
{getMessageParticipantLabel(threadItem)} • {formatDateTime(threadItem.sentAt)}
|
|
24
25
|
</p>
|
|
25
26
|
<div className="mt-2 max-h-[60vh] overflow-y-auto pr-1">
|
|
26
27
|
<MarkdownContent
|
|
@@ -94,6 +94,9 @@ export type MessageDetail = {
|
|
|
94
94
|
senderUserId: string
|
|
95
95
|
senderName?: string | null
|
|
96
96
|
senderEmail?: string | null
|
|
97
|
+
externalName?: string | null
|
|
98
|
+
externalEmail?: string | null
|
|
99
|
+
sourceEntityType?: string | null
|
|
97
100
|
body: string
|
|
98
101
|
bodyFormat?: 'text' | 'markdown'
|
|
99
102
|
sentAt?: string | null
|
|
@@ -2,9 +2,29 @@ import type { MessageFolder } from './useMessagesInboxBulkActions'
|
|
|
2
2
|
|
|
3
3
|
type Translate = (key: string, fallback: string, params?: Record<string, string | number>) => string
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* `Message.sourceEntityType` written by `communication_channels`'
|
|
7
|
+
* `ingest-inbound-message` command, and by nothing else — the outbound bridge
|
|
8
|
+
* treats it as the marker that a message arrived from outside the platform
|
|
9
|
+
* rather than being sent from it. It is the only reliable inbound
|
|
10
|
+
* discriminator: `type` is `channel.<provider>` on the outbound
|
|
11
|
+
* `send-as-user` path too, where `externalName` carries the recipient side.
|
|
12
|
+
*/
|
|
13
|
+
const INBOUND_EXTERNAL_SOURCE_ENTITY_TYPE = 'communication_channels.external_conversation'
|
|
14
|
+
|
|
5
15
|
type MessageParticipantSource = {
|
|
6
16
|
senderName?: string | null
|
|
7
17
|
senderEmail?: string | null
|
|
18
|
+
/**
|
|
19
|
+
* The external counterparty on a message that crosses the platform boundary —
|
|
20
|
+
* the sender for an inbound email/chat ingested by `communication_channels`,
|
|
21
|
+
* the recipient for an outbound reply sent through `inbox_ops`. Which side it
|
|
22
|
+
* represents is decided by `sourceEntityType`, not by whether a platform
|
|
23
|
+
* sender happens to be present.
|
|
24
|
+
*/
|
|
25
|
+
externalName?: string | null
|
|
26
|
+
externalEmail?: string | null
|
|
27
|
+
sourceEntityType?: string | null
|
|
8
28
|
senderUserId: string
|
|
9
29
|
recipientCount?: number | null
|
|
10
30
|
}
|
|
@@ -14,6 +34,37 @@ function normalizeLabel(value: string | null | undefined): string | null {
|
|
|
14
34
|
return normalized ? normalized : null
|
|
15
35
|
}
|
|
16
36
|
|
|
37
|
+
function isInboundExternalMessage(item: MessageParticipantSource): boolean {
|
|
38
|
+
return item.sourceEntityType === INBOUND_EXTERNAL_SOURCE_ENTITY_TYPE
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Human-readable label for a message's author.
|
|
43
|
+
*
|
|
44
|
+
* An ingested inbound message is authored by the external counterparty, even
|
|
45
|
+
* though it is composed under a platform user id: that id is the
|
|
46
|
+
* `communication_channels` system user, or — once an operator assigns the
|
|
47
|
+
* conversation — the assigned agent, who resolves to a real name in the user
|
|
48
|
+
* directory and would otherwise be printed as the author of the customer's own
|
|
49
|
+
* email. So on the inbound side the external identity wins, and the platform
|
|
50
|
+
* identity is only the fallback. Everywhere else the platform sender is the
|
|
51
|
+
* author and the external identity describes the recipient, so the order is
|
|
52
|
+
* reversed. The raw user id remains the last resort in both directions.
|
|
53
|
+
*
|
|
54
|
+
* The single source of truth for every place the messages module prints a
|
|
55
|
+
* participant — the inbox list, the detail header and the conversation rows —
|
|
56
|
+
* so an ingested email renders as "Jane Doe" / "jane@example.com" rather than
|
|
57
|
+
* the `communication_channels` system user id or the agent handling it.
|
|
58
|
+
*/
|
|
59
|
+
export function getMessageParticipantLabel(item: MessageParticipantSource): string {
|
|
60
|
+
const platformIdentity = normalizeLabel(item.senderName) ?? normalizeLabel(item.senderEmail)
|
|
61
|
+
const externalIdentity = normalizeLabel(item.externalName) ?? normalizeLabel(item.externalEmail)
|
|
62
|
+
const preferred = isInboundExternalMessage(item) ? externalIdentity : platformIdentity
|
|
63
|
+
const fallback = isInboundExternalMessage(item) ? platformIdentity : externalIdentity
|
|
64
|
+
|
|
65
|
+
return preferred ?? fallback ?? item.senderUserId
|
|
66
|
+
}
|
|
67
|
+
|
|
17
68
|
export function getMessageListParticipantLabel(
|
|
18
69
|
item: MessageParticipantSource,
|
|
19
70
|
folder: MessageFolder,
|
|
@@ -23,7 +74,5 @@ export function getMessageListParticipantLabel(
|
|
|
23
74
|
return t('messages.list.noRecipient', '(No recipient)')
|
|
24
75
|
}
|
|
25
76
|
|
|
26
|
-
return
|
|
27
|
-
?? normalizeLabel(item.senderEmail)
|
|
28
|
-
?? item.senderUserId
|
|
77
|
+
return getMessageParticipantLabel(item)
|
|
29
78
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
import { parseBooleanFlag } from '@open-mercato/shared/lib/boolean'
|
|
3
3
|
import { sanitizeRichTextHref } from '@open-mercato/shared/lib/html/sanitizeRichText'
|
|
4
|
+
import { channelTypeRequiresExternalEmail } from '../lib/channel-sender-identity'
|
|
4
5
|
|
|
5
6
|
function collectDuplicateRecipientIds(
|
|
6
7
|
recipients: Array<{ userId: string }>,
|
|
@@ -99,13 +100,22 @@ export const messageActionDataSchema = z.object({
|
|
|
99
100
|
expiresAt: z.string().datetime().optional(),
|
|
100
101
|
})
|
|
101
102
|
|
|
102
|
-
|
|
103
|
+
const composeMessageBaseSchema = z.object({
|
|
103
104
|
type: z.string().optional().default('default'),
|
|
104
105
|
visibility: z.enum(['public', 'internal']).nullable().optional(),
|
|
105
106
|
sourceEntityType: z.string().min(1).optional(),
|
|
106
107
|
sourceEntityId: z.string().uuid().optional(),
|
|
107
108
|
externalEmail: z.string().email().optional(),
|
|
108
109
|
externalName: z.string().min(1).max(255).optional(),
|
|
110
|
+
/**
|
|
111
|
+
* Channel type the message originates from, when the caller knows it (#4975).
|
|
112
|
+
* Non-email channels (Discord, Slack, SMS…) have senders with no address, so
|
|
113
|
+
* `externalEmail` is not required for them. Resolved server-side — the HTTP
|
|
114
|
+
* route strips any client-sent value and derives it from the referenced
|
|
115
|
+
* conversation or parent message, so a caller cannot waive the requirement by
|
|
116
|
+
* asserting its own channel type.
|
|
117
|
+
*/
|
|
118
|
+
sourceChannelType: z.string().min(1).max(64).optional(),
|
|
109
119
|
recipients: z.array(messageRecipientSchema).max(100).optional().default([]),
|
|
110
120
|
subject: z.string().max(500).optional().default(''),
|
|
111
121
|
body: z.string().max(50000).optional().default(''),
|
|
@@ -118,7 +128,14 @@ export const composeMessageSchema = z.object({
|
|
|
118
128
|
sendViaEmail: z.boolean().optional().default(false),
|
|
119
129
|
parentMessageId: z.string().uuid().optional(),
|
|
120
130
|
isDraft: z.boolean().optional().default(false),
|
|
121
|
-
})
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
type ComposeMessageRefinementValue = Omit<
|
|
134
|
+
z.infer<typeof composeMessageBaseSchema>,
|
|
135
|
+
'sourceChannelType'
|
|
136
|
+
> & { sourceChannelType?: string }
|
|
137
|
+
|
|
138
|
+
function refineComposeMessage(value: ComposeMessageRefinementValue, ctx: z.RefinementCtx): void {
|
|
122
139
|
const isDraft = value.isDraft ?? false
|
|
123
140
|
const visibility = value.visibility ?? 'internal'
|
|
124
141
|
const recipientCount = value.recipients.length
|
|
@@ -128,7 +145,10 @@ export const composeMessageSchema = z.object({
|
|
|
128
145
|
|
|
129
146
|
if (!isDraft) {
|
|
130
147
|
if (visibility === 'public') {
|
|
131
|
-
|
|
148
|
+
// #4975: an external correspondent is only guaranteed to have an address
|
|
149
|
+
// on an email-typed channel. `channelTypeRequiresExternalEmail` fails
|
|
150
|
+
// closed, so an unknown or absent channel type keeps the original rule.
|
|
151
|
+
if (!hasExternalEmail && channelTypeRequiresExternalEmail(value.sourceChannelType)) {
|
|
132
152
|
ctx.addIssue({
|
|
133
153
|
code: z.ZodIssueCode.custom,
|
|
134
154
|
path: ['externalEmail'],
|
|
@@ -176,7 +196,26 @@ export const composeMessageSchema = z.object({
|
|
|
176
196
|
}
|
|
177
197
|
|
|
178
198
|
validateDefaultWithObjectsPayload(value, ctx)
|
|
179
|
-
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Full compose contract, including the server-resolved `sourceChannelType`.
|
|
203
|
+
* Used by the `messages.messages.compose` command and by the HTTP route AFTER
|
|
204
|
+
* it has resolved the channel type itself.
|
|
205
|
+
*/
|
|
206
|
+
export const composeMessageSchema = composeMessageBaseSchema.superRefine(refineComposeMessage)
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Client-facing compose contract — the same rules minus `sourceChannelType`,
|
|
210
|
+
* which is never accepted from a request body (#4975). Published in OpenAPI so
|
|
211
|
+
* the documented request shape matches what `POST /api/messages` actually reads:
|
|
212
|
+
* the route discards any client-sent channel type, resolves the real one from
|
|
213
|
+
* the referenced conversation or parent message, and only then validates against
|
|
214
|
+
* {@link composeMessageSchema}.
|
|
215
|
+
*/
|
|
216
|
+
export const composeMessageRequestSchema = composeMessageBaseSchema
|
|
217
|
+
.omit({ sourceChannelType: true })
|
|
218
|
+
.superRefine(refineComposeMessage)
|
|
180
219
|
|
|
181
220
|
export const updateDraftSchema = z.object({
|
|
182
221
|
type: z.string().optional(),
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the hub decides whether an external correspondent must be identified by an
|
|
3
|
+
* email address.
|
|
4
|
+
*
|
|
5
|
+
* Background (#4975): `composeMessageSchema` used to require `externalEmail` for
|
|
6
|
+
* every non-draft message with `visibility: 'public'` — which is every message
|
|
7
|
+
* from an external sender. That assumption holds only for email-typed channels.
|
|
8
|
+
* A Discord sender is a snowflake and has no address at all, so inbound Discord
|
|
9
|
+
* failed validation deterministically and the ingest job died in the queue while
|
|
10
|
+
* the channel still reported `Connected`.
|
|
11
|
+
*
|
|
12
|
+
* Variant A of the spec's § Open decision — hub sender-identity contract makes
|
|
13
|
+
* the requirement conditional on the originating channel type, and **fails
|
|
14
|
+
* closed**: only a channel type this list positively recognizes as non-email
|
|
15
|
+
* waives the requirement. An unrecognized, empty or absent channel type keeps
|
|
16
|
+
* the pre-existing behaviour, so no current caller changes and a typo'd or
|
|
17
|
+
* caller-asserted type cannot quietly switch a validation rule off.
|
|
18
|
+
*
|
|
19
|
+
* For these channels the sender identity is not lost — it is carried by
|
|
20
|
+
* `ExternalMessage.sender_identifier` and joined 1:1 to the platform message
|
|
21
|
+
* through `MessageChannelLink`.
|
|
22
|
+
*
|
|
23
|
+
* Adding a channel type here is additive and non-breaking: it only widens the
|
|
24
|
+
* set of inputs the hub accepts.
|
|
25
|
+
*/
|
|
26
|
+
const NON_EMAIL_SENDER_CHANNEL_TYPES = new Set([
|
|
27
|
+
'discord',
|
|
28
|
+
'slack',
|
|
29
|
+
'teams',
|
|
30
|
+
'telegram',
|
|
31
|
+
'signal',
|
|
32
|
+
'whatsapp',
|
|
33
|
+
'messenger',
|
|
34
|
+
'instagram',
|
|
35
|
+
'sms',
|
|
36
|
+
'push',
|
|
37
|
+
])
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* True when a message originating from `channelType` must carry an
|
|
41
|
+
* `externalEmail` to be composed with `visibility: 'public'`.
|
|
42
|
+
*
|
|
43
|
+
* Fail-closed by design — see the note above.
|
|
44
|
+
*/
|
|
45
|
+
export function channelTypeRequiresExternalEmail(channelType?: string | null): boolean {
|
|
46
|
+
if (typeof channelType !== 'string') return true
|
|
47
|
+
const normalized = channelType.trim().toLowerCase()
|
|
48
|
+
if (!normalized) return true
|
|
49
|
+
return !NON_EMAIL_SENDER_CHANNEL_TYPES.has(normalized)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** The recognized non-email channel types, for tests and diagnostics. */
|
|
53
|
+
export function listNonEmailSenderChannelTypes(): string[] {
|
|
54
|
+
return Array.from(NON_EMAIL_SENDER_CHANNEL_TYPES).sort((left, right) => left.localeCompare(right))
|
|
55
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Entity type a channel-backed conversation is exposed under on a message's
|
|
5
|
+
* `sourceEntityType`. Written by `communication_channels`' inbound ingest.
|
|
6
|
+
*/
|
|
7
|
+
const EXTERNAL_CONVERSATION_SOURCE_ENTITY_TYPE = 'communication_channels.external_conversation'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The only parts of a compose body this resolution needs. Read defensively from
|
|
11
|
+
* the raw request body, before the body is validated, because the validation
|
|
12
|
+
* outcome itself depends on the answer (#4975).
|
|
13
|
+
*/
|
|
14
|
+
export const composeSourceHintSchema = z.object({
|
|
15
|
+
sourceEntityType: z.string().optional(),
|
|
16
|
+
sourceEntityId: z.string().uuid().optional(),
|
|
17
|
+
parentMessageId: z.string().uuid().optional(),
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
export type ComposeSourceHint = z.infer<typeof composeSourceHintSchema>
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Whether the compose validator can consult a resolved channel type at all.
|
|
24
|
+
*
|
|
25
|
+
* `sourceChannelType` is read in exactly one branch — a non-draft, public
|
|
26
|
+
* message that carries no address. Every internal reply, every draft and every
|
|
27
|
+
* public message that already supplies an address ignores it, so resolving it
|
|
28
|
+
* for them is a DI resolve plus a database round-trip whose answer is
|
|
29
|
+
* discarded. Mirrors `refineComposeMessage` and reads the raw body defensively,
|
|
30
|
+
* because this runs before validation. Skipping resolution yields `undefined`,
|
|
31
|
+
* which is already the fail-closed value.
|
|
32
|
+
*/
|
|
33
|
+
export function composeRequiresChannelTypeResolution(body: unknown): boolean {
|
|
34
|
+
if (!body || typeof body !== 'object') return false
|
|
35
|
+
const raw = body as Record<string, unknown>
|
|
36
|
+
if (raw.visibility !== 'public') return false
|
|
37
|
+
if (raw.isDraft === true) return false
|
|
38
|
+
const externalEmail = raw.externalEmail
|
|
39
|
+
return !(typeof externalEmail === 'string' && externalEmail.trim().length > 0)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type ResolveChannelTypeService = (
|
|
43
|
+
container: ContainerLike,
|
|
44
|
+
scope: { tenantId: string; organizationId: string | null },
|
|
45
|
+
reference: { externalConversationId?: string | null; messageId?: string | null },
|
|
46
|
+
) => Promise<string | null>
|
|
47
|
+
|
|
48
|
+
type ContainerLike = { resolve: <T = unknown>(name: string) => T }
|
|
49
|
+
|
|
50
|
+
function tryResolveChannelTypeService(
|
|
51
|
+
container: ContainerLike,
|
|
52
|
+
): ResolveChannelTypeService | undefined {
|
|
53
|
+
try {
|
|
54
|
+
return container.resolve<ResolveChannelTypeService>('communicationChannelsResolveChannelType')
|
|
55
|
+
} catch {
|
|
56
|
+
// `communication_channels` is optional: without it no message can originate
|
|
57
|
+
// from a channel, so "unknown" is both correct and fail-closed.
|
|
58
|
+
return undefined
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Resolve the channel type a compose request originates from, server-side.
|
|
64
|
+
*
|
|
65
|
+
* Never derived from the request body's own `sourceChannelType` — that would let
|
|
66
|
+
* any caller waive the `externalEmail` requirement by asserting a channel type.
|
|
67
|
+
* It is looked up from the conversation the message is being composed on, or
|
|
68
|
+
* from the parent message it replies to.
|
|
69
|
+
*
|
|
70
|
+
* Returns `undefined` when nothing can be established, which the compose
|
|
71
|
+
* validator treats as "unknown" and therefore keeps the pre-#4975 rule.
|
|
72
|
+
*/
|
|
73
|
+
export async function resolveComposeSourceChannelType(
|
|
74
|
+
container: ContainerLike,
|
|
75
|
+
scope: { tenantId: string; organizationId: string | null },
|
|
76
|
+
hint: ComposeSourceHint,
|
|
77
|
+
): Promise<string | undefined> {
|
|
78
|
+
const externalConversationId =
|
|
79
|
+
hint.sourceEntityType === EXTERNAL_CONVERSATION_SOURCE_ENTITY_TYPE
|
|
80
|
+
? hint.sourceEntityId ?? null
|
|
81
|
+
: null
|
|
82
|
+
const messageId = hint.parentMessageId ?? null
|
|
83
|
+
if (!externalConversationId && !messageId) return undefined
|
|
84
|
+
|
|
85
|
+
const resolveChannelType = tryResolveChannelTypeService(container)
|
|
86
|
+
if (!resolveChannelType) return undefined
|
|
87
|
+
|
|
88
|
+
const channelType = await resolveChannelType(container, scope, {
|
|
89
|
+
externalConversationId,
|
|
90
|
+
messageId,
|
|
91
|
+
})
|
|
92
|
+
return channelType ?? undefined
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export { EXTERNAL_CONVERSATION_SOURCE_ENTITY_TYPE }
|