@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
|
@@ -94,12 +94,28 @@ function applyExportCounters(batch: ExportBatch): SyncCounterDelta {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
// Adapter batches can legitimately outlast the stale-job sweep window (slow upstream
|
|
97
|
-
// APIs), so the engine must heartbeat while a batch is still being produced.
|
|
97
|
+
// APIs), so the engine must heartbeat while a batch is still being produced. The same
|
|
98
|
+
// tick also polls cancellation, so a cancel lands within one interval instead of waiting
|
|
99
|
+
// out the batch — sharing this timer rather than adding a second one that would double
|
|
100
|
+
// the per-interval round-trips for the whole life of a run.
|
|
98
101
|
const HEARTBEAT_TICK_MS = (STALE_JOB_TIMEOUT_SECONDS * 1000) / 4
|
|
99
102
|
|
|
100
103
|
// Runs `tick` on an interval only while the source iterator is pending, so heartbeats
|
|
101
104
|
// stop the moment the producer dies and genuinely stale jobs still get swept. The outer
|
|
102
105
|
// finally closes the adapter generator on early exits (cancellation, ownership conflict).
|
|
106
|
+
// Our own abort, as opposed to a failure that merely coincided with one. Adapters are told to
|
|
107
|
+
// return rather than throw, but `signal.throwIfAborted()` and an aborted `fetch` both surface as
|
|
108
|
+
// this, and either is a cancellation rather than a fault.
|
|
109
|
+
//
|
|
110
|
+
// Matched structurally on `name` rather than with `instanceof Error`, because those two throw a
|
|
111
|
+
// `DOMException`, and whether that inherits from `Error` depends on the runtime — it does under
|
|
112
|
+
// bare Node 24 and does NOT under the jest environment this is tested in. An `instanceof` test
|
|
113
|
+
// therefore passes or fails on where the code runs, which is not something cancellation should
|
|
114
|
+
// depend on.
|
|
115
|
+
function isAbortError(error: unknown): boolean {
|
|
116
|
+
return typeof error === 'object' && error !== null && (error as { name?: unknown }).name === 'AbortError'
|
|
117
|
+
}
|
|
118
|
+
|
|
103
119
|
async function* withHeartbeat<T>(source: AsyncIterable<T>, tick: () => void, intervalMs: number): AsyncGenerator<T, void, undefined> {
|
|
104
120
|
const iterator = source[Symbol.asyncIterator]()
|
|
105
121
|
try {
|
|
@@ -187,6 +203,32 @@ export function createSyncEngine(deps: EngineDeps) {
|
|
|
187
203
|
}
|
|
188
204
|
}
|
|
189
205
|
|
|
206
|
+
// Rides the heartbeat timer, which is the only thing that runs while the adapter is still
|
|
207
|
+
// producing a batch — the engine's own cancellation check sits in the batch handler and is
|
|
208
|
+
// reached only after a yield. Swallows its own errors because it runs on a timer, where an
|
|
209
|
+
// unhandled rejection is fatal, and stops polling once it has aborted.
|
|
210
|
+
function makeCancellationTick(progressJobId: string | null | undefined, scope: SyncScope, controller: AbortController): () => void {
|
|
211
|
+
if (!progressJobId) return () => {}
|
|
212
|
+
let inFlight = false
|
|
213
|
+
return () => {
|
|
214
|
+
if (inFlight || controller.signal.aborted) return
|
|
215
|
+
inFlight = true
|
|
216
|
+
progressService.isCancellationRequested(progressJobId, scope.tenantId, scope.organizationId)
|
|
217
|
+
.then((cancelled) => {
|
|
218
|
+
if (cancelled) controller.abort()
|
|
219
|
+
})
|
|
220
|
+
.catch((error) => {
|
|
221
|
+
logger.warn('Cancellation poll failed', {
|
|
222
|
+
progressJobId,
|
|
223
|
+
error: error instanceof Error ? error.message : String(error),
|
|
224
|
+
})
|
|
225
|
+
})
|
|
226
|
+
.finally(() => {
|
|
227
|
+
inFlight = false
|
|
228
|
+
})
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
190
232
|
async function refreshCoverageSnapshots(entityTypes: string[] | undefined, scope: SyncScope): Promise<void> {
|
|
191
233
|
if (!entityTypes || entityTypes.length === 0) return
|
|
192
234
|
|
|
@@ -559,10 +601,17 @@ export function createSyncEngine(deps: EngineDeps) {
|
|
|
559
601
|
let processedCount = await seedProcessedCount(run.progressJobId, scope)
|
|
560
602
|
let totalCount: number | null = null
|
|
561
603
|
let committedBatches = activeRun.batchesCompleted ?? 0
|
|
604
|
+
// Whether the last committed batch said the source was exhausted. Distinguishes a stream that
|
|
605
|
+
// drained from one the adapter stopped early — see the post-stream finalize below.
|
|
606
|
+
let streamReportedDone = false
|
|
562
607
|
// Captured while the triggering job's span is still the active one, so
|
|
563
608
|
// every rooted batch trace can link back to it.
|
|
564
609
|
const runTrace = captureTelemetryTrace()
|
|
565
610
|
const spanAttributes = runSpanAttributes(run, providerKey, scope)
|
|
611
|
+
// Declared outside the try because both the catch and the completion path below read it.
|
|
612
|
+
const cancellation = new AbortController()
|
|
613
|
+
const heartbeat = makeHeartbeatTick(run.progressJobId, scope)
|
|
614
|
+
const pollCancellation = makeCancellationTick(run.progressJobId, scope, cancellation)
|
|
566
615
|
|
|
567
616
|
try {
|
|
568
617
|
const streamResult = await forEachBatch(
|
|
@@ -576,8 +625,11 @@ export function createSyncEngine(deps: EngineDeps) {
|
|
|
576
625
|
scope: { organizationId: scope.organizationId, tenantId: scope.tenantId },
|
|
577
626
|
runId: run.id,
|
|
578
627
|
parameters: (run.parameters ?? {}) as RunParameters,
|
|
628
|
+
signal: cancellation.signal,
|
|
579
629
|
}),
|
|
580
|
-
|
|
630
|
+
// `finally` so a synchronous throw from the heartbeat cannot also stop cancellation
|
|
631
|
+
// from being observed for the rest of the run.
|
|
632
|
+
() => { try { heartbeat() } finally { pollCancellation() } },
|
|
581
633
|
HEARTBEAT_TICK_MS,
|
|
582
634
|
),
|
|
583
635
|
{
|
|
@@ -592,7 +644,7 @@ export function createSyncEngine(deps: EngineDeps) {
|
|
|
592
644
|
'data_sync.batch_size': batch.items.length,
|
|
593
645
|
})
|
|
594
646
|
|
|
595
|
-
if (run.progressJobId && await progressService.isCancellationRequested(run.progressJobId, scope.tenantId, scope.organizationId)) {
|
|
647
|
+
if (cancellation.signal.aborted || (run.progressJobId && await progressService.isCancellationRequested(run.progressJobId, scope.tenantId, scope.organizationId))) {
|
|
596
648
|
await finalizeRun(run.id, 'cancelled', scope, undefined, operationalTelemetry)
|
|
597
649
|
return 'stop'
|
|
598
650
|
}
|
|
@@ -621,6 +673,7 @@ export function createSyncEngine(deps: EngineDeps) {
|
|
|
621
673
|
{ expectedBatchesCompleted: committedBatches, persistSharedCursor },
|
|
622
674
|
)
|
|
623
675
|
committedBatches += 1
|
|
676
|
+
streamReportedDone = batch.hasMore === false
|
|
624
677
|
|
|
625
678
|
await updateProgress(run.progressJobId, processedCount, totalCount, scope)
|
|
626
679
|
await refreshCoverageSnapshots(batch.refreshCoverageEntityTypes, scope)
|
|
@@ -657,6 +710,15 @@ export function createSyncEngine(deps: EngineDeps) {
|
|
|
657
710
|
})
|
|
658
711
|
return
|
|
659
712
|
}
|
|
713
|
+
// An adapter that honours the signal may reject instead of returning, so our own abort is
|
|
714
|
+
// a cancellation rather than a fault — and must not leave an `error` entry in the
|
|
715
|
+
// integration log for a run the operator cancelled on purpose. Anything else that merely
|
|
716
|
+
// coincided with the cancel — a rejecting commit, an upstream 500 — is a genuine failure
|
|
717
|
+
// and keeps its log entry, its message, its `failed` status and its failed event.
|
|
718
|
+
if (cancellation.signal.aborted && isAbortError(error)) {
|
|
719
|
+
await finalizeRun(run.id, 'cancelled', scope, undefined, operationalTelemetry)
|
|
720
|
+
return
|
|
721
|
+
}
|
|
660
722
|
const message = error instanceof Error ? error.message : 'Sync import failed'
|
|
661
723
|
await integrationLogService.write(
|
|
662
724
|
{
|
|
@@ -671,6 +733,19 @@ export function createSyncEngine(deps: EngineDeps) {
|
|
|
671
733
|
return
|
|
672
734
|
}
|
|
673
735
|
|
|
736
|
+
// An adapter that honours the signal stops mid-batch and returns WITHOUT yielding, so the
|
|
737
|
+
// batch handler — which owns the only other `cancelled` transition — never runs and the
|
|
738
|
+
// stream reports `completed`.
|
|
739
|
+
//
|
|
740
|
+
// `streamReportedDone` keeps that from swallowing a run that genuinely finished: an adapter
|
|
741
|
+
// that ignores the signal and drains after reporting `hasMore: false` delivered everything it
|
|
742
|
+
// had, even when the cancel landed during the final read. Calling that cancelled would tell
|
|
743
|
+
// the operator a complete sync was partial and leave a finished run resumable.
|
|
744
|
+
if (cancellation.signal.aborted && !streamReportedDone) {
|
|
745
|
+
await finalizeRun(run.id, 'cancelled', scope, undefined, operationalTelemetry)
|
|
746
|
+
return
|
|
747
|
+
}
|
|
748
|
+
|
|
674
749
|
await finalizeRun(run.id, 'completed', scope, undefined, operationalTelemetry)
|
|
675
750
|
},
|
|
676
751
|
|
|
@@ -753,10 +828,17 @@ export function createSyncEngine(deps: EngineDeps) {
|
|
|
753
828
|
const mapping = await resolveMapping(adapter, run.entityType, scope)
|
|
754
829
|
let processedCount = await seedProcessedCount(run.progressJobId, scope)
|
|
755
830
|
let committedBatches = activeRun.batchesCompleted ?? 0
|
|
831
|
+
// Whether the last committed batch said the source was exhausted. Distinguishes a stream that
|
|
832
|
+
// drained from one the adapter stopped early — see the post-stream finalize below.
|
|
833
|
+
let streamReportedDone = false
|
|
756
834
|
// Captured while the triggering job's span is still the active one, so
|
|
757
835
|
// every rooted batch trace can link back to it.
|
|
758
836
|
const runTrace = captureTelemetryTrace()
|
|
759
837
|
const spanAttributes = runSpanAttributes(run, providerKey, scope)
|
|
838
|
+
// Declared outside the try because both the catch and the completion path below read it.
|
|
839
|
+
const cancellation = new AbortController()
|
|
840
|
+
const heartbeat = makeHeartbeatTick(run.progressJobId, scope)
|
|
841
|
+
const pollCancellation = makeCancellationTick(run.progressJobId, scope, cancellation)
|
|
760
842
|
|
|
761
843
|
try {
|
|
762
844
|
const streamResult = await forEachBatch(
|
|
@@ -770,8 +852,11 @@ export function createSyncEngine(deps: EngineDeps) {
|
|
|
770
852
|
scope: { organizationId: scope.organizationId, tenantId: scope.tenantId },
|
|
771
853
|
runId: run.id,
|
|
772
854
|
parameters: (run.parameters ?? {}) as RunParameters,
|
|
855
|
+
signal: cancellation.signal,
|
|
773
856
|
}),
|
|
774
|
-
|
|
857
|
+
// `finally` so a synchronous throw from the heartbeat cannot also stop cancellation
|
|
858
|
+
// from being observed for the rest of the run.
|
|
859
|
+
() => { try { heartbeat() } finally { pollCancellation() } },
|
|
775
860
|
HEARTBEAT_TICK_MS,
|
|
776
861
|
),
|
|
777
862
|
{
|
|
@@ -786,7 +871,7 @@ export function createSyncEngine(deps: EngineDeps) {
|
|
|
786
871
|
'data_sync.batch_size': batch.results.length,
|
|
787
872
|
})
|
|
788
873
|
|
|
789
|
-
if (run.progressJobId && await progressService.isCancellationRequested(run.progressJobId, scope.tenantId, scope.organizationId)) {
|
|
874
|
+
if (cancellation.signal.aborted || (run.progressJobId && await progressService.isCancellationRequested(run.progressJobId, scope.tenantId, scope.organizationId))) {
|
|
790
875
|
await finalizeRun(run.id, 'cancelled', scope, undefined, operationalTelemetry)
|
|
791
876
|
return 'stop'
|
|
792
877
|
}
|
|
@@ -815,6 +900,7 @@ export function createSyncEngine(deps: EngineDeps) {
|
|
|
815
900
|
{ expectedBatchesCompleted: committedBatches, persistSharedCursor },
|
|
816
901
|
)
|
|
817
902
|
committedBatches += 1
|
|
903
|
+
streamReportedDone = batch.hasMore === false
|
|
818
904
|
await updateProgress(run.progressJobId, processedCount, null, scope)
|
|
819
905
|
await logExportItemFailures(run.id, run.integrationId, batch.results, scope)
|
|
820
906
|
|
|
@@ -846,6 +932,15 @@ export function createSyncEngine(deps: EngineDeps) {
|
|
|
846
932
|
})
|
|
847
933
|
return
|
|
848
934
|
}
|
|
935
|
+
// An adapter that honours the signal may reject instead of returning, so our own abort is
|
|
936
|
+
// a cancellation rather than a fault — and must not leave an `error` entry in the
|
|
937
|
+
// integration log for a run the operator cancelled on purpose. Anything else that merely
|
|
938
|
+
// coincided with the cancel — a rejecting commit, an upstream 500 — is a genuine failure
|
|
939
|
+
// and keeps its log entry, its message, its `failed` status and its failed event.
|
|
940
|
+
if (cancellation.signal.aborted && isAbortError(error)) {
|
|
941
|
+
await finalizeRun(run.id, 'cancelled', scope, undefined, operationalTelemetry)
|
|
942
|
+
return
|
|
943
|
+
}
|
|
849
944
|
const message = error instanceof Error ? error.message : 'Sync export failed'
|
|
850
945
|
await integrationLogService.write(
|
|
851
946
|
{
|
|
@@ -860,6 +955,19 @@ export function createSyncEngine(deps: EngineDeps) {
|
|
|
860
955
|
return
|
|
861
956
|
}
|
|
862
957
|
|
|
958
|
+
// An adapter that honours the signal stops mid-batch and returns WITHOUT yielding, so the
|
|
959
|
+
// batch handler — which owns the only other `cancelled` transition — never runs and the
|
|
960
|
+
// stream reports `completed`.
|
|
961
|
+
//
|
|
962
|
+
// `streamReportedDone` keeps that from swallowing a run that genuinely finished: an adapter
|
|
963
|
+
// that ignores the signal and drains after reporting `hasMore: false` delivered everything it
|
|
964
|
+
// had, even when the cancel landed during the final read. Calling that cancelled would tell
|
|
965
|
+
// the operator a complete sync was partial and leave a finished run resumable.
|
|
966
|
+
if (cancellation.signal.aborted && !streamReportedDone) {
|
|
967
|
+
await finalizeRun(run.id, 'cancelled', scope, undefined, operationalTelemetry)
|
|
968
|
+
return
|
|
969
|
+
}
|
|
970
|
+
|
|
863
971
|
await finalizeRun(run.id, 'completed', scope, undefined, operationalTelemetry)
|
|
864
972
|
},
|
|
865
973
|
}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
DATA_SYNC_LOCK_DURATION_MS,
|
|
8
8
|
DATA_SYNC_MAX_STALLED_COUNT,
|
|
9
9
|
} from '../lib/queue-policy'
|
|
10
|
+
import { failAbandonedRun } from '../lib/abandoned-run'
|
|
10
11
|
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
11
12
|
|
|
12
13
|
const logger = createLogger('data_sync').child({ component: 'sync-export' })
|
|
@@ -27,6 +28,9 @@ export const metadata: WorkerMeta = {
|
|
|
27
28
|
concurrency: 5,
|
|
28
29
|
lockDuration: DATA_SYNC_LOCK_DURATION_MS,
|
|
29
30
|
maxStalledCount: DATA_SYNC_MAX_STALLED_COUNT,
|
|
31
|
+
// Declared on the worker, not on the enqueueing queue: the abandonment this reports is a worker
|
|
32
|
+
// restart, and the process that restarts never constructs the producer's queue instance.
|
|
33
|
+
onJobAbandoned: failAbandonedRun,
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
type HandlerContext = JobContext & {
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
DATA_SYNC_LOCK_DURATION_MS,
|
|
8
8
|
DATA_SYNC_MAX_STALLED_COUNT,
|
|
9
9
|
} from '../lib/queue-policy'
|
|
10
|
+
import { failAbandonedRun } from '../lib/abandoned-run'
|
|
10
11
|
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
11
12
|
|
|
12
13
|
const logger = createLogger('data_sync').child({ component: 'sync-import' })
|
|
@@ -27,6 +28,9 @@ export const metadata: WorkerMeta = {
|
|
|
27
28
|
concurrency: 5,
|
|
28
29
|
lockDuration: DATA_SYNC_LOCK_DURATION_MS,
|
|
29
30
|
maxStalledCount: DATA_SYNC_MAX_STALLED_COUNT,
|
|
31
|
+
// Declared on the worker, not on the enqueueing queue: the abandonment this reports is a worker
|
|
32
|
+
// restart, and the process that restarts never constructs the producer's queue instance.
|
|
33
|
+
onJobAbandoned: failAbandonedRun,
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
type HandlerContext = JobContext & {
|
|
@@ -23,6 +23,14 @@ delivery logic** (sender, providers, delivery rows, workers live in the `push_no
|
|
|
23
23
|
— they carry undo snapshots, query-index side effects, and domain events.
|
|
24
24
|
- Treat `push_token` as a secret: **never** include it in list/response field sets. Only
|
|
25
25
|
`push_provider` and `push_token_updated_at` are exposed.
|
|
26
|
+
- Serialize every GET response in **camelCase**, like every other module. The list routes run
|
|
27
|
+
`transformDeviceListItem` (`api/deviceList.ts`) over the query engine's raw projection and the admin
|
|
28
|
+
detail route uses `serializeDeviceDetail` (`api/deviceSerialization.ts`). Both also emit the legacy
|
|
29
|
+
snake_case keys as **deprecated aliases** via `toDeprecatedSnakeCaseAliases`, kept for one minor
|
|
30
|
+
version per `BACKWARD_COMPATIBILITY.md` § 7 and pinned by `TC-DEV-007`; when the bridge is dropped,
|
|
31
|
+
remove the alias spread from those two functions and the deprecated keys from `deviceListItemSchema`
|
|
32
|
+
/ `deviceDetailItemSchema`. Adding a column means adding it to `deviceListFields`, the transform, and
|
|
33
|
+
the schemas. See `.ai/specs/2026-08-24-devices-api-camelcase-responses.md` (#5513).
|
|
26
34
|
- Honor the `pushToken` tri-state on `PUT`: absent key = leave unchanged; explicit `null` = clear
|
|
27
35
|
(revoked OS permission) and bump `push_token_updated_at`. The command uses own-property presence.
|
|
28
36
|
- Keep the list route's CRUD cache tag aligned with the command's `resourceKind`. The list reads
|
|
@@ -89,9 +97,20 @@ write busts both caches (see cache-tag note above).
|
|
|
89
97
|
## ACL
|
|
90
98
|
|
|
91
99
|
`devices.view`, `devices.manage` (self-serve), `devices.admin` (cross-user). Defaults in `setup.ts`:
|
|
92
|
-
`superadmin`/`admin` get `devices
|
|
100
|
+
`superadmin`/`admin` get `devices.*` **plus `auth.users.list`**; `employee` gets `view` + `manage`. Run
|
|
93
101
|
`yarn mercato auth sync-role-acls` after changing `acl.ts`/`setup.ts` to backfill existing tenants.
|
|
94
102
|
|
|
103
|
+
`devices.admin` declares `dependsOn: ['auth.users.list']`: the admin screens name owners by person,
|
|
104
|
+
and the register form's owner picker rejects values that do not resolve to a directory entry, so a
|
|
105
|
+
role holding `devices.admin` without the dependency cannot complete that form. `dependsOn` only
|
|
106
|
+
surfaces the gap in the ACL editor — it does not grant. Run the sync command above after deploying
|
|
107
|
+
an ACL change here.
|
|
108
|
+
|
|
109
|
+
The picker is `allowCustomValues: false`. That rejects free text and an id belonging to nobody; it
|
|
110
|
+
does **not** reject a raw id that is already a known option, because `ComboboxInput` matches on
|
|
111
|
+
`option.value` and `CrudForm` keeps the unfiltered first page as suggestions for the form's
|
|
112
|
+
lifetime. Either way the submitted value is a real user in the caller's scope.
|
|
113
|
+
|
|
95
114
|
## Validation Commands
|
|
96
115
|
|
|
97
116
|
```bash
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
export const features = [
|
|
2
2
|
{ id: 'devices.view', title: 'View own devices', module: 'devices' },
|
|
3
3
|
{ id: 'devices.manage', title: 'Manage own devices', module: 'devices' },
|
|
4
|
-
{
|
|
4
|
+
{
|
|
5
|
+
id: 'devices.admin',
|
|
6
|
+
title: 'Manage devices across users',
|
|
7
|
+
module: 'devices',
|
|
8
|
+
// Managing devices across users means naming the owner, and the admin screens name them by
|
|
9
|
+
// person rather than by UUID: the register form's owner picker and the owner column on both
|
|
10
|
+
// list and detail resolve through `GET /api/auth/users`, which `auth.users.list` gates.
|
|
11
|
+
dependsOn: ['auth.users.list'],
|
|
12
|
+
},
|
|
5
13
|
]
|
|
6
14
|
|
|
7
15
|
export default features
|
|
@@ -15,6 +15,8 @@ import { updateDeviceSchema } from '../../../../data/validators'
|
|
|
15
15
|
import { isOrganizationReadAccessAllowed } from '@open-mercato/core/modules/directory/utils/organizationScopeGuard'
|
|
16
16
|
import { resolveDeviceActorUserId } from '../../../auth'
|
|
17
17
|
import { executeUpdate, executeDeactivate, type DeviceMutationContext } from '../../../deviceOps'
|
|
18
|
+
import { serializeDeviceDetail, deviceDetailItemSchema } from '../../../deviceSerialization'
|
|
19
|
+
import { DEPRECATED_SNAKE_CASE_NOTICE } from '../../../openapi'
|
|
18
20
|
|
|
19
21
|
const logger = createLogger('devices')
|
|
20
22
|
|
|
@@ -38,23 +40,6 @@ async function loadDevice(
|
|
|
38
40
|
return findOneWithDecryption(em, UserDevice, { id, tenantId, deletedAt: null }, undefined, { tenantId })
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
// push_token is a secret and is never returned.
|
|
42
|
-
function serializeDevice(device: UserDevice) {
|
|
43
|
-
return {
|
|
44
|
-
id: device.id,
|
|
45
|
-
user_id: device.userId,
|
|
46
|
-
device_id: device.deviceId,
|
|
47
|
-
platform: device.platform,
|
|
48
|
-
client_app_version: device.clientAppVersion ?? null,
|
|
49
|
-
os_version: device.osVersion ?? null,
|
|
50
|
-
push_provider: device.pushProvider ?? null,
|
|
51
|
-
push_token_updated_at: device.pushTokenUpdatedAt ? device.pushTokenUpdatedAt.toISOString() : null,
|
|
52
|
-
last_seen_at: device.lastSeenAt ? device.lastSeenAt.toISOString() : null,
|
|
53
|
-
created_at: device.createdAt ? device.createdAt.toISOString() : null,
|
|
54
|
-
updated_at: device.updatedAt ? device.updatedAt.toISOString() : null,
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
43
|
export async function GET(req: Request, { params }: { params: { id: string } }) {
|
|
59
44
|
const { translate } = await resolveTranslations()
|
|
60
45
|
try {
|
|
@@ -76,7 +61,7 @@ export async function GET(req: Request, { params }: { params: { id: string } })
|
|
|
76
61
|
if (!isOrganizationReadAccessAllowed({ scope, auth, organizationId: device.organizationId ?? null })) {
|
|
77
62
|
return NextResponse.json({ error: translate('devices.errors.forbidden', 'Access denied') }, { status: 403 })
|
|
78
63
|
}
|
|
79
|
-
return NextResponse.json({ item:
|
|
64
|
+
return NextResponse.json({ item: serializeDeviceDetail(device) })
|
|
80
65
|
} catch (err) {
|
|
81
66
|
if (isCrudHttpError(err)) {
|
|
82
67
|
return NextResponse.json(err.body, { status: err.status })
|
|
@@ -177,21 +162,7 @@ export async function DELETE(req: Request, { params }: { params: { id: string }
|
|
|
177
162
|
|
|
178
163
|
const okResponseSchema = z.object({ ok: z.literal(true), id: z.string().uuid().optional() })
|
|
179
164
|
const errorResponseSchema = z.object({ error: z.string() })
|
|
180
|
-
const detailResponseSchema = z.object({
|
|
181
|
-
item: z.object({
|
|
182
|
-
id: z.string().uuid(),
|
|
183
|
-
user_id: z.string().uuid(),
|
|
184
|
-
device_id: z.string(),
|
|
185
|
-
platform: z.enum(['ios', 'android', 'web']),
|
|
186
|
-
client_app_version: z.string().nullable(),
|
|
187
|
-
os_version: z.string().nullable(),
|
|
188
|
-
push_provider: z.string().nullable(),
|
|
189
|
-
push_token_updated_at: z.string().nullable(),
|
|
190
|
-
last_seen_at: z.string().nullable(),
|
|
191
|
-
created_at: z.string().nullable(),
|
|
192
|
-
updated_at: z.string().nullable(),
|
|
193
|
-
}),
|
|
194
|
-
})
|
|
165
|
+
const detailResponseSchema = z.object({ item: deviceDetailItemSchema })
|
|
195
166
|
|
|
196
167
|
export const openApi: OpenApiRouteDoc = {
|
|
197
168
|
tag: 'Devices (admin)',
|
|
@@ -199,7 +170,7 @@ export const openApi: OpenApiRouteDoc = {
|
|
|
199
170
|
methods: {
|
|
200
171
|
GET: {
|
|
201
172
|
summary: 'Get any device',
|
|
202
|
-
description:
|
|
173
|
+
description: `Admin: fetch a single device by id (push_token is never returned). ${DEPRECATED_SNAKE_CASE_NOTICE}`,
|
|
203
174
|
responses: [{ status: 200, description: 'Device', schema: detailResponseSchema }],
|
|
204
175
|
errors: [
|
|
205
176
|
{ status: 400, description: 'Invalid id', schema: errorResponseSchema },
|
|
@@ -2,6 +2,7 @@ import type { EntityManager } from '@mikro-orm/postgresql'
|
|
|
2
2
|
import { NextResponse } from 'next/server'
|
|
3
3
|
import { z } from 'zod'
|
|
4
4
|
import { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'
|
|
5
|
+
import { toHeaderLabel } from '@open-mercato/shared/lib/crud/exporters'
|
|
5
6
|
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
6
7
|
import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
|
|
7
8
|
import { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'
|
|
@@ -21,7 +22,14 @@ import {
|
|
|
21
22
|
} from '../../../data/validators'
|
|
22
23
|
import { resolveDeviceActorUserId } from '../../auth'
|
|
23
24
|
import { createDevicesCrudOpenApi, createPagedListResponseSchema } from '../../openapi'
|
|
24
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
deviceListSchema,
|
|
27
|
+
deviceListFields,
|
|
28
|
+
deviceListSortFieldMap,
|
|
29
|
+
deviceListItemSchema,
|
|
30
|
+
deviceExportColumnFields,
|
|
31
|
+
transformDeviceListItem,
|
|
32
|
+
} from '../../deviceList'
|
|
25
33
|
import { executeRegister, type DeviceMutationContext } from '../../deviceOps'
|
|
26
34
|
|
|
27
35
|
const logger = createLogger('devices')
|
|
@@ -55,6 +63,11 @@ const crud = makeCrudRoute({
|
|
|
55
63
|
entityId: E.devices.user_device,
|
|
56
64
|
fields: deviceListFields,
|
|
57
65
|
sortFieldMap: deviceListSortFieldMap,
|
|
66
|
+
// The query engine projects raw column names; expose them in camelCase like every other module.
|
|
67
|
+
transformItem: transformDeviceListItem,
|
|
68
|
+
// Without an explicit column set the factory's default export spreads each item, so the deprecated
|
|
69
|
+
// snake_case aliases would double every column in the CSV/JSON/XML export.
|
|
70
|
+
export: { columns: deviceExportColumnFields.map((field) => ({ field, header: toHeaderLabel(field) })) },
|
|
58
71
|
// Tenant + org scope is enforced by the factory (orm.tenantField + orm.orgField); only the optional
|
|
59
72
|
// userId/platform narrowing is left to do here.
|
|
60
73
|
buildFilters: async (query) => {
|
|
@@ -30,25 +30,149 @@ export const deviceListFields: string[] = [
|
|
|
30
30
|
'updated_at',
|
|
31
31
|
]
|
|
32
32
|
|
|
33
|
+
// The admin list enables exports, and the factory's default export derives its columns by spreading
|
|
34
|
+
// each item — which would emit both spellings of every aliased key. Pin the canonical camelCase set
|
|
35
|
+
// so the export stays single-spelled and does not change shape when the aliases are dropped.
|
|
36
|
+
export const deviceExportColumnFields: string[] = [
|
|
37
|
+
'id',
|
|
38
|
+
'tenantId',
|
|
39
|
+
'organizationId',
|
|
40
|
+
'userId',
|
|
41
|
+
'deviceId',
|
|
42
|
+
'platform',
|
|
43
|
+
'clientAppVersion',
|
|
44
|
+
'osVersion',
|
|
45
|
+
'locale',
|
|
46
|
+
'pushProvider',
|
|
47
|
+
'pushTokenUpdatedAt',
|
|
48
|
+
'lastSeenAt',
|
|
49
|
+
'createdAt',
|
|
50
|
+
'updatedAt',
|
|
51
|
+
]
|
|
52
|
+
|
|
33
53
|
export const deviceListSortFieldMap: Record<string, string> = {
|
|
34
54
|
lastSeenAt: 'last_seen_at',
|
|
35
55
|
createdAt: 'created_at',
|
|
36
56
|
updatedAt: 'updated_at',
|
|
37
57
|
}
|
|
38
58
|
|
|
59
|
+
// The query engine projects the raw column names listed in `deviceListFields`. Every other module
|
|
60
|
+
// serializes its list items in camelCase (`sales/orders` → `orderNumber`, `warranty_claims` →
|
|
61
|
+
// `claimNumber`), so the list routes run this transform to expose the platform convention (#5513).
|
|
62
|
+
// The snake_case keys stay alongside as deprecated aliases for one minor version, per the
|
|
63
|
+
// deprecation protocol in BACKWARD_COMPATIBILITY.md § 7 (API Route URLs — response fields).
|
|
64
|
+
export function transformDeviceListItem(item: unknown): unknown {
|
|
65
|
+
const record = toRecord(item)
|
|
66
|
+
if (!Object.keys(record).length) return item
|
|
67
|
+
const camel = {
|
|
68
|
+
id: readString(record, 'id', 'id'),
|
|
69
|
+
tenantId: readString(record, 'tenant_id', 'tenantId'),
|
|
70
|
+
organizationId: readString(record, 'organization_id', 'organizationId'),
|
|
71
|
+
userId: readString(record, 'user_id', 'userId'),
|
|
72
|
+
deviceId: readString(record, 'device_id', 'deviceId'),
|
|
73
|
+
platform: readString(record, 'platform', 'platform'),
|
|
74
|
+
clientAppVersion: readString(record, 'client_app_version', 'clientAppVersion'),
|
|
75
|
+
osVersion: readString(record, 'os_version', 'osVersion'),
|
|
76
|
+
locale: readString(record, 'locale', 'locale'),
|
|
77
|
+
pushProvider: readString(record, 'push_provider', 'pushProvider'),
|
|
78
|
+
pushTokenUpdatedAt: toIso(record.push_token_updated_at ?? record.pushTokenUpdatedAt),
|
|
79
|
+
lastSeenAt: toIso(record.last_seen_at ?? record.lastSeenAt),
|
|
80
|
+
createdAt: toIso(record.created_at ?? record.createdAt),
|
|
81
|
+
updatedAt: toIso(record.updated_at ?? record.updatedAt),
|
|
82
|
+
}
|
|
83
|
+
// Spread the raw record first so anything the projection carries beyond the declared field set
|
|
84
|
+
// (custom-field keys, future columns) survives; the aliases then restate the snake_case keys with
|
|
85
|
+
// the same normalized values as their camelCase counterparts.
|
|
86
|
+
return { ...record, ...camel, ...toDeprecatedSnakeCaseAliases(camel) }
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @deprecated Snake_case device response keys are superseded by the camelCase keys and are removed in
|
|
91
|
+
* the next minor release. Read `deviceId`, `userId`, `lastSeenAt`, … instead. See UPGRADE_NOTES.md.
|
|
92
|
+
*/
|
|
93
|
+
export function toDeprecatedSnakeCaseAliases(item: DeviceResponseItem): Record<string, unknown> {
|
|
94
|
+
const aliases: Record<string, unknown> = {
|
|
95
|
+
tenant_id: item.tenantId,
|
|
96
|
+
organization_id: item.organizationId,
|
|
97
|
+
user_id: item.userId,
|
|
98
|
+
device_id: item.deviceId,
|
|
99
|
+
client_app_version: item.clientAppVersion,
|
|
100
|
+
os_version: item.osVersion,
|
|
101
|
+
push_provider: item.pushProvider,
|
|
102
|
+
push_token_updated_at: item.pushTokenUpdatedAt,
|
|
103
|
+
last_seen_at: item.lastSeenAt,
|
|
104
|
+
created_at: item.createdAt,
|
|
105
|
+
updated_at: item.updatedAt,
|
|
106
|
+
}
|
|
107
|
+
// The detail response never carried tenant/org, so an absent camelCase source must not grow a new
|
|
108
|
+
// key here — only keys the caller actually supplied get an alias.
|
|
109
|
+
for (const key of Object.keys(aliases)) {
|
|
110
|
+
if (aliases[key] === undefined) delete aliases[key]
|
|
111
|
+
}
|
|
112
|
+
return aliases
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export type DeviceResponseItem = {
|
|
116
|
+
tenantId?: string | null
|
|
117
|
+
organizationId?: string | null
|
|
118
|
+
userId: string | null
|
|
119
|
+
deviceId: string | null
|
|
120
|
+
clientAppVersion: string | null
|
|
121
|
+
osVersion: string | null
|
|
122
|
+
pushProvider: string | null
|
|
123
|
+
pushTokenUpdatedAt?: string | null
|
|
124
|
+
lastSeenAt?: string | null
|
|
125
|
+
createdAt?: string | null
|
|
126
|
+
updatedAt: string | null
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function toRecord(value: unknown): Record<string, unknown> {
|
|
130
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : {}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function readString(record: Record<string, unknown>, snakeKey: string, camelKey: string): string | null {
|
|
134
|
+
const value = record[snakeKey] ?? record[camelKey]
|
|
135
|
+
return typeof value === 'string' ? value : null
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function toIso(value: unknown): string | null {
|
|
139
|
+
if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value.toISOString()
|
|
140
|
+
if (typeof value === 'string') {
|
|
141
|
+
const date = new Date(value)
|
|
142
|
+
return Number.isNaN(date.getTime()) ? value : date.toISOString()
|
|
143
|
+
}
|
|
144
|
+
return null
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// In-code contract markers. The shared zodToJsonSchema converter does not currently emit per-property
|
|
148
|
+
// descriptions for object schemas, so the rendered deprecation notice lives on the endpoint description
|
|
149
|
+
// (`DEPRECATED_SNAKE_CASE_NOTICE` in ./openapi); these become visible for free if that changes.
|
|
150
|
+
const deprecatedAlias = (of: string) => `Deprecated alias for \`${of}\`; removed in the next minor release.`
|
|
151
|
+
|
|
39
152
|
export const deviceListItemSchema = z.object({
|
|
40
153
|
id: z.string().uuid(),
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
154
|
+
tenantId: z.string().uuid(),
|
|
155
|
+
organizationId: z.string().uuid().nullable().optional(),
|
|
156
|
+
userId: z.string().uuid(),
|
|
157
|
+
deviceId: z.string(),
|
|
45
158
|
platform: z.enum(['ios', 'android', 'web']),
|
|
46
|
-
|
|
47
|
-
|
|
159
|
+
clientAppVersion: z.string().nullable().optional(),
|
|
160
|
+
osVersion: z.string().nullable().optional(),
|
|
48
161
|
locale: z.string().nullable().optional(),
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
162
|
+
pushProvider: z.string().nullable().optional(),
|
|
163
|
+
pushTokenUpdatedAt: z.string().nullable().optional(),
|
|
164
|
+
lastSeenAt: z.string().nullable().optional(),
|
|
165
|
+
createdAt: z.string().nullable().optional(),
|
|
166
|
+
updatedAt: z.string().nullable().optional(),
|
|
167
|
+
tenant_id: z.string().uuid().describe(deprecatedAlias('tenantId')),
|
|
168
|
+
organization_id: z.string().uuid().nullable().optional().describe(deprecatedAlias('organizationId')),
|
|
169
|
+
user_id: z.string().uuid().describe(deprecatedAlias('userId')),
|
|
170
|
+
device_id: z.string().describe(deprecatedAlias('deviceId')),
|
|
171
|
+
client_app_version: z.string().nullable().optional().describe(deprecatedAlias('clientAppVersion')),
|
|
172
|
+
os_version: z.string().nullable().optional().describe(deprecatedAlias('osVersion')),
|
|
173
|
+
push_provider: z.string().nullable().optional().describe(deprecatedAlias('pushProvider')),
|
|
174
|
+
push_token_updated_at: z.string().nullable().optional().describe(deprecatedAlias('pushTokenUpdatedAt')),
|
|
175
|
+
last_seen_at: z.string().nullable().optional().describe(deprecatedAlias('lastSeenAt')),
|
|
176
|
+
created_at: z.string().nullable().optional().describe(deprecatedAlias('createdAt')),
|
|
177
|
+
updated_at: z.string().nullable().optional().describe(deprecatedAlias('updatedAt')),
|
|
54
178
|
})
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import type { UserDevice } from '../data/entities'
|
|
3
|
+
import { toDeprecatedSnakeCaseAliases, toIso } from './deviceList'
|
|
4
|
+
|
|
5
|
+
// Detail contract for `GET /api/devices/admin/devices/:id`. Keys are camelCase like every other
|
|
6
|
+
// module's responses (#5513); the snake_case keys stay alongside as deprecated aliases for one minor
|
|
7
|
+
// version, per the deprecation protocol in BACKWARD_COMPATIBILITY.md § 7.
|
|
8
|
+
// push_token is a secret and is never returned.
|
|
9
|
+
export function serializeDeviceDetail(device: UserDevice): Record<string, unknown> {
|
|
10
|
+
const camel = {
|
|
11
|
+
id: device.id,
|
|
12
|
+
userId: device.userId,
|
|
13
|
+
deviceId: device.deviceId,
|
|
14
|
+
platform: device.platform,
|
|
15
|
+
clientAppVersion: device.clientAppVersion ?? null,
|
|
16
|
+
osVersion: device.osVersion ?? null,
|
|
17
|
+
pushProvider: device.pushProvider ?? null,
|
|
18
|
+
pushTokenUpdatedAt: toIso(device.pushTokenUpdatedAt),
|
|
19
|
+
lastSeenAt: toIso(device.lastSeenAt),
|
|
20
|
+
createdAt: toIso(device.createdAt),
|
|
21
|
+
updatedAt: toIso(device.updatedAt),
|
|
22
|
+
}
|
|
23
|
+
return { ...camel, ...toDeprecatedSnakeCaseAliases(camel) }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// See the note in ./deviceList — the rendered deprecation notice lives on the endpoint description.
|
|
27
|
+
const deprecatedAlias = (of: string) => `Deprecated alias for \`${of}\`; removed in the next minor release.`
|
|
28
|
+
|
|
29
|
+
export const deviceDetailItemSchema = z.object({
|
|
30
|
+
id: z.string().uuid(),
|
|
31
|
+
userId: z.string().uuid(),
|
|
32
|
+
deviceId: z.string(),
|
|
33
|
+
platform: z.enum(['ios', 'android', 'web']),
|
|
34
|
+
clientAppVersion: z.string().nullable(),
|
|
35
|
+
osVersion: z.string().nullable(),
|
|
36
|
+
pushProvider: z.string().nullable(),
|
|
37
|
+
pushTokenUpdatedAt: z.string().nullable(),
|
|
38
|
+
lastSeenAt: z.string().nullable(),
|
|
39
|
+
createdAt: z.string().nullable(),
|
|
40
|
+
updatedAt: z.string().nullable(),
|
|
41
|
+
user_id: z.string().uuid().describe(deprecatedAlias('userId')),
|
|
42
|
+
device_id: z.string().describe(deprecatedAlias('deviceId')),
|
|
43
|
+
client_app_version: z.string().nullable().describe(deprecatedAlias('clientAppVersion')),
|
|
44
|
+
os_version: z.string().nullable().describe(deprecatedAlias('osVersion')),
|
|
45
|
+
push_provider: z.string().nullable().describe(deprecatedAlias('pushProvider')),
|
|
46
|
+
push_token_updated_at: z.string().nullable().describe(deprecatedAlias('pushTokenUpdatedAt')),
|
|
47
|
+
last_seen_at: z.string().nullable().describe(deprecatedAlias('lastSeenAt')),
|
|
48
|
+
created_at: z.string().nullable().describe(deprecatedAlias('createdAt')),
|
|
49
|
+
updated_at: z.string().nullable().describe(deprecatedAlias('updatedAt')),
|
|
50
|
+
})
|
|
@@ -12,10 +12,18 @@ export function createPagedListResponseSchema(itemSchema: ZodTypeAny) {
|
|
|
12
12
|
|
|
13
13
|
// createCrudOpenApiFactory already falls back to the shared default create/ok response schemas
|
|
14
14
|
// when omitted, so there is nothing module-specific to re-pass or re-export here.
|
|
15
|
+
// The shared zodToJsonSchema converter does not emit per-property descriptions for object schemas, so
|
|
16
|
+
// the `.describe()` markers on the deprecated keys in deviceList.ts never reach the document. State the
|
|
17
|
+
// deprecation in the endpoint description, which does render (#5513).
|
|
18
|
+
export const DEPRECATED_SNAKE_CASE_NOTICE =
|
|
19
|
+
'Response keys are camelCase. The snake_case keys (`user_id`, `device_id`, `last_seen_at`, …) are ' +
|
|
20
|
+
'deprecated aliases of their camelCase counterparts, retained for one minor version and removed in ' +
|
|
21
|
+
'the next; read `userId`, `deviceId`, `lastSeenAt`, … instead.'
|
|
22
|
+
|
|
15
23
|
const buildDevicesCrudOpenApi = createCrudOpenApiFactory({
|
|
16
24
|
defaultTag: 'Devices',
|
|
17
25
|
makeListDescription: ({ pluralLower }) =>
|
|
18
|
-
`Returns the authenticated user's registered ${pluralLower} (admins may list across users)
|
|
26
|
+
`Returns the authenticated user's registered ${pluralLower} (admins may list across users). ${DEPRECATED_SNAKE_CASE_NOTICE}`,
|
|
19
27
|
})
|
|
20
28
|
|
|
21
29
|
export function createDevicesCrudOpenApi(options: CrudOpenApiOptions): OpenApiRouteDoc {
|