@open-mercato/core 0.6.8-develop.7100.1.fbf66fca35 → 0.7.0
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 +1 -13
- package/dist/helpers/integration/api.js.map +2 -2
- package/dist/helpers/integration/communicationChannelsFixtures.js +0 -19
- 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 +1 -3
- package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
- 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 +0 -2
- package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
- package/dist/modules/attachments/di.js +1 -11
- package/dist/modules/attachments/di.js.map +2 -2
- package/dist/modules/attachments/index.js.map +1 -1
- package/dist/modules/attachments/lib/scoped-upload-service.js +2 -15
- package/dist/modules/attachments/lib/scoped-upload-service.js.map +2 -2
- package/dist/modules/attachments/lib/upload-limits.js +2 -6
- package/dist/modules/attachments/lib/upload-limits.js.map +2 -2
- package/dist/modules/audit_logs/backend/audit-logs/page.js +0 -6
- package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
- package/dist/modules/audit_logs/lib/display-helpers.js +11 -19
- package/dist/modules/audit_logs/lib/display-helpers.js.map +2 -2
- package/dist/modules/audit_logs/services/actionLogService.js +12 -57
- package/dist/modules/audit_logs/services/actionLogService.js.map +3 -3
- package/dist/modules/auth/acl.js +5 -30
- package/dist/modules/auth/acl.js.map +2 -2
- package/dist/modules/auth/api/feature-check.js +2 -8
- package/dist/modules/auth/api/feature-check.js.map +2 -2
- package/dist/modules/auth/api/login.js +20 -4
- package/dist/modules/auth/api/login.js.map +2 -2
- package/dist/modules/auth/api/roles/acl/route.js +33 -28
- package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
- package/dist/modules/auth/api/routeError.js +11 -0
- package/dist/modules/auth/api/routeError.js.map +7 -0
- package/dist/modules/auth/api/session/refresh.js +1 -25
- package/dist/modules/auth/api/session/refresh.js.map +2 -2
- package/dist/modules/auth/api/users/acl/route.js +73 -102
- package/dist/modules/auth/api/users/acl/route.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +5 -13
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/backend/roles/[id]/edit/page.meta.js +1 -5
- package/dist/modules/auth/backend/roles/[id]/edit/page.meta.js.map +2 -2
- package/dist/modules/auth/backend/roles/page.js +1 -3
- package/dist/modules/auth/backend/roles/page.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.meta.js +1 -5
- package/dist/modules/auth/backend/users/[id]/edit/page.meta.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +1 -2
- package/dist/modules/auth/backend/users/page.js.map +2 -2
- package/dist/modules/auth/components/AclEditor.js +30 -39
- 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 +1 -5
- package/dist/modules/auth/data/validators.js.map +2 -2
- package/dist/modules/auth/di.js +9 -35
- package/dist/modules/auth/di.js.map +2 -2
- package/dist/modules/auth/frontend/reset/[token]/page.js +0 -46
- 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/services/authService.js +2 -16
- package/dist/modules/auth/services/authService.js.map +2 -2
- package/dist/modules/auth/services/rbacService.js +24 -67
- package/dist/modules/auth/services/rbacService.js.map +3 -3
- package/dist/modules/business_rules/backend/logs/page.js +1 -3
- package/dist/modules/business_rules/backend/logs/page.js.map +2 -2
- package/dist/modules/business_rules/backend/rules/[id]/page.meta.js +6 -1
- package/dist/modules/business_rules/backend/rules/[id]/page.meta.js.map +2 -2
- package/dist/modules/business_rules/backend/rules/create/page.meta.js +5 -1
- package/dist/modules/business_rules/backend/rules/create/page.meta.js.map +2 -2
- package/dist/modules/business_rules/backend/rules/page.js +1 -3
- package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/[id]/page.meta.js +6 -1
- package/dist/modules/business_rules/backend/sets/[id]/page.meta.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/create/page.meta.js +5 -1
- package/dist/modules/business_rules/backend/sets/create/page.meta.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/page.js +1 -3
- 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 +9 -10
- 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 +2 -5
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +2 -2
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js +0 -2
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductsDataTable.js +1 -7
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js +0 -2
- 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 +1 -9
- 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 +10 -95
- 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 +0 -3
- package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +2 -2
- package/dist/modules/communication_channels/commands/ingest-inbound-message.js +1 -14
- package/dist/modules/communication_channels/commands/ingest-inbound-message.js.map +2 -2
- package/dist/modules/communication_channels/di.js +1 -7
- package/dist/modules/communication_channels/di.js.map +2 -2
- package/dist/modules/communication_channels/lib/email-capabilities.js +1 -4
- package/dist/modules/communication_channels/lib/email-capabilities.js.map +2 -2
- package/dist/modules/communication_channels/lib/test-seed.js +2 -41
- package/dist/modules/communication_channels/lib/test-seed.js.map +2 -2
- package/dist/modules/configs/lib/system-status.js +0 -9
- package/dist/modules/configs/lib/system-status.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/page.js +1 -3
- package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js +1 -3
- package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/domain-mappings.js +0 -9
- package/dist/modules/customer_accounts/api/admin/domain-mappings.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +1 -3
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/CustomerAccountsSettingsPageClient.js +84 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/CustomerAccountsSettingsPageClient.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/page.js +7 -81
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js +523 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/PortalUserDetailPageClient.js +731 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/PortalUserDetailPageClient.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js +7 -727
- package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +7 -521
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
- package/dist/modules/customer_accounts/extension-points.js +1 -1
- package/dist/modules/customer_accounts/extension-points.js.map +2 -2
- package/dist/modules/customer_accounts/lib/portalUrl.js +69 -0
- package/dist/modules/customer_accounts/lib/portalUrl.js.map +7 -0
- package/dist/modules/customer_accounts/services/domainMappingService.js +0 -10
- package/dist/modules/customer_accounts/services/domainMappingService.js.map +2 -2
- package/dist/modules/customers/ai-tools/companies-pack.js +1 -4
- package/dist/modules/customers/ai-tools/companies-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/deal-analyzer-pack.js +2 -13
- package/dist/modules/customers/ai-tools/deal-analyzer-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/deals-pack.js +6 -52
- package/dist/modules/customers/ai-tools/deals-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/people-pack.js +1 -4
- package/dist/modules/customers/ai-tools/people-pack.js.map +2 -2
- package/dist/modules/customers/api/activities/route.js +6 -48
- package/dist/modules/customers/api/activities/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/people/route.js +64 -20
- package/dist/modules/customers/api/companies/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/route.js +94 -17
- package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js +5 -8
- 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 +25 -8
- package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/stats/route.js +22 -3
- package/dist/modules/customers/api/deals/[id]/stats/route.js.map +2 -2
- package/dist/modules/customers/api/deals/aggregate/route.js +4 -11
- package/dist/modules/customers/api/deals/aggregate/route.js.map +2 -2
- package/dist/modules/customers/api/deals/map/route.js +1 -2
- package/dist/modules/customers/api/deals/map/route.js.map +2 -2
- package/dist/modules/customers/api/deals/route.js +1 -38
- 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 +1 -3
- package/dist/modules/customers/api/interactions/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/tasks/route.js +4 -27
- package/dist/modules/customers/api/interactions/tasks/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +3 -4
- 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 +10 -11
- package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/people/check-phone/route.js +9 -51
- package/dist/modules/customers/api/people/check-phone/route.js.map +2 -2
- package/dist/modules/customers/api/todos/route.js +5 -30
- package/dist/modules/customers/api/todos/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +4 -6
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +1 -6
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +4 -7
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/Lane.js +13 -4
- 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 +14 -85
- package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js +4 -6
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/backend/hooks/useEmailDuplicateCheck.js +3 -9
- package/dist/modules/customers/backend/hooks/useEmailDuplicateCheck.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +34 -21
- 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 +2 -131
- package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
- package/dist/modules/customers/components/CustomerTodosTable.js +0 -1
- package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
- package/dist/modules/customers/components/DealsKpiStrip.js +6 -7
- 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 +2 -3
- package/dist/modules/customers/components/calendar/EventPeekPopover.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/PeopleField.js +5 -40
- package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/hooks.js +1 -2
- 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/AssignRoleDialog.js +33 -28
- package/dist/modules/customers/components/detail/AssignRoleDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyKpiBar.js +4 -5
- package/dist/modules/customers/components/detail/CompanyKpiBar.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js +1 -3
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
- package/dist/modules/customers/components/detail/DealForm.js +7 -19
- package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
- package/dist/modules/customers/components/detail/DealsSection.js +5 -6
- package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js +11 -35
- package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js +1 -3
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/usePersonTasks.js +13 -19
- 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 +3 -32
- package/dist/modules/customers/data/validators.js.map +2 -2
- package/dist/modules/customers/events.js +0 -5
- package/dist/modules/customers/events.js.map +2 -2
- package/dist/modules/customers/lib/calendar/conflicts.js +2 -8
- package/dist/modules/customers/lib/calendar/conflicts.js.map +2 -2
- package/dist/modules/customers/lib/calendar/editorPayload.js +2 -3
- package/dist/modules/customers/lib/calendar/editorPayload.js.map +2 -2
- package/dist/modules/customers/lib/calendar/mapItem.js +3 -8
- package/dist/modules/customers/lib/calendar/mapItem.js.map +2 -2
- package/dist/modules/customers/lib/dealStatus.js +0 -30
- package/dist/modules/customers/lib/dealStatus.js.map +2 -2
- package/dist/modules/customers/lib/findPeopleByAddresses.js +0 -1
- package/dist/modules/customers/lib/findPeopleByAddresses.js.map +2 -2
- package/dist/modules/customers/lib/personCompanies.js +2 -100
- package/dist/modules/customers/lib/personCompanies.js.map +2 -2
- package/dist/modules/customers/lib/todoCompatibility.js +0 -12
- package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
- package/dist/modules/dashboards/lib/widgetScope.js +1 -6
- package/dist/modules/dashboards/lib/widgetScope.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +1 -3
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/lib/sync-engine.js +6 -72
- package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
- package/dist/modules/data_sync/workers/sync-export.js +1 -5
- package/dist/modules/data_sync/workers/sync-export.js.map +2 -2
- package/dist/modules/data_sync/workers/sync-import.js +1 -5
- package/dist/modules/data_sync/workers/sync-import.js.map +2 -2
- package/dist/modules/devices/acl.js +1 -9
- package/dist/modules/devices/acl.js.map +2 -2
- package/dist/modules/devices/api/admin/devices/[id]/route.js +32 -5
- package/dist/modules/devices/api/admin/devices/[id]/route.js.map +2 -2
- package/dist/modules/devices/api/admin/devices/route.js +1 -14
- package/dist/modules/devices/api/admin/devices/route.js.map +2 -2
- package/dist/modules/devices/api/deviceList.js +12 -99
- package/dist/modules/devices/api/deviceList.js.map +2 -2
- package/dist/modules/devices/api/openapi.js +1 -3
- package/dist/modules/devices/api/openapi.js.map +2 -2
- package/dist/modules/devices/api/route.js +1 -9
- package/dist/modules/devices/api/route.js.map +2 -2
- package/dist/modules/devices/backend/devices/[id]/page.js +26 -10
- package/dist/modules/devices/backend/devices/[id]/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/create/page.js +1 -17
- package/dist/modules/devices/backend/devices/create/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/page.js +34 -28
- package/dist/modules/devices/backend/devices/page.js.map +2 -2
- package/dist/modules/devices/setup.js +2 -6
- package/dist/modules/devices/setup.js.map +2 -2
- package/dist/modules/directory/backend/directory/organizations/page.js +1 -2
- package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/page.js +1 -2
- package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
- package/dist/modules/directory/di.js +0 -9
- package/dist/modules/directory/di.js.map +2 -2
- package/dist/modules/directory/utils/organizationScope.js.map +2 -2
- package/dist/modules/entities/api/records.js +2 -4
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +1 -3
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/eudr/api/plots/route.js +1 -5
- package/dist/modules/eudr/api/plots/route.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/evidence-submissions/[id]/page.meta.js +3 -1
- package/dist/modules/eudr/backend/eudr/evidence-submissions/[id]/page.meta.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/evidence-submissions/create/page.meta.js +1 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/create/page.meta.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js +0 -3
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.meta.js +4 -1
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.meta.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/page.meta.js +2 -2
- package/dist/modules/eudr/backend/eudr/page.meta.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/plots/[id]/page.js +8 -2
- package/dist/modules/eudr/backend/eudr/plots/[id]/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/plots/[id]/page.meta.js +3 -1
- package/dist/modules/eudr/backend/eudr/plots/[id]/page.meta.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/plots/create/page.js +8 -2
- package/dist/modules/eudr/backend/eudr/plots/create/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/plots/create/page.meta.js +1 -0
- package/dist/modules/eudr/backend/eudr/plots/create/page.meta.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/plots/page.js +0 -3
- package/dist/modules/eudr/backend/eudr/plots/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/plots/page.meta.js +4 -1
- package/dist/modules/eudr/backend/eudr/plots/page.meta.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/product-mappings/[id]/page.meta.js +3 -1
- package/dist/modules/eudr/backend/eudr/product-mappings/[id]/page.meta.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/product-mappings/create/page.meta.js +1 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/create/page.meta.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/product-mappings/page.js +0 -3
- package/dist/modules/eudr/backend/eudr/product-mappings/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/product-mappings/page.meta.js +4 -1
- package/dist/modules/eudr/backend/eudr/product-mappings/page.meta.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/risk-assessments/[id]/page.meta.js +3 -1
- package/dist/modules/eudr/backend/eudr/risk-assessments/[id]/page.meta.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/risk-assessments/create/page.meta.js +1 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/create/page.meta.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.js +0 -3
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.meta.js +4 -1
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.meta.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/statements/[id]/page.js +2 -0
- package/dist/modules/eudr/backend/eudr/statements/[id]/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/statements/[id]/page.meta.js +3 -1
- package/dist/modules/eudr/backend/eudr/statements/[id]/page.meta.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/statements/create/page.meta.js +1 -0
- package/dist/modules/eudr/backend/eudr/statements/create/page.meta.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/statements/page.js +30 -28
- package/dist/modules/eudr/backend/eudr/statements/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/statements/page.meta.js +4 -1
- package/dist/modules/eudr/backend/eudr/statements/page.meta.js.map +2 -2
- package/dist/modules/eudr/commands/statements.js +8 -3
- package/dist/modules/eudr/commands/statements.js.map +2 -2
- package/dist/modules/eudr/components/crudErrorI18n.js +21 -1
- package/dist/modules/eudr/components/crudErrorI18n.js.map +2 -2
- package/dist/modules/eudr/components/formConfig.js +6 -2
- package/dist/modules/eudr/components/formConfig.js.map +2 -2
- package/dist/modules/eudr/data/validators.js +1 -4
- package/dist/modules/eudr/data/validators.js.map +2 -2
- package/dist/modules/eudr/lib/statement-lifecycle.js +9 -1
- package/dist/modules/eudr/lib/statement-lifecycle.js.map +2 -2
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +0 -1
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
- package/dist/modules/feature_toggles/components/OverridesTable.js +0 -1
- package/dist/modules/feature_toggles/components/OverridesTable.js.map +2 -2
- package/dist/modules/feature_toggles/defaults.json +8 -0
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js +0 -3
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/page.js +0 -3
- package/dist/modules/inbox_ops/backend/inbox-ops/page.js.map +2 -2
- package/dist/modules/inbox_ops/lib/htmlToPlainText.js +12 -1
- package/dist/modules/inbox_ops/lib/htmlToPlainText.js.map +2 -2
- package/dist/modules/integrations/api/[id]/credentials/route.js +1 -6
- package/dist/modules/integrations/api/[id]/credentials/route.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/[id]/page.js +29 -38
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +9 -36
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
- package/dist/modules/integrations/data/validators.js +3 -11
- package/dist/modules/integrations/data/validators.js.map +2 -2
- package/dist/modules/integrations/lib/credentials-masking.js +2 -6
- package/dist/modules/integrations/lib/credentials-masking.js.map +2 -2
- package/dist/modules/messages/api/[id]/route.js +1 -29
- package/dist/modules/messages/api/[id]/route.js.map +2 -2
- package/dist/modules/messages/api/openapi.js +2 -17
- package/dist/modules/messages/api/openapi.js.map +2 -2
- package/dist/modules/messages/api/route.js +2 -17
- package/dist/modules/messages/api/route.js.map +2 -2
- package/dist/modules/messages/components/MessagesInboxPageClient.js +14 -7
- package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
- package/dist/modules/messages/components/inboxFilters.js +0 -15
- package/dist/modules/messages/components/inboxFilters.js.map +2 -2
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js +1 -11
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js.map +2 -2
- package/dist/modules/messages/components/message-detail/panels/MessageHeader.js +1 -3
- package/dist/modules/messages/components/message-detail/panels/MessageHeader.js.map +2 -2
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js +1 -2
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +2 -2
- package/dist/modules/messages/components/messageListLabels.js +2 -14
- package/dist/modules/messages/components/messageListLabels.js.map +2 -2
- package/dist/modules/messages/data/validators.js +4 -18
- package/dist/modules/messages/data/validators.js.map +2 -2
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +6 -4
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +2 -2
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js +1 -3
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
- package/dist/modules/payment_gateways/lib/webhook-processor.js +0 -7
- package/dist/modules/payment_gateways/lib/webhook-processor.js.map +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js +0 -3
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/push_notifications/backend/push_notifications/page.js +1 -3
- 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 +51 -150
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/lib/search-tokens.js +3 -79
- package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js +1 -3
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js +1 -3
- package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js +0 -3
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +0 -3
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +8 -10
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +1 -79
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/components/PriceWithCurrency.js +5 -7
- package/dist/modules/sales/components/PriceWithCurrency.js.map +2 -2
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +0 -3
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentsSection.js +6 -8
- package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +22 -51
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +19 -84
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js +9 -23
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnsSection.js +6 -8
- package/dist/modules/sales/components/documents/ReturnsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +14 -68
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesOrderDraftLines.js +5 -6
- package/dist/modules/sales/components/documents/SalesOrderDraftLines.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +4 -5
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentsSection.js +6 -8
- package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
- 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 +2 -8
- package/dist/modules/sales/data/entities.js.map +2 -2
- package/dist/modules/sales/extension-points.js +0 -1
- package/dist/modules/sales/extension-points.js.map +2 -2
- package/dist/modules/sales/setup.js +0 -2
- package/dist/modules/sales/setup.js.map +2 -2
- package/dist/modules/sales/widgets/injection/document-history/widget.client.js +44 -2
- package/dist/modules/sales/widgets/injection/document-history/widget.client.js.map +2 -2
- package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js +2 -10
- package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js.map +2 -2
- package/dist/modules/sales/widgets/injection-table.js +7 -4
- package/dist/modules/sales/widgets/injection-table.js.map +2 -2
- package/dist/modules/staff/backend/staff/leave-requests/page.js +0 -3
- package/dist/modules/staff/backend/staff/leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js +0 -3
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/page.js +0 -3
- package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js +0 -3
- package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +0 -3
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js +0 -3
- package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/page.js +18 -29
- package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js +0 -3
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
- package/dist/modules/sync_excel/lib/adapters/customers.js +0 -1
- 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 +9 -12
- package/dist/modules/warranty_claims/api/portal/claims/route.js.map +2 -2
- package/dist/modules/warranty_claims/backend/page.js +0 -3
- package/dist/modules/warranty_claims/backend/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js +0 -3
- 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 +0 -3
- 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 +0 -3
- 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 +0 -3
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js.map +2 -2
- package/dist/modules/wms/api/warehouses/route.js +9 -13
- package/dist/modules/wms/api/warehouses/route.js.map +2 -2
- package/dist/modules/wms/api/zones/route.js +2 -15
- package/dist/modules/wms/api/zones/route.js.map +2 -2
- package/dist/modules/wms/commands/configuration.js +9 -121
- package/dist/modules/wms/commands/configuration.js.map +2 -2
- package/dist/modules/wms/commands/inventory-actions.js +0 -3
- package/dist/modules/wms/commands/inventory-actions.js.map +2 -2
- package/dist/modules/wms/commands/shared.js +1 -9
- package/dist/modules/wms/commands/shared.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js +111 -76
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +3 -3
- package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +0 -1
- package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsLocationDetailPage.js +20 -16
- package/dist/modules/wms/components/backend/WmsLocationDetailPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsLotDetailPage.js +10 -6
- package/dist/modules/wms/components/backend/WmsLotDetailPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsLotsListPage.js +0 -1
- package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsOperationalDashboardPage.js +11 -7
- package/dist/modules/wms/components/backend/WmsOperationalDashboardPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsSkuDetailPage.js +10 -6
- package/dist/modules/wms/components/backend/WmsSkuDetailPage.js.map +2 -2
- package/dist/modules/wms/components/backend/inventoryMutationLoaders.js +20 -27
- package/dist/modules/wms/components/backend/inventoryMutationLoaders.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/page.js +1 -3
- package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
- package/dist/modules/workflows/backend/events/page.js +1 -3
- package/dist/modules/workflows/backend/events/page.js.map +2 -2
- package/dist/modules/workflows/backend/instances/page.js +1 -3
- package/dist/modules/workflows/backend/instances/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/page.js +1 -3
- package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
- package/dist/modules/workflows/lib/activity-executor.js +0 -4
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/package.json +10 -9
- package/src/helpers/integration/api.ts +1 -33
- package/src/helpers/integration/communicationChannelsFixtures.ts +1 -69
- package/src/modules/api_keys/api/keys/route.ts +1 -3
- package/src/modules/api_keys/backend/api-keys/page.tsx +1 -4
- package/src/modules/attachments/AGENTS.md +0 -15
- package/src/modules/attachments/api/route.ts +2 -2
- package/src/modules/attachments/components/AttachmentLibrary.tsx +0 -3
- package/src/modules/attachments/di.ts +0 -16
- package/src/modules/attachments/i18n/de.json +0 -5
- package/src/modules/attachments/i18n/en.json +0 -5
- package/src/modules/attachments/i18n/es.json +0 -5
- package/src/modules/attachments/i18n/ko.json +0 -5
- package/src/modules/attachments/i18n/pl.json +0 -5
- package/src/modules/attachments/index.ts +0 -10
- package/src/modules/attachments/lib/scoped-upload-service.ts +0 -46
- package/src/modules/attachments/lib/upload-limits.ts +2 -6
- package/src/modules/audit_logs/backend/audit-logs/page.tsx +0 -8
- package/src/modules/audit_logs/lib/display-helpers.tsx +32 -42
- package/src/modules/audit_logs/services/actionLogService.ts +11 -74
- package/src/modules/auth/acl.ts +6 -30
- package/src/modules/auth/api/feature-check.ts +3 -10
- package/src/modules/auth/api/login.ts +24 -9
- package/src/modules/auth/api/roles/acl/route.ts +39 -42
- package/src/modules/auth/api/routeError.ts +30 -0
- package/src/modules/auth/api/session/refresh.ts +1 -32
- package/src/modules/auth/api/users/acl/route.ts +101 -185
- package/src/modules/auth/api/users/route.ts +5 -18
- package/src/modules/auth/backend/roles/[id]/edit/page.meta.ts +2 -5
- package/src/modules/auth/backend/roles/page.tsx +2 -4
- package/src/modules/auth/backend/users/[id]/edit/page.meta.ts +2 -5
- package/src/modules/auth/backend/users/page.tsx +2 -3
- package/src/modules/auth/components/AclEditor.tsx +33 -63
- package/src/modules/auth/data/entities.ts +1 -4
- package/src/modules/auth/data/validators.ts +0 -5
- package/src/modules/auth/di.ts +16 -46
- package/src/modules/auth/frontend/reset/[token]/page.tsx +0 -74
- package/src/modules/auth/i18n/de.json +0 -389
- package/src/modules/auth/i18n/en.json +0 -389
- package/src/modules/auth/i18n/es.json +0 -389
- package/src/modules/auth/i18n/ko.json +0 -389
- package/src/modules/auth/i18n/pl.json +2 -391
- package/src/modules/auth/lib/grantChecks.ts +0 -6
- package/src/modules/auth/services/authService.ts +2 -18
- package/src/modules/auth/services/rbacService.ts +24 -110
- package/src/modules/business_rules/backend/logs/page.tsx +1 -4
- package/src/modules/business_rules/backend/rules/[id]/page.meta.ts +5 -0
- package/src/modules/business_rules/backend/rules/create/page.meta.ts +5 -1
- package/src/modules/business_rules/backend/rules/page.tsx +1 -4
- package/src/modules/business_rules/backend/sets/[id]/page.meta.ts +5 -0
- package/src/modules/business_rules/backend/sets/create/page.meta.ts +5 -1
- package/src/modules/business_rules/backend/sets/page.tsx +1 -4
- package/src/modules/business_rules/lib/expression-evaluator.ts +9 -9
- package/src/modules/business_rules/lib/rule-evaluator.ts +9 -10
- 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 +5 -12
- package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +0 -3
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +0 -7
- package/src/modules/catalog/i18n/de.json +0 -1
- package/src/modules/catalog/i18n/en.json +0 -1
- package/src/modules/catalog/i18n/es.json +0 -1
- package/src/modules/catalog/i18n/ko.json +0 -1
- package/src/modules/catalog/i18n/pl.json +0 -1
- package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.tsx +0 -4
- package/src/modules/communication_channels/api/post/channels/[id]/test-send/route.ts +1 -17
- package/src/modules/communication_channels/api/post/test-seed/route.ts +16 -155
- package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +0 -4
- package/src/modules/communication_channels/commands/ingest-inbound-message.ts +1 -38
- package/src/modules/communication_channels/di.ts +0 -7
- package/src/modules/communication_channels/lib/adapter.ts +0 -14
- package/src/modules/communication_channels/lib/email-capabilities.ts +0 -4
- package/src/modules/communication_channels/lib/test-seed.ts +4 -64
- package/src/modules/configs/i18n/de.json +0 -2
- package/src/modules/configs/i18n/en.json +0 -2
- package/src/modules/configs/i18n/es.json +0 -2
- package/src/modules/configs/i18n/ko.json +0 -2
- package/src/modules/configs/i18n/pl.json +0 -2
- package/src/modules/configs/lib/system-status.ts +0 -9
- package/src/modules/currencies/backend/currencies/page.tsx +1 -4
- package/src/modules/currencies/backend/exchange-rates/page.tsx +1 -4
- package/src/modules/customer_accounts/api/admin/domain-mappings.ts +0 -7
- package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +1 -4
- package/src/modules/customer_accounts/backend/customer_accounts/settings/CustomerAccountsSettingsPageClient.tsx +138 -0
- package/src/modules/customer_accounts/backend/customer_accounts/settings/page.tsx +8 -132
- package/src/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.tsx +598 -0
- package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/PortalUserDetailPageClient.tsx +838 -0
- package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/page.tsx +6 -838
- package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +6 -590
- package/src/modules/customer_accounts/extension-points.ts +1 -1
- package/src/modules/customer_accounts/lib/portalUrl.ts +112 -0
- package/src/modules/customer_accounts/services/domainMappingService.ts +0 -10
- package/src/modules/customers/ai-tools/companies-pack.ts +1 -4
- package/src/modules/customers/ai-tools/deal-analyzer-pack.ts +2 -17
- package/src/modules/customers/ai-tools/deals-pack.ts +1 -66
- package/src/modules/customers/ai-tools/people-pack.ts +1 -4
- package/src/modules/customers/api/activities/route.ts +0 -45
- package/src/modules/customers/api/companies/[id]/people/route.ts +73 -24
- package/src/modules/customers/api/companies/[id]/route.ts +107 -24
- package/src/modules/customers/api/dashboard/widgets/customer-todos/route.ts +8 -16
- package/src/modules/customers/api/deals/[id]/companies/route.ts +1 -4
- package/src/modules/customers/api/deals/[id]/people/route.ts +1 -4
- package/src/modules/customers/api/deals/[id]/route.ts +28 -17
- package/src/modules/customers/api/deals/[id]/stats/route.ts +25 -10
- package/src/modules/customers/api/deals/aggregate/route.ts +4 -14
- package/src/modules/customers/api/deals/map/route.ts +0 -1
- package/src/modules/customers/api/deals/route.ts +1 -50
- package/src/modules/customers/api/entity-roles-factory.ts +4 -8
- package/src/modules/customers/api/interactions/route.ts +2 -8
- package/src/modules/customers/api/interactions/tasks/route.ts +1 -24
- package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +4 -12
- package/src/modules/customers/api/people/[id]/companies/context.ts +1 -4
- package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +1 -4
- package/src/modules/customers/api/people/[id]/route.ts +11 -16
- package/src/modules/customers/api/people/check-phone/route.ts +10 -75
- package/src/modules/customers/api/todos/route.ts +2 -27
- package/src/modules/customers/backend/customers/companies/page.tsx +4 -7
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +2 -7
- package/src/modules/customers/backend/customers/deals/page.tsx +4 -10
- package/src/modules/customers/backend/customers/deals/pipeline/components/Lane.tsx +14 -5
- package/src/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.tsx +27 -109
- package/src/modules/customers/backend/customers/people/page.tsx +4 -7
- package/src/modules/customers/backend/hooks/useEmailDuplicateCheck.ts +4 -12
- package/src/modules/customers/commands/deals.ts +59 -34
- package/src/modules/customers/commands/interactions.ts +1 -1
- package/src/modules/customers/commands/personCompanyLinks.ts +8 -224
- package/src/modules/customers/components/CustomerTodosTable.tsx +0 -2
- 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 +2 -4
- package/src/modules/customers/components/calendar/editor/PeopleField.tsx +5 -61
- package/src/modules/customers/components/calendar/editor/hooks.ts +1 -7
- package/src/modules/customers/components/calendar/types.ts +2 -2
- package/src/modules/customers/components/detail/AssignRoleDialog.tsx +12 -7
- package/src/modules/customers/components/detail/CompanyKpiBar.tsx +4 -5
- package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +1 -8
- package/src/modules/customers/components/detail/DealForm.tsx +2 -22
- package/src/modules/customers/components/detail/DealsSection.tsx +5 -11
- package/src/modules/customers/components/detail/EntityTagsDialog.tsx +12 -58
- package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +1 -8
- package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +14 -23
- 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 +5 -15
- package/src/modules/customers/data/entities.ts +1 -1
- package/src/modules/customers/data/validators.ts +9 -50
- package/src/modules/customers/events.ts +0 -5
- package/src/modules/customers/i18n/de.json +1 -9
- package/src/modules/customers/i18n/en.json +1 -9
- package/src/modules/customers/i18n/es.json +1 -9
- package/src/modules/customers/i18n/ko.json +1 -9
- package/src/modules/customers/i18n/pl.json +1 -9
- package/src/modules/customers/lib/calendar/conflicts.ts +2 -10
- package/src/modules/customers/lib/calendar/editorPayload.ts +3 -4
- package/src/modules/customers/lib/calendar/mapItem.ts +3 -8
- package/src/modules/customers/lib/dealStatus.ts +0 -42
- package/src/modules/customers/lib/findPeopleByAddresses.ts +6 -8
- package/src/modules/customers/lib/personCompanies.ts +1 -136
- package/src/modules/customers/lib/todoCompatibility.ts +1 -19
- 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 +0 -6
- package/src/modules/data_sync/AGENTS.md +1 -1
- package/src/modules/data_sync/backend/data-sync/page.tsx +1 -4
- package/src/modules/data_sync/lib/adapter.ts +0 -36
- package/src/modules/data_sync/lib/sync-engine.ts +5 -113
- package/src/modules/data_sync/workers/sync-export.ts +0 -4
- package/src/modules/data_sync/workers/sync-import.ts +0 -4
- package/src/modules/devices/AGENTS.md +1 -20
- package/src/modules/devices/acl.ts +1 -9
- package/src/modules/devices/api/admin/devices/[id]/route.ts +34 -5
- package/src/modules/devices/api/admin/devices/route.ts +1 -14
- package/src/modules/devices/api/deviceList.ts +11 -135
- package/src/modules/devices/api/openapi.ts +1 -9
- package/src/modules/devices/api/route.ts +1 -9
- package/src/modules/devices/backend/devices/[id]/page.tsx +32 -18
- package/src/modules/devices/backend/devices/create/page.tsx +1 -17
- package/src/modules/devices/backend/devices/page.tsx +45 -44
- package/src/modules/devices/i18n/de.json +2 -3
- package/src/modules/devices/i18n/en.json +2 -3
- package/src/modules/devices/i18n/es.json +2 -3
- package/src/modules/devices/i18n/ko.json +2 -3
- package/src/modules/devices/i18n/pl.json +2 -3
- package/src/modules/devices/setup.ts +2 -6
- package/src/modules/directory/backend/directory/organizations/page.tsx +1 -3
- package/src/modules/directory/backend/directory/tenants/page.tsx +1 -3
- package/src/modules/directory/di.ts +2 -14
- package/src/modules/directory/utils/organizationScope.ts +15 -4
- package/src/modules/entities/api/records.ts +0 -2
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +1 -4
- package/src/modules/eudr/api/plots/route.ts +0 -4
- package/src/modules/eudr/backend/eudr/evidence-submissions/[id]/page.meta.ts +2 -0
- package/src/modules/eudr/backend/eudr/evidence-submissions/create/page.meta.ts +1 -0
- package/src/modules/eudr/backend/eudr/evidence-submissions/page.meta.ts +4 -1
- package/src/modules/eudr/backend/eudr/evidence-submissions/page.tsx +0 -4
- package/src/modules/eudr/backend/eudr/page.meta.ts +2 -2
- package/src/modules/eudr/backend/eudr/plots/[id]/page.meta.ts +2 -0
- package/src/modules/eudr/backend/eudr/plots/[id]/page.tsx +8 -2
- package/src/modules/eudr/backend/eudr/plots/create/page.meta.ts +1 -0
- package/src/modules/eudr/backend/eudr/plots/create/page.tsx +8 -2
- package/src/modules/eudr/backend/eudr/plots/page.meta.ts +4 -1
- package/src/modules/eudr/backend/eudr/plots/page.tsx +0 -4
- package/src/modules/eudr/backend/eudr/product-mappings/[id]/page.meta.ts +2 -0
- package/src/modules/eudr/backend/eudr/product-mappings/create/page.meta.ts +1 -0
- package/src/modules/eudr/backend/eudr/product-mappings/page.meta.ts +4 -1
- package/src/modules/eudr/backend/eudr/product-mappings/page.tsx +0 -4
- package/src/modules/eudr/backend/eudr/risk-assessments/[id]/page.meta.ts +2 -0
- package/src/modules/eudr/backend/eudr/risk-assessments/create/page.meta.ts +1 -0
- package/src/modules/eudr/backend/eudr/risk-assessments/page.meta.ts +4 -1
- package/src/modules/eudr/backend/eudr/risk-assessments/page.tsx +0 -4
- package/src/modules/eudr/backend/eudr/statements/[id]/page.meta.ts +2 -0
- package/src/modules/eudr/backend/eudr/statements/[id]/page.tsx +2 -0
- package/src/modules/eudr/backend/eudr/statements/create/page.meta.ts +1 -0
- package/src/modules/eudr/backend/eudr/statements/page.meta.ts +4 -1
- package/src/modules/eudr/backend/eudr/statements/page.tsx +32 -30
- package/src/modules/eudr/commands/statements.ts +7 -2
- package/src/modules/eudr/components/crudErrorI18n.ts +31 -0
- package/src/modules/eudr/components/formConfig.tsx +9 -1
- package/src/modules/eudr/data/validators.ts +1 -16
- package/src/modules/eudr/i18n/de.json +3 -2
- package/src/modules/eudr/i18n/en.json +3 -2
- package/src/modules/eudr/i18n/es.json +3 -2
- package/src/modules/eudr/i18n/ko.json +3 -2
- package/src/modules/eudr/i18n/pl.json +3 -2
- package/src/modules/eudr/lib/statement-lifecycle.ts +8 -0
- package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +1 -2
- package/src/modules/feature_toggles/components/OverridesTable.tsx +1 -2
- package/src/modules/feature_toggles/defaults.json +8 -0
- package/src/modules/inbox_ops/backend/inbox-ops/log/page.tsx +0 -4
- package/src/modules/inbox_ops/backend/inbox-ops/page.tsx +0 -4
- package/src/modules/inbox_ops/lib/htmlToPlainText.ts +17 -1
- package/src/modules/integrations/api/[id]/credentials/route.ts +4 -6
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +31 -61
- package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +9 -44
- package/src/modules/integrations/data/validators.ts +2 -12
- package/src/modules/integrations/i18n/de.json +0 -1
- package/src/modules/integrations/i18n/en.json +0 -1
- package/src/modules/integrations/i18n/es.json +0 -1
- package/src/modules/integrations/i18n/ko.json +0 -1
- package/src/modules/integrations/i18n/pl.json +0 -1
- package/src/modules/integrations/lib/credentials-masking.ts +6 -10
- package/src/modules/messages/api/[id]/route.ts +1 -55
- package/src/modules/messages/api/openapi.ts +0 -20
- package/src/modules/messages/api/route.ts +2 -31
- package/src/modules/messages/components/MessagesInboxPageClient.tsx +16 -9
- package/src/modules/messages/components/inboxFilters.ts +0 -36
- package/src/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.ts +1 -14
- package/src/modules/messages/components/message-detail/panels/MessageHeader.tsx +1 -3
- package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +1 -2
- package/src/modules/messages/components/message-detail/types.ts +0 -3
- package/src/modules/messages/components/messageListLabels.ts +3 -52
- package/src/modules/messages/data/validators.ts +4 -43
- package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +6 -4
- package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +1 -4
- package/src/modules/payment_gateways/lib/webhook-processor.ts +0 -11
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +0 -4
- package/src/modules/push_notifications/backend/push_notifications/page.tsx +1 -4
- package/src/modules/push_notifications/backend/push_notifications/send/page.tsx +4 -4
- package/src/modules/query_index/lib/engine.ts +61 -249
- package/src/modules/query_index/lib/search-tokens.ts +3 -135
- package/src/modules/resources/backend/resources/resource-types/page.tsx +1 -4
- package/src/modules/resources/backend/resources/resources/page.tsx +1 -4
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +0 -4
- package/src/modules/sales/backend/sales/channels/page.tsx +0 -4
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +8 -14
- package/src/modules/sales/commands/documents.ts +0 -93
- package/src/modules/sales/components/PriceWithCurrency.tsx +5 -17
- package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +0 -4
- package/src/modules/sales/components/documents/AdjustmentsSection.tsx +5 -6
- package/src/modules/sales/components/documents/ItemsSection.tsx +18 -56
- package/src/modules/sales/components/documents/LineItemDialog.tsx +21 -138
- package/src/modules/sales/components/documents/PaymentsSection.tsx +9 -20
- package/src/modules/sales/components/documents/ReturnsSection.tsx +5 -6
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +14 -106
- package/src/modules/sales/components/documents/SalesOrderDraftLines.tsx +5 -6
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +4 -5
- package/src/modules/sales/components/documents/ShipmentsSection.tsx +5 -6
- package/src/modules/sales/components/documents/lineItemUtils.ts +2 -7
- package/src/modules/sales/data/entities.ts +0 -6
- package/src/modules/sales/extension-points.ts +0 -1
- package/src/modules/sales/i18n/de.json +37 -8
- package/src/modules/sales/i18n/en.json +37 -8
- package/src/modules/sales/i18n/es.json +37 -8
- package/src/modules/sales/i18n/ko.json +37 -8
- package/src/modules/sales/i18n/pl.json +37 -8
- package/src/modules/sales/migrations/.snapshot-open-mercato.json +0 -60
- package/src/modules/sales/setup.ts +0 -2
- package/src/modules/sales/widgets/injection/document-history/widget.client.tsx +42 -2
- package/src/modules/sales/widgets/injection/payment-gateway-status-column/widget.ts +1 -9
- package/src/modules/sales/widgets/injection-table.ts +7 -4
- package/src/modules/staff/backend/staff/leave-requests/page.tsx +0 -4
- package/src/modules/staff/backend/staff/my-leave-requests/page.tsx +0 -4
- package/src/modules/staff/backend/staff/team-members/page.tsx +0 -6
- package/src/modules/staff/backend/staff/team-roles/page.tsx +0 -4
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +0 -4
- package/src/modules/staff/backend/staff/teams/page.tsx +0 -4
- package/src/modules/staff/backend/staff/timesheets/page.tsx +1 -12
- package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +0 -4
- package/src/modules/sync_excel/lib/adapters/customers.ts +0 -5
- 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 +9 -12
- package/src/modules/warranty_claims/backend/page.tsx +0 -4
- package/src/modules/warranty_claims/backend/warranty_claims/registrations/page.tsx +0 -4
- package/src/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.tsx +0 -4
- package/src/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.tsx +0 -4
- package/src/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.tsx +0 -4
- package/src/modules/wms/api/warehouses/route.ts +9 -13
- package/src/modules/wms/api/zones/route.ts +0 -16
- package/src/modules/wms/commands/configuration.ts +10 -159
- package/src/modules/wms/commands/inventory-actions.ts +0 -3
- package/src/modules/wms/commands/shared.ts +0 -17
- package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +141 -95
- package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +0 -2
- package/src/modules/wms/components/backend/WmsLocationDetailPage.tsx +30 -26
- package/src/modules/wms/components/backend/WmsLotDetailPage.tsx +21 -17
- package/src/modules/wms/components/backend/WmsLotsListPage.tsx +0 -2
- package/src/modules/wms/components/backend/WmsOperationalDashboardPage.tsx +17 -13
- package/src/modules/wms/components/backend/WmsSkuDetailPage.tsx +16 -12
- package/src/modules/wms/components/backend/inventoryMutationLoaders.ts +20 -36
- package/src/modules/wms/i18n/de.json +0 -2
- package/src/modules/wms/i18n/en.json +0 -2
- package/src/modules/wms/i18n/es.json +0 -2
- package/src/modules/wms/i18n/ko.json +0 -2
- package/src/modules/wms/i18n/pl.json +0 -2
- package/src/modules/workflows/backend/definitions/page.tsx +1 -4
- package/src/modules/workflows/backend/events/page.tsx +1 -4
- package/src/modules/workflows/backend/instances/page.tsx +1 -4
- package/src/modules/workflows/backend/tasks/page.tsx +1 -4
- package/src/modules/workflows/lib/activity-executor.ts +0 -9
- package/dist/modules/api_keys/di.js +0 -9
- package/dist/modules/api_keys/di.js.map +0 -7
- package/dist/modules/api_keys/services/principalService.js +0 -31
- package/dist/modules/api_keys/services/principalService.js.map +0 -7
- package/dist/modules/attachments/lib/attachment-service.js +0 -313
- package/dist/modules/attachments/lib/attachment-service.js.map +0 -7
- package/dist/modules/auth/api/reset/validate.js +0 -55
- package/dist/modules/auth/api/reset/validate.js.map +0 -7
- package/dist/modules/auth/commands/acl.js +0 -254
- package/dist/modules/auth/commands/acl.js.map +0 -7
- package/dist/modules/auth/lib/userIdFilter.js +0 -16
- package/dist/modules/auth/lib/userIdFilter.js.map +0 -7
- package/dist/modules/auth/services/principalService.js +0 -200
- package/dist/modules/auth/services/principalService.js.map +0 -7
- package/dist/modules/auth/services/roleOrganizationScope.js +0 -41
- package/dist/modules/auth/services/roleOrganizationScope.js.map +0 -7
- package/dist/modules/communication_channels/lib/outbound-recipient.js +0 -33
- package/dist/modules/communication_channels/lib/outbound-recipient.js.map +0 -7
- package/dist/modules/communication_channels/lib/resolve-channel-type.js +0 -51
- package/dist/modules/communication_channels/lib/resolve-channel-type.js.map +0 -7
- package/dist/modules/customers/backend/customers/deals/pipeline/components/toneClasses.js +0 -18
- package/dist/modules/customers/backend/customers/deals/pipeline/components/toneClasses.js.map +0 -7
- package/dist/modules/customers/lib/calendar/participantIdentity.js +0 -9
- package/dist/modules/customers/lib/calendar/participantIdentity.js.map +0 -7
- package/dist/modules/customers/lib/closureStage.js +0 -45
- package/dist/modules/customers/lib/closureStage.js.map +0 -7
- package/dist/modules/customers/lib/detailReadAccess.js +0 -12
- package/dist/modules/customers/lib/detailReadAccess.js.map +0 -7
- package/dist/modules/data_sync/lib/abandoned-run.js +0 -19
- package/dist/modules/data_sync/lib/abandoned-run.js.map +0 -7
- package/dist/modules/devices/api/deviceSerialization.js +0 -46
- package/dist/modules/devices/api/deviceSerialization.js.map +0 -7
- package/dist/modules/devices/backend/devices/useDeviceUserLabels.js +0 -34
- package/dist/modules/devices/backend/devices/useDeviceUserLabels.js.map +0 -7
- package/dist/modules/devices/backend/devices/userOptions.js +0 -52
- package/dist/modules/devices/backend/devices/userOptions.js.map +0 -7
- package/dist/modules/directory/services/organizationHierarchyService.js +0 -29
- package/dist/modules/directory/services/organizationHierarchyService.js.map +0 -7
- package/dist/modules/directory/services/organizationScopeService.js +0 -56
- package/dist/modules/directory/services/organizationScopeService.js.map +0 -7
- package/dist/modules/integrations/backend/integrations/credential-secret-fields.js +0 -55
- package/dist/modules/integrations/backend/integrations/credential-secret-fields.js.map +0 -7
- package/dist/modules/messages/lib/channel-sender-identity.js +0 -26
- package/dist/modules/messages/lib/channel-sender-identity.js.map +0 -7
- package/dist/modules/messages/lib/composeSourceChannelType.js +0 -41
- package/dist/modules/messages/lib/composeSourceChannelType.js.map +0 -7
- package/dist/modules/query_index/lib/search-entity-policy.js +0 -14
- package/dist/modules/query_index/lib/search-entity-policy.js.map +0 -7
- package/dist/modules/sales/components/documents/lineItemShipmentLock.js +0 -54
- package/dist/modules/sales/components/documents/lineItemShipmentLock.js.map +0 -7
- package/dist/modules/sales/lib/salesChannelsToggleSeed.js +0 -33
- package/dist/modules/sales/lib/salesChannelsToggleSeed.js.map +0 -7
- package/dist/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.js +0 -32
- package/dist/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.js.map +0 -7
- package/dist/modules/wms/api/warehouseSearch.js +0 -21
- package/dist/modules/wms/api/warehouseSearch.js.map +0 -7
- package/dist/modules/wms/components/backend/WarehouseEditDialog.js +0 -158
- package/dist/modules/wms/components/backend/WarehouseEditDialog.js.map +0 -7
- package/dist/modules/wms/components/backend/warehouseFormOptions.js +0 -66
- package/dist/modules/wms/components/backend/warehouseFormOptions.js.map +0 -7
- package/src/modules/api_keys/di.ts +0 -7
- package/src/modules/api_keys/services/principalService.ts +0 -33
- package/src/modules/attachments/lib/attachment-service.ts +0 -468
- package/src/modules/auth/api/reset/validate.ts +0 -57
- package/src/modules/auth/commands/acl.ts +0 -495
- package/src/modules/auth/lib/userIdFilter.ts +0 -31
- package/src/modules/auth/services/principalService.ts +0 -266
- package/src/modules/auth/services/roleOrganizationScope.ts +0 -70
- package/src/modules/communication_channels/lib/outbound-recipient.ts +0 -71
- package/src/modules/communication_channels/lib/resolve-channel-type.ts +0 -99
- package/src/modules/customers/backend/customers/deals/pipeline/components/toneClasses.ts +0 -21
- package/src/modules/customers/lib/calendar/participantIdentity.ts +0 -17
- package/src/modules/customers/lib/closureStage.ts +0 -76
- package/src/modules/customers/lib/detailReadAccess.ts +0 -35
- package/src/modules/data_sync/lib/abandoned-run.ts +0 -56
- package/src/modules/devices/api/deviceSerialization.ts +0 -50
- package/src/modules/devices/backend/devices/useDeviceUserLabels.ts +0 -45
- package/src/modules/devices/backend/devices/userOptions.ts +0 -99
- package/src/modules/directory/services/organizationHierarchyService.ts +0 -34
- package/src/modules/directory/services/organizationScopeService.ts +0 -85
- package/src/modules/integrations/backend/integrations/credential-secret-fields.ts +0 -84
- package/src/modules/messages/lib/channel-sender-identity.ts +0 -55
- package/src/modules/messages/lib/composeSourceChannelType.ts +0 -95
- package/src/modules/query_index/lib/search-entity-policy.ts +0 -46
- package/src/modules/sales/components/documents/lineItemShipmentLock.ts +0 -74
- package/src/modules/sales/lib/salesChannelsToggleSeed.ts +0 -42
- package/src/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.ts +0 -87
- package/src/modules/wms/api/warehouseSearch.ts +0 -23
- package/src/modules/wms/components/backend/WarehouseEditDialog.tsx +0 -216
- package/src/modules/wms/components/backend/warehouseFormOptions.ts +0 -72
package/dist/modules/auth/di.js
CHANGED
|
@@ -6,43 +6,17 @@ import {
|
|
|
6
6
|
isRbacDefaultCacheEnabled,
|
|
7
7
|
resetRbacFallbackCache
|
|
8
8
|
} from "@open-mercato/core/modules/auth/services/rbacDefaultCache";
|
|
9
|
-
import { DefaultAuthPrincipalService } from "./services/principalService.js";
|
|
10
|
-
function resolveOptionalCache(container) {
|
|
11
|
-
try {
|
|
12
|
-
return container.hasRegistration("cache") ? container.resolve("cache") : void 0;
|
|
13
|
-
} catch {
|
|
14
|
-
return void 0;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
function resolveOptionalOrganizationHierarchyService(container) {
|
|
18
|
-
try {
|
|
19
|
-
if (!container.hasRegistration("organizationHierarchyService")) return void 0;
|
|
20
|
-
const candidate = container.resolve("organizationHierarchyService");
|
|
21
|
-
return typeof candidate?.resolveAncestorIds === "function" ? candidate : void 0;
|
|
22
|
-
} catch {
|
|
23
|
-
return void 0;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
9
|
function register(container) {
|
|
27
10
|
container.register({ authService: asClass(AuthService).scoped() });
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
em,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
rbacService: asFunction(function rbacServiceFactory(em) {
|
|
38
|
-
const configuredCache = resolveOptionalCache(container);
|
|
39
|
-
return new RbacService(
|
|
40
|
-
em,
|
|
41
|
-
configuredCache ?? (isRbacDefaultCacheEnabled() ? createRbacFallbackCache() : void 0),
|
|
42
|
-
resolveOptionalOrganizationHierarchyService(container)
|
|
43
|
-
);
|
|
44
|
-
}).scoped()
|
|
45
|
-
});
|
|
11
|
+
if (isRbacDefaultCacheEnabled()) {
|
|
12
|
+
container.register({
|
|
13
|
+
rbacService: asFunction((cradle) => {
|
|
14
|
+
return new RbacService(cradle.em, cradle.cache ?? createRbacFallbackCache());
|
|
15
|
+
}).scoped()
|
|
16
|
+
});
|
|
17
|
+
} else {
|
|
18
|
+
container.register({ rbacService: asClass(RbacService).scoped() });
|
|
19
|
+
}
|
|
46
20
|
}
|
|
47
21
|
export {
|
|
48
22
|
register,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/modules/auth/di.ts"],
|
|
4
|
-
"sourcesContent": ["import { asClass, asFunction } from 'awilix'\nimport type { AppContainer } from '@open-mercato/shared/lib/di/container'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport
|
|
5
|
-
"mappings": "AAAA,SAAS,SAAS,kBAAkB;
|
|
4
|
+
"sourcesContent": ["import { asClass, asFunction } from 'awilix'\nimport type { AppContainer } from '@open-mercato/shared/lib/di/container'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport { AuthService } from '@open-mercato/core/modules/auth/services/authService'\nimport { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport {\n createRbacFallbackCache,\n isRbacDefaultCacheEnabled,\n resetRbacFallbackCache,\n} from '@open-mercato/core/modules/auth/services/rbacDefaultCache'\n\nexport { resetRbacFallbackCache }\n\nexport function register(container: AppContainer) {\n // Register or override core auth service\n container.register({ authService: asClass(AuthService).scoped() })\n // RBAC service. The bare `asClass(...).scoped()` registration matches\n // develop and is the default. Setting `OM_RBAC_DEFAULT_CACHE=on` opts\n // into the in-process LRU fallback for deployments that don't wire a\n // shared CacheStrategy (CLI scripts, lean test bootstraps). Production\n // bootstraps that already register `cache` via `@open-mercato/cache`\n // preempt this fallback because the container's existing `cache`\n // registration wins when `RbacService` reaches for it.\n if (isRbacDefaultCacheEnabled()) {\n container.register({\n rbacService: asFunction((cradle: { em: EntityManager; cache?: CacheStrategy }) => {\n return new RbacService(cradle.em, cradle.cache ?? createRbacFallbackCache())\n }).scoped(),\n })\n } else {\n container.register({ rbacService: asClass(RbacService).scoped() })\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,SAAS,kBAAkB;AAIpC,SAAS,mBAAmB;AAC5B,SAAS,mBAAmB;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAIA,SAAS,SAAS,WAAyB;AAEhD,YAAU,SAAS,EAAE,aAAa,QAAQ,WAAW,EAAE,OAAO,EAAE,CAAC;AAQjE,MAAI,0BAA0B,GAAG;AAC/B,cAAU,SAAS;AAAA,MACjB,aAAa,WAAW,CAAC,WAAyD;AAChF,eAAO,IAAI,YAAY,OAAO,IAAI,OAAO,SAAS,wBAAwB,CAAC;AAAA,MAC7E,CAAC,EAAE,OAAO;AAAA,IACZ,CAAC;AAAA,EACH,OAAO;AACL,cAAU,SAAS,EAAE,aAAa,QAAQ,WAAW,EAAE,OAAO,EAAE,CAAC;AAAA,EACnE;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -5,10 +5,8 @@ import { Button } from "@open-mercato/ui/primitives/button";
|
|
|
5
5
|
import { PasswordInput } from "@open-mercato/ui/primitives/password-input";
|
|
6
6
|
import { Label } from "@open-mercato/ui/primitives/label";
|
|
7
7
|
import { useEffect, useState } from "react";
|
|
8
|
-
import Link from "next/link";
|
|
9
8
|
import { useRouter } from "next/navigation";
|
|
10
9
|
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
11
|
-
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
12
10
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
13
11
|
import { formatPasswordRequirements, getPasswordPolicy, validatePassword } from "@open-mercato/shared/lib/auth/passwordPolicy";
|
|
14
12
|
function ResetWithTokenPage({ params }) {
|
|
@@ -17,35 +15,12 @@ function ResetWithTokenPage({ params }) {
|
|
|
17
15
|
const [error, setError] = useState(null);
|
|
18
16
|
const [submitting, setSubmitting] = useState(false);
|
|
19
17
|
const [clientReady, setClientReady] = useState(false);
|
|
20
|
-
const [tokenState, setTokenState] = useState("checking");
|
|
21
18
|
const passwordPolicy = getPasswordPolicy();
|
|
22
19
|
const passwordRequirements = formatPasswordRequirements(passwordPolicy, t);
|
|
23
20
|
const passwordDescription = passwordRequirements ? t("auth.password.requirements.help", "Password requirements: {requirements}", { requirements: passwordRequirements }) : "";
|
|
24
21
|
useEffect(() => {
|
|
25
22
|
setClientReady(true);
|
|
26
23
|
}, []);
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
let cancelled = false;
|
|
29
|
-
async function checkToken() {
|
|
30
|
-
const body = new FormData();
|
|
31
|
-
body.set("token", params.token);
|
|
32
|
-
try {
|
|
33
|
-
const { ok, result } = await apiCall(
|
|
34
|
-
"/api/auth/reset/validate",
|
|
35
|
-
{ method: "POST", body }
|
|
36
|
-
);
|
|
37
|
-
if (cancelled) return;
|
|
38
|
-
setTokenState(ok && result?.valid === false ? "expired" : "usable");
|
|
39
|
-
} catch {
|
|
40
|
-
if (cancelled) return;
|
|
41
|
-
setTokenState("usable");
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
void checkToken();
|
|
45
|
-
return () => {
|
|
46
|
-
cancelled = true;
|
|
47
|
-
};
|
|
48
|
-
}, [params.token]);
|
|
49
24
|
async function onSubmit(e) {
|
|
50
25
|
e.preventDefault();
|
|
51
26
|
setError(null);
|
|
@@ -84,27 +59,6 @@ function ResetWithTokenPage({ params }) {
|
|
|
84
59
|
setSubmitting(false);
|
|
85
60
|
}
|
|
86
61
|
}
|
|
87
|
-
if (tokenState === "checking") {
|
|
88
|
-
return /* @__PURE__ */ jsx("div", { className: "min-h-svh flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs(Card, { className: "w-full max-w-sm", children: [
|
|
89
|
-
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { children: t("auth.reset.title", "Set a new password") }) }),
|
|
90
|
-
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", "data-auth-token-state": "checking", children: [
|
|
91
|
-
/* @__PURE__ */ jsx(Spinner, { size: "sm" }),
|
|
92
|
-
/* @__PURE__ */ jsx("span", { children: t("auth.reset.token.checking", "Checking your reset link...") })
|
|
93
|
-
] }) })
|
|
94
|
-
] }) });
|
|
95
|
-
}
|
|
96
|
-
if (tokenState === "expired") {
|
|
97
|
-
return /* @__PURE__ */ jsx("div", { className: "min-h-svh flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs(Card, { className: "w-full max-w-sm", children: [
|
|
98
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
99
|
-
/* @__PURE__ */ jsx(CardTitle, { children: t("auth.reset.token.expiredTitle", "This reset link is no longer valid") }),
|
|
100
|
-
/* @__PURE__ */ jsx(CardDescription, { children: t("auth.reset.token.expiredSubtitle", "It has already been used or has expired. Request a new link to set your password.") })
|
|
101
|
-
] }),
|
|
102
|
-
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs("div", { className: "grid gap-3", "data-auth-token-state": "expired", children: [
|
|
103
|
-
/* @__PURE__ */ jsx(Button, { asChild: true, className: "w-full", children: /* @__PURE__ */ jsx(Link, { href: "/reset", children: t("auth.reset.token.requestNew", "Request a new link") }) }),
|
|
104
|
-
/* @__PURE__ */ jsx("div", { className: "text-center", children: /* @__PURE__ */ jsx(Link, { href: "/login", className: "text-xs text-muted-foreground underline", children: t("auth.reset.backToLogin", "Back to login") }) })
|
|
105
|
-
] }) })
|
|
106
|
-
] }) });
|
|
107
|
-
}
|
|
108
62
|
return /* @__PURE__ */ jsx("div", { className: "min-h-svh flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs(Card, { className: "w-full max-w-sm", children: [
|
|
109
63
|
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
110
64
|
/* @__PURE__ */ jsx(CardTitle, { children: t("auth.reset.title", "Set a new password") }),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/auth/frontend/reset/%5Btoken%5D/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@open-mercato/ui/primitives/card'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { PasswordInput } from '@open-mercato/ui/primitives/password-input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { useEffect, useState } from 'react'\nimport
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@open-mercato/ui/primitives/card'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { PasswordInput } from '@open-mercato/ui/primitives/password-input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { useEffect, useState } from 'react'\nimport { useRouter } from 'next/navigation'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { formatPasswordRequirements, getPasswordPolicy, validatePassword } from '@open-mercato/shared/lib/auth/passwordPolicy'\n\nexport default function ResetWithTokenPage({ params }: { params: { token: string } }) {\n const router = useRouter()\n const t = useT()\n const [error, setError] = useState<string | null>(null)\n const [submitting, setSubmitting] = useState(false)\n const [clientReady, setClientReady] = useState(false)\n const passwordPolicy = getPasswordPolicy()\n const passwordRequirements = formatPasswordRequirements(passwordPolicy, t)\n const passwordDescription = passwordRequirements\n ? t('auth.password.requirements.help', 'Password requirements: {requirements}', { requirements: passwordRequirements })\n : ''\n\n useEffect(() => {\n setClientReady(true)\n }, [])\n\n async function onSubmit(e: React.FormEvent<HTMLFormElement>) {\n e.preventDefault()\n setError(null)\n const form = new FormData(e.currentTarget)\n const password = String(form.get('password') ?? '')\n const confirmPassword = String(form.get('confirmPassword') ?? '')\n\n if (!password) {\n setError(t('auth.profile.form.errors.newPasswordRequired', 'New password is required.'))\n return\n }\n if (!confirmPassword) {\n setError(t('auth.profile.form.errors.confirmPasswordRequired', 'Please confirm the new password.'))\n return\n }\n if (password !== confirmPassword) {\n setError(t('auth.profile.form.errors.passwordMismatch', 'Passwords do not match.'))\n return\n }\n if (!validatePassword(password, passwordPolicy).ok) {\n setError(t('auth.profile.form.errors.passwordRequirements', 'Password must meet the requirements.'))\n return\n }\n\n setSubmitting(true)\n try {\n form.set('token', params.token)\n const { ok, result } = await apiCall<{ ok?: boolean; error?: string; redirect?: string }>(\n '/api/auth/reset/confirm',\n { method: 'POST', body: form },\n )\n if (!ok || result?.ok === false) {\n setError(result?.error || t('auth.reset.errors.failed', 'Unable to reset password'))\n return\n }\n router.replace(result?.redirect || '/login')\n } finally {\n setSubmitting(false)\n }\n }\n\n return (\n <div className=\"min-h-svh flex items-center justify-center p-4\">\n <Card className=\"w-full max-w-sm\">\n <CardHeader>\n <CardTitle>{t('auth.reset.title', 'Set a new password')}</CardTitle>\n <CardDescription>{t('auth.reset.subtitle', 'Choose a strong password for your account.')}</CardDescription>\n </CardHeader>\n <CardContent>\n <form className=\"grid gap-3\" onSubmit={onSubmit} data-auth-ready={clientReady ? '1' : '0'}>\n {error && <div className=\"text-sm text-status-error-text\">{error}</div>}\n <div className=\"grid gap-1\">\n <Label htmlFor=\"password\">{t('auth.reset.form.password', 'New password')}</Label>\n <PasswordInput id=\"password\" name=\"password\" required minLength={passwordPolicy.minLength} autoComplete=\"new-password\" />\n {passwordDescription ? (\n <p className=\"text-xs text-muted-foreground\">{passwordDescription}</p>\n ) : null}\n </div>\n <div className=\"grid gap-1\">\n <Label htmlFor=\"confirmPassword\">{t('auth.profile.form.confirmPassword', 'Confirm new password')}</Label>\n <PasswordInput\n id=\"confirmPassword\"\n name=\"confirmPassword\"\n required\n minLength={passwordPolicy.minLength}\n autoComplete=\"new-password\"\n />\n </div>\n <Button type=\"submit\" className=\"mt-2 w-full\" disabled={submitting}>\n {submitting ? t('auth.reset.form.loading', '...') : t('auth.reset.form.submit', 'Update password')}\n </Button>\n </form>\n </CardContent>\n </Card>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/auth/lib/grantChecks.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\nimport { badRequest, CrudHttpError, forbidden } from '@open-mercato/shared/lib/crud/errors'\nimport { hasFeature } from '@open-mercato/shared/security/features'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { Role, RoleAcl, User, UserAcl, UserRole } from '@open-mercato/core/modules/auth/data/entities'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport type { OrganizationScope } from '@open-mercato/core/modules/directory/utils/organizationScope'\n\ntype ActorAcl = {\n isSuperAdmin: boolean\n features: string[]\n organizations: string[] | null\n}\n\ntype GrantCheckContext = {\n em: EntityManager\n rbacService: RbacService\n actorUserId: string | null | undefined\n tenantId: string | null | undefined\n organizationId?: string | null | undefined\n}\n\ntype RoleGrantCheckInput = GrantCheckContext & {\n roles: Role[]\n}\n\ntype RoleTokenGrantCheckInput = GrantCheckContext & {\n roleTokens: unknown\n}\n\ntype UserDestinationRolesInput = {\n em: EntityManager\n targetUserId: string\n destinationTenantId: string | null | undefined\n roleTokens: unknown\n}\n\ntype UserDestinationScopeCheckInput = GrantCheckContext & {\n actorIsSuperAdmin?: boolean\n allowedOrganizationIds?: string[] | null\n destinationTenantId: string | null | undefined\n destinationOrganizationId: string | null | undefined\n roles: Role[]\n}\n\ntype FeatureGrantCheckInput = GrantCheckContext & {\n features: unknown\n isSuperAdmin?: boolean\n organizations?: string[] | null\n}\n\ntype SuperAdminUserTargetInput = GrantCheckContext & {\n targetUserId: string\n actorIsSuperAdmin?: boolean\n}\n\ntype UserTargetAccessInput = SuperAdminUserTargetInput & {\n organizationScope: Pick<OrganizationScope, 'allowedIds'>\n}\n\ntype SuperAdminRoleTargetInput = GrantCheckContext & {\n targetRoleId: string\n actorIsSuperAdmin?: boolean\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n\nexport async function assertActorCanGrantRoleTokens(input: RoleTokenGrantCheckInput): Promise<Role[]> {\n const tokens = normalizeStringList(input.roleTokens)\n if (!tokens.length) return []\n\n const tenantId = normalizeNullableString(input.tenantId)\n const roles = await resolveRolesForGrant(input.em, tokens, tenantId)\n await assertActorCanGrantRoles({ ...input, tenantId, roles })\n return roles\n}\n\nexport async function resolveUserDestinationRoles(input: UserDestinationRolesInput): Promise<Role[]> {\n const destinationTenantId = normalizeNullableString(input.destinationTenantId)\n if (Array.isArray(input.roleTokens)) {\n return resolveRolesForGrant(input.em, normalizeStringList(input.roleTokens), destinationTenantId)\n }\n\n const links = await findWithDecryption(\n input.em,\n UserRole,\n { user: input.targetUserId as unknown as User } as FilterQuery<UserRole>,\n { populate: ['role'] },\n { tenantId: null, organizationId: null },\n )\n const roles: Role[] = []\n for (const link of links) {\n const linkedRole = (link as { role?: Role | string | null }).role\n if (linkedRole && typeof linkedRole === 'object') {\n roles.push(linkedRole)\n continue\n }\n if (typeof linkedRole === 'string') {\n const resolvedRole = await resolveRoleForGrant(input.em, linkedRole, null)\n if (resolvedRole) {\n roles.push(resolvedRole)\n continue\n }\n }\n throw badRequest(await translateAuthError(\n 'auth.users.errors.invalidRoleAssignment',\n 'User has an invalid role assignment',\n ))\n }\n return roles\n}\n\nexport async function assertActorCanAssignUserDestination(\n input: UserDestinationScopeCheckInput,\n): Promise<void> {\n const destinationTenantId = normalizeNullableString(input.destinationTenantId)\n const destinationOrganizationId = normalizeNullableString(input.destinationOrganizationId)\n if (!destinationTenantId || !destinationOrganizationId) {\n return throwUserDestinationOrganizationNotFound(400)\n }\n\n for (const role of input.roles) {\n if (normalizeNullableString(role.tenantId) !== destinationTenantId) {\n throw forbidden(await translateAuthError(\n 'auth.users.errors.roleOutsideDestinationTenant',\n 'Cannot retain or assign a role outside the destination tenant.',\n ))\n }\n }\n\n if (await resolveActorIsSuperAdmin(input)) return\n\n const actorTenantId = normalizeNullableString(input.tenantId)\n if (!actorTenantId || actorTenantId !== destinationTenantId) {\n return throwUserDestinationOrganizationNotFound(404)\n }\n\n const actorAcl = await loadActorAcl(input)\n const allowedOrganizationIds = input.allowedOrganizationIds === undefined\n ? actorAcl.organizations\n : input.allowedOrganizationIds\n if (\n allowedOrganizationIds !== null\n && !allowedOrganizationIds.includes('__all__')\n && !allowedOrganizationIds.includes(destinationOrganizationId)\n ) {\n throw forbidden(await translateAuthError(\n 'auth.users.errors.destinationOrganizationOutsideScope',\n 'Cannot assign user to a destination organization outside actor scope.',\n ))\n }\n\n await assertActorCanGrantRoles({\n ...input,\n tenantId: destinationTenantId,\n roles: input.roles,\n })\n}\n\nexport async function throwUserDestinationOrganizationNotFound(status: 400 | 404): Promise<never> {\n throw new CrudHttpError(status, {\n error: await translateAuthError(\n 'auth.users.errors.organizationNotFound',\n 'Organization not found',\n ),\n })\n}\n\nexport async function assertActorCanGrantRoles(input: RoleGrantCheckInput): Promise<void> {\n if (!input.roles.length) return\n\n const tenantId = normalizeNullableString(input.tenantId)\n const actorAcl = await loadActorAcl({ ...input, tenantId })\n if (actorAcl.isSuperAdmin) return\n\n if (!tenantId) {\n throw forbidden('Tenant context is required to grant roles.')\n }\n\n for (const role of input.roles) {\n const roleTenantId = normalizeNullableString(role.tenantId)\n if (roleTenantId !== tenantId) {\n throw forbidden('Cannot grant a role outside the target tenant.')\n }\n\n const acl = await findOneWithDecryption(\n input.em,\n RoleAcl,\n { role, tenantId } as FilterQuery<RoleAcl>,\n {},\n { tenantId, organizationId: null },\n )\n if (!acl) continue\n\n assertActorCanGrantAclSnapshot(actorAcl, {\n isSuperAdmin: !!acl.isSuperAdmin,\n features: normalizeStringList(acl.featuresJson),\n organizations: normalizeOrganizationList(acl.organizationsJson),\n })\n }\n}\n\nexport async function assertActorCanGrantAcl(input: FeatureGrantCheckInput): Promise<void> {\n const actorAcl = await loadActorAcl(input)\n if (actorAcl.isSuperAdmin) return\n\n const tenantId = normalizeNullableString(input.tenantId)\n if (!tenantId) {\n throw forbidden('Tenant context is required to grant ACL features.')\n }\n\n assertActorCanGrantAclSnapshot(actorAcl, {\n isSuperAdmin: !!input.isSuperAdmin,\n features: normalizeStringList(input.features),\n organizations: input.organizations === undefined ? undefined : normalizeOrganizationList(input.organizations),\n })\n}\n\nexport function normalizeGrantFeatureList(features: unknown): string[] {\n return normalizeStringList(features)\n}\n\nexport async function assertActorCanModifySuperAdminUserTarget(input: SuperAdminUserTargetInput): Promise<void> {\n const actorIsSuperAdmin = await resolveActorIsSuperAdmin(input)\n if (actorIsSuperAdmin) return\n const targetIsSuperAdmin = await isUserEffectivelySuperAdmin(input.em, input.targetUserId)\n if (targetIsSuperAdmin) {\n throw forbidden('Only super administrators can modify super administrator accounts.')\n }\n}\n\nexport async function assertActorCanModifySuperAdminRoleTarget(input: SuperAdminRoleTargetInput): Promise<void> {\n const actorIsSuperAdmin = await resolveActorIsSuperAdmin(input)\n if (actorIsSuperAdmin) return\n const targetIsSuperAdmin = await isRoleEffectivelySuperAdmin(input.em, input.targetRoleId)\n if (targetIsSuperAdmin) {\n throw forbidden('Only super administrators can modify super administrator roles.')\n }\n}\n\n/**\n * `input.tenantId` is the ACTOR's scope, not the target's: the check below is a\n * comparison between the two, so passing a tenant derived from the target turns\n * it into a tautology. Callers that resolve a record scope separately MUST still\n * hand this guard `auth.tenantId`.\n */\nexport async function assertActorCanAccessUserTarget(input: UserTargetAccessInput): Promise<void> {\n const isSuperAdmin = await resolveActorIsSuperAdmin(input)\n if (isSuperAdmin) return\n\n const target = await findOneWithDecryption(\n input.em,\n User,\n { id: input.targetUserId } as FilterQuery<User>,\n {},\n { tenantId: null, organizationId: null },\n )\n // Not found (incl. soft-deleted, which MikroORM's soft-delete filter hides):\n // delegate to the caller. Every wired call site is itself tenant-scoped \u2014 the\n // ACL/consents reads filter by auth.tenantId and the user commands re-load by\n // id within tenant \u2014 so a missing target yields a safe empty/404 there. The\n // guard's job is to block a foreign *existing* target, below.\n if (!target) return\n\n const actorTenantId = normalizeNullableString(input.tenantId)\n const targetTenantId = normalizeNullableString((target as { tenantId?: string | null }).tenantId)\n if (!targetTenantId || targetTenantId !== actorTenantId) {\n throw new CrudHttpError(404, { error: 'User not found' })\n }\n\n if (input.organizationScope.allowedIds !== null) {\n const targetOrganizationId = normalizeNullableString((target as { organizationId?: string | null }).organizationId)\n if (!targetOrganizationId || !input.organizationScope.allowedIds.includes(targetOrganizationId)) {\n throw forbidden('Not authorized to access this user.')\n }\n }\n}\n\nexport async function assertActorCanAccessRoleTarget(input: SuperAdminRoleTargetInput): Promise<void> {\n const isSuperAdmin = await resolveActorIsSuperAdmin(input)\n if (isSuperAdmin) return\n\n const target = await findOneWithDecryption(\n input.em,\n Role,\n { id: input.targetRoleId } as FilterQuery<Role>,\n {},\n { tenantId: null, organizationId: null },\n )\n // Not found (incl. soft-deleted): delegate (see assertActorCanAccessUserTarget).\n if (!target) return\n\n const actorTenantId = normalizeNullableString(input.tenantId)\n const targetTenantId = normalizeNullableString((target as { tenantId?: string | null }).tenantId)\n if (!targetTenantId || targetTenantId !== actorTenantId) {\n throw new CrudHttpError(404, { error: 'Role not found' })\n }\n}\n\nasync function resolveActorIsSuperAdmin(input: GrantCheckContext & { actorIsSuperAdmin?: boolean }): Promise<boolean> {\n if (typeof input.actorIsSuperAdmin === 'boolean') return input.actorIsSuperAdmin\n const acl = await loadActorAcl(input)\n return acl.isSuperAdmin\n}\n\nexport async function isUserEffectivelySuperAdmin(em: EntityManager, userId: string): Promise<boolean> {\n const directGrant = await em.findOne(\n UserAcl,\n { user: userId as unknown, isSuperAdmin: true } as FilterQuery<UserAcl>,\n )\n if (directGrant && (directGrant as { isSuperAdmin?: boolean }).isSuperAdmin === true) return true\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId as unknown } as FilterQuery<UserRole>,\n { populate: ['role'] },\n { tenantId: null, organizationId: null },\n )\n const roleIds = (Array.isArray(links) ? links : [])\n .map((link) => {\n const role = (link as { role?: { id?: unknown } | string | null }).role\n if (!role) return null\n if (typeof role === 'string') return role\n return role.id ? String(role.id) : null\n })\n .filter((id): id is string => typeof id === 'string' && id.length > 0)\n if (!roleIds.length) return false\n const roleGrant = await em.findOne(\n RoleAcl,\n { role: { $in: roleIds } as unknown, isSuperAdmin: true } as FilterQuery<RoleAcl>,\n )\n return !!roleGrant && (roleGrant as { isSuperAdmin?: boolean }).isSuperAdmin === true\n}\n\nexport async function isRoleEffectivelySuperAdmin(em: EntityManager, roleId: string): Promise<boolean> {\n const grant = await em.findOne(\n RoleAcl,\n { role: roleId as unknown, isSuperAdmin: true } as FilterQuery<RoleAcl>,\n )\n return !!grant && (grant as { isSuperAdmin?: boolean }).isSuperAdmin === true\n}\n\nexport async function listSuperAdminUserIds(em: EntityManager, tenantId: string | null): Promise<Set<string>> {\n const ids = new Set<string>()\n const userAclFilter: Record<string, unknown> = { isSuperAdmin: true }\n if (tenantId) userAclFilter.tenantId = tenantId\n const userAcls = await em.find(UserAcl, userAclFilter as FilterQuery<UserAcl>)\n for (const acl of userAcls) {\n const userRef = (acl as { user?: { id?: unknown } | string | null }).user\n const userId = userRef && typeof userRef === 'object'\n ? userRef.id\n : userRef\n if (userId) ids.add(String(userId))\n }\n const roleAcls = await em.find(\n RoleAcl,\n { isSuperAdmin: true } as FilterQuery<RoleAcl>,\n )\n const roleIds = roleAcls\n .map((acl) => {\n const roleRef = (acl as { role?: { id?: unknown } | string | null }).role\n if (!roleRef) return null\n if (typeof roleRef === 'string') return roleRef\n return roleRef.id ? String(roleRef.id) : null\n })\n .filter((id): id is string => typeof id === 'string' && id.length > 0)\n if (roleIds.length) {\n const links = await findWithDecryption(\n em,\n UserRole,\n { role: { $in: roleIds } as unknown } as FilterQuery<UserRole>,\n {},\n { tenantId: null, organizationId: null },\n )\n for (const link of Array.isArray(links) ? links : []) {\n const userRef = (link as { user?: { id?: unknown } | string | null }).user\n const userId = userRef && typeof userRef === 'object'\n ? userRef.id\n : userRef\n if (userId) ids.add(String(userId))\n }\n }\n return ids\n}\n\nasync function loadActorAcl(input: GrantCheckContext): Promise<ActorAcl> {\n const actorUserId = normalizeNullableString(input.actorUserId)\n if (!actorUserId) throw forbidden('Not authorized to grant ACL privileges.')\n\n const acl = await input.rbacService.loadAcl(actorUserId, {\n tenantId: normalizeNullableString(input.tenantId),\n organizationId: normalizeNullableString(input.organizationId),\n })\n\n return {\n isSuperAdmin: !!acl?.isSuperAdmin,\n features: normalizeStringList(acl?.features),\n organizations: normalizeOrganizationList(acl?.organizations),\n }\n}\n\nasync function resolveRolesForGrant(\n em: EntityManager,\n roleTokens: string[],\n tenantId: string | null,\n): Promise<Role[]> {\n const roles: Role[] = []\n const missingRoles: string[] = []\n\n for (const token of roleTokens) {\n const role = await resolveRoleForGrant(em, token, tenantId)\n if (!role) {\n missingRoles.push(token)\n } else {\n roles.push(role)\n }\n }\n\n if (missingRoles.length) {\n const labels = missingRoles.map((role) => `\"${role}\"`).join(', ')\n throw new CrudHttpError(400, { error: `Role(s) not found: ${labels}` })\n }\n\n return roles\n}\n\nasync function resolveRoleForGrant(\n em: EntityManager,\n token: string,\n tenantId: string | null,\n): Promise<Role | null> {\n const where: Record<string, unknown> = UUID_RE.test(token)\n ? { id: token, deletedAt: null }\n : { name: token, deletedAt: null }\n if (tenantId) where.tenantId = tenantId\n return findOneWithDecryption(\n em,\n Role,\n where as FilterQuery<Role>,\n {},\n { tenantId, organizationId: null },\n )\n}\n\nfunction assertActorCanGrantAclSnapshot(\n actorAcl: ActorAcl,\n requested: {\n isSuperAdmin: boolean\n features: string[]\n organizations?: string[] | null\n },\n): void {\n if (requested.isSuperAdmin) {\n throw forbidden('Only super administrators can grant super admin access.')\n }\n\n const actorGrantableFeatures = actorAcl.features.filter((grant) => grant !== '*')\n for (const feature of requested.features) {\n if (feature === '*') {\n throw forbidden('Only super administrators can grant global wildcard access.')\n }\n if (isWildcardFeature(feature)) {\n if (!hasFeature(actorGrantableFeatures, feature)) {\n throw forbidden(`Cannot grant feature wildcard ${feature}.`)\n }\n continue\n }\n if (!hasFeature(actorGrantableFeatures, feature)) {\n throw forbidden(`Cannot grant feature ${feature}.`)\n }\n }\n\n if (requested.organizations !== undefined) {\n assertActorCanGrantOrganizations(actorAcl.organizations, requested.organizations)\n }\n}\n\nfunction assertActorCanGrantOrganizations(\n actorOrganizations: string[] | null,\n requestedOrganizations: string[] | null,\n): void {\n if (actorOrganizations === null || actorOrganizations.includes('__all__')) return\n\n if (requestedOrganizations === null || requestedOrganizations.includes('__all__')) {\n throw forbidden('Cannot grant unrestricted organization access.')\n }\n\n for (const organizationId of requestedOrganizations) {\n if (!actorOrganizations.includes(organizationId)) {\n throw forbidden('Cannot grant organization access outside actor scope.')\n }\n }\n}\n\nfunction normalizeStringList(values: unknown): string[] {\n if (!Array.isArray(values)) return []\n const dedup = new Set<string>()\n for (const value of values) {\n if (typeof value !== 'string') continue\n const trimmed = value.trim()\n if (!trimmed) continue\n dedup.add(trimmed)\n }\n return Array.from(dedup)\n}\n\nfunction normalizeOrganizationList(values: unknown): string[] | null {\n if (values === null || values === undefined) return null\n return normalizeStringList(values)\n}\n\nfunction normalizeNullableString(value: unknown): string | null {\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null\n}\n\nfunction isWildcardFeature(feature: string): boolean {\n return feature.endsWith('.*')\n}\n\nasync function translateAuthError(key: string, fallback: string): Promise<string> {\n const { translate } = await resolveTranslations()\n return translate(key, fallback)\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\nimport { badRequest, CrudHttpError, forbidden } from '@open-mercato/shared/lib/crud/errors'\nimport { hasFeature } from '@open-mercato/shared/security/features'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { Role, RoleAcl, User, UserAcl, UserRole } from '@open-mercato/core/modules/auth/data/entities'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport type { OrganizationScope } from '@open-mercato/core/modules/directory/utils/organizationScope'\n\ntype ActorAcl = {\n isSuperAdmin: boolean\n features: string[]\n organizations: string[] | null\n}\n\ntype GrantCheckContext = {\n em: EntityManager\n rbacService: RbacService\n actorUserId: string | null | undefined\n tenantId: string | null | undefined\n organizationId?: string | null | undefined\n}\n\ntype RoleGrantCheckInput = GrantCheckContext & {\n roles: Role[]\n}\n\ntype RoleTokenGrantCheckInput = GrantCheckContext & {\n roleTokens: unknown\n}\n\ntype UserDestinationRolesInput = {\n em: EntityManager\n targetUserId: string\n destinationTenantId: string | null | undefined\n roleTokens: unknown\n}\n\ntype UserDestinationScopeCheckInput = GrantCheckContext & {\n actorIsSuperAdmin?: boolean\n allowedOrganizationIds?: string[] | null\n destinationTenantId: string | null | undefined\n destinationOrganizationId: string | null | undefined\n roles: Role[]\n}\n\ntype FeatureGrantCheckInput = GrantCheckContext & {\n features: unknown\n isSuperAdmin?: boolean\n organizations?: string[] | null\n}\n\ntype SuperAdminUserTargetInput = GrantCheckContext & {\n targetUserId: string\n actorIsSuperAdmin?: boolean\n}\n\ntype UserTargetAccessInput = SuperAdminUserTargetInput & {\n organizationScope: Pick<OrganizationScope, 'allowedIds'>\n}\n\ntype SuperAdminRoleTargetInput = GrantCheckContext & {\n targetRoleId: string\n actorIsSuperAdmin?: boolean\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n\nexport async function assertActorCanGrantRoleTokens(input: RoleTokenGrantCheckInput): Promise<Role[]> {\n const tokens = normalizeStringList(input.roleTokens)\n if (!tokens.length) return []\n\n const tenantId = normalizeNullableString(input.tenantId)\n const roles = await resolveRolesForGrant(input.em, tokens, tenantId)\n await assertActorCanGrantRoles({ ...input, tenantId, roles })\n return roles\n}\n\nexport async function resolveUserDestinationRoles(input: UserDestinationRolesInput): Promise<Role[]> {\n const destinationTenantId = normalizeNullableString(input.destinationTenantId)\n if (Array.isArray(input.roleTokens)) {\n return resolveRolesForGrant(input.em, normalizeStringList(input.roleTokens), destinationTenantId)\n }\n\n const links = await findWithDecryption(\n input.em,\n UserRole,\n { user: input.targetUserId as unknown as User } as FilterQuery<UserRole>,\n { populate: ['role'] },\n { tenantId: null, organizationId: null },\n )\n const roles: Role[] = []\n for (const link of links) {\n const linkedRole = (link as { role?: Role | string | null }).role\n if (linkedRole && typeof linkedRole === 'object') {\n roles.push(linkedRole)\n continue\n }\n if (typeof linkedRole === 'string') {\n const resolvedRole = await resolveRoleForGrant(input.em, linkedRole, null)\n if (resolvedRole) {\n roles.push(resolvedRole)\n continue\n }\n }\n throw badRequest(await translateAuthError(\n 'auth.users.errors.invalidRoleAssignment',\n 'User has an invalid role assignment',\n ))\n }\n return roles\n}\n\nexport async function assertActorCanAssignUserDestination(\n input: UserDestinationScopeCheckInput,\n): Promise<void> {\n const destinationTenantId = normalizeNullableString(input.destinationTenantId)\n const destinationOrganizationId = normalizeNullableString(input.destinationOrganizationId)\n if (!destinationTenantId || !destinationOrganizationId) {\n return throwUserDestinationOrganizationNotFound(400)\n }\n\n for (const role of input.roles) {\n if (normalizeNullableString(role.tenantId) !== destinationTenantId) {\n throw forbidden(await translateAuthError(\n 'auth.users.errors.roleOutsideDestinationTenant',\n 'Cannot retain or assign a role outside the destination tenant.',\n ))\n }\n }\n\n if (await resolveActorIsSuperAdmin(input)) return\n\n const actorTenantId = normalizeNullableString(input.tenantId)\n if (!actorTenantId || actorTenantId !== destinationTenantId) {\n return throwUserDestinationOrganizationNotFound(404)\n }\n\n const actorAcl = await loadActorAcl(input)\n const allowedOrganizationIds = input.allowedOrganizationIds === undefined\n ? actorAcl.organizations\n : input.allowedOrganizationIds\n if (\n allowedOrganizationIds !== null\n && !allowedOrganizationIds.includes('__all__')\n && !allowedOrganizationIds.includes(destinationOrganizationId)\n ) {\n throw forbidden(await translateAuthError(\n 'auth.users.errors.destinationOrganizationOutsideScope',\n 'Cannot assign user to a destination organization outside actor scope.',\n ))\n }\n\n await assertActorCanGrantRoles({\n ...input,\n tenantId: destinationTenantId,\n roles: input.roles,\n })\n}\n\nexport async function throwUserDestinationOrganizationNotFound(status: 400 | 404): Promise<never> {\n throw new CrudHttpError(status, {\n error: await translateAuthError(\n 'auth.users.errors.organizationNotFound',\n 'Organization not found',\n ),\n })\n}\n\nexport async function assertActorCanGrantRoles(input: RoleGrantCheckInput): Promise<void> {\n if (!input.roles.length) return\n\n const tenantId = normalizeNullableString(input.tenantId)\n const actorAcl = await loadActorAcl({ ...input, tenantId })\n if (actorAcl.isSuperAdmin) return\n\n if (!tenantId) {\n throw forbidden('Tenant context is required to grant roles.')\n }\n\n for (const role of input.roles) {\n const roleTenantId = normalizeNullableString(role.tenantId)\n if (roleTenantId !== tenantId) {\n throw forbidden('Cannot grant a role outside the target tenant.')\n }\n\n const acl = await findOneWithDecryption(\n input.em,\n RoleAcl,\n { role, tenantId } as FilterQuery<RoleAcl>,\n {},\n { tenantId, organizationId: null },\n )\n if (!acl) continue\n\n assertActorCanGrantAclSnapshot(actorAcl, {\n isSuperAdmin: !!acl.isSuperAdmin,\n features: normalizeStringList(acl.featuresJson),\n organizations: normalizeOrganizationList(acl.organizationsJson),\n })\n }\n}\n\nexport async function assertActorCanGrantAcl(input: FeatureGrantCheckInput): Promise<void> {\n const actorAcl = await loadActorAcl(input)\n if (actorAcl.isSuperAdmin) return\n\n const tenantId = normalizeNullableString(input.tenantId)\n if (!tenantId) {\n throw forbidden('Tenant context is required to grant ACL features.')\n }\n\n assertActorCanGrantAclSnapshot(actorAcl, {\n isSuperAdmin: !!input.isSuperAdmin,\n features: normalizeStringList(input.features),\n organizations: input.organizations === undefined ? undefined : normalizeOrganizationList(input.organizations),\n })\n}\n\nexport function normalizeGrantFeatureList(features: unknown): string[] {\n return normalizeStringList(features)\n}\n\nexport async function assertActorCanModifySuperAdminUserTarget(input: SuperAdminUserTargetInput): Promise<void> {\n const actorIsSuperAdmin = await resolveActorIsSuperAdmin(input)\n if (actorIsSuperAdmin) return\n const targetIsSuperAdmin = await isUserEffectivelySuperAdmin(input.em, input.targetUserId)\n if (targetIsSuperAdmin) {\n throw forbidden('Only super administrators can modify super administrator accounts.')\n }\n}\n\nexport async function assertActorCanModifySuperAdminRoleTarget(input: SuperAdminRoleTargetInput): Promise<void> {\n const actorIsSuperAdmin = await resolveActorIsSuperAdmin(input)\n if (actorIsSuperAdmin) return\n const targetIsSuperAdmin = await isRoleEffectivelySuperAdmin(input.em, input.targetRoleId)\n if (targetIsSuperAdmin) {\n throw forbidden('Only super administrators can modify super administrator roles.')\n }\n}\n\nexport async function assertActorCanAccessUserTarget(input: UserTargetAccessInput): Promise<void> {\n const isSuperAdmin = await resolveActorIsSuperAdmin(input)\n if (isSuperAdmin) return\n\n const target = await findOneWithDecryption(\n input.em,\n User,\n { id: input.targetUserId } as FilterQuery<User>,\n {},\n { tenantId: null, organizationId: null },\n )\n // Not found (incl. soft-deleted, which MikroORM's soft-delete filter hides):\n // delegate to the caller. Every wired call site is itself tenant-scoped \u2014 the\n // ACL/consents reads filter by auth.tenantId and the user commands re-load by\n // id within tenant \u2014 so a missing target yields a safe empty/404 there. The\n // guard's job is to block a foreign *existing* target, below.\n if (!target) return\n\n const actorTenantId = normalizeNullableString(input.tenantId)\n const targetTenantId = normalizeNullableString((target as { tenantId?: string | null }).tenantId)\n if (!targetTenantId || targetTenantId !== actorTenantId) {\n throw new CrudHttpError(404, { error: 'User not found' })\n }\n\n if (input.organizationScope.allowedIds !== null) {\n const targetOrganizationId = normalizeNullableString((target as { organizationId?: string | null }).organizationId)\n if (!targetOrganizationId || !input.organizationScope.allowedIds.includes(targetOrganizationId)) {\n throw forbidden('Not authorized to access this user.')\n }\n }\n}\n\nexport async function assertActorCanAccessRoleTarget(input: SuperAdminRoleTargetInput): Promise<void> {\n const isSuperAdmin = await resolveActorIsSuperAdmin(input)\n if (isSuperAdmin) return\n\n const target = await findOneWithDecryption(\n input.em,\n Role,\n { id: input.targetRoleId } as FilterQuery<Role>,\n {},\n { tenantId: null, organizationId: null },\n )\n // Not found (incl. soft-deleted): delegate (see assertActorCanAccessUserTarget).\n if (!target) return\n\n const actorTenantId = normalizeNullableString(input.tenantId)\n const targetTenantId = normalizeNullableString((target as { tenantId?: string | null }).tenantId)\n if (!targetTenantId || targetTenantId !== actorTenantId) {\n throw new CrudHttpError(404, { error: 'Role not found' })\n }\n}\n\nasync function resolveActorIsSuperAdmin(input: GrantCheckContext & { actorIsSuperAdmin?: boolean }): Promise<boolean> {\n if (typeof input.actorIsSuperAdmin === 'boolean') return input.actorIsSuperAdmin\n const acl = await loadActorAcl(input)\n return acl.isSuperAdmin\n}\n\nexport async function isUserEffectivelySuperAdmin(em: EntityManager, userId: string): Promise<boolean> {\n const directGrant = await em.findOne(\n UserAcl,\n { user: userId as unknown, isSuperAdmin: true } as FilterQuery<UserAcl>,\n )\n if (directGrant && (directGrant as { isSuperAdmin?: boolean }).isSuperAdmin === true) return true\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId as unknown } as FilterQuery<UserRole>,\n { populate: ['role'] },\n { tenantId: null, organizationId: null },\n )\n const roleIds = (Array.isArray(links) ? links : [])\n .map((link) => {\n const role = (link as { role?: { id?: unknown } | string | null }).role\n if (!role) return null\n if (typeof role === 'string') return role\n return role.id ? String(role.id) : null\n })\n .filter((id): id is string => typeof id === 'string' && id.length > 0)\n if (!roleIds.length) return false\n const roleGrant = await em.findOne(\n RoleAcl,\n { role: { $in: roleIds } as unknown, isSuperAdmin: true } as FilterQuery<RoleAcl>,\n )\n return !!roleGrant && (roleGrant as { isSuperAdmin?: boolean }).isSuperAdmin === true\n}\n\nexport async function isRoleEffectivelySuperAdmin(em: EntityManager, roleId: string): Promise<boolean> {\n const grant = await em.findOne(\n RoleAcl,\n { role: roleId as unknown, isSuperAdmin: true } as FilterQuery<RoleAcl>,\n )\n return !!grant && (grant as { isSuperAdmin?: boolean }).isSuperAdmin === true\n}\n\nexport async function listSuperAdminUserIds(em: EntityManager, tenantId: string | null): Promise<Set<string>> {\n const ids = new Set<string>()\n const userAclFilter: Record<string, unknown> = { isSuperAdmin: true }\n if (tenantId) userAclFilter.tenantId = tenantId\n const userAcls = await em.find(UserAcl, userAclFilter as FilterQuery<UserAcl>)\n for (const acl of userAcls) {\n const userRef = (acl as { user?: { id?: unknown } | string | null }).user\n const userId = userRef && typeof userRef === 'object'\n ? userRef.id\n : userRef\n if (userId) ids.add(String(userId))\n }\n const roleAcls = await em.find(\n RoleAcl,\n { isSuperAdmin: true } as FilterQuery<RoleAcl>,\n )\n const roleIds = roleAcls\n .map((acl) => {\n const roleRef = (acl as { role?: { id?: unknown } | string | null }).role\n if (!roleRef) return null\n if (typeof roleRef === 'string') return roleRef\n return roleRef.id ? String(roleRef.id) : null\n })\n .filter((id): id is string => typeof id === 'string' && id.length > 0)\n if (roleIds.length) {\n const links = await findWithDecryption(\n em,\n UserRole,\n { role: { $in: roleIds } as unknown } as FilterQuery<UserRole>,\n {},\n { tenantId: null, organizationId: null },\n )\n for (const link of Array.isArray(links) ? links : []) {\n const userRef = (link as { user?: { id?: unknown } | string | null }).user\n const userId = userRef && typeof userRef === 'object'\n ? userRef.id\n : userRef\n if (userId) ids.add(String(userId))\n }\n }\n return ids\n}\n\nasync function loadActorAcl(input: GrantCheckContext): Promise<ActorAcl> {\n const actorUserId = normalizeNullableString(input.actorUserId)\n if (!actorUserId) throw forbidden('Not authorized to grant ACL privileges.')\n\n const acl = await input.rbacService.loadAcl(actorUserId, {\n tenantId: normalizeNullableString(input.tenantId),\n organizationId: normalizeNullableString(input.organizationId),\n })\n\n return {\n isSuperAdmin: !!acl?.isSuperAdmin,\n features: normalizeStringList(acl?.features),\n organizations: normalizeOrganizationList(acl?.organizations),\n }\n}\n\nasync function resolveRolesForGrant(\n em: EntityManager,\n roleTokens: string[],\n tenantId: string | null,\n): Promise<Role[]> {\n const roles: Role[] = []\n const missingRoles: string[] = []\n\n for (const token of roleTokens) {\n const role = await resolveRoleForGrant(em, token, tenantId)\n if (!role) {\n missingRoles.push(token)\n } else {\n roles.push(role)\n }\n }\n\n if (missingRoles.length) {\n const labels = missingRoles.map((role) => `\"${role}\"`).join(', ')\n throw new CrudHttpError(400, { error: `Role(s) not found: ${labels}` })\n }\n\n return roles\n}\n\nasync function resolveRoleForGrant(\n em: EntityManager,\n token: string,\n tenantId: string | null,\n): Promise<Role | null> {\n const where: Record<string, unknown> = UUID_RE.test(token)\n ? { id: token, deletedAt: null }\n : { name: token, deletedAt: null }\n if (tenantId) where.tenantId = tenantId\n return findOneWithDecryption(\n em,\n Role,\n where as FilterQuery<Role>,\n {},\n { tenantId, organizationId: null },\n )\n}\n\nfunction assertActorCanGrantAclSnapshot(\n actorAcl: ActorAcl,\n requested: {\n isSuperAdmin: boolean\n features: string[]\n organizations?: string[] | null\n },\n): void {\n if (requested.isSuperAdmin) {\n throw forbidden('Only super administrators can grant super admin access.')\n }\n\n const actorGrantableFeatures = actorAcl.features.filter((grant) => grant !== '*')\n for (const feature of requested.features) {\n if (feature === '*') {\n throw forbidden('Only super administrators can grant global wildcard access.')\n }\n if (isWildcardFeature(feature)) {\n if (!hasFeature(actorGrantableFeatures, feature)) {\n throw forbidden(`Cannot grant feature wildcard ${feature}.`)\n }\n continue\n }\n if (!hasFeature(actorGrantableFeatures, feature)) {\n throw forbidden(`Cannot grant feature ${feature}.`)\n }\n }\n\n if (requested.organizations !== undefined) {\n assertActorCanGrantOrganizations(actorAcl.organizations, requested.organizations)\n }\n}\n\nfunction assertActorCanGrantOrganizations(\n actorOrganizations: string[] | null,\n requestedOrganizations: string[] | null,\n): void {\n if (actorOrganizations === null || actorOrganizations.includes('__all__')) return\n\n if (requestedOrganizations === null || requestedOrganizations.includes('__all__')) {\n throw forbidden('Cannot grant unrestricted organization access.')\n }\n\n for (const organizationId of requestedOrganizations) {\n if (!actorOrganizations.includes(organizationId)) {\n throw forbidden('Cannot grant organization access outside actor scope.')\n }\n }\n}\n\nfunction normalizeStringList(values: unknown): string[] {\n if (!Array.isArray(values)) return []\n const dedup = new Set<string>()\n for (const value of values) {\n if (typeof value !== 'string') continue\n const trimmed = value.trim()\n if (!trimmed) continue\n dedup.add(trimmed)\n }\n return Array.from(dedup)\n}\n\nfunction normalizeOrganizationList(values: unknown): string[] | null {\n if (values === null || values === undefined) return null\n return normalizeStringList(values)\n}\n\nfunction normalizeNullableString(value: unknown): string | null {\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null\n}\n\nfunction isWildcardFeature(feature: string): boolean {\n return feature.endsWith('.*')\n}\n\nasync function translateAuthError(key: string, fallback: string): Promise<string> {\n const { translate } = await resolveTranslations()\n return translate(key, fallback)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -110,25 +110,11 @@ class AuthService {
|
|
|
110
110
|
await this.em.persist(row).flush();
|
|
111
111
|
return { user, token: rawToken };
|
|
112
112
|
}
|
|
113
|
-
async
|
|
113
|
+
async confirmPasswordReset(token, newPassword) {
|
|
114
114
|
const now = /* @__PURE__ */ new Date();
|
|
115
115
|
const hashedToken = hashAuthToken(token);
|
|
116
116
|
const row = await this.em.findOne(PasswordReset, { token: hashedToken });
|
|
117
|
-
if (!row) return null;
|
|
118
|
-
if (row.usedAt && row.usedAt <= now) return null;
|
|
119
|
-
if (row.expiresAt <= now) return null;
|
|
120
|
-
return row;
|
|
121
|
-
}
|
|
122
|
-
async isPasswordResetTokenValid(token) {
|
|
123
|
-
const row = await this.findUnconsumedPasswordReset(token);
|
|
124
|
-
if (!row) return false;
|
|
125
|
-
const user = await findOneWithDecryption(this.em, User, { id: row.user.id, deletedAt: null });
|
|
126
|
-
return user != null;
|
|
127
|
-
}
|
|
128
|
-
async confirmPasswordReset(token, newPassword) {
|
|
129
|
-
const now = /* @__PURE__ */ new Date();
|
|
130
|
-
const row = await this.findUnconsumedPasswordReset(token);
|
|
131
|
-
if (!row) return null;
|
|
117
|
+
if (!row || row.usedAt && row.usedAt <= now || row.expiresAt <= now) return null;
|
|
132
118
|
const affected = await this.em.nativeUpdate(
|
|
133
119
|
PasswordReset,
|
|
134
120
|
{ id: row.id, usedAt: null },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/auth/services/authService.ts"],
|
|
4
|
-
"sourcesContent": ["import { EntityManager } from '@mikro-orm/postgresql'\nimport { compare, hash } from 'bcryptjs'\nimport { User, Role, UserRole, Session, PasswordReset } from '@open-mercato/core/modules/auth/data/entities'\nimport { emailHashLookupValues } from '@open-mercato/core/modules/auth/lib/emailHash'\nimport { generateAuthToken, hashAuthToken } from '@open-mercato/core/modules/auth/lib/tokenHash'\nimport { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\n\n// A fixed, valid bcrypt hash (cost 10) of a throwaway value no real password\n// can match. verifyPassword compares against it whenever the user is missing or\n// has no password hash, so a failed login spends the same bcrypt CPU time\n// regardless of whether the account exists \u2014 closing the timing side channel\n// for account enumeration (issue #2242).\nconst TIMING_EQUALIZER_PASSWORD_HASH = '$2b$10$OcZrhmZpIzJOjkfwUrk7d.Nl0eHNzOvalBcBlt5Ran.4lj8R3HZg6'\n\nexport class AuthService {\n constructor(private em: EntityManager) {}\n\n async findUserByEmail(email: string) {\n const emailHashes = emailHashLookupValues(email)\n return findOneWithDecryption(this.em, User, {\n deletedAt: null,\n $or: [\n { email },\n { emailHash: { $in: emailHashes } },\n ],\n } as any)\n }\n\n async findUsersByEmail(email: string) {\n const emailHashes = emailHashLookupValues(email)\n return findWithDecryption(this.em, User, {\n deletedAt: null,\n $or: [\n { email },\n { emailHash: { $in: emailHashes } },\n ],\n } as any)\n }\n\n async findUserByEmailAndTenant(email: string, tenantId: string) {\n const emailHashes = emailHashLookupValues(email)\n return findOneWithDecryption(\n this.em,\n User,\n {\n tenantId,\n deletedAt: null,\n $or: [\n { email },\n { emailHash: { $in: emailHashes } },\n ],\n } as any,\n undefined,\n { tenantId },\n )\n }\n\n async verifyPassword(user: User | null, password: string) {\n const storedHash = user?.passwordHash ?? null\n // Always run a bcrypt comparison \u2014 against a fixed dummy hash when the user\n // is absent or has no password \u2014 so login latency does not reveal whether\n // the account exists (timing-based enumeration, issue #2242).\n const matched = await compare(password, storedHash ?? TIMING_EQUALIZER_PASSWORD_HASH)\n return storedHash !== null && matched\n }\n\n async updateLastLoginAt(user: User) {\n const now = new Date()\n // Use native update to avoid flushing unrelated entities that might be pending in this EM\n await this.em.nativeUpdate(User, { id: user.id }, { lastLoginAt: now })\n user.lastLoginAt = now\n }\n\n async getUserRoles(user: User, tenantId?: string | null): Promise<string[]> {\n const resolvedTenantId = tenantId ?? user.tenantId ?? null\n if (!resolvedTenantId) return []\n const links = await findWithDecryption(\n this.em,\n UserRole,\n { user, deletedAt: null, role: { tenantId: resolvedTenantId, deletedAt: null } as any },\n { populate: ['role'] },\n { tenantId: resolvedTenantId, organizationId: user.organizationId ?? null },\n )\n // A populated `role` can still be null when the link points at a soft-deleted\n // role (the Role soft-delete filter suppresses hydration), e.g. an admin link\n // orphaned by a re-seed during interrupted-provisioning recovery. Dropping such\n // links keeps role resolution from throwing on the login / session-refresh hot\n // path, mirroring resolveCanonicalStaffAuthContext in lib/sessionIntegrity.ts.\n return links\n .map((l) => l.role)\n .filter((role): role is Role => !!role)\n .map((role) => role.name)\n .filter((name): name is string => typeof name === 'string' && name.trim().length > 0)\n }\n\n\n async createSession(user: User, expiresAt: Date): Promise<{ session: Session; token: string }> {\n const rawToken = generateAuthToken()\n const tokenHash = hashAuthToken(rawToken)\n const sess = this.em.create(Session as any, { user, token: tokenHash, expiresAt, createdAt: new Date() } as any)\n await this.em.persist(sess).flush()\n return { session: sess as Session, token: rawToken }\n }\n\n async deleteSessionByToken(token: string) {\n const hashedToken = hashAuthToken(token)\n await this.em.nativeDelete(Session, { token: hashedToken })\n }\n\n async deleteSessionById(sessionId: string) {\n await this.em.nativeDelete(Session, { id: sessionId })\n }\n\n async findActiveSessionById(sessionId: string): Promise<Session | null> {\n const session = await this.em.findOne(Session, { id: sessionId, deletedAt: null })\n if (!session) return null\n if (session.expiresAt.getTime() < Date.now()) return null\n return session\n }\n\n async deleteAllUserSessions(userId: string) {\n await this.em.nativeDelete(Session, { user: userId })\n }\n\n async refreshFromSessionToken(token: string) {\n const now = new Date()\n const hashedToken = hashAuthToken(token)\n const sess = await this.em.findOne(Session, { token: hashedToken })\n if (!sess || sess.expiresAt <= now) return null\n const user = await findOneWithDecryption(this.em, User, { id: sess.user.id, deletedAt: null })\n if (!user) return null\n const roles = await this.getUserRoles(user, user.tenantId ?? null)\n return { user, roles, session: sess }\n }\n\n async requestPasswordReset(email: string) {\n const user = await this.findUserByEmail(email)\n if (!user) return null\n const rawToken = generateAuthToken()\n const tokenHash = hashAuthToken(rawToken)\n const expiresAt = new Date(Date.now() + 60 * 60 * 1000)\n const row = this.em.create(PasswordReset as any, { user, token: tokenHash, expiresAt, createdAt: new Date() } as any)\n await this.em.persist(row).flush()\n return { user, token: rawToken }\n }\n\n
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import { EntityManager } from '@mikro-orm/postgresql'\nimport { compare, hash } from 'bcryptjs'\nimport { User, Role, UserRole, Session, PasswordReset } from '@open-mercato/core/modules/auth/data/entities'\nimport { emailHashLookupValues } from '@open-mercato/core/modules/auth/lib/emailHash'\nimport { generateAuthToken, hashAuthToken } from '@open-mercato/core/modules/auth/lib/tokenHash'\nimport { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\n\n// A fixed, valid bcrypt hash (cost 10) of a throwaway value no real password\n// can match. verifyPassword compares against it whenever the user is missing or\n// has no password hash, so a failed login spends the same bcrypt CPU time\n// regardless of whether the account exists \u2014 closing the timing side channel\n// for account enumeration (issue #2242).\nconst TIMING_EQUALIZER_PASSWORD_HASH = '$2b$10$OcZrhmZpIzJOjkfwUrk7d.Nl0eHNzOvalBcBlt5Ran.4lj8R3HZg6'\n\nexport class AuthService {\n constructor(private em: EntityManager) {}\n\n async findUserByEmail(email: string) {\n const emailHashes = emailHashLookupValues(email)\n return findOneWithDecryption(this.em, User, {\n deletedAt: null,\n $or: [\n { email },\n { emailHash: { $in: emailHashes } },\n ],\n } as any)\n }\n\n async findUsersByEmail(email: string) {\n const emailHashes = emailHashLookupValues(email)\n return findWithDecryption(this.em, User, {\n deletedAt: null,\n $or: [\n { email },\n { emailHash: { $in: emailHashes } },\n ],\n } as any)\n }\n\n async findUserByEmailAndTenant(email: string, tenantId: string) {\n const emailHashes = emailHashLookupValues(email)\n return findOneWithDecryption(\n this.em,\n User,\n {\n tenantId,\n deletedAt: null,\n $or: [\n { email },\n { emailHash: { $in: emailHashes } },\n ],\n } as any,\n undefined,\n { tenantId },\n )\n }\n\n async verifyPassword(user: User | null, password: string) {\n const storedHash = user?.passwordHash ?? null\n // Always run a bcrypt comparison \u2014 against a fixed dummy hash when the user\n // is absent or has no password \u2014 so login latency does not reveal whether\n // the account exists (timing-based enumeration, issue #2242).\n const matched = await compare(password, storedHash ?? TIMING_EQUALIZER_PASSWORD_HASH)\n return storedHash !== null && matched\n }\n\n async updateLastLoginAt(user: User) {\n const now = new Date()\n // Use native update to avoid flushing unrelated entities that might be pending in this EM\n await this.em.nativeUpdate(User, { id: user.id }, { lastLoginAt: now })\n user.lastLoginAt = now\n }\n\n async getUserRoles(user: User, tenantId?: string | null): Promise<string[]> {\n const resolvedTenantId = tenantId ?? user.tenantId ?? null\n if (!resolvedTenantId) return []\n const links = await findWithDecryption(\n this.em,\n UserRole,\n { user, deletedAt: null, role: { tenantId: resolvedTenantId, deletedAt: null } as any },\n { populate: ['role'] },\n { tenantId: resolvedTenantId, organizationId: user.organizationId ?? null },\n )\n // A populated `role` can still be null when the link points at a soft-deleted\n // role (the Role soft-delete filter suppresses hydration), e.g. an admin link\n // orphaned by a re-seed during interrupted-provisioning recovery. Dropping such\n // links keeps role resolution from throwing on the login / session-refresh hot\n // path, mirroring resolveCanonicalStaffAuthContext in lib/sessionIntegrity.ts.\n return links\n .map((l) => l.role)\n .filter((role): role is Role => !!role)\n .map((role) => role.name)\n .filter((name): name is string => typeof name === 'string' && name.trim().length > 0)\n }\n\n\n async createSession(user: User, expiresAt: Date): Promise<{ session: Session; token: string }> {\n const rawToken = generateAuthToken()\n const tokenHash = hashAuthToken(rawToken)\n const sess = this.em.create(Session as any, { user, token: tokenHash, expiresAt, createdAt: new Date() } as any)\n await this.em.persist(sess).flush()\n return { session: sess as Session, token: rawToken }\n }\n\n async deleteSessionByToken(token: string) {\n const hashedToken = hashAuthToken(token)\n await this.em.nativeDelete(Session, { token: hashedToken })\n }\n\n async deleteSessionById(sessionId: string) {\n await this.em.nativeDelete(Session, { id: sessionId })\n }\n\n async findActiveSessionById(sessionId: string): Promise<Session | null> {\n const session = await this.em.findOne(Session, { id: sessionId, deletedAt: null })\n if (!session) return null\n if (session.expiresAt.getTime() < Date.now()) return null\n return session\n }\n\n async deleteAllUserSessions(userId: string) {\n await this.em.nativeDelete(Session, { user: userId })\n }\n\n async refreshFromSessionToken(token: string) {\n const now = new Date()\n const hashedToken = hashAuthToken(token)\n const sess = await this.em.findOne(Session, { token: hashedToken })\n if (!sess || sess.expiresAt <= now) return null\n const user = await findOneWithDecryption(this.em, User, { id: sess.user.id, deletedAt: null })\n if (!user) return null\n const roles = await this.getUserRoles(user, user.tenantId ?? null)\n return { user, roles, session: sess }\n }\n\n async requestPasswordReset(email: string) {\n const user = await this.findUserByEmail(email)\n if (!user) return null\n const rawToken = generateAuthToken()\n const tokenHash = hashAuthToken(rawToken)\n const expiresAt = new Date(Date.now() + 60 * 60 * 1000)\n const row = this.em.create(PasswordReset as any, { user, token: tokenHash, expiresAt, createdAt: new Date() } as any)\n await this.em.persist(row).flush()\n return { user, token: rawToken }\n }\n\n async confirmPasswordReset(token: string, newPassword: string): Promise<User | null> {\n const now = new Date()\n const hashedToken = hashAuthToken(token)\n const row = await this.em.findOne(PasswordReset, { token: hashedToken })\n if (!row || (row.usedAt && row.usedAt <= now) || row.expiresAt <= now) return null\n\n // Atomic compare-and-set: only mark used if still unused \u2014 prevents token replay under concurrency\n const affected = await this.em.nativeUpdate(\n PasswordReset,\n { id: row.id, usedAt: null },\n { usedAt: now },\n )\n if (affected === 0) return null\n\n const user = await findOneWithDecryption(this.em, User, { id: row.user.id, deletedAt: null })\n if (!user) return null\n user.passwordHash = await hash(newPassword, 10)\n await this.em.flush()\n await this.deleteAllUserSessions(String(user.id))\n return user\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
resolveEffectiveFeatures
|
|
9
9
|
} from "@open-mercato/shared/security/featurePolicy";
|
|
10
10
|
import { filterGrantsByEnabledModules } from "@open-mercato/shared/security/enabledModulesRegistry";
|
|
11
|
-
import { resolveRoleOrganizationScope, roleAclAllowsOrganization } from "./roleOrganizationScope.js";
|
|
12
11
|
function isAclData(value) {
|
|
13
12
|
if (typeof value !== "object" || value === null) return false;
|
|
14
13
|
const record = value;
|
|
@@ -20,13 +19,9 @@ function isAclData(value) {
|
|
|
20
19
|
}
|
|
21
20
|
return true;
|
|
22
21
|
}
|
|
23
|
-
function isRestrictedRoleAcl(acl) {
|
|
24
|
-
return Array.isArray(acl.organizationsJson) && acl.organizationsJson.length > 0 && !acl.organizationsJson.includes("__all__");
|
|
25
|
-
}
|
|
26
22
|
class RbacService {
|
|
27
|
-
constructor(em, cache
|
|
23
|
+
constructor(em, cache) {
|
|
28
24
|
this.em = em;
|
|
29
|
-
this.organizationHierarchyService = organizationHierarchyService;
|
|
30
25
|
this.cacheTtlMs = 5 * 60 * 1e3;
|
|
31
26
|
// 5 minutes default
|
|
32
27
|
this.cache = null;
|
|
@@ -44,6 +39,12 @@ class RbacService {
|
|
|
44
39
|
hasAllFeatures(required, granted) {
|
|
45
40
|
return authorizeFeatures(required, { grantedFeatures: granted });
|
|
46
41
|
}
|
|
42
|
+
roleAclAllowsOrganization(acl, organizationId) {
|
|
43
|
+
if (!organizationId) return true;
|
|
44
|
+
const organizations = Array.isArray(acl.organizationsJson) ? acl.organizationsJson : null;
|
|
45
|
+
if (!organizations || !organizations.length || organizations.includes("__all__")) return true;
|
|
46
|
+
return organizations.includes(organizationId);
|
|
47
|
+
}
|
|
47
48
|
getCacheKey(userId, scope) {
|
|
48
49
|
return `rbac:${userId}:${scope.tenantId || "null"}:${scope.organizationId || "null"}`;
|
|
49
50
|
}
|
|
@@ -70,7 +71,6 @@ class RbacService {
|
|
|
70
71
|
];
|
|
71
72
|
if (scope.tenantId) {
|
|
72
73
|
tags.push(this.getTenantTag(scope.tenantId));
|
|
73
|
-
tags.push(buildOrgScopeTenantCacheTag(scope.tenantId));
|
|
74
74
|
}
|
|
75
75
|
if (scope.organizationId) {
|
|
76
76
|
tags.push(this.getOrganizationTag(scope.organizationId));
|
|
@@ -167,8 +167,8 @@ class RbacService {
|
|
|
167
167
|
this.globalSuperAdminCache.set(userId, false);
|
|
168
168
|
return false;
|
|
169
169
|
}
|
|
170
|
-
const
|
|
171
|
-
const result =
|
|
170
|
+
const roleSuper = await em.findOne(RoleAcl, { isSuperAdmin: true, role: { $in: roleIds } });
|
|
171
|
+
const result = !!(roleSuper && roleSuper.isSuperAdmin);
|
|
172
172
|
this.globalSuperAdminCache.set(userId, result);
|
|
173
173
|
return result;
|
|
174
174
|
}
|
|
@@ -215,55 +215,28 @@ class RbacService {
|
|
|
215
215
|
}
|
|
216
216
|
const tenantId2 = scope.tenantId || key.tenantId || null;
|
|
217
217
|
const roleIds2 = Array.isArray(key.rolesJson) ? key.rolesJson.filter(Boolean) : [];
|
|
218
|
-
const keyOrganizationId = typeof key.organizationId === "string" && key.organizationId.trim().length > 0 ? key.organizationId.trim() : null;
|
|
219
|
-
const evaluatedOrganizationId = scope.organizationId || keyOrganizationId;
|
|
220
218
|
let isSuper2 = false;
|
|
221
219
|
const features2 = [];
|
|
222
|
-
let
|
|
223
|
-
let hasApplicableRestrictedRole2 = false;
|
|
220
|
+
let organizations2 = key.organizationId ? [key.organizationId] : null;
|
|
224
221
|
if (tenantId2 && roleIds2.length) {
|
|
225
|
-
const roleOrganizationScope = await resolveRoleOrganizationScope(
|
|
226
|
-
this.organizationHierarchyService,
|
|
227
|
-
tenantId2,
|
|
228
|
-
evaluatedOrganizationId
|
|
229
|
-
);
|
|
230
222
|
const racls = await em2.find(RoleAcl, { tenantId: tenantId2, role: { $in: roleIds2 } });
|
|
231
223
|
for (const acl of racls) {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
for (const f of acl.featuresJson) if (!features2.includes(f)) features2.push(f);
|
|
236
|
-
}
|
|
237
|
-
if (isRestrictedRoleAcl(acl)) hasApplicableRestrictedRole2 = true;
|
|
224
|
+
isSuper2 = isSuper2 || !!acl.isSuperAdmin;
|
|
225
|
+
if (Array.isArray(acl.featuresJson)) {
|
|
226
|
+
for (const f of acl.featuresJson) if (!features2.includes(f)) features2.push(f);
|
|
238
227
|
}
|
|
239
|
-
if (
|
|
240
|
-
if (acl.organizationsJson == null
|
|
241
|
-
|
|
228
|
+
if (organizations2 !== null) {
|
|
229
|
+
if (acl.organizationsJson == null) {
|
|
230
|
+
organizations2 = null;
|
|
242
231
|
} else if (Array.isArray(acl.organizationsJson) && acl.organizationsJson.includes("__all__")) {
|
|
243
|
-
|
|
232
|
+
organizations2 = null;
|
|
244
233
|
} else {
|
|
245
|
-
|
|
246
|
-
...roleOrganizations,
|
|
247
|
-
...Array.isArray(acl.organizationsJson) ? acl.organizationsJson : []
|
|
248
|
-
]));
|
|
234
|
+
organizations2 = Array.from(/* @__PURE__ */ new Set([...organizations2 || [], ...acl.organizationsJson]));
|
|
249
235
|
}
|
|
250
236
|
}
|
|
251
237
|
}
|
|
252
|
-
if (roleOrganizations !== null && evaluatedOrganizationId && roleOrganizationScope !== null && roleOrganizationScope.size > 0 && hasApplicableRestrictedRole2 && !roleOrganizations.includes(evaluatedOrganizationId)) {
|
|
253
|
-
roleOrganizations.push(evaluatedOrganizationId);
|
|
254
|
-
}
|
|
255
238
|
}
|
|
256
|
-
|
|
257
|
-
if (keyOrganizationId) {
|
|
258
|
-
const keyOrganizationScope = await resolveRoleOrganizationScope(
|
|
259
|
-
this.organizationHierarchyService,
|
|
260
|
-
tenantId2,
|
|
261
|
-
keyOrganizationId
|
|
262
|
-
);
|
|
263
|
-
organizations2 = roleOrganizations === null || roleOrganizations.some((organizationId) => keyOrganizationScope?.has(organizationId)) ? [keyOrganizationId] : [];
|
|
264
|
-
}
|
|
265
|
-
if (isSuper2 && organizations2 !== null && !features2.includes("*")) features2.push("*");
|
|
266
|
-
const result2 = { isSuperAdmin: isSuper2 && organizations2 === null, features: features2, organizations: organizations2 };
|
|
239
|
+
const result2 = { isSuperAdmin: isSuper2, features: features2, organizations: organizations2 };
|
|
267
240
|
await this.setCache(cacheKey, result2, userId, scope);
|
|
268
241
|
return result2;
|
|
269
242
|
}
|
|
@@ -303,22 +276,13 @@ class RbacService {
|
|
|
303
276
|
let isSuper = false;
|
|
304
277
|
const features = [];
|
|
305
278
|
let organizations = [];
|
|
306
|
-
let hasApplicableRestrictedRole = false;
|
|
307
279
|
if (roleIds.length) {
|
|
308
|
-
const roleOrganizationScope = await resolveRoleOrganizationScope(
|
|
309
|
-
this.organizationHierarchyService,
|
|
310
|
-
tenantId,
|
|
311
|
-
scope.organizationId
|
|
312
|
-
);
|
|
313
280
|
const racls = await em.find(RoleAcl, { tenantId, role: { $in: roleIds } }, {});
|
|
314
281
|
const roleAcls = Array.isArray(racls) ? racls : [];
|
|
315
282
|
for (const r of roleAcls) {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
for (const f of r.featuresJson) if (!features.includes(f)) features.push(f);
|
|
320
|
-
}
|
|
321
|
-
if (isRestrictedRoleAcl(r)) hasApplicableRestrictedRole = true;
|
|
283
|
+
isSuper = isSuper || !!r.isSuperAdmin;
|
|
284
|
+
if (Array.isArray(r.featuresJson)) {
|
|
285
|
+
for (const f of r.featuresJson) if (!features.includes(f)) features.push(f);
|
|
322
286
|
}
|
|
323
287
|
if (organizations !== null) {
|
|
324
288
|
if (r.organizationsJson == null) organizations = null;
|
|
@@ -326,9 +290,6 @@ class RbacService {
|
|
|
326
290
|
else organizations = Array.from(/* @__PURE__ */ new Set([...organizations || [], ...r.organizationsJson]));
|
|
327
291
|
}
|
|
328
292
|
}
|
|
329
|
-
if (organizations !== null && scope.organizationId && roleOrganizationScope !== null && roleOrganizationScope.size > 0 && hasApplicableRestrictedRole && !organizations.includes(scope.organizationId)) {
|
|
330
|
-
organizations.push(scope.organizationId);
|
|
331
|
-
}
|
|
332
293
|
}
|
|
333
294
|
if (organizations && orgId && !organizations.includes(orgId) && !organizations.includes("__all__")) {
|
|
334
295
|
}
|
|
@@ -345,15 +306,11 @@ class RbacService {
|
|
|
345
306
|
async tenantHasFeature(tenantId, feature, opts) {
|
|
346
307
|
if (!tenantId || !feature) return false;
|
|
347
308
|
const em = this.em.fork();
|
|
348
|
-
const roleOrganizationScope = await resolveRoleOrganizationScope(
|
|
349
|
-
this.organizationHierarchyService,
|
|
350
|
-
tenantId,
|
|
351
|
-
opts?.organizationId
|
|
352
|
-
);
|
|
353
309
|
const roleAcls = await em.find(RoleAcl, { tenantId, deletedAt: null }, {});
|
|
354
310
|
const list = Array.isArray(roleAcls) ? roleAcls : [];
|
|
311
|
+
const organizationId = opts?.organizationId ?? null;
|
|
355
312
|
for (const acl of list) {
|
|
356
|
-
if (!roleAclAllowsOrganization(acl,
|
|
313
|
+
if (!this.roleAclAllowsOrganization(acl, organizationId)) continue;
|
|
357
314
|
const grants = Array.isArray(acl.featuresJson) ? acl.featuresJson : [];
|
|
358
315
|
if (authorizeFeatures([feature], {
|
|
359
316
|
grantedFeatures: grants,
|