@open-mercato/core 0.7.0 → 0.7.1-develop.7103.1.41ff100d93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/helpers/integration/api.js +13 -1
- package/dist/helpers/integration/api.js.map +2 -2
- package/dist/helpers/integration/communicationChannelsFixtures.js +19 -0
- package/dist/helpers/integration/communicationChannelsFixtures.js.map +2 -2
- package/dist/modules/api_keys/api/keys/route.js +1 -1
- package/dist/modules/api_keys/api/keys/route.js.map +2 -2
- package/dist/modules/api_keys/backend/api-keys/page.js +3 -1
- package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
- package/dist/modules/api_keys/di.js +9 -0
- package/dist/modules/api_keys/di.js.map +7 -0
- package/dist/modules/api_keys/services/principalService.js +31 -0
- package/dist/modules/api_keys/services/principalService.js.map +7 -0
- package/dist/modules/attachments/api/route.js +2 -2
- package/dist/modules/attachments/api/route.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentLibrary.js +2 -0
- package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
- package/dist/modules/attachments/di.js +11 -1
- package/dist/modules/attachments/di.js.map +2 -2
- package/dist/modules/attachments/index.js.map +1 -1
- package/dist/modules/attachments/lib/attachment-service.js +313 -0
- package/dist/modules/attachments/lib/attachment-service.js.map +7 -0
- package/dist/modules/attachments/lib/scoped-upload-service.js +15 -2
- package/dist/modules/attachments/lib/scoped-upload-service.js.map +2 -2
- package/dist/modules/attachments/lib/upload-limits.js +6 -2
- package/dist/modules/attachments/lib/upload-limits.js.map +2 -2
- package/dist/modules/audit_logs/backend/audit-logs/page.js +6 -0
- package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
- package/dist/modules/audit_logs/lib/display-helpers.js +19 -11
- package/dist/modules/audit_logs/lib/display-helpers.js.map +2 -2
- package/dist/modules/audit_logs/services/actionLogService.js +57 -12
- package/dist/modules/audit_logs/services/actionLogService.js.map +3 -3
- package/dist/modules/auth/acl.js +30 -5
- package/dist/modules/auth/acl.js.map +2 -2
- package/dist/modules/auth/api/feature-check.js +8 -2
- package/dist/modules/auth/api/feature-check.js.map +2 -2
- package/dist/modules/auth/api/login.js +4 -1
- package/dist/modules/auth/api/login.js.map +2 -2
- package/dist/modules/auth/api/reset/validate.js +55 -0
- package/dist/modules/auth/api/reset/validate.js.map +7 -0
- package/dist/modules/auth/api/roles/acl/route.js +28 -33
- package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
- package/dist/modules/auth/api/session/refresh.js +25 -1
- package/dist/modules/auth/api/session/refresh.js.map +2 -2
- package/dist/modules/auth/api/users/acl/route.js +96 -51
- package/dist/modules/auth/api/users/acl/route.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +13 -5
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/backend/roles/[id]/edit/page.meta.js +5 -1
- package/dist/modules/auth/backend/roles/[id]/edit/page.meta.js.map +2 -2
- package/dist/modules/auth/backend/roles/page.js +3 -1
- package/dist/modules/auth/backend/roles/page.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.meta.js +5 -1
- package/dist/modules/auth/backend/users/[id]/edit/page.meta.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +2 -1
- package/dist/modules/auth/backend/users/page.js.map +2 -2
- package/dist/modules/auth/commands/acl.js +254 -0
- package/dist/modules/auth/commands/acl.js.map +7 -0
- package/dist/modules/auth/components/AclEditor.js +39 -30
- package/dist/modules/auth/components/AclEditor.js.map +2 -2
- package/dist/modules/auth/data/entities.js.map +2 -2
- package/dist/modules/auth/data/validators.js +5 -1
- package/dist/modules/auth/data/validators.js.map +2 -2
- package/dist/modules/auth/di.js +35 -9
- package/dist/modules/auth/di.js.map +2 -2
- package/dist/modules/auth/frontend/reset/[token]/page.js +46 -0
- package/dist/modules/auth/frontend/reset/[token]/page.js.map +2 -2
- package/dist/modules/auth/lib/grantChecks.js.map +2 -2
- package/dist/modules/auth/lib/userIdFilter.js +16 -0
- package/dist/modules/auth/lib/userIdFilter.js.map +7 -0
- package/dist/modules/auth/services/authService.js +16 -2
- package/dist/modules/auth/services/authService.js.map +2 -2
- package/dist/modules/auth/services/principalService.js +200 -0
- package/dist/modules/auth/services/principalService.js.map +7 -0
- package/dist/modules/auth/services/rbacService.js +67 -24
- package/dist/modules/auth/services/rbacService.js.map +3 -3
- package/dist/modules/auth/services/roleOrganizationScope.js +41 -0
- package/dist/modules/auth/services/roleOrganizationScope.js.map +7 -0
- package/dist/modules/business_rules/backend/logs/page.js +3 -1
- package/dist/modules/business_rules/backend/logs/page.js.map +2 -2
- package/dist/modules/business_rules/backend/rules/page.js +3 -1
- package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/page.js +3 -1
- package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
- package/dist/modules/business_rules/lib/expression-evaluator.js +9 -9
- package/dist/modules/business_rules/lib/expression-evaluator.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-evaluator.js +10 -9
- package/dist/modules/business_rules/lib/rule-evaluator.js.map +2 -2
- package/dist/modules/catalog/ai-agents.js +1 -1
- package/dist/modules/catalog/ai-agents.js.map +1 -1
- package/dist/modules/catalog/ai-tools/merchandising-pack.js +2 -2
- package/dist/modules/catalog/ai-tools/merchandising-pack.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +5 -2
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +2 -2
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -0
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductsDataTable.js +7 -1
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js +2 -0
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js.map +2 -2
- package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js +9 -1
- package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/test-seed/route.js +95 -10
- package/dist/modules/communication_channels/api/post/test-seed/route.js.map +2 -2
- package/dist/modules/communication_channels/backend/communication_channels/channels/page.js +3 -0
- package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +2 -2
- package/dist/modules/communication_channels/commands/ingest-inbound-message.js +14 -1
- package/dist/modules/communication_channels/commands/ingest-inbound-message.js.map +2 -2
- package/dist/modules/communication_channels/di.js +7 -1
- package/dist/modules/communication_channels/di.js.map +2 -2
- package/dist/modules/communication_channels/lib/email-capabilities.js +4 -1
- package/dist/modules/communication_channels/lib/email-capabilities.js.map +2 -2
- package/dist/modules/communication_channels/lib/outbound-recipient.js +33 -0
- package/dist/modules/communication_channels/lib/outbound-recipient.js.map +7 -0
- package/dist/modules/communication_channels/lib/resolve-channel-type.js +51 -0
- package/dist/modules/communication_channels/lib/resolve-channel-type.js.map +7 -0
- package/dist/modules/communication_channels/lib/test-seed.js +41 -2
- package/dist/modules/communication_channels/lib/test-seed.js.map +2 -2
- package/dist/modules/configs/lib/system-status.js +9 -0
- package/dist/modules/configs/lib/system-status.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/page.js +3 -1
- package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js +3 -1
- package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
- package/dist/modules/currencies/services/rateFetchingService.js +6 -1
- package/dist/modules/currencies/services/rateFetchingService.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/domain-mappings.js +9 -0
- package/dist/modules/customer_accounts/api/admin/domain-mappings.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +3 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js +3 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js.map +2 -2
- package/dist/modules/customer_accounts/services/domainMappingService.js +10 -0
- package/dist/modules/customer_accounts/services/domainMappingService.js.map +2 -2
- package/dist/modules/customers/ai-tools/companies-pack.js +4 -1
- package/dist/modules/customers/ai-tools/companies-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/deal-analyzer-pack.js +13 -2
- package/dist/modules/customers/ai-tools/deal-analyzer-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/deals-pack.js +52 -6
- package/dist/modules/customers/ai-tools/deals-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/people-pack.js +4 -1
- package/dist/modules/customers/ai-tools/people-pack.js.map +2 -2
- package/dist/modules/customers/api/activities/route.js +48 -6
- package/dist/modules/customers/api/activities/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/people/route.js +20 -64
- package/dist/modules/customers/api/companies/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/route.js +17 -94
- package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js +8 -5
- package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/companies/route.js +1 -1
- package/dist/modules/customers/api/deals/[id]/companies/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/people/route.js +1 -1
- package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/route.js +8 -25
- package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/stats/route.js +3 -22
- package/dist/modules/customers/api/deals/[id]/stats/route.js.map +2 -2
- package/dist/modules/customers/api/deals/aggregate/route.js +14 -9
- package/dist/modules/customers/api/deals/aggregate/route.js.map +2 -2
- package/dist/modules/customers/api/deals/map/route.js +5 -5
- package/dist/modules/customers/api/deals/map/route.js.map +2 -2
- package/dist/modules/customers/api/deals/route.js +38 -1
- package/dist/modules/customers/api/deals/route.js.map +2 -2
- package/dist/modules/customers/api/entity-roles-factory.js +4 -4
- package/dist/modules/customers/api/entity-roles-factory.js.map +2 -2
- package/dist/modules/customers/api/interactions/route.js +3 -1
- package/dist/modules/customers/api/interactions/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/tasks/route.js +27 -4
- package/dist/modules/customers/api/interactions/tasks/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +4 -3
- package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/context.js +1 -1
- package/dist/modules/customers/api/people/[id]/companies/context.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +1 -1
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/route.js +11 -10
- package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/people/check-phone/route.js +51 -9
- package/dist/modules/customers/api/people/check-phone/route.js.map +2 -2
- package/dist/modules/customers/api/todos/route.js +30 -5
- package/dist/modules/customers/api/todos/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +4 -2
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +6 -1
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +5 -2
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/Lane.js +4 -13
- package/dist/modules/customers/backend/customers/deals/pipeline/components/Lane.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js +85 -14
- package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/toneClasses.js +18 -0
- package/dist/modules/customers/backend/customers/deals/pipeline/components/toneClasses.js.map +7 -0
- package/dist/modules/customers/backend/customers/people/page.js +4 -2
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/backend/hooks/useEmailDuplicateCheck.js +9 -3
- package/dist/modules/customers/backend/hooks/useEmailDuplicateCheck.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +21 -34
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js.map +1 -1
- package/dist/modules/customers/commands/personCompanyLinks.js +131 -2
- package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
- package/dist/modules/customers/components/CustomerTodosTable.js +1 -0
- package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
- package/dist/modules/customers/components/DealsKpiStrip.js +7 -6
- package/dist/modules/customers/components/DealsKpiStrip.js.map +2 -2
- package/dist/modules/customers/components/calendar/AgendaList.js +2 -2
- package/dist/modules/customers/components/calendar/AgendaList.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js +1 -1
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarScreen.js +1 -1
- package/dist/modules/customers/components/calendar/CalendarScreen.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js +1 -1
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js.map +2 -2
- package/dist/modules/customers/components/calendar/EventBlock.js +1 -1
- package/dist/modules/customers/components/calendar/EventBlock.js.map +2 -2
- package/dist/modules/customers/components/calendar/EventPeekPopover.js +3 -2
- package/dist/modules/customers/components/calendar/EventPeekPopover.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/PeopleField.js +40 -5
- package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/hooks.js +2 -1
- package/dist/modules/customers/components/calendar/editor/hooks.js.map +2 -2
- package/dist/modules/customers/components/calendar/types.js +1 -1
- package/dist/modules/customers/components/calendar/types.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyKpiBar.js +5 -4
- package/dist/modules/customers/components/detail/CompanyKpiBar.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js +3 -1
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
- package/dist/modules/customers/components/detail/DealForm.js +19 -7
- package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
- package/dist/modules/customers/components/detail/DealsSection.js +6 -5
- package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js +35 -11
- package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js +3 -1
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/usePersonTasks.js +19 -13
- package/dist/modules/customers/components/detail/hooks/usePersonTasks.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/ParticipantsField.js +4 -4
- package/dist/modules/customers/components/detail/schedule/ParticipantsField.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +3 -3
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
- package/dist/modules/customers/components/detail/utils.js +5 -5
- package/dist/modules/customers/components/detail/utils.js.map +2 -2
- package/dist/modules/customers/data/entities.js.map +1 -1
- package/dist/modules/customers/data/validators.js +32 -3
- package/dist/modules/customers/data/validators.js.map +2 -2
- package/dist/modules/customers/events.js +5 -0
- package/dist/modules/customers/events.js.map +2 -2
- package/dist/modules/customers/lib/calendar/conflicts.js +8 -2
- package/dist/modules/customers/lib/calendar/conflicts.js.map +2 -2
- package/dist/modules/customers/lib/calendar/editorPayload.js +3 -2
- package/dist/modules/customers/lib/calendar/editorPayload.js.map +2 -2
- package/dist/modules/customers/lib/calendar/mapItem.js +8 -3
- package/dist/modules/customers/lib/calendar/mapItem.js.map +2 -2
- package/dist/modules/customers/lib/calendar/participantIdentity.js +9 -0
- package/dist/modules/customers/lib/calendar/participantIdentity.js.map +7 -0
- package/dist/modules/customers/lib/closureStage.js +45 -0
- package/dist/modules/customers/lib/closureStage.js.map +7 -0
- package/dist/modules/customers/lib/dealStatus.js +30 -0
- package/dist/modules/customers/lib/dealStatus.js.map +2 -2
- package/dist/modules/customers/lib/detailReadAccess.js +12 -0
- package/dist/modules/customers/lib/detailReadAccess.js.map +7 -0
- package/dist/modules/customers/lib/findPeopleByAddresses.js +1 -0
- package/dist/modules/customers/lib/findPeopleByAddresses.js.map +2 -2
- package/dist/modules/customers/lib/personCompanies.js +100 -2
- package/dist/modules/customers/lib/personCompanies.js.map +2 -2
- package/dist/modules/customers/lib/todoCompatibility.js +12 -0
- package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
- package/dist/modules/dashboards/lib/widgetScope.js +6 -1
- package/dist/modules/dashboards/lib/widgetScope.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +3 -1
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/lib/abandoned-run.js +19 -0
- package/dist/modules/data_sync/lib/abandoned-run.js.map +7 -0
- package/dist/modules/data_sync/lib/sync-engine.js +72 -6
- package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
- package/dist/modules/data_sync/workers/sync-export.js +5 -1
- package/dist/modules/data_sync/workers/sync-export.js.map +2 -2
- package/dist/modules/data_sync/workers/sync-import.js +5 -1
- package/dist/modules/data_sync/workers/sync-import.js.map +2 -2
- package/dist/modules/devices/acl.js +9 -1
- package/dist/modules/devices/acl.js.map +2 -2
- package/dist/modules/devices/api/admin/devices/[id]/route.js +5 -32
- package/dist/modules/devices/api/admin/devices/[id]/route.js.map +2 -2
- package/dist/modules/devices/api/admin/devices/route.js +14 -1
- package/dist/modules/devices/api/admin/devices/route.js.map +2 -2
- package/dist/modules/devices/api/deviceList.js +99 -12
- package/dist/modules/devices/api/deviceList.js.map +2 -2
- package/dist/modules/devices/api/deviceSerialization.js +46 -0
- package/dist/modules/devices/api/deviceSerialization.js.map +7 -0
- package/dist/modules/devices/api/openapi.js +3 -1
- package/dist/modules/devices/api/openapi.js.map +2 -2
- package/dist/modules/devices/api/route.js +9 -1
- package/dist/modules/devices/api/route.js.map +2 -2
- package/dist/modules/devices/backend/devices/[id]/page.js +10 -26
- package/dist/modules/devices/backend/devices/[id]/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/create/page.js +17 -1
- package/dist/modules/devices/backend/devices/create/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/page.js +28 -34
- package/dist/modules/devices/backend/devices/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/useDeviceUserLabels.js +34 -0
- package/dist/modules/devices/backend/devices/useDeviceUserLabels.js.map +7 -0
- package/dist/modules/devices/backend/devices/userOptions.js +52 -0
- package/dist/modules/devices/backend/devices/userOptions.js.map +7 -0
- package/dist/modules/devices/setup.js +6 -2
- package/dist/modules/devices/setup.js.map +2 -2
- package/dist/modules/directory/backend/directory/organizations/page.js +2 -1
- package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/page.js +2 -1
- package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
- package/dist/modules/directory/di.js +9 -0
- package/dist/modules/directory/di.js.map +2 -2
- package/dist/modules/directory/services/organizationHierarchyService.js +29 -0
- package/dist/modules/directory/services/organizationHierarchyService.js.map +7 -0
- package/dist/modules/directory/services/organizationScopeService.js +56 -0
- package/dist/modules/directory/services/organizationScopeService.js.map +7 -0
- package/dist/modules/directory/utils/organizationScope.js.map +2 -2
- package/dist/modules/entities/api/records.js +4 -2
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +3 -1
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/eudr/api/plots/route.js +5 -1
- package/dist/modules/eudr/api/plots/route.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/plots/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/plots/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/product-mappings/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/statements/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/statements/page.js.map +2 -2
- package/dist/modules/eudr/commands/statements.js +0 -3
- package/dist/modules/eudr/commands/statements.js.map +2 -2
- package/dist/modules/eudr/data/validators.js +4 -1
- package/dist/modules/eudr/data/validators.js.map +2 -2
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +1 -0
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
- package/dist/modules/feature_toggles/components/OverridesTable.js +1 -0
- package/dist/modules/feature_toggles/components/OverridesTable.js.map +2 -2
- package/dist/modules/feature_toggles/defaults.json +0 -8
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js +3 -0
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/page.js +3 -0
- package/dist/modules/inbox_ops/backend/inbox-ops/page.js.map +2 -2
- package/dist/modules/inbox_ops/lib/htmlToPlainText.js +1 -12
- package/dist/modules/inbox_ops/lib/htmlToPlainText.js.map +2 -2
- package/dist/modules/integrations/api/[id]/credentials/route.js +6 -1
- package/dist/modules/integrations/api/[id]/credentials/route.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/[id]/page.js +38 -29
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +36 -9
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/credential-secret-fields.js +55 -0
- package/dist/modules/integrations/backend/integrations/credential-secret-fields.js.map +7 -0
- package/dist/modules/integrations/data/validators.js +11 -3
- package/dist/modules/integrations/data/validators.js.map +2 -2
- package/dist/modules/integrations/lib/credentials-masking.js +6 -2
- package/dist/modules/integrations/lib/credentials-masking.js.map +2 -2
- package/dist/modules/messages/api/[id]/route.js +29 -1
- package/dist/modules/messages/api/[id]/route.js.map +2 -2
- package/dist/modules/messages/api/openapi.js +17 -2
- package/dist/modules/messages/api/openapi.js.map +2 -2
- package/dist/modules/messages/api/route.js +17 -2
- package/dist/modules/messages/api/route.js.map +2 -2
- package/dist/modules/messages/components/MessagesInboxPageClient.js +7 -14
- package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
- package/dist/modules/messages/components/inboxFilters.js +15 -0
- package/dist/modules/messages/components/inboxFilters.js.map +2 -2
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js +11 -1
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js.map +2 -2
- package/dist/modules/messages/components/message-detail/panels/MessageHeader.js +3 -1
- package/dist/modules/messages/components/message-detail/panels/MessageHeader.js.map +2 -2
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js +2 -1
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +2 -2
- package/dist/modules/messages/components/messageListLabels.js +14 -2
- package/dist/modules/messages/components/messageListLabels.js.map +2 -2
- package/dist/modules/messages/data/validators.js +18 -4
- package/dist/modules/messages/data/validators.js.map +2 -2
- package/dist/modules/messages/lib/channel-sender-identity.js +26 -0
- package/dist/modules/messages/lib/channel-sender-identity.js.map +7 -0
- package/dist/modules/messages/lib/composeSourceChannelType.js +41 -0
- package/dist/modules/messages/lib/composeSourceChannelType.js.map +7 -0
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +4 -6
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +2 -2
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js +3 -1
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
- package/dist/modules/payment_gateways/lib/webhook-processor.js +7 -0
- package/dist/modules/payment_gateways/lib/webhook-processor.js.map +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js +3 -0
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/push_notifications/backend/push_notifications/page.js +3 -1
- package/dist/modules/push_notifications/backend/push_notifications/page.js.map +2 -2
- package/dist/modules/push_notifications/backend/push_notifications/send/page.js +1 -1
- package/dist/modules/push_notifications/backend/push_notifications/send/page.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +150 -51
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/lib/search-entity-policy.js +14 -0
- package/dist/modules/query_index/lib/search-entity-policy.js.map +7 -0
- package/dist/modules/query_index/lib/search-tokens.js +79 -3
- package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js +3 -1
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js +3 -1
- package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js +3 -0
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +3 -0
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +10 -8
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +79 -1
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/components/PriceWithCurrency.js +7 -5
- package/dist/modules/sales/components/PriceWithCurrency.js.map +2 -2
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +3 -0
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentsSection.js +8 -6
- package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +51 -22
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +83 -18
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js +23 -9
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnsSection.js +8 -6
- package/dist/modules/sales/components/documents/ReturnsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +68 -14
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesOrderDraftLines.js +6 -5
- package/dist/modules/sales/components/documents/SalesOrderDraftLines.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +5 -4
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentsSection.js +8 -6
- package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/lineItemShipmentLock.js +54 -0
- package/dist/modules/sales/components/documents/lineItemShipmentLock.js.map +7 -0
- package/dist/modules/sales/components/documents/lineItemUtils.js +2 -2
- package/dist/modules/sales/components/documents/lineItemUtils.js.map +2 -2
- package/dist/modules/sales/data/entities.js +8 -2
- package/dist/modules/sales/data/entities.js.map +2 -2
- package/dist/modules/sales/extension-points.js +1 -0
- package/dist/modules/sales/extension-points.js.map +2 -2
- package/dist/modules/sales/lib/salesChannelsToggleSeed.js +33 -0
- package/dist/modules/sales/lib/salesChannelsToggleSeed.js.map +7 -0
- package/dist/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.js +32 -0
- package/dist/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.js.map +7 -0
- package/dist/modules/sales/setup.js +2 -0
- package/dist/modules/sales/setup.js.map +2 -2
- package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js +10 -2
- package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js.map +2 -2
- package/dist/modules/sales/widgets/injection-table.js +4 -7
- package/dist/modules/sales/widgets/injection-table.js.map +2 -2
- package/dist/modules/staff/backend/staff/leave-requests/page.js +3 -0
- package/dist/modules/staff/backend/staff/leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js +3 -0
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/page.js +3 -0
- package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js +3 -0
- package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +3 -0
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js +3 -0
- package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/page.js +29 -18
- package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js +3 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
- package/dist/modules/sync_excel/lib/adapters/customers.js +1 -0
- package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
- package/dist/modules/warranty_claims/api/assignees/route.js +3 -3
- package/dist/modules/warranty_claims/api/assignees/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/attachments/route.js +2 -2
- package/dist/modules/warranty_claims/api/portal/attachments/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/route.js +12 -9
- package/dist/modules/warranty_claims/api/portal/claims/route.js.map +2 -2
- package/dist/modules/warranty_claims/backend/page.js +3 -0
- package/dist/modules/warranty_claims/backend/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js +3 -0
- package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js +3 -0
- package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js +3 -0
- package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js.map +2 -2
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js +3 -0
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js.map +2 -2
- package/dist/modules/wms/api/warehouseSearch.js +21 -0
- package/dist/modules/wms/api/warehouseSearch.js.map +7 -0
- package/dist/modules/wms/api/warehouses/route.js +13 -9
- package/dist/modules/wms/api/warehouses/route.js.map +2 -2
- package/dist/modules/wms/api/zones/route.js +15 -2
- package/dist/modules/wms/api/zones/route.js.map +2 -2
- package/dist/modules/wms/commands/configuration.js +121 -9
- package/dist/modules/wms/commands/configuration.js.map +2 -2
- package/dist/modules/wms/commands/inventory-actions.js +3 -0
- package/dist/modules/wms/commands/inventory-actions.js.map +2 -2
- package/dist/modules/wms/commands/shared.js +9 -1
- package/dist/modules/wms/commands/shared.js.map +2 -2
- package/dist/modules/wms/components/backend/WarehouseEditDialog.js +158 -0
- package/dist/modules/wms/components/backend/WarehouseEditDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js +76 -111
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +3 -3
- package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +1 -0
- package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsLotsListPage.js +1 -0
- package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +2 -2
- package/dist/modules/wms/components/backend/inventoryMutationLoaders.js +27 -20
- package/dist/modules/wms/components/backend/inventoryMutationLoaders.js.map +2 -2
- package/dist/modules/wms/components/backend/warehouseFormOptions.js +66 -0
- package/dist/modules/wms/components/backend/warehouseFormOptions.js.map +7 -0
- package/dist/modules/workflows/backend/definitions/page.js +3 -1
- package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
- package/dist/modules/workflows/backend/events/page.js +3 -1
- package/dist/modules/workflows/backend/events/page.js.map +2 -2
- package/dist/modules/workflows/backend/instances/page.js +3 -1
- package/dist/modules/workflows/backend/instances/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/page.js +3 -1
- package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
- package/dist/modules/workflows/lib/activity-executor.js +4 -0
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/package.json +9 -10
- package/src/helpers/integration/api.ts +33 -1
- package/src/helpers/integration/communicationChannelsFixtures.ts +69 -1
- package/src/modules/api_keys/api/keys/route.ts +3 -1
- package/src/modules/api_keys/backend/api-keys/page.tsx +4 -1
- package/src/modules/api_keys/di.ts +7 -0
- package/src/modules/api_keys/services/principalService.ts +33 -0
- package/src/modules/attachments/AGENTS.md +15 -0
- package/src/modules/attachments/api/route.ts +2 -2
- package/src/modules/attachments/components/AttachmentLibrary.tsx +3 -0
- package/src/modules/attachments/di.ts +16 -0
- package/src/modules/attachments/i18n/de.json +5 -0
- package/src/modules/attachments/i18n/en.json +5 -0
- package/src/modules/attachments/i18n/es.json +5 -0
- package/src/modules/attachments/i18n/ko.json +5 -0
- package/src/modules/attachments/i18n/pl.json +5 -0
- package/src/modules/attachments/index.ts +10 -0
- package/src/modules/attachments/lib/attachment-service.ts +468 -0
- package/src/modules/attachments/lib/scoped-upload-service.ts +46 -0
- package/src/modules/attachments/lib/upload-limits.ts +6 -2
- package/src/modules/audit_logs/backend/audit-logs/page.tsx +8 -0
- package/src/modules/audit_logs/lib/display-helpers.tsx +42 -32
- package/src/modules/audit_logs/services/actionLogService.ts +74 -11
- package/src/modules/auth/acl.ts +30 -6
- package/src/modules/auth/api/feature-check.ts +10 -3
- package/src/modules/auth/api/login.ts +9 -1
- package/src/modules/auth/api/reset/validate.ts +57 -0
- package/src/modules/auth/api/roles/acl/route.ts +42 -39
- package/src/modules/auth/api/session/refresh.ts +32 -1
- package/src/modules/auth/api/users/acl/route.ts +177 -53
- package/src/modules/auth/api/users/route.ts +18 -5
- package/src/modules/auth/backend/roles/[id]/edit/page.meta.ts +5 -2
- package/src/modules/auth/backend/roles/page.tsx +4 -2
- package/src/modules/auth/backend/users/[id]/edit/page.meta.ts +5 -2
- package/src/modules/auth/backend/users/page.tsx +3 -2
- package/src/modules/auth/commands/acl.ts +495 -0
- package/src/modules/auth/components/AclEditor.tsx +63 -33
- package/src/modules/auth/data/entities.ts +4 -1
- package/src/modules/auth/data/validators.ts +5 -0
- package/src/modules/auth/di.ts +46 -16
- package/src/modules/auth/frontend/reset/[token]/page.tsx +74 -0
- package/src/modules/auth/i18n/de.json +389 -0
- package/src/modules/auth/i18n/en.json +389 -0
- package/src/modules/auth/i18n/es.json +389 -0
- package/src/modules/auth/i18n/ko.json +389 -0
- package/src/modules/auth/i18n/pl.json +391 -2
- package/src/modules/auth/lib/grantChecks.ts +6 -0
- package/src/modules/auth/lib/userIdFilter.ts +31 -0
- package/src/modules/auth/services/authService.ts +18 -2
- package/src/modules/auth/services/principalService.ts +266 -0
- package/src/modules/auth/services/rbacService.ts +110 -24
- package/src/modules/auth/services/roleOrganizationScope.ts +70 -0
- package/src/modules/business_rules/backend/logs/page.tsx +4 -1
- package/src/modules/business_rules/backend/rules/page.tsx +4 -1
- package/src/modules/business_rules/backend/sets/page.tsx +4 -1
- package/src/modules/business_rules/lib/expression-evaluator.ts +9 -9
- package/src/modules/business_rules/lib/rule-evaluator.ts +10 -9
- package/src/modules/catalog/ai-agents.ts +1 -1
- package/src/modules/catalog/ai-tools/merchandising-pack.ts +2 -2
- package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +12 -5
- package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +3 -0
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +7 -0
- package/src/modules/catalog/i18n/de.json +1 -0
- package/src/modules/catalog/i18n/en.json +1 -0
- package/src/modules/catalog/i18n/es.json +1 -0
- package/src/modules/catalog/i18n/ko.json +1 -0
- package/src/modules/catalog/i18n/pl.json +1 -0
- package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.tsx +4 -0
- package/src/modules/communication_channels/api/post/channels/[id]/test-send/route.ts +17 -1
- package/src/modules/communication_channels/api/post/test-seed/route.ts +155 -16
- package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +4 -0
- package/src/modules/communication_channels/commands/ingest-inbound-message.ts +38 -1
- package/src/modules/communication_channels/di.ts +7 -0
- package/src/modules/communication_channels/lib/adapter.ts +14 -0
- package/src/modules/communication_channels/lib/email-capabilities.ts +4 -0
- package/src/modules/communication_channels/lib/outbound-recipient.ts +71 -0
- package/src/modules/communication_channels/lib/resolve-channel-type.ts +99 -0
- package/src/modules/communication_channels/lib/test-seed.ts +64 -4
- package/src/modules/configs/i18n/de.json +2 -0
- package/src/modules/configs/i18n/en.json +2 -0
- package/src/modules/configs/i18n/es.json +2 -0
- package/src/modules/configs/i18n/ko.json +2 -0
- package/src/modules/configs/i18n/pl.json +2 -0
- package/src/modules/configs/lib/system-status.ts +9 -0
- package/src/modules/currencies/AGENTS.md +3 -0
- package/src/modules/currencies/backend/currencies/page.tsx +4 -1
- package/src/modules/currencies/backend/exchange-rates/page.tsx +4 -1
- package/src/modules/currencies/services/README.md +45 -0
- package/src/modules/currencies/services/rateFetchingService.ts +6 -1
- package/src/modules/customer_accounts/api/admin/domain-mappings.ts +7 -0
- package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +4 -1
- package/src/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.tsx +4 -1
- package/src/modules/customer_accounts/services/domainMappingService.ts +10 -0
- package/src/modules/customers/ai-tools/companies-pack.ts +4 -1
- package/src/modules/customers/ai-tools/deal-analyzer-pack.ts +17 -2
- package/src/modules/customers/ai-tools/deals-pack.ts +66 -1
- package/src/modules/customers/ai-tools/people-pack.ts +4 -1
- package/src/modules/customers/api/activities/route.ts +45 -0
- package/src/modules/customers/api/companies/[id]/people/route.ts +24 -73
- package/src/modules/customers/api/companies/[id]/route.ts +24 -107
- package/src/modules/customers/api/dashboard/widgets/customer-todos/route.ts +16 -8
- package/src/modules/customers/api/deals/[id]/companies/route.ts +4 -1
- package/src/modules/customers/api/deals/[id]/people/route.ts +4 -1
- package/src/modules/customers/api/deals/[id]/route.ts +17 -28
- package/src/modules/customers/api/deals/[id]/stats/route.ts +10 -25
- package/src/modules/customers/api/deals/aggregate/route.ts +17 -9
- package/src/modules/customers/api/deals/map/route.ts +4 -4
- package/src/modules/customers/api/deals/route.ts +50 -1
- package/src/modules/customers/api/entity-roles-factory.ts +8 -4
- package/src/modules/customers/api/interactions/route.ts +8 -2
- package/src/modules/customers/api/interactions/tasks/route.ts +24 -1
- package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +12 -4
- package/src/modules/customers/api/people/[id]/companies/context.ts +4 -1
- package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +4 -1
- package/src/modules/customers/api/people/[id]/route.ts +16 -11
- package/src/modules/customers/api/people/check-phone/route.ts +75 -10
- package/src/modules/customers/api/todos/route.ts +27 -2
- package/src/modules/customers/backend/customers/companies/page.tsx +5 -2
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +7 -2
- package/src/modules/customers/backend/customers/deals/page.tsx +8 -2
- package/src/modules/customers/backend/customers/deals/pipeline/components/Lane.tsx +5 -14
- package/src/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.tsx +109 -27
- package/src/modules/customers/backend/customers/deals/pipeline/components/toneClasses.ts +21 -0
- package/src/modules/customers/backend/customers/people/page.tsx +5 -2
- package/src/modules/customers/backend/hooks/useEmailDuplicateCheck.ts +12 -4
- package/src/modules/customers/commands/deals.ts +34 -59
- package/src/modules/customers/commands/interactions.ts +1 -1
- package/src/modules/customers/commands/personCompanyLinks.ts +224 -8
- package/src/modules/customers/components/CustomerTodosTable.tsx +2 -0
- package/src/modules/customers/components/DealsKpiStrip.tsx +7 -7
- package/src/modules/customers/components/calendar/AgendaList.tsx +3 -3
- package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +1 -1
- package/src/modules/customers/components/calendar/CalendarScreen.tsx +1 -1
- package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +1 -1
- package/src/modules/customers/components/calendar/EventBlock.tsx +2 -2
- package/src/modules/customers/components/calendar/EventPeekPopover.tsx +4 -2
- package/src/modules/customers/components/calendar/editor/PeopleField.tsx +61 -5
- package/src/modules/customers/components/calendar/editor/hooks.ts +7 -1
- package/src/modules/customers/components/calendar/types.ts +2 -2
- package/src/modules/customers/components/detail/CompanyKpiBar.tsx +5 -4
- package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +8 -1
- package/src/modules/customers/components/detail/DealForm.tsx +22 -2
- package/src/modules/customers/components/detail/DealsSection.tsx +11 -5
- package/src/modules/customers/components/detail/EntityTagsDialog.tsx +58 -12
- package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +8 -1
- package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +23 -14
- package/src/modules/customers/components/detail/schedule/ParticipantsField.tsx +5 -5
- package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +5 -5
- package/src/modules/customers/components/detail/types.ts +1 -1
- package/src/modules/customers/components/detail/utils.ts +15 -5
- package/src/modules/customers/data/entities.ts +1 -1
- package/src/modules/customers/data/validators.ts +50 -9
- package/src/modules/customers/events.ts +5 -0
- package/src/modules/customers/i18n/de.json +9 -1
- package/src/modules/customers/i18n/en.json +9 -1
- package/src/modules/customers/i18n/es.json +9 -1
- package/src/modules/customers/i18n/ko.json +9 -1
- package/src/modules/customers/i18n/pl.json +9 -1
- package/src/modules/customers/lib/calendar/conflicts.ts +10 -2
- package/src/modules/customers/lib/calendar/editorPayload.ts +4 -3
- package/src/modules/customers/lib/calendar/mapItem.ts +8 -3
- package/src/modules/customers/lib/calendar/participantIdentity.ts +17 -0
- package/src/modules/customers/lib/closureStage.ts +76 -0
- package/src/modules/customers/lib/dealStatus.ts +42 -0
- package/src/modules/customers/lib/detailReadAccess.ts +35 -0
- package/src/modules/customers/lib/findPeopleByAddresses.ts +8 -6
- package/src/modules/customers/lib/personCompanies.ts +136 -1
- package/src/modules/customers/lib/todoCompatibility.ts +19 -1
- package/src/modules/dashboards/i18n/es.json +4 -4
- package/src/modules/dashboards/i18n/pl.json +7 -7
- package/src/modules/dashboards/lib/widgetScope.ts +6 -0
- package/src/modules/data_sync/AGENTS.md +1 -1
- package/src/modules/data_sync/backend/data-sync/page.tsx +4 -1
- package/src/modules/data_sync/lib/abandoned-run.ts +56 -0
- package/src/modules/data_sync/lib/adapter.ts +36 -0
- package/src/modules/data_sync/lib/sync-engine.ts +113 -5
- package/src/modules/data_sync/workers/sync-export.ts +4 -0
- package/src/modules/data_sync/workers/sync-import.ts +4 -0
- package/src/modules/devices/AGENTS.md +20 -1
- package/src/modules/devices/acl.ts +9 -1
- package/src/modules/devices/api/admin/devices/[id]/route.ts +5 -34
- package/src/modules/devices/api/admin/devices/route.ts +14 -1
- package/src/modules/devices/api/deviceList.ts +135 -11
- package/src/modules/devices/api/deviceSerialization.ts +50 -0
- package/src/modules/devices/api/openapi.ts +9 -1
- package/src/modules/devices/api/route.ts +9 -1
- package/src/modules/devices/backend/devices/[id]/page.tsx +18 -32
- package/src/modules/devices/backend/devices/create/page.tsx +17 -1
- package/src/modules/devices/backend/devices/page.tsx +44 -45
- package/src/modules/devices/backend/devices/useDeviceUserLabels.ts +45 -0
- package/src/modules/devices/backend/devices/userOptions.ts +99 -0
- package/src/modules/devices/i18n/de.json +3 -2
- package/src/modules/devices/i18n/en.json +3 -2
- package/src/modules/devices/i18n/es.json +3 -2
- package/src/modules/devices/i18n/ko.json +3 -2
- package/src/modules/devices/i18n/pl.json +3 -2
- package/src/modules/devices/setup.ts +6 -2
- package/src/modules/directory/backend/directory/organizations/page.tsx +3 -1
- package/src/modules/directory/backend/directory/tenants/page.tsx +3 -1
- package/src/modules/directory/di.ts +14 -2
- package/src/modules/directory/services/organizationHierarchyService.ts +34 -0
- package/src/modules/directory/services/organizationScopeService.ts +85 -0
- package/src/modules/directory/utils/organizationScope.ts +4 -15
- package/src/modules/entities/api/records.ts +2 -0
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +4 -1
- package/src/modules/eudr/api/plots/route.ts +4 -0
- package/src/modules/eudr/backend/eudr/evidence-submissions/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/plots/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/product-mappings/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/risk-assessments/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/statements/page.tsx +4 -0
- package/src/modules/eudr/commands/statements.ts +0 -3
- package/src/modules/eudr/data/validators.ts +16 -1
- package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +2 -1
- package/src/modules/feature_toggles/components/OverridesTable.tsx +2 -1
- package/src/modules/feature_toggles/defaults.json +0 -8
- package/src/modules/inbox_ops/backend/inbox-ops/log/page.tsx +4 -0
- package/src/modules/inbox_ops/backend/inbox-ops/page.tsx +4 -0
- package/src/modules/inbox_ops/lib/htmlToPlainText.ts +1 -17
- package/src/modules/integrations/api/[id]/credentials/route.ts +6 -4
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +61 -31
- package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +44 -9
- package/src/modules/integrations/backend/integrations/credential-secret-fields.ts +84 -0
- package/src/modules/integrations/data/validators.ts +12 -2
- package/src/modules/integrations/i18n/de.json +1 -0
- package/src/modules/integrations/i18n/en.json +1 -0
- package/src/modules/integrations/i18n/es.json +1 -0
- package/src/modules/integrations/i18n/ko.json +1 -0
- package/src/modules/integrations/i18n/pl.json +1 -0
- package/src/modules/integrations/lib/credentials-masking.ts +10 -6
- package/src/modules/messages/api/[id]/route.ts +55 -1
- package/src/modules/messages/api/openapi.ts +20 -0
- package/src/modules/messages/api/route.ts +31 -2
- package/src/modules/messages/components/MessagesInboxPageClient.tsx +9 -16
- package/src/modules/messages/components/inboxFilters.ts +36 -0
- package/src/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.ts +14 -1
- package/src/modules/messages/components/message-detail/panels/MessageHeader.tsx +3 -1
- package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +2 -1
- package/src/modules/messages/components/message-detail/types.ts +3 -0
- package/src/modules/messages/components/messageListLabels.ts +52 -3
- package/src/modules/messages/data/validators.ts +43 -4
- package/src/modules/messages/lib/channel-sender-identity.ts +55 -0
- package/src/modules/messages/lib/composeSourceChannelType.ts +95 -0
- package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +4 -6
- package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +4 -1
- package/src/modules/payment_gateways/lib/webhook-processor.ts +11 -0
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +4 -0
- package/src/modules/push_notifications/backend/push_notifications/page.tsx +4 -1
- package/src/modules/push_notifications/backend/push_notifications/send/page.tsx +4 -4
- package/src/modules/query_index/lib/engine.ts +249 -61
- package/src/modules/query_index/lib/search-entity-policy.ts +46 -0
- package/src/modules/query_index/lib/search-tokens.ts +135 -3
- package/src/modules/resources/backend/resources/resource-types/page.tsx +4 -1
- package/src/modules/resources/backend/resources/resources/page.tsx +4 -1
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +4 -0
- package/src/modules/sales/backend/sales/channels/page.tsx +4 -0
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +14 -8
- package/src/modules/sales/commands/documents.ts +93 -0
- package/src/modules/sales/components/PriceWithCurrency.tsx +17 -5
- package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +4 -0
- package/src/modules/sales/components/documents/AdjustmentsSection.tsx +6 -5
- package/src/modules/sales/components/documents/ItemsSection.tsx +56 -18
- package/src/modules/sales/components/documents/LineItemDialog.tsx +137 -20
- package/src/modules/sales/components/documents/PaymentsSection.tsx +20 -9
- package/src/modules/sales/components/documents/ReturnsSection.tsx +6 -5
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +106 -14
- package/src/modules/sales/components/documents/SalesOrderDraftLines.tsx +6 -5
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +5 -4
- package/src/modules/sales/components/documents/ShipmentsSection.tsx +6 -5
- package/src/modules/sales/components/documents/lineItemShipmentLock.ts +74 -0
- package/src/modules/sales/components/documents/lineItemUtils.ts +7 -2
- package/src/modules/sales/data/entities.ts +6 -0
- package/src/modules/sales/extension-points.ts +1 -0
- package/src/modules/sales/i18n/de.json +8 -0
- package/src/modules/sales/i18n/en.json +8 -0
- package/src/modules/sales/i18n/es.json +8 -0
- package/src/modules/sales/i18n/ko.json +8 -0
- package/src/modules/sales/i18n/pl.json +8 -0
- package/src/modules/sales/lib/salesChannelsToggleSeed.ts +42 -0
- package/src/modules/sales/migrations/.snapshot-open-mercato.json +60 -0
- package/src/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.ts +87 -0
- package/src/modules/sales/setup.ts +2 -0
- package/src/modules/sales/widgets/injection/payment-gateway-status-column/widget.ts +9 -1
- package/src/modules/sales/widgets/injection-table.ts +4 -7
- package/src/modules/staff/backend/staff/leave-requests/page.tsx +4 -0
- package/src/modules/staff/backend/staff/my-leave-requests/page.tsx +4 -0
- package/src/modules/staff/backend/staff/team-members/page.tsx +6 -0
- package/src/modules/staff/backend/staff/team-roles/page.tsx +4 -0
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +4 -0
- package/src/modules/staff/backend/staff/teams/page.tsx +4 -0
- package/src/modules/staff/backend/staff/timesheets/page.tsx +12 -1
- package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +4 -0
- package/src/modules/sync_excel/lib/adapters/customers.ts +5 -0
- package/src/modules/warranty_claims/api/assignees/route.ts +3 -3
- package/src/modules/warranty_claims/api/portal/attachments/route.ts +2 -2
- package/src/modules/warranty_claims/api/portal/claims/route.ts +12 -9
- package/src/modules/warranty_claims/backend/page.tsx +4 -0
- package/src/modules/warranty_claims/backend/warranty_claims/registrations/page.tsx +4 -0
- package/src/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.tsx +4 -0
- package/src/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.tsx +4 -0
- package/src/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.tsx +4 -0
- package/src/modules/wms/api/warehouseSearch.ts +23 -0
- package/src/modules/wms/api/warehouses/route.ts +13 -9
- package/src/modules/wms/api/zones/route.ts +16 -0
- package/src/modules/wms/commands/configuration.ts +159 -10
- package/src/modules/wms/commands/inventory-actions.ts +3 -0
- package/src/modules/wms/commands/shared.ts +17 -0
- package/src/modules/wms/components/backend/WarehouseEditDialog.tsx +216 -0
- package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +95 -141
- package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +2 -0
- package/src/modules/wms/components/backend/WmsLotsListPage.tsx +2 -0
- package/src/modules/wms/components/backend/inventoryMutationLoaders.ts +36 -20
- package/src/modules/wms/components/backend/warehouseFormOptions.ts +72 -0
- package/src/modules/wms/i18n/de.json +2 -0
- package/src/modules/wms/i18n/en.json +2 -0
- package/src/modules/wms/i18n/es.json +2 -0
- package/src/modules/wms/i18n/ko.json +2 -0
- package/src/modules/wms/i18n/pl.json +2 -0
- package/src/modules/workflows/backend/definitions/page.tsx +4 -1
- package/src/modules/workflows/backend/events/page.tsx +4 -1
- package/src/modules/workflows/backend/instances/page.tsx +4 -1
- package/src/modules/workflows/backend/tasks/page.tsx +4 -1
- package/src/modules/workflows/lib/activity-executor.ts +9 -0
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import type { AuthContext } from '@open-mercato/shared/lib/auth/server'
|
|
3
|
+
import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
|
|
4
|
+
import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
5
|
+
import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
|
|
6
|
+
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
7
|
+
import { Attachment, AttachmentPartition } from '../data/entities'
|
|
8
|
+
import { assertAttachmentScopeInvariant, checkAttachmentAccess } from './access'
|
|
9
|
+
import type { StorageDriverFactory } from './drivers'
|
|
10
|
+
import { buildAttachmentFileUrl } from './imageUrls'
|
|
11
|
+
import {
|
|
12
|
+
isScopedAttachmentUploadError,
|
|
13
|
+
type ScopedAttachmentUploadErrorCode,
|
|
14
|
+
type ScopedAttachmentUploadService,
|
|
15
|
+
} from './scoped-upload-service'
|
|
16
|
+
import { readAttachmentMetadata, type AttachmentAssignment } from './metadata'
|
|
17
|
+
import {
|
|
18
|
+
buildAttachmentContentDisposition,
|
|
19
|
+
canRenderInlineAttachment,
|
|
20
|
+
hasDangerousExecutableExtension,
|
|
21
|
+
} from './security'
|
|
22
|
+
import {
|
|
23
|
+
isMultipartRequestWithinUploadLimit,
|
|
24
|
+
resolveAttachmentMaxBytes,
|
|
25
|
+
resolveAttachmentMultipartMaxBytes,
|
|
26
|
+
} from './upload-limits'
|
|
27
|
+
|
|
28
|
+
const logger = createLogger('attachments').child({ component: 'attachment-service' })
|
|
29
|
+
|
|
30
|
+
type AttachmentErrorMessage = {
|
|
31
|
+
key: string
|
|
32
|
+
fallback: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The scoped upload service reports failures as machine codes. Each maps to the
|
|
37
|
+
* translation key the public attachment route uses for the same condition, and
|
|
38
|
+
* the key is resolved server-side before it reaches the response body — clients
|
|
39
|
+
* render the `error` field verbatim, so handing them a raw key would surface
|
|
40
|
+
* `attachments.errors.quotaExceeded` as the user-facing message.
|
|
41
|
+
*/
|
|
42
|
+
const SCOPED_UPLOAD_ERROR_MESSAGES: Record<ScopedAttachmentUploadErrorCode, AttachmentErrorMessage> = {
|
|
43
|
+
dangerous_executable: {
|
|
44
|
+
key: 'attachments.errors.dangerousExecutable',
|
|
45
|
+
fallback: 'Executable file types are not allowed as attachments.',
|
|
46
|
+
},
|
|
47
|
+
max_upload_size: {
|
|
48
|
+
key: 'attachments.errors.maxUploadSize',
|
|
49
|
+
fallback: 'Attachment exceeds the maximum upload size.',
|
|
50
|
+
},
|
|
51
|
+
active_content: {
|
|
52
|
+
key: 'attachments.errors.activeContentBlocked',
|
|
53
|
+
fallback: 'Active content uploads are not allowed.',
|
|
54
|
+
},
|
|
55
|
+
partition_unavailable: {
|
|
56
|
+
key: 'attachments.errors.partitionUnavailable',
|
|
57
|
+
fallback: 'Attachment partition is not available for this scope.',
|
|
58
|
+
},
|
|
59
|
+
quota_exceeded: {
|
|
60
|
+
key: 'attachments.errors.quotaExceeded',
|
|
61
|
+
fallback: 'Attachment storage quota exceeded for this tenant.',
|
|
62
|
+
},
|
|
63
|
+
quota_target_exists: {
|
|
64
|
+
key: 'attachments.errors.storagePathExists',
|
|
65
|
+
fallback: 'The target storage path already exists.',
|
|
66
|
+
},
|
|
67
|
+
quota_unavailable: {
|
|
68
|
+
key: 'attachments.errors.quotaUnavailable',
|
|
69
|
+
fallback: 'Storage quota accounting is unavailable.',
|
|
70
|
+
},
|
|
71
|
+
quota_recovery_unsupported: {
|
|
72
|
+
key: 'attachments.errors.quotaRecoveryUnsupported',
|
|
73
|
+
fallback: 'Storage driver cannot participate in quota recovery.',
|
|
74
|
+
},
|
|
75
|
+
storage_failed: {
|
|
76
|
+
key: 'attachments.errors.storageFailed',
|
|
77
|
+
fallback: 'Failed to store the attachment file.',
|
|
78
|
+
},
|
|
79
|
+
persistence_failed: {
|
|
80
|
+
key: 'attachments.errors.persistenceFailed',
|
|
81
|
+
fallback: 'Failed to persist attachment.',
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const UPLOAD_FAILED_MESSAGE: AttachmentErrorMessage = {
|
|
86
|
+
key: 'attachments.errors.uploadFailed',
|
|
87
|
+
fallback: 'Attachment upload failed.',
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const UPLOAD_SERVICE_UNAVAILABLE_MESSAGE: AttachmentErrorMessage = {
|
|
91
|
+
key: 'attachments.errors.uploadServiceUnavailable',
|
|
92
|
+
fallback: 'The attachment upload service is not available.',
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function translateAttachmentError(message: AttachmentErrorMessage): Promise<string> {
|
|
96
|
+
const { t } = await resolveTranslations()
|
|
97
|
+
return t(message.key, message.fallback)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export type AttachmentOwner = {
|
|
101
|
+
entityId: string
|
|
102
|
+
recordId: string
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export type CreateScopedAttachmentInput = AttachmentOwner & {
|
|
106
|
+
tenantId: string
|
|
107
|
+
organizationId: string
|
|
108
|
+
partitionCode: string
|
|
109
|
+
fileName: string
|
|
110
|
+
declaredMimeType?: string | null
|
|
111
|
+
buffer: Buffer
|
|
112
|
+
assignments?: AttachmentAssignment[]
|
|
113
|
+
/**
|
|
114
|
+
* Persists a module-owned link inside the same transaction as the Attachment
|
|
115
|
+
* row. The callback receives only the generated id, never an Attachment
|
|
116
|
+
* entity or storage implementation.
|
|
117
|
+
*/
|
|
118
|
+
persistLink?: (tx: EntityManager, attachmentId: string) => Promise<void> | void
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export type CreatedScopedAttachment = {
|
|
122
|
+
id: string
|
|
123
|
+
url: string
|
|
124
|
+
fileName: string
|
|
125
|
+
mimeType: string
|
|
126
|
+
fileSize: number
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export type ReadScopedAttachmentInput = {
|
|
130
|
+
attachmentId: string
|
|
131
|
+
auth: NonNullable<AuthContext>
|
|
132
|
+
expectedOwner: AttachmentOwner
|
|
133
|
+
expectedAssignment?: AttachmentAssignment
|
|
134
|
+
expectedPartitionCode?: string
|
|
135
|
+
requirePrivatePartition?: boolean
|
|
136
|
+
forceDownload?: boolean
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export type ReadScopedAttachmentResult = {
|
|
140
|
+
buffer: Buffer
|
|
141
|
+
contentType: string
|
|
142
|
+
contentDisposition: string
|
|
143
|
+
fileName: string
|
|
144
|
+
mimeType: string
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export type ReleaseScopedAttachmentInput = {
|
|
148
|
+
attachmentId: string
|
|
149
|
+
tenantId: string
|
|
150
|
+
organizationId: string
|
|
151
|
+
expectedOwner: AttachmentOwner
|
|
152
|
+
/**
|
|
153
|
+
* Required: releasing an attachment deletes the row *and* the provider bytes,
|
|
154
|
+
* so the caller must name the one assignment it owns. The release only
|
|
155
|
+
* proceeds when that assignment is the attachment's sole reference.
|
|
156
|
+
*/
|
|
157
|
+
expectedAssignment: AttachmentAssignment
|
|
158
|
+
expectedPartitionCode?: string
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export type AttachmentProviderCleanup = () => Promise<void>
|
|
162
|
+
|
|
163
|
+
export interface AttachmentService {
|
|
164
|
+
validateUpload(input: {
|
|
165
|
+
contentLength?: string | null
|
|
166
|
+
fileName?: string
|
|
167
|
+
fileSize?: number
|
|
168
|
+
}): void
|
|
169
|
+
readUploadForm?(request: Request): Promise<FormData>
|
|
170
|
+
createScoped(input: CreateScopedAttachmentInput): Promise<CreatedScopedAttachment>
|
|
171
|
+
readScoped(input: ReadScopedAttachmentInput): Promise<ReadScopedAttachmentResult>
|
|
172
|
+
releaseScoped?(
|
|
173
|
+
input: ReleaseScopedAttachmentInput,
|
|
174
|
+
options?: { em?: EntityManager; flush?: boolean },
|
|
175
|
+
): Promise<AttachmentProviderCleanup | void>
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function readRequestBodyWithinLimit(request: Request, maxBytes: number): Promise<Uint8Array> {
|
|
179
|
+
const reader = request.body?.getReader()
|
|
180
|
+
if (!reader) throw new CrudHttpError(400, { error: 'File is required' })
|
|
181
|
+
const chunks: Uint8Array[] = []
|
|
182
|
+
let totalBytes = 0
|
|
183
|
+
try {
|
|
184
|
+
while (true) {
|
|
185
|
+
const { done, value } = await reader.read()
|
|
186
|
+
if (done) break
|
|
187
|
+
totalBytes += value.byteLength
|
|
188
|
+
if (totalBytes > maxBytes) {
|
|
189
|
+
await reader.cancel()
|
|
190
|
+
throw new CrudHttpError(413, { error: 'Attachment exceeds the maximum upload size.' })
|
|
191
|
+
}
|
|
192
|
+
chunks.push(value)
|
|
193
|
+
}
|
|
194
|
+
} finally {
|
|
195
|
+
reader.releaseLock()
|
|
196
|
+
}
|
|
197
|
+
const body = new Uint8Array(totalBytes)
|
|
198
|
+
let offset = 0
|
|
199
|
+
for (const chunk of chunks) {
|
|
200
|
+
body.set(chunk, offset)
|
|
201
|
+
offset += chunk.byteLength
|
|
202
|
+
}
|
|
203
|
+
return body
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
function assignmentMatches(candidate: AttachmentAssignment, expected: AttachmentAssignment): boolean {
|
|
208
|
+
return candidate.type === expected.type && candidate.id === expected.id
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function partitionMatchesScope(
|
|
212
|
+
partition: AttachmentPartition,
|
|
213
|
+
tenantId: string | null | undefined,
|
|
214
|
+
organizationId: string | null | undefined,
|
|
215
|
+
): boolean {
|
|
216
|
+
const partitionTenantId = partition.tenantId ?? null
|
|
217
|
+
const partitionOrganizationId = partition.organizationId ?? null
|
|
218
|
+
if (partitionTenantId === null && partitionOrganizationId === null) return true
|
|
219
|
+
if (partitionTenantId === null || partitionOrganizationId === null) return false
|
|
220
|
+
return partitionTenantId === tenantId && partitionOrganizationId === organizationId
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export class DefaultAttachmentService implements AttachmentService {
|
|
224
|
+
/**
|
|
225
|
+
* The scoped upload service is supplied as a *resolver*, not an instance:
|
|
226
|
+
* resolving it eagerly would drag its own dependencies (notably `dataEngine`)
|
|
227
|
+
* into every container that merely constructs an `attachmentService`, even
|
|
228
|
+
* one that never uploads. `createScoped` requires it — module uploads must
|
|
229
|
+
* share the one reservation ledger rather than run a parallel quota
|
|
230
|
+
* mechanism — so its absence surfaces there, at the call that needs it.
|
|
231
|
+
*/
|
|
232
|
+
constructor(
|
|
233
|
+
private readonly em: EntityManager,
|
|
234
|
+
private readonly storageDriverFactory: StorageDriverFactory,
|
|
235
|
+
private readonly resolveScopedUploadService?: (() => ScopedAttachmentUploadService | null) | null,
|
|
236
|
+
) {}
|
|
237
|
+
|
|
238
|
+
validateUpload(input: {
|
|
239
|
+
contentLength?: string | null
|
|
240
|
+
fileName?: string
|
|
241
|
+
fileSize?: number
|
|
242
|
+
}): void {
|
|
243
|
+
if (!isMultipartRequestWithinUploadLimit(input.contentLength ?? null)) {
|
|
244
|
+
throw new CrudHttpError(413, { error: 'Attachment exceeds the maximum upload size.' })
|
|
245
|
+
}
|
|
246
|
+
if (input.fileName && hasDangerousExecutableExtension(input.fileName)) {
|
|
247
|
+
throw new CrudHttpError(400, { error: 'Executable file types are not allowed as attachments.' })
|
|
248
|
+
}
|
|
249
|
+
if (typeof input.fileSize === 'number' && input.fileSize > resolveAttachmentMaxBytes(null)) {
|
|
250
|
+
throw new CrudHttpError(413, { error: 'Attachment exceeds the maximum upload size.' })
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async readUploadForm(request: Request): Promise<FormData> {
|
|
255
|
+
this.validateUpload({ contentLength: request.headers.get('content-length') })
|
|
256
|
+
const contentType = request.headers.get('content-type') ?? ''
|
|
257
|
+
if (!contentType.toLowerCase().includes('multipart/form-data')) {
|
|
258
|
+
throw new CrudHttpError(400, { error: 'Expected multipart/form-data' })
|
|
259
|
+
}
|
|
260
|
+
const body = await readRequestBodyWithinLimit(request, resolveAttachmentMultipartMaxBytes())
|
|
261
|
+
const responseBody = body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength) as ArrayBuffer
|
|
262
|
+
try {
|
|
263
|
+
return await new Response(responseBody, { headers: { 'content-type': contentType } }).formData()
|
|
264
|
+
} catch {
|
|
265
|
+
throw new CrudHttpError(400, { error: 'Invalid multipart/form-data' })
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async createScoped(input: CreateScopedAttachmentInput): Promise<CreatedScopedAttachment> {
|
|
270
|
+
assertAttachmentScopeInvariant(input)
|
|
271
|
+
this.validateUpload({ fileName: input.fileName, fileSize: input.buffer.length })
|
|
272
|
+
|
|
273
|
+
// Delegate to the platform's scoped upload service rather than repeating its
|
|
274
|
+
// work. It owns the fenced quota lease (reserve → storing → stored →
|
|
275
|
+
// complete) that the recovery worker reconciles, writes to the provider
|
|
276
|
+
// outside the database transaction, and emits the attachment CRUD side
|
|
277
|
+
// effects. The previous implementation here ran a *second*, independent
|
|
278
|
+
// quota mechanism on a different advisory-lock key that counted only
|
|
279
|
+
// committed rows, so it could not see an in-flight reservation from the
|
|
280
|
+
// public attachment route and the two paths could jointly exceed a tenant's
|
|
281
|
+
// quota — and it wrote to storage inside the transaction, so a crash before
|
|
282
|
+
// commit left bytes nothing accounted for.
|
|
283
|
+
let uploadService: ScopedAttachmentUploadService | null = null
|
|
284
|
+
try {
|
|
285
|
+
uploadService = this.resolveScopedUploadService?.() ?? null
|
|
286
|
+
} catch (error) {
|
|
287
|
+
logger.error('Scoped attachment upload service could not be resolved', { err: error })
|
|
288
|
+
}
|
|
289
|
+
if (!uploadService) {
|
|
290
|
+
throw new CrudHttpError(500, {
|
|
291
|
+
error: await translateAttachmentError(UPLOAD_SERVICE_UNAVAILABLE_MESSAGE),
|
|
292
|
+
})
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
let attachment: Attachment
|
|
296
|
+
try {
|
|
297
|
+
attachment = await uploadService.upload({
|
|
298
|
+
tenantId: input.tenantId,
|
|
299
|
+
organizationId: input.organizationId,
|
|
300
|
+
entityId: input.entityId,
|
|
301
|
+
recordId: input.recordId,
|
|
302
|
+
fileName: input.fileName,
|
|
303
|
+
buffer: input.buffer,
|
|
304
|
+
declaredMimeType: input.declaredMimeType ?? null,
|
|
305
|
+
assignments: input.assignments,
|
|
306
|
+
partitionCode: input.partitionCode,
|
|
307
|
+
requirePrivatePartition: true,
|
|
308
|
+
persistLink: input.persistLink,
|
|
309
|
+
})
|
|
310
|
+
} catch (error) {
|
|
311
|
+
if (isScopedAttachmentUploadError(error)) {
|
|
312
|
+
const message = SCOPED_UPLOAD_ERROR_MESSAGES[error.code] ?? UPLOAD_FAILED_MESSAGE
|
|
313
|
+
throw new CrudHttpError(error.status, { error: await translateAttachmentError(message) })
|
|
314
|
+
}
|
|
315
|
+
throw error
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return {
|
|
319
|
+
id: attachment.id,
|
|
320
|
+
url: attachment.url ?? buildAttachmentFileUrl(attachment.id),
|
|
321
|
+
fileName: attachment.fileName,
|
|
322
|
+
mimeType: attachment.mimeType,
|
|
323
|
+
fileSize: attachment.fileSize,
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
async readScoped(input: ReadScopedAttachmentInput): Promise<ReadScopedAttachmentResult> {
|
|
328
|
+
// Scope the lookup at the database boundary so a foreign-tenant row is
|
|
329
|
+
// never materialized, then keep checkAttachmentAccess below as defense in
|
|
330
|
+
// depth. This service only ever stores fully scoped rows, so global rows
|
|
331
|
+
// and super-admin status deliberately do not widen the requested scope —
|
|
332
|
+
// a super admin reads another tenant's attachment by switching scope, not
|
|
333
|
+
// by bypassing the filter.
|
|
334
|
+
const attachment = await findOneWithDecryption(
|
|
335
|
+
this.em,
|
|
336
|
+
Attachment,
|
|
337
|
+
{
|
|
338
|
+
id: input.attachmentId,
|
|
339
|
+
tenantId: input.auth.tenantId ?? null,
|
|
340
|
+
organizationId: input.auth.orgId ?? null,
|
|
341
|
+
},
|
|
342
|
+
undefined,
|
|
343
|
+
{ tenantId: input.auth.tenantId, organizationId: input.auth.orgId },
|
|
344
|
+
)
|
|
345
|
+
if (!attachment) throw new CrudHttpError(404, { error: 'Attachment not found' })
|
|
346
|
+
const partition = await findOneWithDecryption(
|
|
347
|
+
this.em,
|
|
348
|
+
AttachmentPartition,
|
|
349
|
+
{ code: attachment.partitionCode },
|
|
350
|
+
undefined,
|
|
351
|
+
{ tenantId: input.auth.tenantId, organizationId: input.auth.orgId },
|
|
352
|
+
)
|
|
353
|
+
if (!partition) throw new CrudHttpError(500, { error: 'Attachment partition is not configured' })
|
|
354
|
+
|
|
355
|
+
const access = checkAttachmentAccess(input.auth, attachment, partition, { requireAuthForPublic: true })
|
|
356
|
+
if (!access.ok) {
|
|
357
|
+
throw new CrudHttpError(access.status, { error: access.status === 401 ? 'Unauthorized' : 'Forbidden' })
|
|
358
|
+
}
|
|
359
|
+
if (!partitionMatchesScope(partition, input.auth.tenantId, input.auth.orgId)) {
|
|
360
|
+
throw new CrudHttpError(403, { error: 'Attachment partition is not accessible for this scope' })
|
|
361
|
+
}
|
|
362
|
+
if (input.requirePrivatePartition && partition.isPublic) {
|
|
363
|
+
throw new CrudHttpError(403, { error: 'Attachment partition is not accessible for this resource' })
|
|
364
|
+
}
|
|
365
|
+
if (input.expectedPartitionCode && attachment.partitionCode !== input.expectedPartitionCode) {
|
|
366
|
+
throw new CrudHttpError(404, { error: 'Attachment not found' })
|
|
367
|
+
}
|
|
368
|
+
if (
|
|
369
|
+
attachment.entityId !== input.expectedOwner.entityId ||
|
|
370
|
+
attachment.recordId !== input.expectedOwner.recordId
|
|
371
|
+
) {
|
|
372
|
+
throw new CrudHttpError(404, { error: 'Attachment not found' })
|
|
373
|
+
}
|
|
374
|
+
if (input.expectedAssignment) {
|
|
375
|
+
const assignments = readAttachmentMetadata(attachment.storageMetadata).assignments ?? []
|
|
376
|
+
if (!assignments.some((candidate) => assignmentMatches(candidate, input.expectedAssignment!))) {
|
|
377
|
+
throw new CrudHttpError(404, { error: 'Attachment not found' })
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const driver = await this.storageDriverFactory.resolveForPartition(attachment.partitionCode, {
|
|
382
|
+
tenantId: attachment.tenantId ?? '',
|
|
383
|
+
organizationId: attachment.organizationId ?? '',
|
|
384
|
+
})
|
|
385
|
+
let result: Awaited<ReturnType<typeof driver.read>>
|
|
386
|
+
try {
|
|
387
|
+
result = await driver.read(attachment.partitionCode, attachment.storagePath)
|
|
388
|
+
} catch {
|
|
389
|
+
throw new CrudHttpError(404, { error: 'File not available' })
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const mimeType = attachment.mimeType || 'application/octet-stream'
|
|
393
|
+
const renderInline = !input.forceDownload && canRenderInlineAttachment(mimeType)
|
|
394
|
+
return {
|
|
395
|
+
buffer: result.buffer,
|
|
396
|
+
contentType: renderInline ? result.contentType ?? mimeType : 'application/octet-stream',
|
|
397
|
+
contentDisposition: buildAttachmentContentDisposition(
|
|
398
|
+
attachment.fileName,
|
|
399
|
+
renderInline ? 'inline' : 'attachment',
|
|
400
|
+
),
|
|
401
|
+
fileName: attachment.fileName,
|
|
402
|
+
mimeType,
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
async releaseScoped(
|
|
407
|
+
input: ReleaseScopedAttachmentInput,
|
|
408
|
+
options: { em?: EntityManager; flush?: boolean } = {},
|
|
409
|
+
): Promise<AttachmentProviderCleanup | void> {
|
|
410
|
+
const em = options.em ?? this.em
|
|
411
|
+
// The type makes `expectedAssignment` mandatory, but this service is handed
|
|
412
|
+
// out through untyped DI resolution and consumed through structural ports in
|
|
413
|
+
// other packages, so the shared-reference guard is enforced at runtime too:
|
|
414
|
+
// without it a caller could destroy an attachment other records still link.
|
|
415
|
+
const expectedAssignment = input.expectedAssignment
|
|
416
|
+
if (!expectedAssignment) {
|
|
417
|
+
throw new CrudHttpError(500, {
|
|
418
|
+
error: 'Attachment release requires the expected assignment of the releasing record',
|
|
419
|
+
})
|
|
420
|
+
}
|
|
421
|
+
const isInTransaction = (em as { isInTransaction?: () => boolean }).isInTransaction
|
|
422
|
+
if (
|
|
423
|
+
options.flush !== false
|
|
424
|
+
&& typeof isInTransaction === 'function'
|
|
425
|
+
&& isInTransaction.call(em)
|
|
426
|
+
) {
|
|
427
|
+
throw new CrudHttpError(500, {
|
|
428
|
+
error: 'Attachment release inside an ambient transaction requires flush: false and deferred provider cleanup',
|
|
429
|
+
})
|
|
430
|
+
}
|
|
431
|
+
const scope = { tenantId: input.tenantId, organizationId: input.organizationId }
|
|
432
|
+
const attachment = await findOneWithDecryption(
|
|
433
|
+
em,
|
|
434
|
+
Attachment,
|
|
435
|
+
{
|
|
436
|
+
id: input.attachmentId,
|
|
437
|
+
tenantId: input.tenantId,
|
|
438
|
+
organizationId: input.organizationId,
|
|
439
|
+
},
|
|
440
|
+
undefined,
|
|
441
|
+
scope,
|
|
442
|
+
)
|
|
443
|
+
if (!attachment) throw new CrudHttpError(404, { error: 'Attachment not found' })
|
|
444
|
+
if (
|
|
445
|
+
attachment.entityId !== input.expectedOwner.entityId
|
|
446
|
+
|| attachment.recordId !== input.expectedOwner.recordId
|
|
447
|
+
|| (input.expectedPartitionCode && attachment.partitionCode !== input.expectedPartitionCode)
|
|
448
|
+
) {
|
|
449
|
+
throw new CrudHttpError(404, { error: 'Attachment not found' })
|
|
450
|
+
}
|
|
451
|
+
const assignments = readAttachmentMetadata(attachment.storageMetadata).assignments ?? []
|
|
452
|
+
if (!assignments.some((candidate) => assignmentMatches(candidate, expectedAssignment))) {
|
|
453
|
+
throw new CrudHttpError(409, { error: 'Attachment is still referenced by another record' })
|
|
454
|
+
}
|
|
455
|
+
if (assignments.some((candidate) => !assignmentMatches(candidate, expectedAssignment))) {
|
|
456
|
+
throw new CrudHttpError(409, { error: 'Attachment is still referenced by another record' })
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const driver = await this.storageDriverFactory.resolveForPartition(attachment.partitionCode, scope)
|
|
460
|
+
const deleteProviderBytes = () => driver.delete(attachment.partitionCode, attachment.storagePath)
|
|
461
|
+
em.remove(attachment)
|
|
462
|
+
if (options.flush === false) {
|
|
463
|
+
return deleteProviderBytes
|
|
464
|
+
}
|
|
465
|
+
await em.flush()
|
|
466
|
+
await deleteProviderBytes()
|
|
467
|
+
}
|
|
468
|
+
}
|
|
@@ -2,6 +2,7 @@ import { randomUUID } from 'node:crypto'
|
|
|
2
2
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
3
3
|
import type { DataEngine } from '@open-mercato/shared/lib/data/engine'
|
|
4
4
|
import { emitCrudSideEffects } from '@open-mercato/shared/lib/commands/helpers'
|
|
5
|
+
import { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'
|
|
5
6
|
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
6
7
|
import { Attachment, AttachmentPartition } from '../data/entities'
|
|
7
8
|
import { attachmentCrudEvents, attachmentCrudIndexer } from './crud'
|
|
@@ -40,7 +41,16 @@ export type ScopedAttachmentUploadErrorCode =
|
|
|
40
41
|
| 'storage_failed'
|
|
41
42
|
| 'persistence_failed'
|
|
42
43
|
|
|
44
|
+
// Use Symbol.for so the marker survives module duplication across bundle
|
|
45
|
+
// boundaries. The production build emits this module into several server
|
|
46
|
+
// chunks, so a consumer's `instanceof` compares against a different copy of the
|
|
47
|
+
// class than the DI-resolved service threw from: the check silently fails, the
|
|
48
|
+
// error escapes the caller's catch, and a deliberate 400/413 surfaces as a 500.
|
|
49
|
+
const SCOPED_ATTACHMENT_UPLOAD_ERROR_MARKER = Symbol.for('@open-mercato/ScopedAttachmentUploadError')
|
|
50
|
+
|
|
43
51
|
export class ScopedAttachmentUploadError extends Error {
|
|
52
|
+
readonly [SCOPED_ATTACHMENT_UPLOAD_ERROR_MARKER] = true
|
|
53
|
+
|
|
44
54
|
constructor(
|
|
45
55
|
public readonly code: ScopedAttachmentUploadErrorCode,
|
|
46
56
|
public readonly status: number,
|
|
@@ -50,6 +60,17 @@ export class ScopedAttachmentUploadError extends Error {
|
|
|
50
60
|
}
|
|
51
61
|
}
|
|
52
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Bundle-safe check for `ScopedAttachmentUploadError`. Prefer this over
|
|
65
|
+
* `instanceof` at every call site — the class is duplicated across server
|
|
66
|
+
* chunks, so `instanceof` is only reliable inside this module.
|
|
67
|
+
*/
|
|
68
|
+
export function isScopedAttachmentUploadError(error: unknown): error is ScopedAttachmentUploadError {
|
|
69
|
+
return Boolean(error)
|
|
70
|
+
&& typeof error === 'object'
|
|
71
|
+
&& (error as Record<symbol, unknown>)[SCOPED_ATTACHMENT_UPLOAD_ERROR_MARKER] === true
|
|
72
|
+
}
|
|
73
|
+
|
|
53
74
|
export type ScopedAttachmentUploadInput = {
|
|
54
75
|
tenantId: string
|
|
55
76
|
organizationId: string
|
|
@@ -62,6 +83,21 @@ export type ScopedAttachmentUploadInput = {
|
|
|
62
83
|
assignments?: AttachmentAssignment[]
|
|
63
84
|
partitionCode?: string | null
|
|
64
85
|
maxBytes?: number
|
|
86
|
+
/**
|
|
87
|
+
* Reject a partition flagged public, so a module-owned upload (documents,
|
|
88
|
+
* warranty claims) never lands where an anonymous reader can reach it. The
|
|
89
|
+
* tenant/organization half of that guarantee is not this flag's job: the
|
|
90
|
+
* partition lookup below already matches only a global partition or one owned
|
|
91
|
+
* by this tenant and organization, whether or not the flag is set.
|
|
92
|
+
*/
|
|
93
|
+
requirePrivatePartition?: boolean
|
|
94
|
+
/**
|
|
95
|
+
* Persists a module-owned link row inside the same transaction as the
|
|
96
|
+
* Attachment, so a link failure cannot leave a committed orphan attachment.
|
|
97
|
+
* The callback receives only the generated id, never the entity or the
|
|
98
|
+
* storage implementation.
|
|
99
|
+
*/
|
|
100
|
+
persistLink?: (tx: EntityManager, attachmentId: string) => Promise<void> | void
|
|
65
101
|
}
|
|
66
102
|
|
|
67
103
|
type QuotaRecoveryScheduler = (
|
|
@@ -102,6 +138,9 @@ export class ScopedAttachmentUploadService {
|
|
|
102
138
|
],
|
|
103
139
|
})
|
|
104
140
|
if (!partition) throw new ScopedAttachmentUploadError('partition_unavailable', 400)
|
|
141
|
+
if (input.requirePrivatePartition && partition.isPublic) {
|
|
142
|
+
throw new ScopedAttachmentUploadError('partition_unavailable', 403)
|
|
143
|
+
}
|
|
105
144
|
|
|
106
145
|
const driver = await storageDriverFactory.resolveForPartition(partition.code, {
|
|
107
146
|
tenantId: input.tenantId,
|
|
@@ -210,11 +249,18 @@ export class ScopedAttachmentUploadService {
|
|
|
210
249
|
})
|
|
211
250
|
assertAttachmentScopeInvariant({ tenantId: attachment.tenantId, organizationId: attachment.organizationId })
|
|
212
251
|
await tx.persist(attachment).flush()
|
|
252
|
+
await input.persistLink?.(tx, attachmentId)
|
|
213
253
|
await attachmentQuotaService.completeAttachment(reservation.id, reservation.leaseToken, tx)
|
|
214
254
|
})
|
|
215
255
|
} catch (error) {
|
|
216
256
|
await this.compensateStorage(driver, partition.code, storedPath, reservation)
|
|
217
257
|
logger.error('Scoped attachment persistence failed', { err: error })
|
|
258
|
+
// `persistLink` is where callers run their own authorization (the
|
|
259
|
+
// documents module re-checks the edit capability inside this
|
|
260
|
+
// transaction), so a deliberate HTTP error from it must reach the route
|
|
261
|
+
// with its own status. Flattening it to 500 turns a documented 403 into
|
|
262
|
+
// an apparent server fault.
|
|
263
|
+
if (isCrudHttpError(error)) throw error
|
|
218
264
|
throw new ScopedAttachmentUploadError('persistence_failed', 500)
|
|
219
265
|
}
|
|
220
266
|
|
|
@@ -39,11 +39,15 @@ export function resolveAttachmentMaxBytes(fieldMaxAttachmentSizeMb?: number | nu
|
|
|
39
39
|
return Math.min(defaultMaxBytes, Math.floor(fieldMaxAttachmentSizeMb * 1024 * 1024))
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
export function resolveAttachmentMultipartMaxBytes(): number {
|
|
43
|
+
return resolveDefaultAttachmentMaxUploadBytes() + MULTIPART_CONTENT_LENGTH_OVERHEAD_BYTES
|
|
44
|
+
}
|
|
45
|
+
|
|
42
46
|
export function isMultipartRequestWithinUploadLimit(contentLengthHeader: string | null): boolean {
|
|
43
47
|
if (!contentLengthHeader) return true
|
|
44
48
|
const contentLength = Number(contentLengthHeader)
|
|
45
|
-
if (!Number.
|
|
46
|
-
return contentLength <= (
|
|
49
|
+
if (!Number.isSafeInteger(contentLength) || contentLength <= 0) return false
|
|
50
|
+
return contentLength <= resolveAttachmentMultipartMaxBytes()
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
export class MultipartUploadLimitError extends Error {
|
|
@@ -21,6 +21,7 @@ type ActionLogResponse = {
|
|
|
21
21
|
pageSize: number
|
|
22
22
|
total: number
|
|
23
23
|
totalPages: number
|
|
24
|
+
totalIsCapped?: boolean
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
type AccessLogResponse = {
|
|
@@ -30,6 +31,7 @@ type AccessLogResponse = {
|
|
|
30
31
|
pageSize: number
|
|
31
32
|
total: number
|
|
32
33
|
totalPages: number
|
|
34
|
+
totalIsCapped?: boolean
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
type TabOption = 'actions' | 'access'
|
|
@@ -48,11 +50,13 @@ export default function AuditLogsPage() {
|
|
|
48
50
|
const [actionsPageSize, setActionsPageSize] = React.useState(DEFAULT_PAGE_SIZE)
|
|
49
51
|
const [actionsTotal, setActionsTotal] = React.useState(0)
|
|
50
52
|
const [actionsTotalPages, setActionsTotalPages] = React.useState(1)
|
|
53
|
+
const [actionsTotalIsCapped, setActionsTotalIsCapped] = React.useState(false)
|
|
51
54
|
const actionsPageSizeRef = React.useRef(DEFAULT_PAGE_SIZE)
|
|
52
55
|
const [accessPage, setAccessPage] = React.useState(1)
|
|
53
56
|
const [accessPageSize, setAccessPageSize] = React.useState(DEFAULT_PAGE_SIZE)
|
|
54
57
|
const [accessTotal, setAccessTotal] = React.useState(0)
|
|
55
58
|
const [accessTotalPages, setAccessTotalPages] = React.useState(1)
|
|
59
|
+
const [accessTotalIsCapped, setAccessTotalIsCapped] = React.useState(false)
|
|
56
60
|
const accessPageSizeRef = React.useRef(DEFAULT_PAGE_SIZE)
|
|
57
61
|
|
|
58
62
|
const fetchActions = React.useCallback(async (page: number, pageSize: number) => {
|
|
@@ -95,6 +99,7 @@ export default function AuditLogsPage() {
|
|
|
95
99
|
})
|
|
96
100
|
setActionsTotal(actionsRes.total ?? (actionsRes.items?.length ?? 0))
|
|
97
101
|
setActionsTotalPages(actionsRes.totalPages ?? 1)
|
|
102
|
+
setActionsTotalIsCapped(actionsRes.totalIsCapped === true)
|
|
98
103
|
setAccessLogs(accessRes.items ?? [])
|
|
99
104
|
const resolvedPage = accessRes.page ?? accessPageNum
|
|
100
105
|
const resolvedPageSize = accessRes.pageSize ?? accessPageSizeNum
|
|
@@ -111,6 +116,7 @@ export default function AuditLogsPage() {
|
|
|
111
116
|
})
|
|
112
117
|
setAccessTotal(resolvedTotal)
|
|
113
118
|
setAccessTotalPages(resolvedTotalPages)
|
|
119
|
+
setAccessTotalIsCapped(accessRes.totalIsCapped === true)
|
|
114
120
|
}, [fetchActions, fetchAccess])
|
|
115
121
|
|
|
116
122
|
const loadWithState = React.useCallback(async (
|
|
@@ -210,6 +216,7 @@ export default function AuditLogsPage() {
|
|
|
210
216
|
pageSize: actionsPageSize,
|
|
211
217
|
total: actionsTotal,
|
|
212
218
|
totalPages: actionsTotalPages,
|
|
219
|
+
totalIsCapped: actionsTotalIsCapped,
|
|
213
220
|
onPageChange: handleActionsPageChange,
|
|
214
221
|
}}
|
|
215
222
|
/>
|
|
@@ -225,6 +232,7 @@ export default function AuditLogsPage() {
|
|
|
225
232
|
pageSize: accessPageSize,
|
|
226
233
|
total: accessTotal,
|
|
227
234
|
totalPages: accessTotalPages,
|
|
235
|
+
totalIsCapped: accessTotalIsCapped,
|
|
228
236
|
onPageChange: handleAccessPageChange,
|
|
229
237
|
}}
|
|
230
238
|
/>
|