@open-mercato/core 0.7.0 → 0.7.1-develop.7102.1.b41f7e3e51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/helpers/integration/api.js +13 -1
- package/dist/helpers/integration/api.js.map +2 -2
- package/dist/helpers/integration/communicationChannelsFixtures.js +19 -0
- package/dist/helpers/integration/communicationChannelsFixtures.js.map +2 -2
- package/dist/modules/api_keys/api/keys/route.js +1 -1
- package/dist/modules/api_keys/api/keys/route.js.map +2 -2
- package/dist/modules/api_keys/backend/api-keys/page.js +3 -1
- package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
- package/dist/modules/api_keys/di.js +9 -0
- package/dist/modules/api_keys/di.js.map +7 -0
- package/dist/modules/api_keys/services/principalService.js +31 -0
- package/dist/modules/api_keys/services/principalService.js.map +7 -0
- package/dist/modules/attachments/api/route.js +2 -2
- package/dist/modules/attachments/api/route.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentLibrary.js +2 -0
- package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
- package/dist/modules/attachments/di.js +11 -1
- package/dist/modules/attachments/di.js.map +2 -2
- package/dist/modules/attachments/index.js.map +1 -1
- package/dist/modules/attachments/lib/attachment-service.js +313 -0
- package/dist/modules/attachments/lib/attachment-service.js.map +7 -0
- package/dist/modules/attachments/lib/scoped-upload-service.js +15 -2
- package/dist/modules/attachments/lib/scoped-upload-service.js.map +2 -2
- package/dist/modules/attachments/lib/upload-limits.js +6 -2
- package/dist/modules/attachments/lib/upload-limits.js.map +2 -2
- package/dist/modules/audit_logs/backend/audit-logs/page.js +6 -0
- package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
- package/dist/modules/audit_logs/lib/display-helpers.js +19 -11
- package/dist/modules/audit_logs/lib/display-helpers.js.map +2 -2
- package/dist/modules/audit_logs/services/actionLogService.js +57 -12
- package/dist/modules/audit_logs/services/actionLogService.js.map +3 -3
- package/dist/modules/auth/acl.js +30 -5
- package/dist/modules/auth/acl.js.map +2 -2
- package/dist/modules/auth/api/feature-check.js +8 -2
- package/dist/modules/auth/api/feature-check.js.map +2 -2
- package/dist/modules/auth/api/login.js +4 -1
- package/dist/modules/auth/api/login.js.map +2 -2
- package/dist/modules/auth/api/reset/validate.js +55 -0
- package/dist/modules/auth/api/reset/validate.js.map +7 -0
- package/dist/modules/auth/api/roles/acl/route.js +28 -33
- package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
- package/dist/modules/auth/api/session/refresh.js +25 -1
- package/dist/modules/auth/api/session/refresh.js.map +2 -2
- package/dist/modules/auth/api/users/acl/route.js +96 -51
- package/dist/modules/auth/api/users/acl/route.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +13 -5
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/backend/roles/[id]/edit/page.meta.js +5 -1
- package/dist/modules/auth/backend/roles/[id]/edit/page.meta.js.map +2 -2
- package/dist/modules/auth/backend/roles/page.js +3 -1
- package/dist/modules/auth/backend/roles/page.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.meta.js +5 -1
- package/dist/modules/auth/backend/users/[id]/edit/page.meta.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +2 -1
- package/dist/modules/auth/backend/users/page.js.map +2 -2
- package/dist/modules/auth/commands/acl.js +254 -0
- package/dist/modules/auth/commands/acl.js.map +7 -0
- package/dist/modules/auth/components/AclEditor.js +39 -30
- package/dist/modules/auth/components/AclEditor.js.map +2 -2
- package/dist/modules/auth/data/entities.js.map +2 -2
- package/dist/modules/auth/data/validators.js +5 -1
- package/dist/modules/auth/data/validators.js.map +2 -2
- package/dist/modules/auth/di.js +35 -9
- package/dist/modules/auth/di.js.map +2 -2
- package/dist/modules/auth/frontend/reset/[token]/page.js +46 -0
- package/dist/modules/auth/frontend/reset/[token]/page.js.map +2 -2
- package/dist/modules/auth/lib/grantChecks.js.map +2 -2
- package/dist/modules/auth/lib/userIdFilter.js +16 -0
- package/dist/modules/auth/lib/userIdFilter.js.map +7 -0
- package/dist/modules/auth/services/authService.js +16 -2
- package/dist/modules/auth/services/authService.js.map +2 -2
- package/dist/modules/auth/services/principalService.js +200 -0
- package/dist/modules/auth/services/principalService.js.map +7 -0
- package/dist/modules/auth/services/rbacService.js +67 -24
- package/dist/modules/auth/services/rbacService.js.map +3 -3
- package/dist/modules/auth/services/roleOrganizationScope.js +41 -0
- package/dist/modules/auth/services/roleOrganizationScope.js.map +7 -0
- package/dist/modules/business_rules/backend/logs/page.js +3 -1
- package/dist/modules/business_rules/backend/logs/page.js.map +2 -2
- package/dist/modules/business_rules/backend/rules/page.js +3 -1
- package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/page.js +3 -1
- package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
- package/dist/modules/business_rules/lib/expression-evaluator.js +9 -9
- package/dist/modules/business_rules/lib/expression-evaluator.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-evaluator.js +10 -9
- package/dist/modules/business_rules/lib/rule-evaluator.js.map +2 -2
- package/dist/modules/catalog/ai-agents.js +1 -1
- package/dist/modules/catalog/ai-agents.js.map +1 -1
- package/dist/modules/catalog/ai-tools/merchandising-pack.js +2 -2
- package/dist/modules/catalog/ai-tools/merchandising-pack.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +5 -2
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +2 -2
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -0
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductsDataTable.js +7 -1
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js +2 -0
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js.map +2 -2
- package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js +9 -1
- package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/test-seed/route.js +95 -10
- package/dist/modules/communication_channels/api/post/test-seed/route.js.map +2 -2
- package/dist/modules/communication_channels/backend/communication_channels/channels/page.js +3 -0
- package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +2 -2
- package/dist/modules/communication_channels/commands/ingest-inbound-message.js +14 -1
- package/dist/modules/communication_channels/commands/ingest-inbound-message.js.map +2 -2
- package/dist/modules/communication_channels/di.js +7 -1
- package/dist/modules/communication_channels/di.js.map +2 -2
- package/dist/modules/communication_channels/lib/email-capabilities.js +4 -1
- package/dist/modules/communication_channels/lib/email-capabilities.js.map +2 -2
- package/dist/modules/communication_channels/lib/outbound-recipient.js +33 -0
- package/dist/modules/communication_channels/lib/outbound-recipient.js.map +7 -0
- package/dist/modules/communication_channels/lib/resolve-channel-type.js +51 -0
- package/dist/modules/communication_channels/lib/resolve-channel-type.js.map +7 -0
- package/dist/modules/communication_channels/lib/test-seed.js +41 -2
- package/dist/modules/communication_channels/lib/test-seed.js.map +2 -2
- package/dist/modules/configs/lib/system-status.js +9 -0
- package/dist/modules/configs/lib/system-status.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/page.js +3 -1
- package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js +3 -1
- package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
- package/dist/modules/currencies/services/rateFetchingService.js +6 -1
- package/dist/modules/currencies/services/rateFetchingService.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/domain-mappings.js +9 -0
- package/dist/modules/customer_accounts/api/admin/domain-mappings.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +3 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js +3 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js.map +2 -2
- package/dist/modules/customer_accounts/services/domainMappingService.js +10 -0
- package/dist/modules/customer_accounts/services/domainMappingService.js.map +2 -2
- package/dist/modules/customers/ai-tools/companies-pack.js +4 -1
- package/dist/modules/customers/ai-tools/companies-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/deal-analyzer-pack.js +13 -2
- package/dist/modules/customers/ai-tools/deal-analyzer-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/deals-pack.js +52 -6
- package/dist/modules/customers/ai-tools/deals-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/people-pack.js +4 -1
- package/dist/modules/customers/ai-tools/people-pack.js.map +2 -2
- package/dist/modules/customers/api/activities/route.js +48 -6
- package/dist/modules/customers/api/activities/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/people/route.js +20 -64
- package/dist/modules/customers/api/companies/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/route.js +17 -94
- package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js +8 -5
- package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/companies/route.js +1 -1
- package/dist/modules/customers/api/deals/[id]/companies/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/people/route.js +1 -1
- package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/route.js +8 -25
- package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/stats/route.js +3 -22
- package/dist/modules/customers/api/deals/[id]/stats/route.js.map +2 -2
- package/dist/modules/customers/api/deals/aggregate/route.js +11 -4
- package/dist/modules/customers/api/deals/aggregate/route.js.map +2 -2
- package/dist/modules/customers/api/deals/map/route.js +2 -1
- package/dist/modules/customers/api/deals/map/route.js.map +2 -2
- package/dist/modules/customers/api/deals/route.js +38 -1
- package/dist/modules/customers/api/deals/route.js.map +2 -2
- package/dist/modules/customers/api/entity-roles-factory.js +4 -4
- package/dist/modules/customers/api/entity-roles-factory.js.map +2 -2
- package/dist/modules/customers/api/interactions/route.js +3 -1
- package/dist/modules/customers/api/interactions/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/tasks/route.js +27 -4
- package/dist/modules/customers/api/interactions/tasks/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +4 -3
- package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/context.js +1 -1
- package/dist/modules/customers/api/people/[id]/companies/context.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +1 -1
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/route.js +11 -10
- package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/people/check-phone/route.js +51 -9
- package/dist/modules/customers/api/people/check-phone/route.js.map +2 -2
- package/dist/modules/customers/api/todos/route.js +30 -5
- package/dist/modules/customers/api/todos/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +4 -2
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +6 -1
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +5 -2
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/Lane.js +4 -13
- package/dist/modules/customers/backend/customers/deals/pipeline/components/Lane.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js +85 -14
- package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/toneClasses.js +18 -0
- package/dist/modules/customers/backend/customers/deals/pipeline/components/toneClasses.js.map +7 -0
- package/dist/modules/customers/backend/customers/people/page.js +4 -2
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/backend/hooks/useEmailDuplicateCheck.js +9 -3
- package/dist/modules/customers/backend/hooks/useEmailDuplicateCheck.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +21 -34
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js.map +1 -1
- package/dist/modules/customers/commands/personCompanyLinks.js +131 -2
- package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
- package/dist/modules/customers/components/CustomerTodosTable.js +1 -0
- package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
- package/dist/modules/customers/components/DealsKpiStrip.js +7 -6
- package/dist/modules/customers/components/DealsKpiStrip.js.map +2 -2
- package/dist/modules/customers/components/calendar/AgendaList.js +2 -2
- package/dist/modules/customers/components/calendar/AgendaList.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js +1 -1
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarScreen.js +1 -1
- package/dist/modules/customers/components/calendar/CalendarScreen.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js +1 -1
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js.map +2 -2
- package/dist/modules/customers/components/calendar/EventBlock.js +1 -1
- package/dist/modules/customers/components/calendar/EventBlock.js.map +2 -2
- package/dist/modules/customers/components/calendar/EventPeekPopover.js +3 -2
- package/dist/modules/customers/components/calendar/EventPeekPopover.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/PeopleField.js +40 -5
- package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/hooks.js +2 -1
- package/dist/modules/customers/components/calendar/editor/hooks.js.map +2 -2
- package/dist/modules/customers/components/calendar/types.js +1 -1
- package/dist/modules/customers/components/calendar/types.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyKpiBar.js +5 -4
- package/dist/modules/customers/components/detail/CompanyKpiBar.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js +3 -1
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
- package/dist/modules/customers/components/detail/DealForm.js +19 -7
- package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
- package/dist/modules/customers/components/detail/DealsSection.js +6 -5
- package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js +35 -11
- package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js +3 -1
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/usePersonTasks.js +19 -13
- package/dist/modules/customers/components/detail/hooks/usePersonTasks.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/ParticipantsField.js +4 -4
- package/dist/modules/customers/components/detail/schedule/ParticipantsField.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +3 -3
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
- package/dist/modules/customers/components/detail/utils.js +5 -5
- package/dist/modules/customers/components/detail/utils.js.map +2 -2
- package/dist/modules/customers/data/entities.js.map +1 -1
- package/dist/modules/customers/data/validators.js +32 -3
- package/dist/modules/customers/data/validators.js.map +2 -2
- package/dist/modules/customers/events.js +5 -0
- package/dist/modules/customers/events.js.map +2 -2
- package/dist/modules/customers/lib/calendar/conflicts.js +8 -2
- package/dist/modules/customers/lib/calendar/conflicts.js.map +2 -2
- package/dist/modules/customers/lib/calendar/editorPayload.js +3 -2
- package/dist/modules/customers/lib/calendar/editorPayload.js.map +2 -2
- package/dist/modules/customers/lib/calendar/mapItem.js +8 -3
- package/dist/modules/customers/lib/calendar/mapItem.js.map +2 -2
- package/dist/modules/customers/lib/calendar/participantIdentity.js +9 -0
- package/dist/modules/customers/lib/calendar/participantIdentity.js.map +7 -0
- package/dist/modules/customers/lib/closureStage.js +45 -0
- package/dist/modules/customers/lib/closureStage.js.map +7 -0
- package/dist/modules/customers/lib/dealStatus.js +30 -0
- package/dist/modules/customers/lib/dealStatus.js.map +2 -2
- package/dist/modules/customers/lib/detailReadAccess.js +12 -0
- package/dist/modules/customers/lib/detailReadAccess.js.map +7 -0
- package/dist/modules/customers/lib/findPeopleByAddresses.js +1 -0
- package/dist/modules/customers/lib/findPeopleByAddresses.js.map +2 -2
- package/dist/modules/customers/lib/personCompanies.js +100 -2
- package/dist/modules/customers/lib/personCompanies.js.map +2 -2
- package/dist/modules/customers/lib/todoCompatibility.js +12 -0
- package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
- package/dist/modules/dashboards/lib/widgetScope.js +6 -1
- package/dist/modules/dashboards/lib/widgetScope.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +3 -1
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/lib/abandoned-run.js +19 -0
- package/dist/modules/data_sync/lib/abandoned-run.js.map +7 -0
- package/dist/modules/data_sync/lib/sync-engine.js +72 -6
- package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
- package/dist/modules/data_sync/workers/sync-export.js +5 -1
- package/dist/modules/data_sync/workers/sync-export.js.map +2 -2
- package/dist/modules/data_sync/workers/sync-import.js +5 -1
- package/dist/modules/data_sync/workers/sync-import.js.map +2 -2
- package/dist/modules/devices/acl.js +9 -1
- package/dist/modules/devices/acl.js.map +2 -2
- package/dist/modules/devices/api/admin/devices/[id]/route.js +5 -32
- package/dist/modules/devices/api/admin/devices/[id]/route.js.map +2 -2
- package/dist/modules/devices/api/admin/devices/route.js +14 -1
- package/dist/modules/devices/api/admin/devices/route.js.map +2 -2
- package/dist/modules/devices/api/deviceList.js +99 -12
- package/dist/modules/devices/api/deviceList.js.map +2 -2
- package/dist/modules/devices/api/deviceSerialization.js +46 -0
- package/dist/modules/devices/api/deviceSerialization.js.map +7 -0
- package/dist/modules/devices/api/openapi.js +3 -1
- package/dist/modules/devices/api/openapi.js.map +2 -2
- package/dist/modules/devices/api/route.js +9 -1
- package/dist/modules/devices/api/route.js.map +2 -2
- package/dist/modules/devices/backend/devices/[id]/page.js +10 -26
- package/dist/modules/devices/backend/devices/[id]/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/create/page.js +17 -1
- package/dist/modules/devices/backend/devices/create/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/page.js +28 -34
- package/dist/modules/devices/backend/devices/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/useDeviceUserLabels.js +34 -0
- package/dist/modules/devices/backend/devices/useDeviceUserLabels.js.map +7 -0
- package/dist/modules/devices/backend/devices/userOptions.js +52 -0
- package/dist/modules/devices/backend/devices/userOptions.js.map +7 -0
- package/dist/modules/devices/setup.js +6 -2
- package/dist/modules/devices/setup.js.map +2 -2
- package/dist/modules/directory/backend/directory/organizations/page.js +2 -1
- package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/page.js +2 -1
- package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
- package/dist/modules/directory/di.js +9 -0
- package/dist/modules/directory/di.js.map +2 -2
- package/dist/modules/directory/services/organizationHierarchyService.js +29 -0
- package/dist/modules/directory/services/organizationHierarchyService.js.map +7 -0
- package/dist/modules/directory/services/organizationScopeService.js +56 -0
- package/dist/modules/directory/services/organizationScopeService.js.map +7 -0
- package/dist/modules/directory/utils/organizationScope.js.map +2 -2
- package/dist/modules/entities/api/records.js +4 -2
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +3 -1
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/eudr/api/plots/route.js +5 -1
- package/dist/modules/eudr/api/plots/route.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/plots/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/plots/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/product-mappings/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/statements/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/statements/page.js.map +2 -2
- package/dist/modules/eudr/commands/statements.js +0 -3
- package/dist/modules/eudr/commands/statements.js.map +2 -2
- package/dist/modules/eudr/data/validators.js +4 -1
- package/dist/modules/eudr/data/validators.js.map +2 -2
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +1 -0
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
- package/dist/modules/feature_toggles/components/OverridesTable.js +1 -0
- package/dist/modules/feature_toggles/components/OverridesTable.js.map +2 -2
- package/dist/modules/feature_toggles/defaults.json +0 -8
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js +3 -0
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/page.js +3 -0
- package/dist/modules/inbox_ops/backend/inbox-ops/page.js.map +2 -2
- package/dist/modules/inbox_ops/lib/htmlToPlainText.js +1 -12
- package/dist/modules/inbox_ops/lib/htmlToPlainText.js.map +2 -2
- package/dist/modules/integrations/api/[id]/credentials/route.js +6 -1
- package/dist/modules/integrations/api/[id]/credentials/route.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/[id]/page.js +38 -29
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +36 -9
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/credential-secret-fields.js +55 -0
- package/dist/modules/integrations/backend/integrations/credential-secret-fields.js.map +7 -0
- package/dist/modules/integrations/data/validators.js +11 -3
- package/dist/modules/integrations/data/validators.js.map +2 -2
- package/dist/modules/integrations/lib/credentials-masking.js +6 -2
- package/dist/modules/integrations/lib/credentials-masking.js.map +2 -2
- package/dist/modules/messages/api/[id]/route.js +29 -1
- package/dist/modules/messages/api/[id]/route.js.map +2 -2
- package/dist/modules/messages/api/openapi.js +17 -2
- package/dist/modules/messages/api/openapi.js.map +2 -2
- package/dist/modules/messages/api/route.js +17 -2
- package/dist/modules/messages/api/route.js.map +2 -2
- package/dist/modules/messages/components/MessagesInboxPageClient.js +7 -14
- package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
- package/dist/modules/messages/components/inboxFilters.js +15 -0
- package/dist/modules/messages/components/inboxFilters.js.map +2 -2
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js +11 -1
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js.map +2 -2
- package/dist/modules/messages/components/message-detail/panels/MessageHeader.js +3 -1
- package/dist/modules/messages/components/message-detail/panels/MessageHeader.js.map +2 -2
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js +2 -1
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +2 -2
- package/dist/modules/messages/components/messageListLabels.js +14 -2
- package/dist/modules/messages/components/messageListLabels.js.map +2 -2
- package/dist/modules/messages/data/validators.js +18 -4
- package/dist/modules/messages/data/validators.js.map +2 -2
- package/dist/modules/messages/lib/channel-sender-identity.js +26 -0
- package/dist/modules/messages/lib/channel-sender-identity.js.map +7 -0
- package/dist/modules/messages/lib/composeSourceChannelType.js +41 -0
- package/dist/modules/messages/lib/composeSourceChannelType.js.map +7 -0
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +4 -6
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +2 -2
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js +3 -1
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
- package/dist/modules/payment_gateways/lib/webhook-processor.js +7 -0
- package/dist/modules/payment_gateways/lib/webhook-processor.js.map +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js +3 -0
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/push_notifications/backend/push_notifications/page.js +3 -1
- package/dist/modules/push_notifications/backend/push_notifications/page.js.map +2 -2
- package/dist/modules/push_notifications/backend/push_notifications/send/page.js +1 -1
- package/dist/modules/push_notifications/backend/push_notifications/send/page.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +150 -51
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/lib/search-entity-policy.js +14 -0
- package/dist/modules/query_index/lib/search-entity-policy.js.map +7 -0
- package/dist/modules/query_index/lib/search-tokens.js +79 -3
- package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js +3 -1
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js +3 -1
- package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js +3 -0
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +3 -0
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +10 -8
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +79 -1
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/components/PriceWithCurrency.js +7 -5
- package/dist/modules/sales/components/PriceWithCurrency.js.map +2 -2
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +3 -0
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentsSection.js +8 -6
- package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +51 -22
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +83 -18
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js +23 -9
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnsSection.js +8 -6
- package/dist/modules/sales/components/documents/ReturnsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +68 -14
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesOrderDraftLines.js +6 -5
- package/dist/modules/sales/components/documents/SalesOrderDraftLines.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +5 -4
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentsSection.js +8 -6
- package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/lineItemShipmentLock.js +54 -0
- package/dist/modules/sales/components/documents/lineItemShipmentLock.js.map +7 -0
- package/dist/modules/sales/components/documents/lineItemUtils.js +2 -2
- package/dist/modules/sales/components/documents/lineItemUtils.js.map +2 -2
- package/dist/modules/sales/data/entities.js +8 -2
- package/dist/modules/sales/data/entities.js.map +2 -2
- package/dist/modules/sales/extension-points.js +1 -0
- package/dist/modules/sales/extension-points.js.map +2 -2
- package/dist/modules/sales/lib/salesChannelsToggleSeed.js +33 -0
- package/dist/modules/sales/lib/salesChannelsToggleSeed.js.map +7 -0
- package/dist/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.js +32 -0
- package/dist/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.js.map +7 -0
- package/dist/modules/sales/setup.js +2 -0
- package/dist/modules/sales/setup.js.map +2 -2
- package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js +10 -2
- package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js.map +2 -2
- package/dist/modules/sales/widgets/injection-table.js +4 -7
- package/dist/modules/sales/widgets/injection-table.js.map +2 -2
- package/dist/modules/staff/backend/staff/leave-requests/page.js +3 -0
- package/dist/modules/staff/backend/staff/leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js +3 -0
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/page.js +3 -0
- package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js +3 -0
- package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +3 -0
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js +3 -0
- package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/page.js +29 -18
- package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js +3 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
- package/dist/modules/sync_excel/lib/adapters/customers.js +1 -0
- package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
- package/dist/modules/warranty_claims/api/assignees/route.js +3 -3
- package/dist/modules/warranty_claims/api/assignees/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/attachments/route.js +2 -2
- package/dist/modules/warranty_claims/api/portal/attachments/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/route.js +12 -9
- package/dist/modules/warranty_claims/api/portal/claims/route.js.map +2 -2
- package/dist/modules/warranty_claims/backend/page.js +3 -0
- package/dist/modules/warranty_claims/backend/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js +3 -0
- package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js +3 -0
- package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js +3 -0
- package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js.map +2 -2
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js +3 -0
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js.map +2 -2
- package/dist/modules/wms/api/warehouseSearch.js +21 -0
- package/dist/modules/wms/api/warehouseSearch.js.map +7 -0
- package/dist/modules/wms/api/warehouses/route.js +13 -9
- package/dist/modules/wms/api/warehouses/route.js.map +2 -2
- package/dist/modules/wms/api/zones/route.js +15 -2
- package/dist/modules/wms/api/zones/route.js.map +2 -2
- package/dist/modules/wms/commands/configuration.js +121 -9
- package/dist/modules/wms/commands/configuration.js.map +2 -2
- package/dist/modules/wms/commands/inventory-actions.js +3 -0
- package/dist/modules/wms/commands/inventory-actions.js.map +2 -2
- package/dist/modules/wms/commands/shared.js +9 -1
- package/dist/modules/wms/commands/shared.js.map +2 -2
- package/dist/modules/wms/components/backend/WarehouseEditDialog.js +158 -0
- package/dist/modules/wms/components/backend/WarehouseEditDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js +76 -111
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +3 -3
- package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +1 -0
- package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsLotsListPage.js +1 -0
- package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +2 -2
- package/dist/modules/wms/components/backend/inventoryMutationLoaders.js +27 -20
- package/dist/modules/wms/components/backend/inventoryMutationLoaders.js.map +2 -2
- package/dist/modules/wms/components/backend/warehouseFormOptions.js +66 -0
- package/dist/modules/wms/components/backend/warehouseFormOptions.js.map +7 -0
- package/dist/modules/workflows/backend/definitions/page.js +3 -1
- package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
- package/dist/modules/workflows/backend/events/page.js +3 -1
- package/dist/modules/workflows/backend/events/page.js.map +2 -2
- package/dist/modules/workflows/backend/instances/page.js +3 -1
- package/dist/modules/workflows/backend/instances/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/page.js +3 -1
- package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
- package/dist/modules/workflows/lib/activity-executor.js +4 -0
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/package.json +9 -10
- package/src/helpers/integration/api.ts +33 -1
- package/src/helpers/integration/communicationChannelsFixtures.ts +69 -1
- package/src/modules/api_keys/api/keys/route.ts +3 -1
- package/src/modules/api_keys/backend/api-keys/page.tsx +4 -1
- package/src/modules/api_keys/di.ts +7 -0
- package/src/modules/api_keys/services/principalService.ts +33 -0
- package/src/modules/attachments/AGENTS.md +15 -0
- package/src/modules/attachments/api/route.ts +2 -2
- package/src/modules/attachments/components/AttachmentLibrary.tsx +3 -0
- package/src/modules/attachments/di.ts +16 -0
- package/src/modules/attachments/i18n/de.json +5 -0
- package/src/modules/attachments/i18n/en.json +5 -0
- package/src/modules/attachments/i18n/es.json +5 -0
- package/src/modules/attachments/i18n/ko.json +5 -0
- package/src/modules/attachments/i18n/pl.json +5 -0
- package/src/modules/attachments/index.ts +10 -0
- package/src/modules/attachments/lib/attachment-service.ts +468 -0
- package/src/modules/attachments/lib/scoped-upload-service.ts +46 -0
- package/src/modules/attachments/lib/upload-limits.ts +6 -2
- package/src/modules/audit_logs/backend/audit-logs/page.tsx +8 -0
- package/src/modules/audit_logs/lib/display-helpers.tsx +42 -32
- package/src/modules/audit_logs/services/actionLogService.ts +74 -11
- package/src/modules/auth/acl.ts +30 -6
- package/src/modules/auth/api/feature-check.ts +10 -3
- package/src/modules/auth/api/login.ts +9 -1
- package/src/modules/auth/api/reset/validate.ts +57 -0
- package/src/modules/auth/api/roles/acl/route.ts +42 -39
- package/src/modules/auth/api/session/refresh.ts +32 -1
- package/src/modules/auth/api/users/acl/route.ts +177 -53
- package/src/modules/auth/api/users/route.ts +18 -5
- package/src/modules/auth/backend/roles/[id]/edit/page.meta.ts +5 -2
- package/src/modules/auth/backend/roles/page.tsx +4 -2
- package/src/modules/auth/backend/users/[id]/edit/page.meta.ts +5 -2
- package/src/modules/auth/backend/users/page.tsx +3 -2
- package/src/modules/auth/commands/acl.ts +495 -0
- package/src/modules/auth/components/AclEditor.tsx +63 -33
- package/src/modules/auth/data/entities.ts +4 -1
- package/src/modules/auth/data/validators.ts +5 -0
- package/src/modules/auth/di.ts +46 -16
- package/src/modules/auth/frontend/reset/[token]/page.tsx +74 -0
- package/src/modules/auth/i18n/de.json +389 -0
- package/src/modules/auth/i18n/en.json +389 -0
- package/src/modules/auth/i18n/es.json +389 -0
- package/src/modules/auth/i18n/ko.json +389 -0
- package/src/modules/auth/i18n/pl.json +391 -2
- package/src/modules/auth/lib/grantChecks.ts +6 -0
- package/src/modules/auth/lib/userIdFilter.ts +31 -0
- package/src/modules/auth/services/authService.ts +18 -2
- package/src/modules/auth/services/principalService.ts +266 -0
- package/src/modules/auth/services/rbacService.ts +110 -24
- package/src/modules/auth/services/roleOrganizationScope.ts +70 -0
- package/src/modules/business_rules/backend/logs/page.tsx +4 -1
- package/src/modules/business_rules/backend/rules/page.tsx +4 -1
- package/src/modules/business_rules/backend/sets/page.tsx +4 -1
- package/src/modules/business_rules/lib/expression-evaluator.ts +9 -9
- package/src/modules/business_rules/lib/rule-evaluator.ts +10 -9
- package/src/modules/catalog/ai-agents.ts +1 -1
- package/src/modules/catalog/ai-tools/merchandising-pack.ts +2 -2
- package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +12 -5
- package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +3 -0
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +7 -0
- package/src/modules/catalog/i18n/de.json +1 -0
- package/src/modules/catalog/i18n/en.json +1 -0
- package/src/modules/catalog/i18n/es.json +1 -0
- package/src/modules/catalog/i18n/ko.json +1 -0
- package/src/modules/catalog/i18n/pl.json +1 -0
- package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.tsx +4 -0
- package/src/modules/communication_channels/api/post/channels/[id]/test-send/route.ts +17 -1
- package/src/modules/communication_channels/api/post/test-seed/route.ts +155 -16
- package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +4 -0
- package/src/modules/communication_channels/commands/ingest-inbound-message.ts +38 -1
- package/src/modules/communication_channels/di.ts +7 -0
- package/src/modules/communication_channels/lib/adapter.ts +14 -0
- package/src/modules/communication_channels/lib/email-capabilities.ts +4 -0
- package/src/modules/communication_channels/lib/outbound-recipient.ts +71 -0
- package/src/modules/communication_channels/lib/resolve-channel-type.ts +99 -0
- package/src/modules/communication_channels/lib/test-seed.ts +64 -4
- package/src/modules/configs/i18n/de.json +2 -0
- package/src/modules/configs/i18n/en.json +2 -0
- package/src/modules/configs/i18n/es.json +2 -0
- package/src/modules/configs/i18n/ko.json +2 -0
- package/src/modules/configs/i18n/pl.json +2 -0
- package/src/modules/configs/lib/system-status.ts +9 -0
- package/src/modules/currencies/AGENTS.md +3 -0
- package/src/modules/currencies/backend/currencies/page.tsx +4 -1
- package/src/modules/currencies/backend/exchange-rates/page.tsx +4 -1
- package/src/modules/currencies/services/README.md +45 -0
- package/src/modules/currencies/services/rateFetchingService.ts +6 -1
- package/src/modules/customer_accounts/api/admin/domain-mappings.ts +7 -0
- package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +4 -1
- package/src/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.tsx +4 -1
- package/src/modules/customer_accounts/services/domainMappingService.ts +10 -0
- package/src/modules/customers/ai-tools/companies-pack.ts +4 -1
- package/src/modules/customers/ai-tools/deal-analyzer-pack.ts +17 -2
- package/src/modules/customers/ai-tools/deals-pack.ts +66 -1
- package/src/modules/customers/ai-tools/people-pack.ts +4 -1
- package/src/modules/customers/api/activities/route.ts +45 -0
- package/src/modules/customers/api/companies/[id]/people/route.ts +24 -73
- package/src/modules/customers/api/companies/[id]/route.ts +24 -107
- package/src/modules/customers/api/dashboard/widgets/customer-todos/route.ts +16 -8
- package/src/modules/customers/api/deals/[id]/companies/route.ts +4 -1
- package/src/modules/customers/api/deals/[id]/people/route.ts +4 -1
- package/src/modules/customers/api/deals/[id]/route.ts +17 -28
- package/src/modules/customers/api/deals/[id]/stats/route.ts +10 -25
- package/src/modules/customers/api/deals/aggregate/route.ts +14 -4
- package/src/modules/customers/api/deals/map/route.ts +1 -0
- package/src/modules/customers/api/deals/route.ts +50 -1
- package/src/modules/customers/api/entity-roles-factory.ts +8 -4
- package/src/modules/customers/api/interactions/route.ts +8 -2
- package/src/modules/customers/api/interactions/tasks/route.ts +24 -1
- package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +12 -4
- package/src/modules/customers/api/people/[id]/companies/context.ts +4 -1
- package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +4 -1
- package/src/modules/customers/api/people/[id]/route.ts +16 -11
- package/src/modules/customers/api/people/check-phone/route.ts +75 -10
- package/src/modules/customers/api/todos/route.ts +27 -2
- package/src/modules/customers/backend/customers/companies/page.tsx +5 -2
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +7 -2
- package/src/modules/customers/backend/customers/deals/page.tsx +8 -2
- package/src/modules/customers/backend/customers/deals/pipeline/components/Lane.tsx +5 -14
- package/src/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.tsx +109 -27
- package/src/modules/customers/backend/customers/deals/pipeline/components/toneClasses.ts +21 -0
- package/src/modules/customers/backend/customers/people/page.tsx +5 -2
- package/src/modules/customers/backend/hooks/useEmailDuplicateCheck.ts +12 -4
- package/src/modules/customers/commands/deals.ts +34 -59
- package/src/modules/customers/commands/interactions.ts +1 -1
- package/src/modules/customers/commands/personCompanyLinks.ts +224 -8
- package/src/modules/customers/components/CustomerTodosTable.tsx +2 -0
- package/src/modules/customers/components/DealsKpiStrip.tsx +7 -7
- package/src/modules/customers/components/calendar/AgendaList.tsx +3 -3
- package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +1 -1
- package/src/modules/customers/components/calendar/CalendarScreen.tsx +1 -1
- package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +1 -1
- package/src/modules/customers/components/calendar/EventBlock.tsx +2 -2
- package/src/modules/customers/components/calendar/EventPeekPopover.tsx +4 -2
- package/src/modules/customers/components/calendar/editor/PeopleField.tsx +61 -5
- package/src/modules/customers/components/calendar/editor/hooks.ts +7 -1
- package/src/modules/customers/components/calendar/types.ts +2 -2
- package/src/modules/customers/components/detail/CompanyKpiBar.tsx +5 -4
- package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +8 -1
- package/src/modules/customers/components/detail/DealForm.tsx +22 -2
- package/src/modules/customers/components/detail/DealsSection.tsx +11 -5
- package/src/modules/customers/components/detail/EntityTagsDialog.tsx +58 -12
- package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +8 -1
- package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +23 -14
- package/src/modules/customers/components/detail/schedule/ParticipantsField.tsx +5 -5
- package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +5 -5
- package/src/modules/customers/components/detail/types.ts +1 -1
- package/src/modules/customers/components/detail/utils.ts +15 -5
- package/src/modules/customers/data/entities.ts +1 -1
- package/src/modules/customers/data/validators.ts +50 -9
- package/src/modules/customers/events.ts +5 -0
- package/src/modules/customers/i18n/de.json +9 -1
- package/src/modules/customers/i18n/en.json +9 -1
- package/src/modules/customers/i18n/es.json +9 -1
- package/src/modules/customers/i18n/ko.json +9 -1
- package/src/modules/customers/i18n/pl.json +9 -1
- package/src/modules/customers/lib/calendar/conflicts.ts +10 -2
- package/src/modules/customers/lib/calendar/editorPayload.ts +4 -3
- package/src/modules/customers/lib/calendar/mapItem.ts +8 -3
- package/src/modules/customers/lib/calendar/participantIdentity.ts +17 -0
- package/src/modules/customers/lib/closureStage.ts +76 -0
- package/src/modules/customers/lib/dealStatus.ts +42 -0
- package/src/modules/customers/lib/detailReadAccess.ts +35 -0
- package/src/modules/customers/lib/findPeopleByAddresses.ts +8 -6
- package/src/modules/customers/lib/personCompanies.ts +136 -1
- package/src/modules/customers/lib/todoCompatibility.ts +19 -1
- package/src/modules/dashboards/i18n/es.json +4 -4
- package/src/modules/dashboards/i18n/pl.json +7 -7
- package/src/modules/dashboards/lib/widgetScope.ts +6 -0
- package/src/modules/data_sync/AGENTS.md +1 -1
- package/src/modules/data_sync/backend/data-sync/page.tsx +4 -1
- package/src/modules/data_sync/lib/abandoned-run.ts +56 -0
- package/src/modules/data_sync/lib/adapter.ts +36 -0
- package/src/modules/data_sync/lib/sync-engine.ts +113 -5
- package/src/modules/data_sync/workers/sync-export.ts +4 -0
- package/src/modules/data_sync/workers/sync-import.ts +4 -0
- package/src/modules/devices/AGENTS.md +20 -1
- package/src/modules/devices/acl.ts +9 -1
- package/src/modules/devices/api/admin/devices/[id]/route.ts +5 -34
- package/src/modules/devices/api/admin/devices/route.ts +14 -1
- package/src/modules/devices/api/deviceList.ts +135 -11
- package/src/modules/devices/api/deviceSerialization.ts +50 -0
- package/src/modules/devices/api/openapi.ts +9 -1
- package/src/modules/devices/api/route.ts +9 -1
- package/src/modules/devices/backend/devices/[id]/page.tsx +18 -32
- package/src/modules/devices/backend/devices/create/page.tsx +17 -1
- package/src/modules/devices/backend/devices/page.tsx +44 -45
- package/src/modules/devices/backend/devices/useDeviceUserLabels.ts +45 -0
- package/src/modules/devices/backend/devices/userOptions.ts +99 -0
- package/src/modules/devices/i18n/de.json +3 -2
- package/src/modules/devices/i18n/en.json +3 -2
- package/src/modules/devices/i18n/es.json +3 -2
- package/src/modules/devices/i18n/ko.json +3 -2
- package/src/modules/devices/i18n/pl.json +3 -2
- package/src/modules/devices/setup.ts +6 -2
- package/src/modules/directory/backend/directory/organizations/page.tsx +3 -1
- package/src/modules/directory/backend/directory/tenants/page.tsx +3 -1
- package/src/modules/directory/di.ts +14 -2
- package/src/modules/directory/services/organizationHierarchyService.ts +34 -0
- package/src/modules/directory/services/organizationScopeService.ts +85 -0
- package/src/modules/directory/utils/organizationScope.ts +4 -15
- package/src/modules/entities/api/records.ts +2 -0
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +4 -1
- package/src/modules/eudr/api/plots/route.ts +4 -0
- package/src/modules/eudr/backend/eudr/evidence-submissions/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/plots/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/product-mappings/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/risk-assessments/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/statements/page.tsx +4 -0
- package/src/modules/eudr/commands/statements.ts +0 -3
- package/src/modules/eudr/data/validators.ts +16 -1
- package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +2 -1
- package/src/modules/feature_toggles/components/OverridesTable.tsx +2 -1
- package/src/modules/feature_toggles/defaults.json +0 -8
- package/src/modules/inbox_ops/backend/inbox-ops/log/page.tsx +4 -0
- package/src/modules/inbox_ops/backend/inbox-ops/page.tsx +4 -0
- package/src/modules/inbox_ops/lib/htmlToPlainText.ts +1 -17
- package/src/modules/integrations/api/[id]/credentials/route.ts +6 -4
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +61 -31
- package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +44 -9
- package/src/modules/integrations/backend/integrations/credential-secret-fields.ts +84 -0
- package/src/modules/integrations/data/validators.ts +12 -2
- package/src/modules/integrations/i18n/de.json +1 -0
- package/src/modules/integrations/i18n/en.json +1 -0
- package/src/modules/integrations/i18n/es.json +1 -0
- package/src/modules/integrations/i18n/ko.json +1 -0
- package/src/modules/integrations/i18n/pl.json +1 -0
- package/src/modules/integrations/lib/credentials-masking.ts +10 -6
- package/src/modules/messages/api/[id]/route.ts +55 -1
- package/src/modules/messages/api/openapi.ts +20 -0
- package/src/modules/messages/api/route.ts +31 -2
- package/src/modules/messages/components/MessagesInboxPageClient.tsx +9 -16
- package/src/modules/messages/components/inboxFilters.ts +36 -0
- package/src/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.ts +14 -1
- package/src/modules/messages/components/message-detail/panels/MessageHeader.tsx +3 -1
- package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +2 -1
- package/src/modules/messages/components/message-detail/types.ts +3 -0
- package/src/modules/messages/components/messageListLabels.ts +52 -3
- package/src/modules/messages/data/validators.ts +43 -4
- package/src/modules/messages/lib/channel-sender-identity.ts +55 -0
- package/src/modules/messages/lib/composeSourceChannelType.ts +95 -0
- package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +4 -6
- package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +4 -1
- package/src/modules/payment_gateways/lib/webhook-processor.ts +11 -0
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +4 -0
- package/src/modules/push_notifications/backend/push_notifications/page.tsx +4 -1
- package/src/modules/push_notifications/backend/push_notifications/send/page.tsx +4 -4
- package/src/modules/query_index/lib/engine.ts +249 -61
- package/src/modules/query_index/lib/search-entity-policy.ts +46 -0
- package/src/modules/query_index/lib/search-tokens.ts +135 -3
- package/src/modules/resources/backend/resources/resource-types/page.tsx +4 -1
- package/src/modules/resources/backend/resources/resources/page.tsx +4 -1
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +4 -0
- package/src/modules/sales/backend/sales/channels/page.tsx +4 -0
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +14 -8
- package/src/modules/sales/commands/documents.ts +93 -0
- package/src/modules/sales/components/PriceWithCurrency.tsx +17 -5
- package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +4 -0
- package/src/modules/sales/components/documents/AdjustmentsSection.tsx +6 -5
- package/src/modules/sales/components/documents/ItemsSection.tsx +56 -18
- package/src/modules/sales/components/documents/LineItemDialog.tsx +137 -20
- package/src/modules/sales/components/documents/PaymentsSection.tsx +20 -9
- package/src/modules/sales/components/documents/ReturnsSection.tsx +6 -5
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +106 -14
- package/src/modules/sales/components/documents/SalesOrderDraftLines.tsx +6 -5
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +5 -4
- package/src/modules/sales/components/documents/ShipmentsSection.tsx +6 -5
- package/src/modules/sales/components/documents/lineItemShipmentLock.ts +74 -0
- package/src/modules/sales/components/documents/lineItemUtils.ts +7 -2
- package/src/modules/sales/data/entities.ts +6 -0
- package/src/modules/sales/extension-points.ts +1 -0
- package/src/modules/sales/i18n/de.json +8 -0
- package/src/modules/sales/i18n/en.json +8 -0
- package/src/modules/sales/i18n/es.json +8 -0
- package/src/modules/sales/i18n/ko.json +8 -0
- package/src/modules/sales/i18n/pl.json +8 -0
- package/src/modules/sales/lib/salesChannelsToggleSeed.ts +42 -0
- package/src/modules/sales/migrations/.snapshot-open-mercato.json +60 -0
- package/src/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.ts +87 -0
- package/src/modules/sales/setup.ts +2 -0
- package/src/modules/sales/widgets/injection/payment-gateway-status-column/widget.ts +9 -1
- package/src/modules/sales/widgets/injection-table.ts +4 -7
- package/src/modules/staff/backend/staff/leave-requests/page.tsx +4 -0
- package/src/modules/staff/backend/staff/my-leave-requests/page.tsx +4 -0
- package/src/modules/staff/backend/staff/team-members/page.tsx +6 -0
- package/src/modules/staff/backend/staff/team-roles/page.tsx +4 -0
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +4 -0
- package/src/modules/staff/backend/staff/teams/page.tsx +4 -0
- package/src/modules/staff/backend/staff/timesheets/page.tsx +12 -1
- package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +4 -0
- package/src/modules/sync_excel/lib/adapters/customers.ts +5 -0
- package/src/modules/warranty_claims/api/assignees/route.ts +3 -3
- package/src/modules/warranty_claims/api/portal/attachments/route.ts +2 -2
- package/src/modules/warranty_claims/api/portal/claims/route.ts +12 -9
- package/src/modules/warranty_claims/backend/page.tsx +4 -0
- package/src/modules/warranty_claims/backend/warranty_claims/registrations/page.tsx +4 -0
- package/src/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.tsx +4 -0
- package/src/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.tsx +4 -0
- package/src/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.tsx +4 -0
- package/src/modules/wms/api/warehouseSearch.ts +23 -0
- package/src/modules/wms/api/warehouses/route.ts +13 -9
- package/src/modules/wms/api/zones/route.ts +16 -0
- package/src/modules/wms/commands/configuration.ts +159 -10
- package/src/modules/wms/commands/inventory-actions.ts +3 -0
- package/src/modules/wms/commands/shared.ts +17 -0
- package/src/modules/wms/components/backend/WarehouseEditDialog.tsx +216 -0
- package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +95 -141
- package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +2 -0
- package/src/modules/wms/components/backend/WmsLotsListPage.tsx +2 -0
- package/src/modules/wms/components/backend/inventoryMutationLoaders.ts +36 -20
- package/src/modules/wms/components/backend/warehouseFormOptions.ts +72 -0
- package/src/modules/wms/i18n/de.json +2 -0
- package/src/modules/wms/i18n/en.json +2 -0
- package/src/modules/wms/i18n/es.json +2 -0
- package/src/modules/wms/i18n/ko.json +2 -0
- package/src/modules/wms/i18n/pl.json +2 -0
- package/src/modules/workflows/backend/definitions/page.tsx +4 -1
- package/src/modules/workflows/backend/events/page.tsx +4 -1
- package/src/modules/workflows/backend/instances/page.tsx +4 -1
- package/src/modules/workflows/backend/tasks/page.tsx +4 -1
- package/src/modules/workflows/lib/activity-executor.ts +9 -0
|
@@ -8,6 +8,7 @@ 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";
|
|
11
12
|
function isAclData(value) {
|
|
12
13
|
if (typeof value !== "object" || value === null) return false;
|
|
13
14
|
const record = value;
|
|
@@ -19,9 +20,13 @@ function isAclData(value) {
|
|
|
19
20
|
}
|
|
20
21
|
return true;
|
|
21
22
|
}
|
|
23
|
+
function isRestrictedRoleAcl(acl) {
|
|
24
|
+
return Array.isArray(acl.organizationsJson) && acl.organizationsJson.length > 0 && !acl.organizationsJson.includes("__all__");
|
|
25
|
+
}
|
|
22
26
|
class RbacService {
|
|
23
|
-
constructor(em, cache) {
|
|
27
|
+
constructor(em, cache, organizationHierarchyService) {
|
|
24
28
|
this.em = em;
|
|
29
|
+
this.organizationHierarchyService = organizationHierarchyService;
|
|
25
30
|
this.cacheTtlMs = 5 * 60 * 1e3;
|
|
26
31
|
// 5 minutes default
|
|
27
32
|
this.cache = null;
|
|
@@ -39,12 +44,6 @@ class RbacService {
|
|
|
39
44
|
hasAllFeatures(required, granted) {
|
|
40
45
|
return authorizeFeatures(required, { grantedFeatures: granted });
|
|
41
46
|
}
|
|
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
|
-
}
|
|
48
47
|
getCacheKey(userId, scope) {
|
|
49
48
|
return `rbac:${userId}:${scope.tenantId || "null"}:${scope.organizationId || "null"}`;
|
|
50
49
|
}
|
|
@@ -71,6 +70,7 @@ class RbacService {
|
|
|
71
70
|
];
|
|
72
71
|
if (scope.tenantId) {
|
|
73
72
|
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 roleSupers = await em.find(RoleAcl, { isSuperAdmin: true, role: { $in: roleIds } });
|
|
171
|
+
const result = roleSupers.some((roleAcl) => !!roleAcl.isSuperAdmin && !isRestrictedRoleAcl(roleAcl));
|
|
172
172
|
this.globalSuperAdminCache.set(userId, result);
|
|
173
173
|
return result;
|
|
174
174
|
}
|
|
@@ -215,28 +215,55 @@ 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;
|
|
218
220
|
let isSuper2 = false;
|
|
219
221
|
const features2 = [];
|
|
220
|
-
let
|
|
222
|
+
let roleOrganizations = [];
|
|
223
|
+
let hasApplicableRestrictedRole2 = false;
|
|
221
224
|
if (tenantId2 && roleIds2.length) {
|
|
225
|
+
const roleOrganizationScope = await resolveRoleOrganizationScope(
|
|
226
|
+
this.organizationHierarchyService,
|
|
227
|
+
tenantId2,
|
|
228
|
+
evaluatedOrganizationId
|
|
229
|
+
);
|
|
222
230
|
const racls = await em2.find(RoleAcl, { tenantId: tenantId2, role: { $in: roleIds2 } });
|
|
223
231
|
for (const acl of racls) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
232
|
+
if (roleAclAllowsOrganization(acl, roleOrganizationScope)) {
|
|
233
|
+
isSuper2 = isSuper2 || !!acl.isSuperAdmin;
|
|
234
|
+
if (Array.isArray(acl.featuresJson)) {
|
|
235
|
+
for (const f of acl.featuresJson) if (!features2.includes(f)) features2.push(f);
|
|
236
|
+
}
|
|
237
|
+
if (isRestrictedRoleAcl(acl)) hasApplicableRestrictedRole2 = true;
|
|
227
238
|
}
|
|
228
|
-
if (
|
|
229
|
-
if (acl.organizationsJson == null) {
|
|
230
|
-
|
|
239
|
+
if (roleOrganizations !== null) {
|
|
240
|
+
if (acl.organizationsJson == null || Array.isArray(acl.organizationsJson) && acl.organizationsJson.length === 0) {
|
|
241
|
+
roleOrganizations = null;
|
|
231
242
|
} else if (Array.isArray(acl.organizationsJson) && acl.organizationsJson.includes("__all__")) {
|
|
232
|
-
|
|
243
|
+
roleOrganizations = null;
|
|
233
244
|
} else {
|
|
234
|
-
|
|
245
|
+
roleOrganizations = Array.from(/* @__PURE__ */ new Set([
|
|
246
|
+
...roleOrganizations,
|
|
247
|
+
...Array.isArray(acl.organizationsJson) ? acl.organizationsJson : []
|
|
248
|
+
]));
|
|
235
249
|
}
|
|
236
250
|
}
|
|
237
251
|
}
|
|
252
|
+
if (roleOrganizations !== null && evaluatedOrganizationId && roleOrganizationScope !== null && roleOrganizationScope.size > 0 && hasApplicableRestrictedRole2 && !roleOrganizations.includes(evaluatedOrganizationId)) {
|
|
253
|
+
roleOrganizations.push(evaluatedOrganizationId);
|
|
254
|
+
}
|
|
238
255
|
}
|
|
239
|
-
|
|
256
|
+
let organizations2 = roleOrganizations;
|
|
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 };
|
|
240
267
|
await this.setCache(cacheKey, result2, userId, scope);
|
|
241
268
|
return result2;
|
|
242
269
|
}
|
|
@@ -276,13 +303,22 @@ class RbacService {
|
|
|
276
303
|
let isSuper = false;
|
|
277
304
|
const features = [];
|
|
278
305
|
let organizations = [];
|
|
306
|
+
let hasApplicableRestrictedRole = false;
|
|
279
307
|
if (roleIds.length) {
|
|
308
|
+
const roleOrganizationScope = await resolveRoleOrganizationScope(
|
|
309
|
+
this.organizationHierarchyService,
|
|
310
|
+
tenantId,
|
|
311
|
+
scope.organizationId
|
|
312
|
+
);
|
|
280
313
|
const racls = await em.find(RoleAcl, { tenantId, role: { $in: roleIds } }, {});
|
|
281
314
|
const roleAcls = Array.isArray(racls) ? racls : [];
|
|
282
315
|
for (const r of roleAcls) {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
316
|
+
if (roleAclAllowsOrganization(r, roleOrganizationScope)) {
|
|
317
|
+
isSuper = isSuper || !!r.isSuperAdmin;
|
|
318
|
+
if (Array.isArray(r.featuresJson)) {
|
|
319
|
+
for (const f of r.featuresJson) if (!features.includes(f)) features.push(f);
|
|
320
|
+
}
|
|
321
|
+
if (isRestrictedRoleAcl(r)) hasApplicableRestrictedRole = true;
|
|
286
322
|
}
|
|
287
323
|
if (organizations !== null) {
|
|
288
324
|
if (r.organizationsJson == null) organizations = null;
|
|
@@ -290,6 +326,9 @@ class RbacService {
|
|
|
290
326
|
else organizations = Array.from(/* @__PURE__ */ new Set([...organizations || [], ...r.organizationsJson]));
|
|
291
327
|
}
|
|
292
328
|
}
|
|
329
|
+
if (organizations !== null && scope.organizationId && roleOrganizationScope !== null && roleOrganizationScope.size > 0 && hasApplicableRestrictedRole && !organizations.includes(scope.organizationId)) {
|
|
330
|
+
organizations.push(scope.organizationId);
|
|
331
|
+
}
|
|
293
332
|
}
|
|
294
333
|
if (organizations && orgId && !organizations.includes(orgId) && !organizations.includes("__all__")) {
|
|
295
334
|
}
|
|
@@ -306,11 +345,15 @@ class RbacService {
|
|
|
306
345
|
async tenantHasFeature(tenantId, feature, opts) {
|
|
307
346
|
if (!tenantId || !feature) return false;
|
|
308
347
|
const em = this.em.fork();
|
|
348
|
+
const roleOrganizationScope = await resolveRoleOrganizationScope(
|
|
349
|
+
this.organizationHierarchyService,
|
|
350
|
+
tenantId,
|
|
351
|
+
opts?.organizationId
|
|
352
|
+
);
|
|
309
353
|
const roleAcls = await em.find(RoleAcl, { tenantId, deletedAt: null }, {});
|
|
310
354
|
const list = Array.isArray(roleAcls) ? roleAcls : [];
|
|
311
|
-
const organizationId = opts?.organizationId ?? null;
|
|
312
355
|
for (const acl of list) {
|
|
313
|
-
if (!
|
|
356
|
+
if (!roleAclAllowsOrganization(acl, roleOrganizationScope)) continue;
|
|
314
357
|
const grants = Array.isArray(acl.featuresJson) ? acl.featuresJson : [];
|
|
315
358
|
if (authorizeFeatures([feature], {
|
|
316
359
|
grantedFeatures: grants,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/auth/services/rbacService.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport { getCurrentCacheTenant, runWithCacheTenant } from '@open-mercato/cache'\nimport { UserAcl, RoleAcl, User, UserRole } from '@open-mercato/core/modules/auth/data/entities'\nimport { ApiKey } from '@open-mercato/core/modules/api_keys/data/entities'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { buildOrgScopeUserCacheTag, buildOrgScopeTenantCacheTag } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport {\n authorizeFeatures,\n resolveEffectiveFeatures,\n} from '@open-mercato/shared/security/featurePolicy'\nimport { filterGrantsByEnabledModules } from '@open-mercato/shared/security/enabledModulesRegistry'\n\ninterface AclData {\n isSuperAdmin: boolean\n features: string[]\n organizations: string[] | null\n}\n\nfunction isAclData(value: unknown): value is AclData {\n if (typeof value !== 'object' || value === null) return false\n const record = value as Partial<AclData>\n if (typeof record.isSuperAdmin !== 'boolean') return false\n if (!Array.isArray(record.features) || record.features.some((feature) => typeof feature !== 'string')) return false\n if (record.organizations !== null && record.organizations !== undefined) {\n if (!Array.isArray(record.organizations)) return false\n if (record.organizations.some((org) => typeof org !== 'string')) return false\n }\n return true\n}\n\nexport class RbacService {\n private cacheTtlMs: number = 5 * 60 * 1000 // 5 minutes default\n private cache: CacheStrategy | null = null\n private globalSuperAdminCache = new Map<string, boolean>()\n\n constructor(private em: EntityManager, cache?: CacheStrategy) {\n this.cache = cache || null\n }\n\n /**\n * Set cache TTL in milliseconds\n * @param ttlMs - Time to live in milliseconds\n */\n setCacheTtl(ttlMs: number) {\n this.cacheTtlMs = ttlMs\n }\n\n /** Compatibility wrapper for callers that already have both feature lists. */\n public hasAllFeatures(required: string[], granted: string[]): boolean {\n return authorizeFeatures(required, { grantedFeatures: granted })\n }\n\n private roleAclAllowsOrganization(acl: RoleAcl, organizationId: string | null | undefined): boolean {\n if (!organizationId) return true\n const organizations = Array.isArray(acl.organizationsJson) ? acl.organizationsJson : null\n if (!organizations || !organizations.length || organizations.includes('__all__')) return true\n return organizations.includes(organizationId)\n }\n\n private getCacheKey(userId: string, scope: { tenantId: string | null; organizationId: string | null }): string {\n return `rbac:${userId}:${scope.tenantId || 'null'}:${scope.organizationId || 'null'}`\n }\n\n private getUserTag(userId: string): string {\n return `rbac:user:${userId}`\n }\n\n private getTenantTag(tenantId: string): string {\n return `rbac:tenant:${tenantId}`\n }\n\n private getOrganizationTag(organizationId: string): string {\n return `rbac:org:${organizationId}`\n }\n\n private async getFromCache(cacheKey: string): Promise<AclData | null> {\n if (!this.cache) return null\n const cached = await this.cache.get(cacheKey)\n if (!cached) return null\n return isAclData(cached) ? cached : null\n }\n\n private async setCache(cacheKey: string, data: AclData, userId: string, scope: { tenantId: string | null; organizationId: string | null }): Promise<void> {\n if (!this.cache) return\n\n const tags = [\n this.getUserTag(userId),\n 'rbac:all'\n ]\n\n if (scope.tenantId) {\n tags.push(this.getTenantTag(scope.tenantId))\n }\n\n if (scope.organizationId) {\n tags.push(this.getOrganizationTag(scope.organizationId))\n }\n\n await this.cache.set(cacheKey, data, {\n ttl: this.cacheTtlMs,\n tags\n })\n }\n\n /**\n * Invalidates cached ACL data for a specific user across all tenants and organizations.\n * Call this when a user's roles or user-specific ACL is modified.\n * \n * @param userId - The ID of the user whose cache should be invalidated\n */\n async invalidateUserCache(userId: string): Promise<void> {\n this.globalSuperAdminCache.delete(userId)\n // Also drop the directory OrganizationScope cache for this user. That scope's\n // accessible-org set is derived from this user's ACL/role grants, so any\n // permission change that invalidates the RBAC cache must invalidate the\n // resolved scope too. This is the missing `org-scope:user:*` caller required\n // before the cross-request scope TTL can be safely enabled (issue #2259).\n await this.deleteCacheByTags([this.getUserTag(userId), buildOrgScopeUserCacheTag(userId)])\n }\n\n /**\n * Invalidates cached ACL data for all users within a specific tenant.\n * Call this when a role's ACL is modified, since roles are tenant-scoped\n * and affect all users in that tenant who have that role.\n * \n * @param tenantId - The ID of the tenant whose cache should be invalidated\n */\n async invalidateTenantCache(tenantId: string): Promise<void> {\n this.globalSuperAdminCache.clear()\n // Role ACL changes invalidate every user in the tenant; the resolved\n // OrganizationScope for those users derives from the same grants, so drop\n // the tenant-tagged scope entries alongside the RBAC ones (issue #2259).\n await this.deleteCacheByTags([this.getTenantTag(tenantId), buildOrgScopeTenantCacheTag(tenantId)], [tenantId])\n }\n\n /**\n * Invalidates cached ACL data for all users within a specific organization.\n * Call this when organization-level permissions or visibility changes.\n * \n * @param organizationId - The ID of the organization whose cache should be invalidated\n */\n async invalidateOrganizationCache(organizationId: string): Promise<void> {\n await this.deleteCacheByTags([this.getOrganizationTag(organizationId)])\n }\n\n /**\n * Clears all cached ACL data.\n * Use this for bulk operations or system-wide ACL changes.\n */\n async invalidateAllCache(): Promise<void> {\n this.globalSuperAdminCache.clear()\n await this.deleteCacheByTags(['rbac:all'])\n }\n\n private async deleteCacheByTags(tags: string[], tenantHints?: Array<string | null>): Promise<void> {\n if (!this.cache) return\n const contexts = new Set<string | null>()\n const current = getCurrentCacheTenant()\n contexts.add(current ?? null)\n contexts.add(null)\n if (Array.isArray(tenantHints)) {\n for (const hint of tenantHints) {\n contexts.add(hint ?? null)\n }\n }\n for (const ctx of contexts) {\n if (ctx === current) {\n await this.cache.deleteByTags(tags)\n } else {\n await runWithCacheTenant(ctx, async () => {\n await this.cache!.deleteByTags(tags)\n })\n }\n }\n }\n\n private async isGlobalSuperAdmin(userId: string): Promise<boolean> {\n if (this.globalSuperAdminCache.has(userId)) return this.globalSuperAdminCache.get(userId)!\n const em = this.em.fork()\n const userSuper = await em.findOne(UserAcl, { user: userId as any, isSuperAdmin: true })\n if (userSuper && (userSuper as any).isSuperAdmin) {\n this.globalSuperAdminCache.set(userId, true)\n return true\n }\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId as any },\n { populate: ['role'] },\n { tenantId: null, organizationId: null },\n )\n const linkList = Array.isArray(links) ? links : []\n if (!linkList.length) {\n this.globalSuperAdminCache.set(userId, false)\n return false\n }\n const roleIds = Array.from(new Set(linkList.map((link) => {\n const role = link.role as any\n return role?.id ? String(role.id) : null\n }).filter((id): id is string => typeof id === 'string' && id.length > 0)))\n if (!roleIds.length) {\n this.globalSuperAdminCache.set(userId, false)\n return false\n }\n const roleSuper = await em.findOne(RoleAcl, { isSuperAdmin: true, role: { $in: roleIds as any } } as any)\n const result = !!(roleSuper && (roleSuper as any).isSuperAdmin)\n this.globalSuperAdminCache.set(userId, result)\n return result\n }\n\n /**\n * Loads the Access Control List (ACL) for a user within a given scope.\n * \n * The ACL resolution follows this priority:\n * 1. Per-user ACL (UserAcl) - if exists, use it exclusively\n * 2. Aggregated role ACLs (RoleAcl) - combine permissions from all user's roles\n * \n * Results are cached for performance (default 5 minutes TTL).\n * Cache is automatically invalidated when ACL-related data changes.\n * \n * @param userId - The ID of the user\n * @param scope - The tenant and organization context for ACL evaluation\n * @returns An object containing:\n * - isSuperAdmin: If true, user has unrestricted access to all features\n * - features: Array of feature strings (may include wildcards like 'entities.*')\n * - organizations: Array of organization IDs user can access, or null for all organizations\n * \n * @example\n * const acl = await rbacService.loadAcl('user-123', { tenantId: 'tenant-1', organizationId: 'org-1' })\n * // Returns: { isSuperAdmin: false, features: ['users.view', 'entities.*'], organizations: ['org-1', 'org-2'] }\n */\n async loadAcl(userId: string, scope: { tenantId: string | null; organizationId: string | null }): Promise<{\n isSuperAdmin: boolean\n features: string[]\n organizations: string[] | null\n }> {\n const cacheKey = this.getCacheKey(userId, scope)\n const cached = await this.getFromCache(cacheKey)\n if (cached) return cached\n\n if (!userId.startsWith('api_key:')) {\n if (await this.isGlobalSuperAdmin(userId)) {\n const result = { isSuperAdmin: true, features: ['*'], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n }\n\n if (userId.startsWith('api_key:')) {\n const apiKeyId = userId.slice('api_key:'.length)\n const em = this.em.fork()\n const key = await em.findOne(ApiKey, { id: apiKeyId, deletedAt: null })\n if (!key || (key.expiresAt && key.expiresAt.getTime() < Date.now())) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n const tenantId = scope.tenantId || key.tenantId || null\n const roleIds = Array.isArray(key.rolesJson) ? key.rolesJson.filter(Boolean) : []\n let isSuper = false\n const features: string[] = []\n let organizations: string[] | null = key.organizationId ? [key.organizationId] : null\n if (tenantId && roleIds.length) {\n const racls = await em.find(RoleAcl, { tenantId, role: { $in: roleIds as any } } as any)\n for (const acl of racls) {\n isSuper = isSuper || !!acl.isSuperAdmin\n if (Array.isArray(acl.featuresJson)) {\n for (const f of acl.featuresJson) if (!features.includes(f)) features.push(f)\n }\n if (organizations !== null) {\n if (acl.organizationsJson == null) {\n organizations = null\n } else if (Array.isArray(acl.organizationsJson) && acl.organizationsJson.includes('__all__')) {\n organizations = null\n } else {\n organizations = Array.from(new Set([...(organizations || []), ...acl.organizationsJson]))\n }\n }\n }\n }\n const result = { isSuperAdmin: isSuper, features, organizations }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Use a forked EntityManager to avoid inheriting an aborted transaction from callers\n const em = this.em.fork()\n const user = await em.findOne(User, { id: userId })\n if (!user) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n const tenantId = scope.tenantId || user.tenantId || null\n const orgId = scope.organizationId || user.organizationId || null\n\n if (!tenantId) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Per-user ACL first\n const uacl = await em.findOne(UserAcl, { user: userId as any, tenantId })\n if (uacl) {\n const result = {\n isSuperAdmin: !!uacl.isSuperAdmin,\n features: Array.isArray(uacl.featuresJson) ? (uacl.featuresJson as string[]) : [],\n organizations: Array.isArray(uacl.organizationsJson) ? (uacl.organizationsJson as string[]) : null,\n }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Aggregate role ACLs\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId as any, role: { tenantId } } as any,\n { populate: ['role'] },\n { tenantId, organizationId: orgId },\n )\n const linkList = Array.isArray(links) ? links : []\n const roleIds = linkList.map((l) => (l.role as any)?.id).filter(Boolean)\n let isSuper = false\n const features: string[] = []\n let organizations: string[] | null = []\n if (roleIds.length) {\n const racls = await em.find(RoleAcl, { tenantId, role: { $in: roleIds as any } } as any, {})\n const roleAcls = Array.isArray(racls) ? racls : []\n for (const r of roleAcls) {\n isSuper = isSuper || !!r.isSuperAdmin\n if (Array.isArray(r.featuresJson)) for (const f of r.featuresJson) if (!features.includes(f)) features.push(f)\n if (organizations !== null) {\n if (r.organizationsJson == null) organizations = null\n else if (Array.isArray(r.organizationsJson) && r.organizationsJson.includes('__all__')) organizations = null\n else organizations = Array.from(new Set([...(organizations || []), ...r.organizationsJson]))\n }\n }\n }\n if (organizations && orgId && !organizations.includes(orgId) && !organizations.includes('__all__')) {\n // Out-of-scope org; caller will enforce\n }\n const result = { isSuperAdmin: isSuper, features, organizations }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n /**\n * Checks whether any tenant role grants a feature.\n *\n * This supports non-user runtimes such as scheduler workers that execute with\n * tenant scope but without an authenticated user.\n */\n async tenantHasFeature(\n tenantId: string | null | undefined,\n feature: string,\n opts?: { organizationId?: string | null },\n ): Promise<boolean> {\n if (!tenantId || !feature) return false\n\n const em = this.em.fork()\n const roleAcls = await em.find(RoleAcl, { tenantId, deletedAt: null } as any, {})\n const list = Array.isArray(roleAcls) ? roleAcls : []\n const organizationId = opts?.organizationId ?? null\n\n for (const acl of list) {\n if (!this.roleAclAllowsOrganization(acl, organizationId)) continue\n const grants = Array.isArray(acl.featuresJson) ? acl.featuresJson : []\n if (authorizeFeatures([feature], {\n grantedFeatures: grants,\n unrestricted: acl.isSuperAdmin,\n })) {\n return true\n }\n }\n\n return false\n }\n\n /**\n * Checks if a user has all required features within a given scope.\n *\n * This is the primary authorization check method used throughout the application.\n * It combines feature checking with organization visibility validation.\n *\n * Authorization logic:\n * 1. No features required \u2192 always returns true\n * 2. User is super admin \u2192 always returns true\n * 3. Organization restriction check: If the user's ACL has a restricted organization list\n * and the requested organization is not in that list \u2192 returns false\n * 4. Feature matching: User must have all required features (supports wildcards)\n *\n * @param userId - The ID of the user\n * @param required - Array of feature strings to check (e.g., ['users.view', 'users.edit'])\n * @param scope - The tenant and organization context for authorization\n * @returns true if the user has all required features and organization access, false otherwise\n *\n * @example\n * // Check if user can view and edit users\n * const canManageUsers = await rbacService.userHasAllFeatures(\n * 'user-123',\n * ['users.view', 'users.edit'],\n * { tenantId: 'tenant-1', organizationId: 'org-1' }\n * )\n *\n * @example\n * // Check with wildcard features\n * const canAccessEntities = await rbacService.userHasAllFeatures(\n * 'user-123',\n * ['entities.records.view'],\n * { tenantId: 'tenant-1', organizationId: 'org-1' }\n * )\n * // Returns true if user has 'entities.*', '*', or 'entities.records.view'\n */\n async userHasAllFeatures(userId: string, required: string[], scope: { tenantId: string | null; organizationId: string | null }): Promise<boolean> {\n if (!required.length) return true\n const acl = await this.loadAcl(userId, scope)\n const organizationAllowed = acl.isSuperAdmin\n || !acl.organizations\n || !scope.organizationId\n || acl.organizations.includes(scope.organizationId)\n || acl.organizations.includes('__all__')\n return authorizeFeatures(required, {\n grantedFeatures: acl.features,\n unrestricted: acl.isSuperAdmin,\n scopeAllowed: organizationAllowed,\n })\n }\n\n /**\n * Returns the user's infrastructure grant list, filtered to enabled modules.\n * The result may contain wildcards; authoritative checks must still go through\n * `authorizeFeatures` or `userHasAllFeatures` so null overrides are enforced.\n */\n async getGrantedFeatures(\n userId: string,\n scope: { tenantId: string | null; organizationId: string | null },\n ): Promise<string[]> {\n const acl = await this.loadAcl(userId, scope)\n if (acl.isSuperAdmin) return filterGrantsByEnabledModules(['*'])\n if (\n acl.organizations &&\n scope.organizationId &&\n !acl.organizations.includes(scope.organizationId) &&\n !acl.organizations.includes('__all__')\n ) {\n return []\n }\n return filterGrantsByEnabledModules(acl.features)\n }\n\n /** Returns concrete active feature IDs for browser capability payloads. */\n async getEffectiveFeatures(\n userId: string,\n scope: { tenantId: string | null; organizationId: string | null },\n ): Promise<string[]> {\n const acl = await this.loadAcl(userId, scope)\n const organizationAllowed = acl.isSuperAdmin\n || !acl.organizations\n || !scope.organizationId\n || acl.organizations.includes(scope.organizationId)\n || acl.organizations.includes('__all__')\n if (!organizationAllowed) return []\n return resolveEffectiveFeatures(acl.isSuperAdmin ? ['*'] : acl.features)\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["result", "em", "tenantId", "roleIds", "isSuper", "features", "organizations"]
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport { getCurrentCacheTenant, runWithCacheTenant } from '@open-mercato/cache'\nimport { UserAcl, RoleAcl, User, UserRole } from '@open-mercato/core/modules/auth/data/entities'\nimport { ApiKey } from '@open-mercato/core/modules/api_keys/data/entities'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport type { OrganizationHierarchyService } from '@open-mercato/shared/lib/auth/principal-service'\nimport { buildOrgScopeUserCacheTag, buildOrgScopeTenantCacheTag } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport {\n authorizeFeatures,\n resolveEffectiveFeatures,\n} from '@open-mercato/shared/security/featurePolicy'\nimport { filterGrantsByEnabledModules } from '@open-mercato/shared/security/enabledModulesRegistry'\nimport { resolveRoleOrganizationScope, roleAclAllowsOrganization } from './roleOrganizationScope'\n\ninterface AclData {\n isSuperAdmin: boolean\n features: string[]\n organizations: string[] | null\n}\n\nfunction isAclData(value: unknown): value is AclData {\n if (typeof value !== 'object' || value === null) return false\n const record = value as Partial<AclData>\n if (typeof record.isSuperAdmin !== 'boolean') return false\n if (!Array.isArray(record.features) || record.features.some((feature) => typeof feature !== 'string')) return false\n if (record.organizations !== null && record.organizations !== undefined) {\n if (!Array.isArray(record.organizations)) return false\n if (record.organizations.some((org) => typeof org !== 'string')) return false\n }\n return true\n}\n\nfunction isRestrictedRoleAcl(acl: Pick<RoleAcl, 'organizationsJson'>): boolean {\n return Array.isArray(acl.organizationsJson)\n && acl.organizationsJson.length > 0\n && !acl.organizationsJson.includes('__all__')\n}\n\nexport class RbacService {\n private cacheTtlMs: number = 5 * 60 * 1000 // 5 minutes default\n private cache: CacheStrategy | null = null\n private globalSuperAdminCache = new Map<string, boolean>()\n\n constructor(\n private em: EntityManager,\n cache?: CacheStrategy,\n private readonly organizationHierarchyService?: OrganizationHierarchyService,\n ) {\n this.cache = cache || null\n }\n\n /**\n * Set cache TTL in milliseconds\n * @param ttlMs - Time to live in milliseconds\n */\n setCacheTtl(ttlMs: number) {\n this.cacheTtlMs = ttlMs\n }\n\n /** Compatibility wrapper for callers that already have both feature lists. */\n public hasAllFeatures(required: string[], granted: string[]): boolean {\n return authorizeFeatures(required, { grantedFeatures: granted })\n }\n\n private getCacheKey(userId: string, scope: { tenantId: string | null; organizationId: string | null }): string {\n return `rbac:${userId}:${scope.tenantId || 'null'}:${scope.organizationId || 'null'}`\n }\n\n private getUserTag(userId: string): string {\n return `rbac:user:${userId}`\n }\n\n private getTenantTag(tenantId: string): string {\n return `rbac:tenant:${tenantId}`\n }\n\n private getOrganizationTag(organizationId: string): string {\n return `rbac:org:${organizationId}`\n }\n\n private async getFromCache(cacheKey: string): Promise<AclData | null> {\n if (!this.cache) return null\n const cached = await this.cache.get(cacheKey)\n if (!cached) return null\n return isAclData(cached) ? cached : null\n }\n\n private async setCache(cacheKey: string, data: AclData, userId: string, scope: { tenantId: string | null; organizationId: string | null }): Promise<void> {\n if (!this.cache) return\n\n const tags = [\n this.getUserTag(userId),\n 'rbac:all'\n ]\n\n if (scope.tenantId) {\n tags.push(this.getTenantTag(scope.tenantId))\n // Scoped role projections depend on the selected organization's ancestor\n // chain, so Directory hierarchy changes must evict them as well as the\n // separately cached OrganizationScope entries.\n tags.push(buildOrgScopeTenantCacheTag(scope.tenantId))\n }\n\n if (scope.organizationId) {\n tags.push(this.getOrganizationTag(scope.organizationId))\n }\n\n await this.cache.set(cacheKey, data, {\n ttl: this.cacheTtlMs,\n tags\n })\n }\n\n /**\n * Invalidates cached ACL data for a specific user across all tenants and organizations.\n * Call this when a user's roles or user-specific ACL is modified.\n * \n * @param userId - The ID of the user whose cache should be invalidated\n */\n async invalidateUserCache(userId: string): Promise<void> {\n this.globalSuperAdminCache.delete(userId)\n // Also drop the directory OrganizationScope cache for this user. That scope's\n // accessible-org set is derived from this user's ACL/role grants, so any\n // permission change that invalidates the RBAC cache must invalidate the\n // resolved scope too. This is the missing `org-scope:user:*` caller required\n // before the cross-request scope TTL can be safely enabled (issue #2259).\n await this.deleteCacheByTags([this.getUserTag(userId), buildOrgScopeUserCacheTag(userId)])\n }\n\n /**\n * Invalidates cached ACL data for all users within a specific tenant.\n * Call this when a role's ACL is modified, since roles are tenant-scoped\n * and affect all users in that tenant who have that role.\n * \n * @param tenantId - The ID of the tenant whose cache should be invalidated\n */\n async invalidateTenantCache(tenantId: string): Promise<void> {\n this.globalSuperAdminCache.clear()\n // Role ACL changes invalidate every user in the tenant; the resolved\n // OrganizationScope for those users derives from the same grants, so drop\n // the tenant-tagged scope entries alongside the RBAC ones (issue #2259).\n await this.deleteCacheByTags([this.getTenantTag(tenantId), buildOrgScopeTenantCacheTag(tenantId)], [tenantId])\n }\n\n /**\n * Invalidates cached ACL data for all users within a specific organization.\n * Call this when organization-level permissions or visibility changes.\n * \n * @param organizationId - The ID of the organization whose cache should be invalidated\n */\n async invalidateOrganizationCache(organizationId: string): Promise<void> {\n await this.deleteCacheByTags([this.getOrganizationTag(organizationId)])\n }\n\n /**\n * Clears all cached ACL data.\n * Use this for bulk operations or system-wide ACL changes.\n */\n async invalidateAllCache(): Promise<void> {\n this.globalSuperAdminCache.clear()\n await this.deleteCacheByTags(['rbac:all'])\n }\n\n private async deleteCacheByTags(tags: string[], tenantHints?: Array<string | null>): Promise<void> {\n if (!this.cache) return\n const contexts = new Set<string | null>()\n const current = getCurrentCacheTenant()\n contexts.add(current ?? null)\n contexts.add(null)\n if (Array.isArray(tenantHints)) {\n for (const hint of tenantHints) {\n contexts.add(hint ?? null)\n }\n }\n for (const ctx of contexts) {\n if (ctx === current) {\n await this.cache.deleteByTags(tags)\n } else {\n await runWithCacheTenant(ctx, async () => {\n await this.cache!.deleteByTags(tags)\n })\n }\n }\n }\n\n private async isGlobalSuperAdmin(userId: string): Promise<boolean> {\n if (this.globalSuperAdminCache.has(userId)) return this.globalSuperAdminCache.get(userId)!\n const em = this.em.fork()\n const userSuper = await em.findOne(UserAcl, { user: userId as any, isSuperAdmin: true })\n if (userSuper && (userSuper as any).isSuperAdmin) {\n this.globalSuperAdminCache.set(userId, true)\n return true\n }\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId as any },\n { populate: ['role'] },\n { tenantId: null, organizationId: null },\n )\n const linkList = Array.isArray(links) ? links : []\n if (!linkList.length) {\n this.globalSuperAdminCache.set(userId, false)\n return false\n }\n const roleIds = Array.from(new Set(linkList.map((link) => {\n const role = link.role as any\n return role?.id ? String(role.id) : null\n }).filter((id): id is string => typeof id === 'string' && id.length > 0)))\n if (!roleIds.length) {\n this.globalSuperAdminCache.set(userId, false)\n return false\n }\n const roleSupers = await em.find(RoleAcl, { isSuperAdmin: true, role: { $in: roleIds as any } } as any)\n const result = roleSupers.some((roleAcl) => (\n !!roleAcl.isSuperAdmin && !isRestrictedRoleAcl(roleAcl)\n ))\n this.globalSuperAdminCache.set(userId, result)\n return result\n }\n\n /**\n * Loads the Access Control List (ACL) for a user within a given scope.\n * \n * The ACL resolution follows this priority:\n * 1. Per-user ACL (UserAcl) - if exists, use it exclusively\n * 2. Aggregated role ACLs (RoleAcl) - combine permissions from all user's roles\n * \n * Results are cached for performance (default 5 minutes TTL).\n * Cache is automatically invalidated when ACL-related data changes.\n * \n * @param userId - The ID of the user\n * @param scope - The tenant and organization context for ACL evaluation\n * @returns An object containing:\n * - isSuperAdmin: If true, user has unrestricted access to all features\n * - features: Array of feature strings (may include wildcards like 'entities.*')\n * - organizations: Array of organization IDs user can access, or null for all organizations\n * \n * @example\n * const acl = await rbacService.loadAcl('user-123', { tenantId: 'tenant-1', organizationId: 'org-1' })\n * // Returns: { isSuperAdmin: false, features: ['users.view', 'entities.*'], organizations: ['org-1', 'org-2'] }\n */\n async loadAcl(userId: string, scope: { tenantId: string | null; organizationId: string | null }): Promise<{\n isSuperAdmin: boolean\n features: string[]\n organizations: string[] | null\n }> {\n const cacheKey = this.getCacheKey(userId, scope)\n const cached = await this.getFromCache(cacheKey)\n if (cached) return cached\n\n // Direct user-level super-admin grants and unrestricted role-level\n // super-admin grants are global. Organization-restricted role grants are\n // deliberately excluded by isGlobalSuperAdmin and continue through the\n // scoped ACL projection below.\n if (!userId.startsWith('api_key:')) {\n if (await this.isGlobalSuperAdmin(userId)) {\n const result = { isSuperAdmin: true, features: ['*'], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n }\n\n if (userId.startsWith('api_key:')) {\n const apiKeyId = userId.slice('api_key:'.length)\n const em = this.em.fork()\n const key = await em.findOne(ApiKey, { id: apiKeyId, deletedAt: null })\n if (!key || (key.expiresAt && key.expiresAt.getTime() < Date.now())) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n const tenantId = scope.tenantId || key.tenantId || null\n const roleIds = Array.isArray(key.rolesJson) ? key.rolesJson.filter(Boolean) : []\n const keyOrganizationId = typeof key.organizationId === 'string' && key.organizationId.trim().length > 0\n ? key.organizationId.trim()\n : null\n const evaluatedOrganizationId = scope.organizationId || keyOrganizationId\n let isSuper = false\n const features: string[] = []\n let roleOrganizations: string[] | null = []\n let hasApplicableRestrictedRole = false\n if (tenantId && roleIds.length) {\n const roleOrganizationScope = await resolveRoleOrganizationScope(\n this.organizationHierarchyService,\n tenantId,\n evaluatedOrganizationId,\n )\n const racls = await em.find(RoleAcl, { tenantId, role: { $in: roleIds as any } } as any)\n for (const acl of racls) {\n if (roleAclAllowsOrganization(acl, roleOrganizationScope)) {\n isSuper = isSuper || !!acl.isSuperAdmin\n if (Array.isArray(acl.featuresJson)) {\n for (const f of acl.featuresJson) if (!features.includes(f)) features.push(f)\n }\n if (isRestrictedRoleAcl(acl)) hasApplicableRestrictedRole = true\n }\n if (roleOrganizations !== null) {\n if (acl.organizationsJson == null || (Array.isArray(acl.organizationsJson) && acl.organizationsJson.length === 0)) {\n roleOrganizations = null\n } else if (Array.isArray(acl.organizationsJson) && acl.organizationsJson.includes('__all__')) {\n roleOrganizations = null\n } else {\n roleOrganizations = Array.from(new Set([\n ...roleOrganizations,\n ...(Array.isArray(acl.organizationsJson) ? acl.organizationsJson : []),\n ]))\n }\n }\n }\n if (\n roleOrganizations !== null\n && evaluatedOrganizationId\n && roleOrganizationScope !== null\n && roleOrganizationScope.size > 0\n && hasApplicableRestrictedRole\n && !roleOrganizations.includes(evaluatedOrganizationId)\n ) {\n roleOrganizations.push(evaluatedOrganizationId)\n }\n }\n let organizations = roleOrganizations\n if (keyOrganizationId) {\n const keyOrganizationScope = await resolveRoleOrganizationScope(\n this.organizationHierarchyService,\n tenantId,\n keyOrganizationId,\n )\n organizations = roleOrganizations === null\n || roleOrganizations.some((organizationId) => keyOrganizationScope?.has(organizationId))\n ? [keyOrganizationId]\n : []\n }\n // A role-level super-admin grant still respects the API key's effective\n // organization allowlist. Represent it as a wildcard feature whenever\n // the key is restricted so downstream super-admin shortcuts cannot\n // bypass the key or role organization bounds.\n if (isSuper && organizations !== null && !features.includes('*')) features.push('*')\n const result = { isSuperAdmin: isSuper && organizations === null, features, organizations }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Use a forked EntityManager to avoid inheriting an aborted transaction from callers\n const em = this.em.fork()\n const user = await em.findOne(User, { id: userId })\n if (!user) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n const tenantId = scope.tenantId || user.tenantId || null\n const orgId = scope.organizationId || user.organizationId || null\n\n if (!tenantId) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Per-user ACL first\n const uacl = await em.findOne(UserAcl, { user: userId as any, tenantId })\n if (uacl) {\n const result = {\n isSuperAdmin: !!uacl.isSuperAdmin,\n features: Array.isArray(uacl.featuresJson) ? (uacl.featuresJson as string[]) : [],\n organizations: Array.isArray(uacl.organizationsJson) ? (uacl.organizationsJson as string[]) : null,\n }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Aggregate role ACLs\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId as any, role: { tenantId } } as any,\n { populate: ['role'] },\n { tenantId, organizationId: orgId },\n )\n const linkList = Array.isArray(links) ? links : []\n const roleIds = linkList.map((l) => (l.role as any)?.id).filter(Boolean)\n let isSuper = false\n const features: string[] = []\n let organizations: string[] | null = []\n let hasApplicableRestrictedRole = false\n if (roleIds.length) {\n const roleOrganizationScope = await resolveRoleOrganizationScope(\n this.organizationHierarchyService,\n tenantId,\n scope.organizationId,\n )\n const racls = await em.find(RoleAcl, { tenantId, role: { $in: roleIds as any } } as any, {})\n const roleAcls = Array.isArray(racls) ? racls : []\n for (const r of roleAcls) {\n if (roleAclAllowsOrganization(r, roleOrganizationScope)) {\n isSuper = isSuper || !!r.isSuperAdmin\n if (Array.isArray(r.featuresJson)) for (const f of r.featuresJson) if (!features.includes(f)) features.push(f)\n if (isRestrictedRoleAcl(r)) hasApplicableRestrictedRole = true\n }\n if (organizations !== null) {\n // For a user principal an empty allowlist is a deny-all scope (#4033), not\n // \"unrestricted\": it must merge to an empty set so scoped reads and deletes\n // fail closed. Only an absent allowlist or an explicit '__all__' widens to\n // every organization. (The API-key branch above deliberately differs \u2014 an\n // empty role list there means the key inherits the key's own scope.)\n if (r.organizationsJson == null) organizations = null\n else if (Array.isArray(r.organizationsJson) && r.organizationsJson.includes('__all__')) organizations = null\n else organizations = Array.from(new Set([...(organizations || []), ...r.organizationsJson]))\n }\n }\n if (\n organizations !== null\n && scope.organizationId\n && roleOrganizationScope !== null\n && roleOrganizationScope.size > 0\n && hasApplicableRestrictedRole\n && !organizations.includes(scope.organizationId)\n ) {\n organizations.push(scope.organizationId)\n }\n }\n if (organizations && orgId && !organizations.includes(orgId) && !organizations.includes('__all__')) {\n // Out-of-scope org; caller will enforce\n }\n const result = { isSuperAdmin: isSuper, features, organizations }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n /**\n * Checks whether any tenant role grants a feature.\n *\n * This supports non-user runtimes such as scheduler workers that execute with\n * tenant scope but without an authenticated user.\n */\n async tenantHasFeature(\n tenantId: string | null | undefined,\n feature: string,\n opts?: { organizationId?: string | null },\n ): Promise<boolean> {\n if (!tenantId || !feature) return false\n\n const em = this.em.fork()\n const roleOrganizationScope = await resolveRoleOrganizationScope(\n this.organizationHierarchyService,\n tenantId,\n opts?.organizationId,\n )\n const roleAcls = await em.find(RoleAcl, { tenantId, deletedAt: null } as any, {})\n const list = Array.isArray(roleAcls) ? roleAcls : []\n\n for (const acl of list) {\n if (!roleAclAllowsOrganization(acl, roleOrganizationScope)) continue\n const grants = Array.isArray(acl.featuresJson) ? acl.featuresJson : []\n if (authorizeFeatures([feature], {\n grantedFeatures: grants,\n unrestricted: acl.isSuperAdmin,\n })) {\n return true\n }\n }\n\n return false\n }\n\n /**\n * Checks if a user has all required features within a given scope.\n *\n * This is the primary authorization check method used throughout the application.\n * It combines feature checking with organization visibility validation.\n *\n * Authorization logic:\n * 1. No features required \u2192 always returns true\n * 2. User is super admin \u2192 always returns true\n * 3. Organization restriction check: If the user's ACL has a restricted organization list\n * and the requested organization is not in that list \u2192 returns false\n * 4. Feature matching: User must have all required features (supports wildcards)\n *\n * @param userId - The ID of the user\n * @param required - Array of feature strings to check (e.g., ['users.view', 'users.edit'])\n * @param scope - The tenant and organization context for authorization\n * @returns true if the user has all required features and organization access, false otherwise\n *\n * @example\n * // Check if user can view and edit users\n * const canManageUsers = await rbacService.userHasAllFeatures(\n * 'user-123',\n * ['users.view', 'users.edit'],\n * { tenantId: 'tenant-1', organizationId: 'org-1' }\n * )\n *\n * @example\n * // Check with wildcard features\n * const canAccessEntities = await rbacService.userHasAllFeatures(\n * 'user-123',\n * ['entities.records.view'],\n * { tenantId: 'tenant-1', organizationId: 'org-1' }\n * )\n * // Returns true if user has 'entities.*', '*', or 'entities.records.view'\n */\n async userHasAllFeatures(userId: string, required: string[], scope: { tenantId: string | null; organizationId: string | null }): Promise<boolean> {\n if (!required.length) return true\n const acl = await this.loadAcl(userId, scope)\n const organizationAllowed = acl.isSuperAdmin\n || !acl.organizations\n || !scope.organizationId\n || acl.organizations.includes(scope.organizationId)\n || acl.organizations.includes('__all__')\n return authorizeFeatures(required, {\n grantedFeatures: acl.features,\n unrestricted: acl.isSuperAdmin,\n scopeAllowed: organizationAllowed,\n })\n }\n\n /**\n * Returns the user's infrastructure grant list, filtered to enabled modules.\n * The result may contain wildcards; authoritative checks must still go through\n * `authorizeFeatures` or `userHasAllFeatures` so null overrides are enforced.\n */\n async getGrantedFeatures(\n userId: string,\n scope: { tenantId: string | null; organizationId: string | null },\n ): Promise<string[]> {\n const acl = await this.loadAcl(userId, scope)\n if (acl.isSuperAdmin) return filterGrantsByEnabledModules(['*'])\n if (\n acl.organizations &&\n scope.organizationId &&\n !acl.organizations.includes(scope.organizationId) &&\n !acl.organizations.includes('__all__')\n ) {\n return []\n }\n return filterGrantsByEnabledModules(acl.features)\n }\n\n /** Returns concrete active feature IDs for browser capability payloads. */\n async getEffectiveFeatures(\n userId: string,\n scope: { tenantId: string | null; organizationId: string | null },\n ): Promise<string[]> {\n const acl = await this.loadAcl(userId, scope)\n const organizationAllowed = acl.isSuperAdmin\n || !acl.organizations\n || !scope.organizationId\n || acl.organizations.includes(scope.organizationId)\n || acl.organizations.includes('__all__')\n if (!organizationAllowed) return []\n return resolveEffectiveFeatures(acl.isSuperAdmin ? ['*'] : acl.features)\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["result", "em", "tenantId", "roleIds", "isSuper", "features", "hasApplicableRestrictedRole", "organizations"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
function normalizeId(value) {
|
|
2
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
3
|
+
}
|
|
4
|
+
async function resolveRoleOrganizationScope(hierarchyService, tenantId, organizationId) {
|
|
5
|
+
const selectedId = normalizeId(organizationId);
|
|
6
|
+
if (!selectedId) return null;
|
|
7
|
+
const normalizedTenantId = normalizeId(tenantId);
|
|
8
|
+
if (!normalizedTenantId) return /* @__PURE__ */ new Set();
|
|
9
|
+
const ids = /* @__PURE__ */ new Set([selectedId]);
|
|
10
|
+
if (!hierarchyService) return ids;
|
|
11
|
+
const ancestorIds = await hierarchyService.resolveAncestorIds({
|
|
12
|
+
tenantId: normalizedTenantId,
|
|
13
|
+
organizationId: selectedId
|
|
14
|
+
});
|
|
15
|
+
if (ancestorIds === null) return /* @__PURE__ */ new Set();
|
|
16
|
+
for (const ancestorId of ancestorIds) {
|
|
17
|
+
const normalized = normalizeId(ancestorId);
|
|
18
|
+
if (normalized) ids.add(normalized);
|
|
19
|
+
}
|
|
20
|
+
return ids;
|
|
21
|
+
}
|
|
22
|
+
function roleAclAllowsOrganization(acl, scope) {
|
|
23
|
+
if (!scope) return true;
|
|
24
|
+
const organizations = Array.isArray(acl.organizationsJson) ? acl.organizationsJson : null;
|
|
25
|
+
if (!organizations || organizations.length === 0 || organizations.includes("__all__")) return true;
|
|
26
|
+
return organizations.some((organizationId) => scope.has(organizationId));
|
|
27
|
+
}
|
|
28
|
+
function roleAclGrantsPrincipalOrganization(acl, scope) {
|
|
29
|
+
if (!scope) return true;
|
|
30
|
+
const organizations = Array.isArray(acl.organizationsJson) ? acl.organizationsJson : null;
|
|
31
|
+
if (!organizations) return true;
|
|
32
|
+
if (organizations.length === 0) return false;
|
|
33
|
+
if (organizations.includes("__all__")) return true;
|
|
34
|
+
return organizations.some((organizationId) => scope.has(organizationId));
|
|
35
|
+
}
|
|
36
|
+
export {
|
|
37
|
+
resolveRoleOrganizationScope,
|
|
38
|
+
roleAclAllowsOrganization,
|
|
39
|
+
roleAclGrantsPrincipalOrganization
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=roleOrganizationScope.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/auth/services/roleOrganizationScope.ts"],
|
|
4
|
+
"sourcesContent": ["import type { OrganizationHierarchyService } from '@open-mercato/shared/lib/auth/principal-service'\nimport type { RoleAcl } from '../data/entities'\n\nexport type RoleOrganizationScope = ReadonlySet<string> | null\n\nfunction normalizeId(value: unknown): string | null {\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null\n}\n\nexport async function resolveRoleOrganizationScope(\n hierarchyService: OrganizationHierarchyService | null | undefined,\n tenantId: string | null | undefined,\n organizationId: string | null | undefined,\n): Promise<RoleOrganizationScope> {\n const selectedId = normalizeId(organizationId)\n if (!selectedId) return null\n const normalizedTenantId = normalizeId(tenantId)\n if (!normalizedTenantId) return new Set()\n\n const ids = new Set<string>([selectedId])\n // Auth remains independently usable when Directory is disabled: exact-org\n // grants still apply, while parent-to-descendant expansion fails closed.\n if (!hierarchyService) return ids\n\n const ancestorIds = await hierarchyService.resolveAncestorIds({\n tenantId: normalizedTenantId,\n organizationId: selectedId,\n })\n // A registered Directory seam can prove an invalid/wrong-tenant selection.\n // Fail closed for restricted roles in that case.\n if (ancestorIds === null) return new Set()\n for (const ancestorId of ancestorIds) {\n const normalized = normalizeId(ancestorId)\n if (normalized) ids.add(normalized)\n }\n return ids\n}\n\nexport function roleAclAllowsOrganization(\n acl: Pick<RoleAcl, 'organizationsJson'>,\n scope: RoleOrganizationScope,\n): boolean {\n if (!scope) return true\n const organizations = Array.isArray(acl.organizationsJson) ? acl.organizationsJson : null\n if (!organizations || organizations.length === 0 || organizations.includes('__all__')) return true\n return organizations.some((organizationId) => scope.has(organizationId))\n}\n\n/**\n * Principal eligibility \u2014 which roles may be selected as, or resolved into, an explicit share\n * target \u2014 follows the human-principal deny-all contract instead: an empty allowlist grants no\n * organization reach, so such a role must not become a share principal here (#4033).\n *\n * This deliberately differs from `roleAclAllowsOrganization` above, which governs *feature*\n * evaluation and keeps the wider \"an empty list applies everywhere\" meaning, and from the\n * API-key projection, where an empty list means \"inherit the key's own organization binding\".\n * Without this split a user who reaches an organization through a second role could inherit\n * viewer/editor access from a share assigned to a deny-all role.\n */\nexport function roleAclGrantsPrincipalOrganization(\n acl: Pick<RoleAcl, 'organizationsJson'>,\n scope: RoleOrganizationScope,\n): boolean {\n if (!scope) return true\n const organizations = Array.isArray(acl.organizationsJson) ? acl.organizationsJson : null\n if (!organizations) return true\n if (organizations.length === 0) return false\n if (organizations.includes('__all__')) return true\n return organizations.some((organizationId) => scope.has(organizationId))\n}\n"],
|
|
5
|
+
"mappings": "AAKA,SAAS,YAAY,OAA+B;AAClD,SAAO,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,IAAI,MAAM,KAAK,IAAI;AAC/E;AAEA,eAAsB,6BACpB,kBACA,UACA,gBACgC;AAChC,QAAM,aAAa,YAAY,cAAc;AAC7C,MAAI,CAAC,WAAY,QAAO;AACxB,QAAM,qBAAqB,YAAY,QAAQ;AAC/C,MAAI,CAAC,mBAAoB,QAAO,oBAAI,IAAI;AAExC,QAAM,MAAM,oBAAI,IAAY,CAAC,UAAU,CAAC;AAGxC,MAAI,CAAC,iBAAkB,QAAO;AAE9B,QAAM,cAAc,MAAM,iBAAiB,mBAAmB;AAAA,IAC5D,UAAU;AAAA,IACV,gBAAgB;AAAA,EAClB,CAAC;AAGD,MAAI,gBAAgB,KAAM,QAAO,oBAAI,IAAI;AACzC,aAAW,cAAc,aAAa;AACpC,UAAM,aAAa,YAAY,UAAU;AACzC,QAAI,WAAY,KAAI,IAAI,UAAU;AAAA,EACpC;AACA,SAAO;AACT;AAEO,SAAS,0BACd,KACA,OACS;AACT,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,gBAAgB,MAAM,QAAQ,IAAI,iBAAiB,IAAI,IAAI,oBAAoB;AACrF,MAAI,CAAC,iBAAiB,cAAc,WAAW,KAAK,cAAc,SAAS,SAAS,EAAG,QAAO;AAC9F,SAAO,cAAc,KAAK,CAAC,mBAAmB,MAAM,IAAI,cAAc,CAAC;AACzE;AAaO,SAAS,mCACd,KACA,OACS;AACT,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,gBAAgB,MAAM,QAAQ,IAAI,iBAAiB,IAAI,IAAI,oBAAoB;AACrF,MAAI,CAAC,cAAe,QAAO;AAC3B,MAAI,cAAc,WAAW,EAAG,QAAO;AACvC,MAAI,cAAc,SAAS,SAAS,EAAG,QAAO;AAC9C,SAAO,cAAc,KAAK,CAAC,mBAAmB,MAAM,IAAI,cAAc,CAAC;AACzE;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -12,6 +12,7 @@ function ExecutionLogsPage() {
|
|
|
12
12
|
const [pageSize] = React.useState(50);
|
|
13
13
|
const [total, setTotal] = React.useState(0);
|
|
14
14
|
const [totalPages, setTotalPages] = React.useState(1);
|
|
15
|
+
const [totalIsCapped, setTotalIsCapped] = React.useState(false);
|
|
15
16
|
const t = useT();
|
|
16
17
|
const [filterValues, setFilterValues] = React.useState({});
|
|
17
18
|
const { data, isLoading, error } = useQuery({
|
|
@@ -38,6 +39,7 @@ function ExecutionLogsPage() {
|
|
|
38
39
|
if (response) {
|
|
39
40
|
setTotal(response.total || 0);
|
|
40
41
|
setTotalPages(response.totalPages || 1);
|
|
42
|
+
setTotalIsCapped(response?.totalIsCapped === true);
|
|
41
43
|
}
|
|
42
44
|
return response?.items || [];
|
|
43
45
|
}
|
|
@@ -179,7 +181,7 @@ function ExecutionLogsPage() {
|
|
|
179
181
|
onFiltersClear: handleFiltersClear,
|
|
180
182
|
isLoading,
|
|
181
183
|
error: error ? t("business_rules.logs.messages.loadFailed") : void 0,
|
|
182
|
-
pagination: { page, pageSize, total, totalPages, onPageChange: setPage }
|
|
184
|
+
pagination: { page, pageSize, total, totalPages, totalIsCapped, onPageChange: setPage }
|
|
183
185
|
}
|
|
184
186
|
) }) });
|
|
185
187
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/business_rules/backend/logs/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useQuery } from '@tanstack/react-query'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\n\ntype RuleExecutionLog = {\n id: string\n ruleId: string\n rule?: {\n id: string\n ruleId: string\n ruleName: string\n ruleType: string\n } | null\n entityType: string\n entityId: string | null\n eventType: string | null\n executedAt: string\n executionTimeMs: number\n executionResult: 'SUCCESS' | 'FAILURE' | 'ERROR'\n resultValue: any | null\n errorMessage: string | null\n inputContext: any | null\n outputContext: any | null\n executedBy: string | null\n tenantId: string | null\n organizationId: string | null\n}\n\ntype LogsResponse = {\n items: RuleExecutionLog[]\n total: number\n totalPages: number\n}\n\nexport default function ExecutionLogsPage() {\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(50)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const t = useT()\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n\n const { data, isLoading, error } = useQuery({\n queryKey: ['business-rules', 'logs', filterValues, page],\n queryFn: async () => {\n const params = new URLSearchParams()\n params.set('page', page.toString())\n params.set('pageSize', pageSize.toString())\n params.set('sortField', 'executedAt')\n params.set('sortDir', 'desc')\n\n if (filterValues.ruleId) params.set('ruleId', filterValues.ruleId as string)\n if (filterValues.entityType) params.set('entityType', filterValues.entityType as string)\n if (filterValues.executionResult) params.set('executionResult', filterValues.executionResult as string)\n if (filterValues.executedBy) params.set('executedBy', filterValues.executedBy as string)\n if (filterValues.executedAtFrom) params.set('executedAtFrom', filterValues.executedAtFrom as string)\n if (filterValues.executedAtTo) params.set('executedAtTo', filterValues.executedAtTo as string)\n\n const result = await apiCall<LogsResponse>(\n `/api/business_rules/logs?${params.toString()}`\n )\n\n if (!result.ok) {\n throw new Error('Failed to fetch execution logs')\n }\n\n const response = result.result\n if (response) {\n setTotal(response.total || 0)\n setTotalPages(response.totalPages || 1)\n }\n\n return response?.items || []\n },\n })\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n const next: FilterValues = {}\n Object.entries(values).forEach(([key, value]) => {\n if (value !== undefined) next[key] = value\n })\n setFilterValues(next)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n }, [])\n\n const filters: FilterDef[] = [\n {\n id: 'entityType',\n type: 'text',\n label: t('business_rules.logs.filters.entityType'),\n placeholder: t('business_rules.logs.filters.entityTypePlaceholder'),\n },\n {\n id: 'executionResult',\n type: 'select',\n label: t('business_rules.logs.filters.result'),\n options: [\n { value: '', label: t('common.all') },\n { value: 'SUCCESS', label: t('business_rules.logs.result.success') },\n { value: 'FAILURE', label: t('business_rules.logs.result.failure') },\n { value: 'ERROR', label: t('business_rules.logs.result.error') },\n ],\n },\n {\n id: 'executedBy',\n type: 'text',\n label: t('business_rules.logs.filters.executedBy'),\n placeholder: t('business_rules.logs.filters.executedByPlaceholder'),\n },\n {\n id: 'executedAtFrom',\n type: 'dateRange',\n label: t('business_rules.logs.filters.dateFrom'),\n },\n {\n id: 'executedAtTo',\n type: 'dateRange',\n label: t('business_rules.logs.filters.dateTo'),\n },\n ]\n\n const getResultBadgeClass = (result: string) => {\n switch (result) {\n case 'SUCCESS':\n return 'bg-green-100 text-green-800'\n case 'FAILURE':\n return 'bg-yellow-100 text-yellow-800'\n case 'ERROR':\n return 'bg-red-100 text-red-800'\n default:\n return 'bg-muted text-foreground'\n }\n }\n\n const columns: ColumnDef<RuleExecutionLog>[] = [\n {\n id: 'executedAt',\n header: t('business_rules.logs.fields.executedAt'),\n accessorKey: 'executedAt',\n cell: ({ row }) => (\n <div className=\"text-sm\">\n {new Date(row.original.executedAt).toLocaleString()}\n </div>\n ),\n },\n {\n id: 'rule',\n header: t('business_rules.logs.fields.rule'),\n cell: ({ row }) => (\n <div>\n {row.original.rule ? (\n <Link\n href={`/backend/rules/${row.original.rule.id}`}\n className=\"text-blue-600 hover:text-blue-800 hover:underline font-medium\"\n >\n {row.original.rule.ruleName}\n </Link>\n ) : (\n <span className=\"text-muted-foreground text-sm\">\n {t('business_rules.logs.ruleDeleted')}\n </span>\n )}\n {row.original.rule && (\n <div className=\"text-xs text-muted-foreground mt-0.5\">\n {row.original.rule.ruleType}\n </div>\n )}\n </div>\n ),\n },\n {\n id: 'entity',\n header: t('business_rules.logs.fields.entity'),\n cell: ({ row }) => (\n <div className=\"text-sm\">\n <div className=\"font-medium\">{row.original.entityType}</div>\n {row.original.entityId && (\n <div className=\"text-xs text-muted-foreground truncate max-w-[200px]\" title={row.original.entityId}>\n {row.original.entityId}\n </div>\n )}\n </div>\n ),\n },\n {\n id: 'result',\n header: t('business_rules.logs.fields.result'),\n accessorKey: 'executionResult',\n cell: ({ row }) => (\n <span\n className={`inline-flex items-center px-2 py-1 rounded text-xs font-medium ${getResultBadgeClass(\n row.original.executionResult\n )}`}\n >\n {t(`business_rules.logs.result.${row.original.executionResult.toLowerCase()}`)}\n </span>\n ),\n },\n {\n id: 'executionTime',\n header: t('business_rules.logs.fields.executionTime'),\n accessorKey: 'executionTimeMs',\n cell: ({ row }) => (\n <div className=\"text-sm text-muted-foreground\">\n {row.original.executionTimeMs}ms\n </div>\n ),\n },\n {\n id: 'actions',\n header: '',\n cell: ({ row }) => (\n <Link\n href={`/backend/logs/${row.original.id}`}\n className=\"text-sm text-blue-600 hover:text-blue-800 hover:underline\"\n >\n {t('common.details')}\n </Link>\n ),\n },\n ]\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('business_rules.logs.list.title')}\n columns={columns}\n data={data || []}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n isLoading={isLoading}\n error={error ? t('business_rules.logs.messages.loadFailed') : undefined}\n pagination={{ page, pageSize, total, totalPages, onPageChange: setPage }}\n />\n </PageBody>\n </Page>\n )\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useQuery } from '@tanstack/react-query'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\n\ntype RuleExecutionLog = {\n id: string\n ruleId: string\n rule?: {\n id: string\n ruleId: string\n ruleName: string\n ruleType: string\n } | null\n entityType: string\n entityId: string | null\n eventType: string | null\n executedAt: string\n executionTimeMs: number\n executionResult: 'SUCCESS' | 'FAILURE' | 'ERROR'\n resultValue: any | null\n errorMessage: string | null\n inputContext: any | null\n outputContext: any | null\n executedBy: string | null\n tenantId: string | null\n organizationId: string | null\n}\n\ntype LogsResponse = {\n items: RuleExecutionLog[]\n total: number\n totalPages: number\n totalIsCapped?: boolean\n}\n\nexport default function ExecutionLogsPage() {\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(50)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [totalIsCapped, setTotalIsCapped] = React.useState(false)\n const t = useT()\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n\n const { data, isLoading, error } = useQuery({\n queryKey: ['business-rules', 'logs', filterValues, page],\n queryFn: async () => {\n const params = new URLSearchParams()\n params.set('page', page.toString())\n params.set('pageSize', pageSize.toString())\n params.set('sortField', 'executedAt')\n params.set('sortDir', 'desc')\n\n if (filterValues.ruleId) params.set('ruleId', filterValues.ruleId as string)\n if (filterValues.entityType) params.set('entityType', filterValues.entityType as string)\n if (filterValues.executionResult) params.set('executionResult', filterValues.executionResult as string)\n if (filterValues.executedBy) params.set('executedBy', filterValues.executedBy as string)\n if (filterValues.executedAtFrom) params.set('executedAtFrom', filterValues.executedAtFrom as string)\n if (filterValues.executedAtTo) params.set('executedAtTo', filterValues.executedAtTo as string)\n\n const result = await apiCall<LogsResponse>(\n `/api/business_rules/logs?${params.toString()}`\n )\n\n if (!result.ok) {\n throw new Error('Failed to fetch execution logs')\n }\n\n const response = result.result\n if (response) {\n setTotal(response.total || 0)\n setTotalPages(response.totalPages || 1)\n setTotalIsCapped(response?.totalIsCapped === true)\n }\n\n return response?.items || []\n },\n })\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n const next: FilterValues = {}\n Object.entries(values).forEach(([key, value]) => {\n if (value !== undefined) next[key] = value\n })\n setFilterValues(next)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n }, [])\n\n const filters: FilterDef[] = [\n {\n id: 'entityType',\n type: 'text',\n label: t('business_rules.logs.filters.entityType'),\n placeholder: t('business_rules.logs.filters.entityTypePlaceholder'),\n },\n {\n id: 'executionResult',\n type: 'select',\n label: t('business_rules.logs.filters.result'),\n options: [\n { value: '', label: t('common.all') },\n { value: 'SUCCESS', label: t('business_rules.logs.result.success') },\n { value: 'FAILURE', label: t('business_rules.logs.result.failure') },\n { value: 'ERROR', label: t('business_rules.logs.result.error') },\n ],\n },\n {\n id: 'executedBy',\n type: 'text',\n label: t('business_rules.logs.filters.executedBy'),\n placeholder: t('business_rules.logs.filters.executedByPlaceholder'),\n },\n {\n id: 'executedAtFrom',\n type: 'dateRange',\n label: t('business_rules.logs.filters.dateFrom'),\n },\n {\n id: 'executedAtTo',\n type: 'dateRange',\n label: t('business_rules.logs.filters.dateTo'),\n },\n ]\n\n const getResultBadgeClass = (result: string) => {\n switch (result) {\n case 'SUCCESS':\n return 'bg-green-100 text-green-800'\n case 'FAILURE':\n return 'bg-yellow-100 text-yellow-800'\n case 'ERROR':\n return 'bg-red-100 text-red-800'\n default:\n return 'bg-muted text-foreground'\n }\n }\n\n const columns: ColumnDef<RuleExecutionLog>[] = [\n {\n id: 'executedAt',\n header: t('business_rules.logs.fields.executedAt'),\n accessorKey: 'executedAt',\n cell: ({ row }) => (\n <div className=\"text-sm\">\n {new Date(row.original.executedAt).toLocaleString()}\n </div>\n ),\n },\n {\n id: 'rule',\n header: t('business_rules.logs.fields.rule'),\n cell: ({ row }) => (\n <div>\n {row.original.rule ? (\n <Link\n href={`/backend/rules/${row.original.rule.id}`}\n className=\"text-blue-600 hover:text-blue-800 hover:underline font-medium\"\n >\n {row.original.rule.ruleName}\n </Link>\n ) : (\n <span className=\"text-muted-foreground text-sm\">\n {t('business_rules.logs.ruleDeleted')}\n </span>\n )}\n {row.original.rule && (\n <div className=\"text-xs text-muted-foreground mt-0.5\">\n {row.original.rule.ruleType}\n </div>\n )}\n </div>\n ),\n },\n {\n id: 'entity',\n header: t('business_rules.logs.fields.entity'),\n cell: ({ row }) => (\n <div className=\"text-sm\">\n <div className=\"font-medium\">{row.original.entityType}</div>\n {row.original.entityId && (\n <div className=\"text-xs text-muted-foreground truncate max-w-[200px]\" title={row.original.entityId}>\n {row.original.entityId}\n </div>\n )}\n </div>\n ),\n },\n {\n id: 'result',\n header: t('business_rules.logs.fields.result'),\n accessorKey: 'executionResult',\n cell: ({ row }) => (\n <span\n className={`inline-flex items-center px-2 py-1 rounded text-xs font-medium ${getResultBadgeClass(\n row.original.executionResult\n )}`}\n >\n {t(`business_rules.logs.result.${row.original.executionResult.toLowerCase()}`)}\n </span>\n ),\n },\n {\n id: 'executionTime',\n header: t('business_rules.logs.fields.executionTime'),\n accessorKey: 'executionTimeMs',\n cell: ({ row }) => (\n <div className=\"text-sm text-muted-foreground\">\n {row.original.executionTimeMs}ms\n </div>\n ),\n },\n {\n id: 'actions',\n header: '',\n cell: ({ row }) => (\n <Link\n href={`/backend/logs/${row.original.id}`}\n className=\"text-sm text-blue-600 hover:text-blue-800 hover:underline\"\n >\n {t('common.details')}\n </Link>\n ),\n },\n ]\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('business_rules.logs.list.title')}\n columns={columns}\n data={data || []}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n isLoading={isLoading}\n error={error ? t('business_rules.logs.messages.loadFailed') : undefined}\n pagination={{ page, pageSize, total, totalPages, totalIsCapped, onPageChange: setPage }}\n />\n </PageBody>\n </Page>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -20,6 +20,7 @@ function RulesListPage() {
|
|
|
20
20
|
const [pageSize] = React.useState(20);
|
|
21
21
|
const [total, setTotal] = React.useState(0);
|
|
22
22
|
const [totalPages, setTotalPages] = React.useState(1);
|
|
23
|
+
const [totalIsCapped, setTotalIsCapped] = React.useState(false);
|
|
23
24
|
const t = useT();
|
|
24
25
|
const router = useRouter();
|
|
25
26
|
const queryClient = useQueryClient();
|
|
@@ -48,6 +49,7 @@ function RulesListPage() {
|
|
|
48
49
|
if (response) {
|
|
49
50
|
setTotal(response.total || 0);
|
|
50
51
|
setTotalPages(response.totalPages || 1);
|
|
52
|
+
setTotalIsCapped(response?.totalIsCapped === true);
|
|
51
53
|
}
|
|
52
54
|
return response?.items || [];
|
|
53
55
|
}
|
|
@@ -277,7 +279,7 @@ function RulesListPage() {
|
|
|
277
279
|
createLabel: t("business_rules.actions.create")
|
|
278
280
|
}
|
|
279
281
|
),
|
|
280
|
-
pagination: { page, pageSize, total, totalPages, onPageChange: setPage }
|
|
282
|
+
pagination: { page, pageSize, total, totalPages, totalIsCapped, onPageChange: setPage }
|
|
281
283
|
}
|
|
282
284
|
) }),
|
|
283
285
|
ConfirmDialogElement
|