@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
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { registerCommand } from "@open-mercato/shared/lib/commands";
|
|
2
|
+
import { snapshotsEqual } from "@open-mercato/shared/lib/commands/helpers";
|
|
3
|
+
import { withAtomicFlush } from "@open-mercato/shared/lib/commands/flush";
|
|
4
|
+
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
5
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
6
|
+
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
7
|
+
import { Role, RoleAcl, User, UserAcl } from "@open-mercato/core/modules/auth/data/entities";
|
|
8
|
+
const logger = createLogger("auth").child({ component: "acl-commands" });
|
|
9
|
+
const EMPTY_ACL_SNAPSHOT = {
|
|
10
|
+
isSuperAdmin: false,
|
|
11
|
+
features: [],
|
|
12
|
+
organizations: null
|
|
13
|
+
};
|
|
14
|
+
function compareIdentifiers(left, right) {
|
|
15
|
+
if (left === right) return 0;
|
|
16
|
+
return left < right ? -1 : 1;
|
|
17
|
+
}
|
|
18
|
+
function toSortedList(values) {
|
|
19
|
+
if (!Array.isArray(values)) return [];
|
|
20
|
+
return [...values].filter((value) => typeof value === "string").sort(compareIdentifiers);
|
|
21
|
+
}
|
|
22
|
+
function captureAclSnapshot(acl) {
|
|
23
|
+
if (!acl) return { ...EMPTY_ACL_SNAPSHOT };
|
|
24
|
+
return {
|
|
25
|
+
isSuperAdmin: Boolean(acl.isSuperAdmin),
|
|
26
|
+
features: toSortedList(acl.featuresJson),
|
|
27
|
+
organizations: Array.isArray(acl.organizationsJson) ? toSortedList(acl.organizationsJson) : null
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function holdsGrants(snapshot) {
|
|
31
|
+
return snapshot.isSuperAdmin || snapshot.features.length > 0;
|
|
32
|
+
}
|
|
33
|
+
function resolveEffect(before, after) {
|
|
34
|
+
if (!holdsGrants(before) && holdsGrants(after)) return "granted";
|
|
35
|
+
if (holdsGrants(before) && !holdsGrants(after)) return "revoked";
|
|
36
|
+
return "changed";
|
|
37
|
+
}
|
|
38
|
+
function resolveEm(ctx) {
|
|
39
|
+
return ctx.container.resolve("em");
|
|
40
|
+
}
|
|
41
|
+
function resolveOrganizationId(ctx, tenantId) {
|
|
42
|
+
if ((ctx.auth?.tenantId ?? null) !== tenantId) return null;
|
|
43
|
+
return ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null;
|
|
44
|
+
}
|
|
45
|
+
async function deleteCacheTags(ctx, tags) {
|
|
46
|
+
let cache;
|
|
47
|
+
try {
|
|
48
|
+
cache = ctx.container.resolve("cache");
|
|
49
|
+
} catch (err) {
|
|
50
|
+
logger.debug("No cache registered for ACL tag invalidation", { err, tags });
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (!cache?.deleteByTags) return;
|
|
54
|
+
await cache.deleteByTags(tags);
|
|
55
|
+
}
|
|
56
|
+
const AUTH_ROLE_ACL_UPDATE_COMMAND_ID = "auth.role-acl.update";
|
|
57
|
+
const AUTH_USER_ACL_UPDATE_COMMAND_ID = "auth.user-acl.update";
|
|
58
|
+
async function loadTargetSafely(config, input, ctx) {
|
|
59
|
+
try {
|
|
60
|
+
return await config.loadTarget(resolveEm(ctx).fork(), input, ctx);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
logger.warn("Could not resolve the ACL target for the audit entry", {
|
|
63
|
+
err,
|
|
64
|
+
commandId: config.id,
|
|
65
|
+
resourceId: config.resourceId(input),
|
|
66
|
+
tenantId: input.tenantId
|
|
67
|
+
});
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function buildAuditContext(params) {
|
|
72
|
+
const context = {};
|
|
73
|
+
if (params.target) context.target = params.target;
|
|
74
|
+
if (params.effect) context.effect = params.effect;
|
|
75
|
+
if (params.sanitizedRequest) context.sanitizedRequest = params.sanitizedRequest;
|
|
76
|
+
return Object.keys(context).length ? context : null;
|
|
77
|
+
}
|
|
78
|
+
function createAclUpdateCommand(config) {
|
|
79
|
+
return {
|
|
80
|
+
id: config.id,
|
|
81
|
+
// See "Auth ACL Commands — Undo Policy" at top of file.
|
|
82
|
+
isUndoable: false,
|
|
83
|
+
async prepare(input, ctx) {
|
|
84
|
+
const existing = await config.loadAcl(resolveEm(ctx).fork(), input);
|
|
85
|
+
return { before: captureAclSnapshot(existing) };
|
|
86
|
+
},
|
|
87
|
+
async execute(input, ctx) {
|
|
88
|
+
const em = resolveEm(ctx);
|
|
89
|
+
const existing = await config.loadAcl(em, input);
|
|
90
|
+
await config.persist({ em, input, existing });
|
|
91
|
+
try {
|
|
92
|
+
await config.invalidate({ ctx, input });
|
|
93
|
+
} catch (err) {
|
|
94
|
+
logger.error("ACL cache invalidation failed after a committed permission change", {
|
|
95
|
+
err,
|
|
96
|
+
commandId: config.id,
|
|
97
|
+
resourceId: config.resourceId(input),
|
|
98
|
+
tenantId: input.tenantId
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
resourceId: config.resourceId(input),
|
|
103
|
+
tenantId: input.tenantId,
|
|
104
|
+
organizationId: resolveOrganizationId(ctx, input.tenantId)
|
|
105
|
+
};
|
|
106
|
+
},
|
|
107
|
+
captureAfter: async (input, _result, ctx) => {
|
|
108
|
+
const persisted = await config.loadAcl(resolveEm(ctx).fork(), input);
|
|
109
|
+
if (persisted) return captureAclSnapshot(persisted);
|
|
110
|
+
return config.snapshotWhenAbsent(input);
|
|
111
|
+
},
|
|
112
|
+
buildLog: async ({ input, result, ctx, snapshots }) => {
|
|
113
|
+
const before = snapshots.before ?? null;
|
|
114
|
+
const after = snapshots.after ?? null;
|
|
115
|
+
const changed = !before || !after || !snapshotsEqual(before, after);
|
|
116
|
+
const sanitizedRequest = config.sanitizedRequest?.(input) ?? null;
|
|
117
|
+
if (!changed && !sanitizedRequest) return { skipLog: true };
|
|
118
|
+
const { translate } = await resolveTranslations();
|
|
119
|
+
const target = await loadTargetSafely(config, input, ctx);
|
|
120
|
+
return {
|
|
121
|
+
actionLabel: translate(config.labelKey, config.labelFallback),
|
|
122
|
+
resourceKind: config.resourceKind,
|
|
123
|
+
resourceId: result.resourceId,
|
|
124
|
+
tenantId: result.tenantId,
|
|
125
|
+
organizationId: result.organizationId,
|
|
126
|
+
snapshotBefore: before,
|
|
127
|
+
snapshotAfter: after,
|
|
128
|
+
context: buildAuditContext({
|
|
129
|
+
target,
|
|
130
|
+
// A sanitized-only entry is written *because* nothing changed, so
|
|
131
|
+
// labelling it would have the trail assert a permission change that
|
|
132
|
+
// never happened.
|
|
133
|
+
effect: changed && before && after ? resolveEffect(before, after) : null,
|
|
134
|
+
sanitizedRequest
|
|
135
|
+
})
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
const updateRoleAclCommand = createAclUpdateCommand({
|
|
141
|
+
id: AUTH_ROLE_ACL_UPDATE_COMMAND_ID,
|
|
142
|
+
resourceKind: "auth.role_acl",
|
|
143
|
+
labelKey: "auth.audit.roleAcl.update",
|
|
144
|
+
labelFallback: "Change role permissions",
|
|
145
|
+
resourceId: (input) => input.roleId,
|
|
146
|
+
loadAcl: (em, input) => em.findOne(RoleAcl, { role: input.roleId, tenantId: input.tenantId }),
|
|
147
|
+
persist: async ({ em, input, existing }) => {
|
|
148
|
+
const acl = existing ?? em.create(RoleAcl, {
|
|
149
|
+
role: em.getReference(Role, input.roleId),
|
|
150
|
+
tenantId: input.tenantId,
|
|
151
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
152
|
+
isSuperAdmin: false
|
|
153
|
+
});
|
|
154
|
+
await withAtomicFlush(
|
|
155
|
+
em,
|
|
156
|
+
[
|
|
157
|
+
() => {
|
|
158
|
+
acl.organizationsJson = input.organizations;
|
|
159
|
+
acl.isSuperAdmin = input.isSuperAdmin;
|
|
160
|
+
acl.featuresJson = input.features;
|
|
161
|
+
em.persist(acl);
|
|
162
|
+
}
|
|
163
|
+
],
|
|
164
|
+
{ transaction: true, label: AUTH_ROLE_ACL_UPDATE_COMMAND_ID }
|
|
165
|
+
);
|
|
166
|
+
},
|
|
167
|
+
invalidate: async ({ ctx, input }) => {
|
|
168
|
+
const rbacService = ctx.container.resolve("rbacService");
|
|
169
|
+
await rbacService.invalidateTenantCache(input.tenantId);
|
|
170
|
+
await deleteCacheTags(ctx, [`rbac:tenant:${input.tenantId}`]);
|
|
171
|
+
},
|
|
172
|
+
snapshotWhenAbsent: () => null,
|
|
173
|
+
// Looked up by id alone: the entry already names this role through
|
|
174
|
+
// `resource_id`, and a tenant predicate would only blank the label when a
|
|
175
|
+
// super admin edits a role from outside the tenant scope they are writing in.
|
|
176
|
+
loadTarget: async (em, input) => {
|
|
177
|
+
const role = await em.findOne(Role, { id: input.roleId });
|
|
178
|
+
if (!role) return null;
|
|
179
|
+
return { kind: "role", id: input.roleId, name: role.name ?? null };
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
const updateUserAclCommand = createAclUpdateCommand({
|
|
183
|
+
id: AUTH_USER_ACL_UPDATE_COMMAND_ID,
|
|
184
|
+
resourceKind: "auth.user_acl",
|
|
185
|
+
labelKey: "auth.audit.userAcl.update",
|
|
186
|
+
labelFallback: "Change user permissions",
|
|
187
|
+
resourceId: (input) => input.userId,
|
|
188
|
+
loadAcl: (em, input) => em.findOne(UserAcl, { user: input.userId, tenantId: input.tenantId }),
|
|
189
|
+
persist: async ({ em, input, existing }) => {
|
|
190
|
+
if (input.clear) {
|
|
191
|
+
if (!existing) return;
|
|
192
|
+
const aclToRemove = existing;
|
|
193
|
+
await withAtomicFlush(
|
|
194
|
+
em,
|
|
195
|
+
[
|
|
196
|
+
() => {
|
|
197
|
+
em.remove(aclToRemove);
|
|
198
|
+
}
|
|
199
|
+
],
|
|
200
|
+
{ transaction: true, label: AUTH_USER_ACL_UPDATE_COMMAND_ID }
|
|
201
|
+
);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const acl = existing ?? em.create(UserAcl, {
|
|
205
|
+
user: em.getReference(User, input.userId),
|
|
206
|
+
tenantId: input.tenantId,
|
|
207
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
208
|
+
isSuperAdmin: false
|
|
209
|
+
});
|
|
210
|
+
await withAtomicFlush(
|
|
211
|
+
em,
|
|
212
|
+
[
|
|
213
|
+
() => {
|
|
214
|
+
acl.isSuperAdmin = input.isSuperAdmin;
|
|
215
|
+
acl.featuresJson = input.features;
|
|
216
|
+
acl.organizationsJson = input.organizations;
|
|
217
|
+
em.persist(acl);
|
|
218
|
+
}
|
|
219
|
+
],
|
|
220
|
+
{ transaction: true, label: AUTH_USER_ACL_UPDATE_COMMAND_ID }
|
|
221
|
+
);
|
|
222
|
+
},
|
|
223
|
+
invalidate: async ({ ctx, input }) => {
|
|
224
|
+
const rbacService = ctx.container.resolve("rbacService");
|
|
225
|
+
await rbacService.invalidateUserCache(input.userId);
|
|
226
|
+
await deleteCacheTags(ctx, [`rbac:user:${input.userId}`]);
|
|
227
|
+
},
|
|
228
|
+
// Clearing removes the row, so an absent row is the real post-state here.
|
|
229
|
+
snapshotWhenAbsent: (input) => input.clear ? { ...EMPTY_ACL_SNAPSHOT } : null,
|
|
230
|
+
// `userId` arrives in the request body and `auth:user` carries encrypted
|
|
231
|
+
// personal data, so the lookup is tenant-scoped: an id belonging to another
|
|
232
|
+
// tenant must not be decrypted under this scope and stamped into this
|
|
233
|
+
// tenant's trail. A global account (`users.tenant_id` is nullable) still
|
|
234
|
+
// resolves, mirroring how the role route widens its own lookup.
|
|
235
|
+
loadTarget: async (em, input, ctx) => {
|
|
236
|
+
const user = await findOneWithDecryption(
|
|
237
|
+
em,
|
|
238
|
+
User,
|
|
239
|
+
{ id: input.userId, $or: [{ tenantId: input.tenantId }, { tenantId: null }] },
|
|
240
|
+
{},
|
|
241
|
+
{ tenantId: input.tenantId, organizationId: ctx.auth?.orgId ?? null }
|
|
242
|
+
);
|
|
243
|
+
if (!user) return null;
|
|
244
|
+
return { kind: "user", id: input.userId, email: user.email ?? null, name: user.name ?? null };
|
|
245
|
+
},
|
|
246
|
+
sanitizedRequest: (input) => input.requested ?? null
|
|
247
|
+
});
|
|
248
|
+
registerCommand(updateRoleAclCommand);
|
|
249
|
+
registerCommand(updateUserAclCommand);
|
|
250
|
+
export {
|
|
251
|
+
AUTH_ROLE_ACL_UPDATE_COMMAND_ID,
|
|
252
|
+
AUTH_USER_ACL_UPDATE_COMMAND_ID
|
|
253
|
+
};
|
|
254
|
+
//# sourceMappingURL=acl.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/auth/commands/acl.ts"],
|
|
4
|
+
"sourcesContent": ["// =============================================================================\n// Auth ACL Commands \u2014 Undo Policy\n// =============================================================================\n//\n// Neither command in this file defines `undo` or `redo`, so the command bus\n// never mints an undo token for them: `CommandBus.isUndoable()` requires a\n// handler-provided `undo`. The explicit `isUndoable: false` below is executable\n// documentation of that intent, not the mechanism \u2014 the guarantee comes from\n// the absence of the handlers, and the unit tests pin both.\n//\n// The policy is deliberate even though an ACL grant is trivially reversible.\n// The undo and redo endpoints are gated on `audit_logs.undo_self` /\n// `audit_logs.undo_tenant` (and their redo counterparts), not on\n// `auth.acl.manage`. `audit_logs.undo_self` is a default `employee` grant and\n// `audit_logs.undo_tenant` reaches every `admin` through `audit_logs.*`, so an\n// undoable ACL command would let a caller revert or replay someone else's\n// permission change without ever holding the feature that authorizes editing\n// permissions.\n//\n// Reversal stays available to the callers who are actually authorized for it:\n// re-submitting the ACL form, gated on `auth.acl.manage` and guarded by\n// `assertActorCanGrantAcl`. The audit log still captures the full before/after\n// via `buildLog`, so any such correction is itself fully traceable.\n// =============================================================================\nimport type { CommandHandler, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { snapshotsEqual } from '@open-mercato/shared/lib/commands/helpers'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\nimport { Role, RoleAcl, User, UserAcl } from '@open-mercato/core/modules/auth/data/entities'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\n\nconst logger = createLogger('auth').child({ component: 'acl-commands' })\n\ntype TaggableCache = { deleteByTags?: (tags: string[]) => Promise<void> | void }\n\n/** Structural view of the fields both `RoleAcl` and `UserAcl` expose. */\ntype AclRecord = {\n isSuperAdmin: boolean\n featuresJson?: string[] | null\n organizationsJson?: string[] | null\n}\n\n/**\n * Audit snapshot of a single ACL row.\n *\n * `features` and `organizations` are grant *sets*, but `features_json` /\n * `organizations_json` preserve the client's insertion order. The command bus\n * derives `changes` from these snapshots with a deep equality check that is\n * order-sensitive for arrays, so an unsorted snapshot would report a spurious\n * `features` change every time an admin re-saves an unmodified form. Sorting\n * here makes the derived diff reflect real grant changes only.\n *\n * `organizations: null` (visible in every organization) is deliberately\n * distinct from `[]` (visible in none).\n */\ntype AclSnapshot = {\n isSuperAdmin: boolean\n features: string[]\n organizations: string[] | null\n}\n\nconst EMPTY_ACL_SNAPSHOT: AclSnapshot = {\n isSuperAdmin: false,\n features: [],\n organizations: null,\n}\n\n/**\n * Identity of the role or user an entry is about.\n *\n * `action_logs` keeps only `resource_id`, so an entry degrades to a bare UUID\n * the moment the role or account is deleted \u2014 exactly when the trail matters\n * most. This rides in `context` rather than in the snapshots because the\n * command bus derives `changes` from the two snapshots with a deep comparison:\n * a target renamed between two ACL edits would otherwise be reported as a\n * permission change, and the no-op guard below would stop recognising an\n * unchanged ACL.\n */\ntype AclTarget =\n | { kind: 'user'; id: string; email: string | null; name: string | null }\n | { kind: 'role'; id: string; name: string | null }\n\n/**\n * What the caller asked for when the route trimmed the request instead of\n * refusing it.\n *\n * `sanitizeTenantFeatures` drops restricted grants silently, so such a request\n * leaves `before` and `after` identical and is indistinguishable from a no-op \u2014\n * which `buildLog` skips. Recording the original request both keeps the attempt\n * visible and exempts the entry from that guard.\n *\n * Features are the only axis carried, because they are the only one the route\n * can trim: a super-admin request is honoured or refused outright, and\n * organizations are never sanitized. Recording either would put a value next to\n * the snapshots that always matches them, inviting a reader to diff the two and\n * conclude a grant was refused.\n */\ntype SanitizedAclRequest = {\n features: string[]\n}\n\n/** How the change reads at a glance, without diffing two grant lists. */\ntype AclChangeEffect = 'granted' | 'changed' | 'revoked'\n\n/**\n * Codepoint ordering rather than `localeCompare`: these snapshots are persisted\n * audit records, so the ordering must not shift with the runtime's default\n * locale. Feature and organization ids are opaque ASCII identifiers that are\n * never shown in this order to a user.\n *\n * The default comparator would coerce and compare the same way today, but\n * omitting one is banned repo-wide (`explicit-sort-comparators.test.ts`,\n * #3620): the ordering must be stated rather than inherited, so it cannot\n * silently change meaning if a call site ever drifts to non-strings. This is\n * the canonical-key form that audit prescribes.\n */\nfunction compareIdentifiers(left: string, right: string): number {\n if (left === right) return 0\n return left < right ? -1 : 1\n}\n\nfunction toSortedList(values: unknown): string[] {\n if (!Array.isArray(values)) return []\n return [...values].filter((value): value is string => typeof value === 'string').sort(compareIdentifiers)\n}\n\nfunction captureAclSnapshot(acl: AclRecord | null | undefined): AclSnapshot {\n if (!acl) return { ...EMPTY_ACL_SNAPSHOT }\n return {\n isSuperAdmin: Boolean(acl.isSuperAdmin),\n features: toSortedList(acl.featuresJson),\n organizations: Array.isArray(acl.organizationsJson) ? toSortedList(acl.organizationsJson) : null,\n }\n}\n\nfunction holdsGrants(snapshot: AclSnapshot): boolean {\n return snapshot.isSuperAdmin || snapshot.features.length > 0\n}\n\nfunction resolveEffect(before: AclSnapshot, after: AclSnapshot): AclChangeEffect {\n if (!holdsGrants(before) && holdsGrants(after)) return 'granted'\n if (holdsGrants(before) && !holdsGrants(after)) return 'revoked'\n return 'changed'\n}\n\nfunction resolveEm(ctx: CommandRuntimeContext): EntityManager {\n return ctx.container.resolve('em') as EntityManager\n}\n\n/**\n * The log row's organization must belong to the same tenant as the row itself.\n *\n * A super admin may edit a role in a tenant other than their own, and\n * `ActionLogService.buildListQuery` filters with strict equality\n * (`organization_id = ?`, applied only when the reader supplies one). Stamping\n * the actor's organization onto a row scoped to a different tenant produces a\n * (tenant B, organization from tenant A) pair that no reader can ever match, so\n * the cross-tenant permission change \u2014 exactly the record worth keeping \u2014\n * becomes invisible. `null` is the honest value there: it still reaches\n * tenant-scoped readers whose organization filter is unset.\n */\nfunction resolveOrganizationId(ctx: CommandRuntimeContext, tenantId: string): string | null {\n if ((ctx.auth?.tenantId ?? null) !== tenantId) return null\n return ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null\n}\n\n/**\n * A runtime with no cache registered (CLI, workers, tests) is a configuration,\n * not a failure, so resolution is guarded here. An adapter that *is* wired and\n * then throws is a failure, and it propagates to the single error-level guard\n * in `execute` \u2014 the same one that covers the `rbacService` half of this\n * invalidation. Reporting one half at `debug` and the other at `error` would\n * hide a nav cache still serving revoked grants.\n */\nasync function deleteCacheTags(ctx: CommandRuntimeContext, tags: string[]): Promise<void> {\n let cache: TaggableCache | undefined\n try {\n cache = ctx.container.resolve('cache') as TaggableCache | undefined\n } catch (err) {\n logger.debug('No cache registered for ACL tag invalidation', { err, tags })\n return\n }\n if (!cache?.deleteByTags) return\n await cache.deleteByTags(tags)\n}\n\ntype AclCommandValues = {\n isSuperAdmin: boolean\n features: string[]\n organizations: string[] | null\n}\n\ntype AclCommandInput = AclCommandValues & { tenantId: string }\n\nexport type RoleAclUpdateInput = AclCommandInput & {\n roleId: string\n}\n\nexport type UserAclUpdateInput = AclCommandInput & {\n userId: string\n /** Mirrors the route's `!hasCustomAcl`: drop the override row instead of upserting it. */\n clear: boolean\n /** Set by the route only when it wrote less than the caller asked for. */\n requested?: SanitizedAclRequest | null\n}\n\nexport type AclUpdateResult = {\n resourceId: string\n tenantId: string\n organizationId: string | null\n}\n\nexport const AUTH_ROLE_ACL_UPDATE_COMMAND_ID = 'auth.role-acl.update'\nexport const AUTH_USER_ACL_UPDATE_COMMAND_ID = 'auth.user-acl.update'\n\ntype AclCommandConfig<TInput extends AclCommandInput> = {\n id: string\n resourceKind: string\n labelKey: string\n labelFallback: string\n resourceId: (input: TInput) => string\n loadAcl: (em: EntityManager, input: TInput) => Promise<AclRecord | null>\n persist: (params: { em: EntityManager; input: TInput; existing: AclRecord | null }) => Promise<void>\n invalidate: (params: { ctx: CommandRuntimeContext; input: TInput }) => Promise<void>\n /**\n * Post-state when the row is absent after the write. Only the user command's\n * clear path legitimately removes the row; anywhere else a missing row means\n * the re-read failed, which must be logged as \"unknown\" rather than guessed.\n */\n snapshotWhenAbsent: (input: TInput) => AclSnapshot | null\n /** Human-readable identity of the target; `null` when it cannot be resolved. */\n loadTarget: (em: EntityManager, input: TInput, ctx: CommandRuntimeContext) => Promise<AclTarget | null>\n /** Only the user route sanitizes, so only it can report a trimmed request. */\n sanitizedRequest?: (input: TInput) => SanitizedAclRequest | null\n}\n\n/**\n * Enrichment must never cost the entry.\n *\n * The bus persists the log after `execute` has already committed the permission\n * change, so a throw from the target lookup would leave the write recorded\n * nowhere \u2014 the same \"committed but unaudited\" hole the cache-invalidation\n * guard in `execute` closes. A missing label is a far smaller loss.\n */\nasync function loadTargetSafely<TInput extends AclCommandInput>(\n config: AclCommandConfig<TInput>,\n input: TInput,\n ctx: CommandRuntimeContext,\n): Promise<AclTarget | null> {\n try {\n return await config.loadTarget(resolveEm(ctx).fork(), input, ctx)\n } catch (err) {\n logger.warn('Could not resolve the ACL target for the audit entry', {\n err,\n commandId: config.id,\n resourceId: config.resourceId(input),\n tenantId: input.tenantId,\n })\n return null\n }\n}\n\nfunction buildAuditContext(params: {\n target: AclTarget | null\n effect: AclChangeEffect | null\n sanitizedRequest: SanitizedAclRequest | null\n}): Record<string, unknown> | null {\n const context: Record<string, unknown> = {}\n if (params.target) context.target = params.target\n if (params.effect) context.effect = params.effect\n if (params.sanitizedRequest) context.sanitizedRequest = params.sanitizedRequest\n return Object.keys(context).length ? context : null\n}\n\n/**\n * Both ACL commands differ only in entity, lookup key, cache invalidation and\n * labels \u2014 `prepare`, `captureAfter` and `buildLog` are otherwise identical.\n * Sharing them here keeps the two audit-entry shapes from drifting apart.\n */\nfunction createAclUpdateCommand<TInput extends AclCommandInput>(\n config: AclCommandConfig<TInput>,\n): CommandHandler<TInput, AclUpdateResult> {\n return {\n id: config.id,\n // See \"Auth ACL Commands \u2014 Undo Policy\" at top of file.\n isUndoable: false,\n async prepare(input, ctx) {\n const existing = await config.loadAcl(resolveEm(ctx).fork(), input)\n return { before: captureAclSnapshot(existing) }\n },\n async execute(input, ctx) {\n const em = resolveEm(ctx)\n const existing = await config.loadAcl(em, input)\n await config.persist({ em, input, existing })\n // Cache invalidation runs only after the write commits, never inside the\n // atomic flush \u2014 and must never propagate. The command bus persists the\n // action log *after* `execute` returns, so a throw here would commit the\n // permission change and then suppress its audit entry: precisely the\n // \"committed but unaudited\" hole these commands exist to close, and it\n // would open exactly when infrastructure is already degraded.\n // `RbacService.deleteCacheByTags` awaits the cache adapter without a\n // guard of its own, so an outage does reach us here.\n //\n // The resulting staleness (a revoked grant served from cache until its\n // TTL) is not introduced by swallowing \u2014 it happens either way once the\n // adapter is down. Logging at error level keeps it alarmable instead of\n // trading a recorded change for an HTTP 500 that misreports a write which\n // did commit.\n try {\n await config.invalidate({ ctx, input })\n } catch (err) {\n logger.error('ACL cache invalidation failed after a committed permission change', {\n err,\n commandId: config.id,\n resourceId: config.resourceId(input),\n tenantId: input.tenantId,\n })\n }\n return {\n resourceId: config.resourceId(input),\n tenantId: input.tenantId,\n organizationId: resolveOrganizationId(ctx, input.tenantId),\n }\n },\n captureAfter: async (input, _result, ctx) => {\n // Read the committed row back rather than echoing the request, so a grant\n // the route sanitized away can never be logged as if it had been applied.\n const persisted = await config.loadAcl(resolveEm(ctx).fork(), input)\n if (persisted) return captureAclSnapshot(persisted)\n return config.snapshotWhenAbsent(input)\n },\n buildLog: async ({ input, result, ctx, snapshots }) => {\n const before = (snapshots.before as AclSnapshot | undefined) ?? null\n const after = (snapshots.after as AclSnapshot | undefined) ?? null\n // An unknown post-state (`after: null`, the failed re-read) counts as a\n // change: it is the one case where the entry is the only evidence left.\n // Both snapshots leave `captureAclSnapshot` with their grant lists sorted,\n // so the shared order-sensitive comparison is a set comparison here.\n const changed = !before || !after || !snapshotsEqual(before, after)\n const sanitizedRequest = config.sanitizedRequest?.(input) ?? null\n // The admin user-edit page PUTs the ACL on every save, even when only the\n // name or the roles changed, and most accounts carry no per-user override\n // at all \u2014 so recording an unchanged ACL faithfully buries the real\n // permission changes under identical empty entries. A request the route\n // trimmed rather than refused also arrives with `before == after`; that\n // one is an escalation attempt and must survive this guard.\n if (!changed && !sanitizedRequest) return { skipLog: true }\n const { translate } = await resolveTranslations()\n const target = await loadTargetSafely(config, input, ctx)\n return {\n actionLabel: translate(config.labelKey, config.labelFallback),\n resourceKind: config.resourceKind,\n resourceId: result.resourceId,\n tenantId: result.tenantId,\n organizationId: result.organizationId,\n snapshotBefore: before,\n snapshotAfter: after,\n context: buildAuditContext({\n target,\n // A sanitized-only entry is written *because* nothing changed, so\n // labelling it would have the trail assert a permission change that\n // never happened.\n effect: changed && before && after ? resolveEffect(before, after) : null,\n sanitizedRequest,\n }),\n }\n },\n }\n}\n\nconst updateRoleAclCommand = createAclUpdateCommand<RoleAclUpdateInput>({\n id: AUTH_ROLE_ACL_UPDATE_COMMAND_ID,\n resourceKind: 'auth.role_acl',\n labelKey: 'auth.audit.roleAcl.update',\n labelFallback: 'Change role permissions',\n resourceId: (input) => input.roleId,\n loadAcl: (em, input) =>\n em.findOne(RoleAcl, { role: input.roleId as unknown as Role, tenantId: input.tenantId }),\n persist: async ({ em, input, existing }) => {\n const acl =\n (existing as RoleAcl | null) ??\n em.create(RoleAcl, {\n role: em.getReference(Role, input.roleId),\n tenantId: input.tenantId,\n createdAt: new Date(),\n isSuperAdmin: false,\n })\n await withAtomicFlush(\n em,\n [\n () => {\n acl.organizationsJson = input.organizations\n acl.isSuperAdmin = input.isSuperAdmin\n acl.featuresJson = input.features\n em.persist(acl)\n },\n ],\n { transaction: true, label: AUTH_ROLE_ACL_UPDATE_COMMAND_ID },\n )\n },\n invalidate: async ({ ctx, input }) => {\n // Every user in the tenant inherits this role's grants, so the whole tenant\n // scope is invalidated.\n const rbacService = ctx.container.resolve('rbacService') as RbacService\n await rbacService.invalidateTenantCache(input.tenantId)\n // Sidebar nav caches depend on RBAC; invalidate tenant scope nav caches\n await deleteCacheTags(ctx, [`rbac:tenant:${input.tenantId}`])\n },\n snapshotWhenAbsent: () => null,\n // Looked up by id alone: the entry already names this role through\n // `resource_id`, and a tenant predicate would only blank the label when a\n // super admin edits a role from outside the tenant scope they are writing in.\n loadTarget: async (em, input) => {\n const role = await em.findOne(Role, { id: input.roleId } as FilterQuery<Role>)\n if (!role) return null\n return { kind: 'role', id: input.roleId, name: role.name ?? null }\n },\n})\n\nconst updateUserAclCommand = createAclUpdateCommand<UserAclUpdateInput>({\n id: AUTH_USER_ACL_UPDATE_COMMAND_ID,\n resourceKind: 'auth.user_acl',\n labelKey: 'auth.audit.userAcl.update',\n labelFallback: 'Change user permissions',\n resourceId: (input) => input.userId,\n loadAcl: (em, input) =>\n em.findOne(UserAcl, { user: input.userId as unknown as User, tenantId: input.tenantId }),\n persist: async ({ em, input, existing }) => {\n if (input.clear) {\n if (!existing) return\n const aclToRemove = existing as UserAcl\n await withAtomicFlush(\n em,\n [\n () => {\n em.remove(aclToRemove)\n },\n ],\n { transaction: true, label: AUTH_USER_ACL_UPDATE_COMMAND_ID },\n )\n return\n }\n const acl =\n (existing as UserAcl | null) ??\n em.create(UserAcl, {\n user: em.getReference(User, input.userId),\n tenantId: input.tenantId,\n createdAt: new Date(),\n isSuperAdmin: false,\n })\n await withAtomicFlush(\n em,\n [\n () => {\n acl.isSuperAdmin = input.isSuperAdmin\n acl.featuresJson = input.features\n acl.organizationsJson = input.organizations\n em.persist(acl)\n },\n ],\n { transaction: true, label: AUTH_USER_ACL_UPDATE_COMMAND_ID },\n )\n },\n invalidate: async ({ ctx, input }) => {\n const rbacService = ctx.container.resolve('rbacService') as RbacService\n await rbacService.invalidateUserCache(input.userId)\n await deleteCacheTags(ctx, [`rbac:user:${input.userId}`])\n },\n // Clearing removes the row, so an absent row is the real post-state here.\n snapshotWhenAbsent: (input) => (input.clear ? { ...EMPTY_ACL_SNAPSHOT } : null),\n // `userId` arrives in the request body and `auth:user` carries encrypted\n // personal data, so the lookup is tenant-scoped: an id belonging to another\n // tenant must not be decrypted under this scope and stamped into this\n // tenant's trail. A global account (`users.tenant_id` is nullable) still\n // resolves, mirroring how the role route widens its own lookup.\n loadTarget: async (em, input, ctx) => {\n const user = await findOneWithDecryption(\n em,\n User,\n { id: input.userId, $or: [{ tenantId: input.tenantId }, { tenantId: null }] } as FilterQuery<User>,\n {},\n { tenantId: input.tenantId, organizationId: ctx.auth?.orgId ?? null },\n )\n if (!user) return null\n return { kind: 'user', id: input.userId, email: user.email ?? null, name: user.name ?? null }\n },\n sanitizedRequest: (input) => input.requested ?? null,\n})\n\nregisterCommand(updateRoleAclCommand)\nregisterCommand(updateUserAclCommand)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -7,9 +7,6 @@ import Link from "next/link";
|
|
|
7
7
|
import { hasFeature, matchFeature } from "@open-mercato/shared/security/features";
|
|
8
8
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
9
9
|
import { AclDependencyDiagnosticsPanel } from "./AclDependencyDiagnosticsPanel.js";
|
|
10
|
-
function toTitleCase(value) {
|
|
11
|
-
return value.replace(/[-_.]/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
|
|
12
|
-
}
|
|
13
10
|
function normalizeFeatureArray(input) {
|
|
14
11
|
if (!Array.isArray(input)) return [];
|
|
15
12
|
const dedup = /* @__PURE__ */ new Set();
|
|
@@ -26,12 +23,13 @@ function isTenantRestrictedFeature(feature) {
|
|
|
26
23
|
if (feature.startsWith("directory.tenants")) return true;
|
|
27
24
|
return false;
|
|
28
25
|
}
|
|
29
|
-
function formatWildcardLabel(moduleId, wildcard) {
|
|
26
|
+
function formatWildcardLabel(t, moduleId, wildcard) {
|
|
30
27
|
if (!wildcard.endsWith(".*")) return wildcard;
|
|
31
28
|
const prefix = `${moduleId}.`;
|
|
32
29
|
const suffix = wildcard.startsWith(prefix) ? wildcard.slice(prefix.length, -2) : wildcard.slice(0, -2);
|
|
33
|
-
if (!suffix) return "All features";
|
|
34
|
-
|
|
30
|
+
if (!suffix) return t("auth.acl.wildcards.allFeatures", "All features");
|
|
31
|
+
const group = suffix.split(".").map((segment) => segment.replace(/[-_]/g, " ").replace(/\b\w/g, (char) => char.toUpperCase())).join(" / ");
|
|
32
|
+
return t("auth.acl.wildcards.allGroup", "All permissions in {group}", { group });
|
|
35
33
|
}
|
|
36
34
|
function buildRoleSummaries(items, allowedNames) {
|
|
37
35
|
const summaries = [];
|
|
@@ -209,19 +207,27 @@ function AclEditor({
|
|
|
209
207
|
const grouped = React.useMemo(() => {
|
|
210
208
|
const moduleMap = /* @__PURE__ */ new Map();
|
|
211
209
|
for (const m of modules) {
|
|
212
|
-
moduleMap.set(m.id, m.title);
|
|
210
|
+
moduleMap.set(m.id, t(`auth.acl.modules.${m.id}`, m.title));
|
|
213
211
|
}
|
|
214
212
|
const map = /* @__PURE__ */ new Map();
|
|
215
213
|
for (const f of features) {
|
|
216
214
|
const moduleId = f.module;
|
|
217
215
|
const moduleTitle = moduleMap.get(moduleId) || moduleId;
|
|
216
|
+
const localizedFeature = {
|
|
217
|
+
...f,
|
|
218
|
+
title: t(`auth.acl.features.${f.id}`, f.title)
|
|
219
|
+
};
|
|
218
220
|
if (!map.has(moduleId)) {
|
|
219
221
|
map.set(moduleId, { moduleId, moduleTitle, features: [] });
|
|
220
222
|
}
|
|
221
|
-
map.get(moduleId).features.push(
|
|
223
|
+
map.get(moduleId).features.push(localizedFeature);
|
|
222
224
|
}
|
|
223
225
|
return Array.from(map.values()).sort((a, b) => a.moduleTitle.localeCompare(b.moduleTitle));
|
|
224
|
-
}, [features, modules]);
|
|
226
|
+
}, [features, modules, t]);
|
|
227
|
+
const localizedFeatures = React.useMemo(
|
|
228
|
+
() => grouped.flatMap((group) => group.features),
|
|
229
|
+
[grouped]
|
|
230
|
+
);
|
|
225
231
|
const hasGlobalWildcard = granted.includes("*");
|
|
226
232
|
const hasOrganizationRestriction = Array.isArray(organizations) && organizations.length > 0;
|
|
227
233
|
const showOrganizationWarning = (kind === "role" || overrideEnabled) && canEditOrganizations && !isSuperAdmin && hasOrganizationRestriction && granted.length === 0;
|
|
@@ -243,16 +249,18 @@ function AclEditor({
|
|
|
243
249
|
};
|
|
244
250
|
const isFeatureCoveredByWildcard = (featureId) => granted.some((feature) => (feature === "*" || feature.endsWith(".*")) && matchFeature(featureId, feature));
|
|
245
251
|
const isFeatureChecked = (featureId) => hasFeature(granted, featureId);
|
|
246
|
-
if (loading)
|
|
252
|
+
if (loading) {
|
|
253
|
+
return /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: t("auth.acl.loading", "Loading access control\u2026") });
|
|
254
|
+
}
|
|
247
255
|
const showRoleBanner = kind === "user" && !hasCustomAcl && !overrideEnabled;
|
|
248
256
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
249
|
-
showRoleBanner && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-
|
|
250
|
-
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-
|
|
251
|
-
/* @__PURE__ */ jsxs("div", { className: "text-sm text-
|
|
252
|
-
"This user currently inherits permissions from their assigned roles.",
|
|
257
|
+
showRoleBanner && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-status-info-border bg-status-info-bg p-4", children: [
|
|
258
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-status-info-text mb-2", children: t("auth.acl.inherited.title", "Permissions inherited from roles") }),
|
|
259
|
+
/* @__PURE__ */ jsxs("div", { className: "text-sm text-status-info-text mb-3", children: [
|
|
260
|
+
t("auth.acl.inherited.description", "This user currently inherits permissions from their assigned roles."),
|
|
253
261
|
roleDetails.length > 0 && /* @__PURE__ */ jsxs("span", { children: [
|
|
254
262
|
" ",
|
|
255
|
-
"Assigned roles:",
|
|
263
|
+
t("auth.acl.inherited.assignedRoles", "Assigned roles:"),
|
|
256
264
|
" ",
|
|
257
265
|
roleDetails.map((role, idx) => {
|
|
258
266
|
const roleId = typeof role?.id === "string" && role.id.length > 0 ? role.id : `role-${idx}`;
|
|
@@ -263,7 +271,7 @@ function AclEditor({
|
|
|
263
271
|
Link,
|
|
264
272
|
{
|
|
265
273
|
href: `/backend/roles/${roleId}/edit`,
|
|
266
|
-
className: "font-semibold text-
|
|
274
|
+
className: "font-semibold text-status-info-text underline",
|
|
267
275
|
children: roleName
|
|
268
276
|
}
|
|
269
277
|
)
|
|
@@ -282,7 +290,7 @@ function AclEditor({
|
|
|
282
290
|
onChange: (e) => setOverrideEnabled(e.target.checked)
|
|
283
291
|
}
|
|
284
292
|
),
|
|
285
|
-
/* @__PURE__ */ jsx("label", { htmlFor: "overrideAcl", className: "text-sm text-
|
|
293
|
+
/* @__PURE__ */ jsx("label", { htmlFor: "overrideAcl", className: "text-sm text-status-info-text font-medium", children: t("auth.acl.inherited.override", "Override permissions for this user only") })
|
|
286
294
|
] })
|
|
287
295
|
] }),
|
|
288
296
|
(kind === "role" || overrideEnabled) && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -298,13 +306,13 @@ function AclEditor({
|
|
|
298
306
|
onChange: (e) => setIsSuperAdmin(!!e.target.checked)
|
|
299
307
|
}
|
|
300
308
|
),
|
|
301
|
-
/* @__PURE__ */ jsx("label", { htmlFor: "isSuperAdmin", className: "text-sm", children: "Super Admin (all features)" })
|
|
309
|
+
/* @__PURE__ */ jsx("label", { htmlFor: "isSuperAdmin", className: "text-sm", children: t("auth.acl.superAdmin.label", "Super Admin (all features)") })
|
|
302
310
|
] }),
|
|
303
|
-
!actorIsSuperAdmin && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Only super administrators can change this option." }),
|
|
311
|
+
!actorIsSuperAdmin && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("auth.acl.superAdmin.hint", "Only super administrators can change this option.") }),
|
|
304
312
|
!isSuperAdmin && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
305
|
-
hasGlobalWildcard && /* @__PURE__ */ jsxs("div", { className: "rounded border border-
|
|
306
|
-
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-
|
|
307
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs text-
|
|
313
|
+
hasGlobalWildcard && /* @__PURE__ */ jsxs("div", { className: "rounded border border-status-info-border bg-status-info-bg p-3", children: [
|
|
314
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-status-info-text", children: t("auth.acl.globalWildcard.title", "Global wildcard (*) enabled") }),
|
|
315
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs text-status-info-text mt-1", children: t("auth.acl.globalWildcard.description", "This grants access to all features in the system.") }),
|
|
308
316
|
/* @__PURE__ */ jsx(
|
|
309
317
|
Button,
|
|
310
318
|
{
|
|
@@ -312,7 +320,7 @@ function AclEditor({
|
|
|
312
320
|
size: "sm",
|
|
313
321
|
className: "mt-2",
|
|
314
322
|
onClick: () => updateGranted((prev) => prev.filter((x) => x !== "*")),
|
|
315
|
-
children: "Remove global wildcard"
|
|
323
|
+
children: t("auth.acl.globalWildcard.remove", "Remove global wildcard")
|
|
316
324
|
}
|
|
317
325
|
)
|
|
318
326
|
] }),
|
|
@@ -320,7 +328,7 @@ function AclEditor({
|
|
|
320
328
|
AclDependencyDiagnosticsPanel,
|
|
321
329
|
{
|
|
322
330
|
granted,
|
|
323
|
-
catalog:
|
|
331
|
+
catalog: localizedFeatures,
|
|
324
332
|
onGrantedChange: updateGranted,
|
|
325
333
|
hideUnknownReferences: process.env.NODE_ENV === "production"
|
|
326
334
|
}
|
|
@@ -360,13 +368,14 @@ function AclEditor({
|
|
|
360
368
|
}
|
|
361
369
|
),
|
|
362
370
|
/* @__PURE__ */ jsxs("label", { htmlFor: `module-${group.moduleId}`, className: "text-sm text-muted-foreground", children: [
|
|
363
|
-
"
|
|
364
|
-
|
|
371
|
+
t("auth.acl.allModuleFeatures", "All"),
|
|
372
|
+
" ",
|
|
373
|
+
moduleWildcard && !hasGlobalWildcard ? /* @__PURE__ */ jsxs("span", { className: "font-medium text-status-info-text", children: [
|
|
365
374
|
"(",
|
|
366
375
|
group.moduleId,
|
|
367
376
|
".*)"
|
|
368
377
|
] }) : "",
|
|
369
|
-
moduleRestricted ? /* @__PURE__ */ jsx("span", { className: "ml-2 text-xs font-medium text-muted-foreground", children: "(manage via super admin)" }) : null
|
|
378
|
+
moduleRestricted ? /* @__PURE__ */ jsx("span", { className: "ml-2 text-xs font-medium text-muted-foreground", children: t("auth.acl.manageViaSuperAdmin", "(manage via super admin)") }) : null
|
|
370
379
|
] })
|
|
371
380
|
] })
|
|
372
381
|
] }),
|
|
@@ -393,7 +402,7 @@ function AclEditor({
|
|
|
393
402
|
htmlFor: `wildcard-${wildcard}`,
|
|
394
403
|
className: `text-sm ${disabled ? "text-muted-foreground" : ""}`,
|
|
395
404
|
children: [
|
|
396
|
-
formatWildcardLabel(group.moduleId, wildcard),
|
|
405
|
+
formatWildcardLabel(t, group.moduleId, wildcard),
|
|
397
406
|
" ",
|
|
398
407
|
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-xs font-mono", children: [
|
|
399
408
|
"(",
|
|
@@ -467,7 +476,7 @@ function AclEditor({
|
|
|
467
476
|
] }),
|
|
468
477
|
canEditOrganizations && /* @__PURE__ */ jsxs("div", { className: "rounded border p-3", children: [
|
|
469
478
|
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium mb-2", children: t("auth.acl.organizationsScope", "Organizations scope") }),
|
|
470
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground mb-2", children: "Empty
|
|
479
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground mb-2", children: t("auth.acl.organizationsScopeHint", "Empty means all organizations. Select one or more to restrict access.") }),
|
|
471
480
|
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-2", children: orgOptions.map((o) => {
|
|
472
481
|
const checked = organizations == null ? false : (organizations || []).includes(o.id);
|
|
473
482
|
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
@@ -482,7 +491,7 @@ function AclEditor({
|
|
|
482
491
|
] }, o.id);
|
|
483
492
|
}) }),
|
|
484
493
|
/* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => setOrganizations(null), children: t("auth.acl.allowAllOrganizations", "Allow all organizations") }) }),
|
|
485
|
-
showOrganizationWarning && /* @__PURE__ */ jsx("div", { className: "mt-3 rounded border border-
|
|
494
|
+
showOrganizationWarning && /* @__PURE__ */ jsx("div", { className: "mt-3 rounded border border-status-warning-border bg-status-warning-bg px-3 py-2 text-sm text-status-warning-text", children: t("auth.acl.organizationWarning", "Organization restrictions are saved only when at least one feature override is selected. Add a feature or enable a module wildcard before saving.") })
|
|
486
495
|
] })
|
|
487
496
|
] })
|
|
488
497
|
] });
|