@open-mercato/core 0.6.6-develop.6465.1.019f0fb26f → 0.6.6-develop.6471.1.9ab5bdd79a
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/dist/bootstrap.js +13 -11
- package/dist/bootstrap.js.map +2 -2
- package/dist/helpers/integration/queue-runner.js +4 -2
- package/dist/helpers/integration/queue-runner.js.map +2 -2
- package/dist/modules/api_keys/services/apiKeyService.js +5 -3
- package/dist/modules/api_keys/services/apiKeyService.js.map +2 -2
- package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js +4 -2
- package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js.map +2 -2
- package/dist/modules/attachments/api/library/[id]/route.js +3 -1
- package/dist/modules/attachments/api/library/[id]/route.js.map +2 -2
- package/dist/modules/attachments/api/route.js +8 -6
- package/dist/modules/attachments/api/route.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js +5 -3
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
- package/dist/modules/attachments/lib/assignmentDetails.js +3 -1
- package/dist/modules/attachments/lib/assignmentDetails.js.map +2 -2
- package/dist/modules/attachments/lib/drivers/driverFactory.js +3 -1
- package/dist/modules/attachments/lib/drivers/driverFactory.js.map +2 -2
- package/dist/modules/attachments/lib/ocrQueue.js +10 -11
- package/dist/modules/attachments/lib/ocrQueue.js.map +2 -2
- package/dist/modules/attachments/lib/ocrService.js +6 -4
- package/dist/modules/attachments/lib/ocrService.js.map +2 -2
- package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js +3 -1
- package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js.map +2 -2
- package/dist/modules/audit_logs/api/audit-logs/actions/undo/route.js +3 -1
- package/dist/modules/audit_logs/api/audit-logs/actions/undo/route.js.map +2 -2
- package/dist/modules/audit_logs/backend/audit-logs/page.js +3 -1
- package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
- package/dist/modules/audit_logs/components/AuditLogsActions.js +4 -2
- package/dist/modules/audit_logs/components/AuditLogsActions.js.map +2 -2
- package/dist/modules/audit_logs/services/accessLogService.js +4 -2
- package/dist/modules/audit_logs/services/accessLogService.js.map +2 -2
- package/dist/modules/audit_logs/services/actionLogService.js +7 -5
- package/dist/modules/audit_logs/services/actionLogService.js.map +3 -3
- package/dist/modules/auth/api/profile/route.js +4 -2
- package/dist/modules/auth/api/profile/route.js.map +2 -2
- package/dist/modules/auth/api/reset/confirm.js +3 -1
- package/dist/modules/auth/api/reset/confirm.js.map +2 -2
- package/dist/modules/auth/api/reset.js +4 -2
- package/dist/modules/auth/api/reset.js.map +2 -2
- package/dist/modules/auth/api/roles/route.js +3 -1
- package/dist/modules/auth/api/roles/route.js.map +2 -2
- package/dist/modules/auth/api/sidebar/variants/route.js +3 -1
- package/dist/modules/auth/api/sidebar/variants/route.js.map +2 -2
- package/dist/modules/auth/api/users/resend-invite/route.js +4 -2
- package/dist/modules/auth/api/users/resend-invite/route.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +3 -1
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/backend/auth/profile/page.js +3 -1
- package/dist/modules/auth/backend/auth/profile/page.js.map +2 -2
- package/dist/modules/auth/backend/profile/change-password/page.js +3 -1
- package/dist/modules/auth/backend/profile/change-password/page.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.js +5 -3
- package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/users/create/page.js +4 -2
- package/dist/modules/auth/backend/users/create/page.js.map +2 -2
- package/dist/modules/auth/cli.js +10 -0
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/auth/commands/users.js +4 -2
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/auth/lib/consentIntegrity.js +3 -3
- package/dist/modules/auth/lib/consentIntegrity.js.map +2 -2
- package/dist/modules/auth/lib/setup-app.js +9 -10
- package/dist/modules/auth/lib/setup-app.js.map +2 -2
- package/dist/modules/auth/lib/tenantAccess.js +3 -1
- package/dist/modules/auth/lib/tenantAccess.js.map +2 -2
- package/dist/modules/auth/lib/tokenHash.js +3 -3
- package/dist/modules/auth/lib/tokenHash.js.map +2 -2
- package/dist/modules/business_rules/api/rules/route.js +4 -2
- package/dist/modules/business_rules/api/rules/route.js.map +2 -2
- package/dist/modules/business_rules/lib/expression-evaluator.js +7 -5
- package/dist/modules/business_rules/lib/expression-evaluator.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-engine.js +5 -3
- package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-evaluator.js +11 -12
- package/dist/modules/business_rules/lib/rule-evaluator.js.map +2 -2
- package/dist/modules/business_rules/subscribers/crud-rule-trigger.js +3 -1
- package/dist/modules/business_rules/subscribers/crud-rule-trigger.js.map +2 -2
- package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js +3 -1
- package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js.map +2 -2
- package/dist/modules/catalog/ai-agents-context.js +4 -5
- package/dist/modules/catalog/ai-agents-context.js.map +2 -2
- package/dist/modules/catalog/ai-tools/_shared.js +3 -1
- package/dist/modules/catalog/ai-tools/_shared.js.map +2 -2
- package/dist/modules/catalog/ai-tools/authoring-pack.js +3 -1
- package/dist/modules/catalog/ai-tools/authoring-pack.js.map +2 -2
- package/dist/modules/catalog/ai-tools/merchandising-pack.js +3 -1
- package/dist/modules/catalog/ai-tools/merchandising-pack.js.map +2 -2
- package/dist/modules/catalog/api/dictionaries/[key]/route.js +3 -1
- package/dist/modules/catalog/api/dictionaries/[key]/route.js.map +2 -2
- package/dist/modules/catalog/api/prices/route.js +3 -1
- package/dist/modules/catalog/api/prices/route.js.map +2 -2
- package/dist/modules/catalog/api/products/route.js +5 -3
- package/dist/modules/catalog/api/products/route.js.map +2 -2
- package/dist/modules/catalog/api/settings/route.js +4 -2
- package/dist/modules/catalog/api/settings/route.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +14 -12
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +8 -6
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/create/page.js +5 -3
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/create/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/create/page.js +5 -6
- package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/optionSchemaClient.js +3 -1
- package/dist/modules/catalog/backend/catalog/products/optionSchemaClient.js.map +2 -2
- package/dist/modules/catalog/components/PriceKindSettings.js +5 -3
- package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
- package/dist/modules/catalog/components/UnitPriceDisplaySettings.js +4 -2
- package/dist/modules/catalog/components/UnitPriceDisplaySettings.js.map +2 -2
- package/dist/modules/catalog/inbox-actions.js +4 -2
- package/dist/modules/catalog/inbox-actions.js.map +2 -2
- package/dist/modules/catalog/seed/examples.js +4 -5
- package/dist/modules/catalog/seed/examples.js.map +2 -2
- package/dist/modules/catalog/subscribers/low-stock-notification.js +3 -1
- package/dist/modules/catalog/subscribers/low-stock-notification.js.map +2 -2
- package/dist/modules/catalog/widgets/injection/product-seo/state.js +3 -1
- package/dist/modules/catalog/widgets/injection/product-seo/state.js.map +2 -2
- package/dist/modules/communication_channels/api/get/oauth/[provider]/callback/route.js +12 -11
- package/dist/modules/communication_channels/api/get/oauth/[provider]/callback/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/channels/[id]/import-history/route.js +3 -1
- package/dist/modules/communication_channels/api/post/channels/[id]/import-history/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/channels/[id]/push/register/route.js +3 -1
- package/dist/modules/communication_channels/api/post/channels/[id]/push/register/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/webhook/[provider]/route.js +5 -3
- package/dist/modules/communication_channels/api/post/webhook/[provider]/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/webhooks/gmail/route.js +6 -6
- package/dist/modules/communication_channels/api/post/webhooks/gmail/route.js.map +2 -2
- package/dist/modules/communication_channels/commands/connect-credential-channel.js +4 -6
- package/dist/modules/communication_channels/commands/connect-credential-channel.js.map +2 -2
- package/dist/modules/communication_channels/commands/delete-channel.js +3 -3
- package/dist/modules/communication_channels/commands/delete-channel.js.map +2 -2
- package/dist/modules/communication_channels/commands/deliver-outbound-message.js +4 -5
- package/dist/modules/communication_channels/commands/deliver-outbound-message.js.map +2 -2
- package/dist/modules/communication_channels/commands/disconnect-channel.js +3 -3
- package/dist/modules/communication_channels/commands/disconnect-channel.js.map +2 -2
- package/dist/modules/communication_channels/commands/ingest-inbound-message.js +5 -12
- package/dist/modules/communication_channels/commands/ingest-inbound-message.js.map +2 -2
- package/dist/modules/communication_channels/commands/push-unregister.js +3 -3
- package/dist/modules/communication_channels/commands/push-unregister.js.map +2 -2
- package/dist/modules/communication_channels/commands/reassign-conversation.js +5 -3
- package/dist/modules/communication_channels/commands/reassign-conversation.js.map +2 -2
- package/dist/modules/communication_channels/lib/dead-letter.js +3 -3
- package/dist/modules/communication_channels/lib/dead-letter.js.map +2 -2
- package/dist/modules/communication_channels/lib/email-mime.js +4 -6
- package/dist/modules/communication_channels/lib/email-mime.js.map +2 -2
- package/dist/modules/communication_channels/lib/oauth-client-config.js +5 -3
- package/dist/modules/communication_channels/lib/oauth-client-config.js.map +2 -2
- package/dist/modules/communication_channels/lib/send-as-user.js +3 -1
- package/dist/modules/communication_channels/lib/send-as-user.js.map +2 -2
- package/dist/modules/communication_channels/lib/thread-token.js +4 -2
- package/dist/modules/communication_channels/lib/thread-token.js.map +2 -2
- package/dist/modules/communication_channels/setup.js +3 -4
- package/dist/modules/communication_channels/setup.js.map +2 -2
- package/dist/modules/communication_channels/workers/channel-import-history.js +4 -6
- package/dist/modules/communication_channels/workers/channel-import-history.js.map +2 -2
- package/dist/modules/communication_channels/workers/gmail-history-sync.js +8 -16
- package/dist/modules/communication_channels/workers/gmail-history-sync.js.map +2 -2
- package/dist/modules/communication_channels/workers/gmail-renew-watch.js +5 -7
- package/dist/modules/communication_channels/workers/gmail-renew-watch.js.map +2 -2
- package/dist/modules/communication_channels/workers/outbound-delivery.js +6 -12
- package/dist/modules/communication_channels/workers/outbound-delivery.js.map +2 -2
- package/dist/modules/communication_channels/workers/poll-channel.js +7 -15
- package/dist/modules/communication_channels/workers/poll-channel.js.map +2 -2
- package/dist/modules/communication_channels/workers/poll-tick.js +5 -6
- package/dist/modules/communication_channels/workers/poll-tick.js.map +2 -2
- package/dist/modules/communication_channels/workers/reaction-processor.js +5 -9
- package/dist/modules/communication_channels/workers/reaction-processor.js.map +2 -2
- package/dist/modules/configs/api/cache/route.js +4 -2
- package/dist/modules/configs/api/cache/route.js.map +2 -2
- package/dist/modules/configs/api/system-status/route.js +4 -2
- package/dist/modules/configs/api/system-status/route.js.map +2 -2
- package/dist/modules/configs/api/upgrade-actions/route.js +4 -2
- package/dist/modules/configs/api/upgrade-actions/route.js.map +2 -2
- package/dist/modules/configs/components/ModuleTelemetryPanel.js +3 -1
- package/dist/modules/configs/components/ModuleTelemetryPanel.js.map +2 -2
- package/dist/modules/configs/lib/touchGeneratedBarrels.js +2 -1
- package/dist/modules/configs/lib/touchGeneratedBarrels.js.map +2 -2
- package/dist/modules/configs/services/upgradeActionsService.js +6 -3
- package/dist/modules/configs/services/upgradeActionsService.js.map +2 -2
- package/dist/modules/currencies/components/CurrencyFetchingConfig.js +3 -1
- package/dist/modules/currencies/components/CurrencyFetchingConfig.js.map +2 -2
- package/dist/modules/currencies/lib/exchangeRateFormConfig.js +3 -1
- package/dist/modules/currencies/lib/exchangeRateFormConfig.js.map +2 -2
- package/dist/modules/currencies/services/providers/nbp.js +6 -4
- package/dist/modules/currencies/services/providers/nbp.js.map +2 -2
- package/dist/modules/currencies/services/providers/raiffeisen.js +7 -7
- package/dist/modules/currencies/services/providers/raiffeisen.js.map +2 -2
- package/dist/modules/customer_accounts/api/domain-resolve/all.js +6 -5
- package/dist/modules/customer_accounts/api/domain-resolve/all.js.map +2 -2
- package/dist/modules/customer_accounts/api/signup.js +4 -2
- package/dist/modules/customer_accounts/api/signup.js.map +2 -2
- package/dist/modules/customer_accounts/lib/customerAuthServer.js +3 -1
- package/dist/modules/customer_accounts/lib/customerAuthServer.js.map +2 -2
- package/dist/modules/customer_accounts/subscribers/autoLinkCrm.js +3 -1
- package/dist/modules/customer_accounts/subscribers/autoLinkCrm.js.map +2 -2
- package/dist/modules/customer_accounts/subscribers/autoLinkCrmReverse.js +3 -1
- package/dist/modules/customer_accounts/subscribers/autoLinkCrmReverse.js.map +2 -2
- package/dist/modules/customer_accounts/subscribers/unlinkOnCompanyDelete.js +3 -1
- package/dist/modules/customer_accounts/subscribers/unlinkOnCompanyDelete.js.map +2 -2
- package/dist/modules/customer_accounts/subscribers/unlinkOnPersonDelete.js +3 -1
- package/dist/modules/customer_accounts/subscribers/unlinkOnPersonDelete.js.map +2 -2
- package/dist/modules/customers/ai-agents-context.js +4 -5
- package/dist/modules/customers/ai-agents-context.js.map +2 -2
- package/dist/modules/customers/api/activities/route.js +6 -4
- package/dist/modules/customers/api/activities/route.js.map +2 -2
- package/dist/modules/customers/api/comments/route.js +3 -1
- package/dist/modules/customers/api/comments/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/people/route.js +3 -1
- package/dist/modules/customers/api/companies/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/route.js +5 -3
- package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/companies/route.js +5 -3
- package/dist/modules/customers/api/companies/route.js.map +2 -2
- package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js +3 -1
- package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js.map +2 -2
- package/dist/modules/customers/api/dashboard/widgets/new-customers/route.js +3 -1
- package/dist/modules/customers/api/dashboard/widgets/new-customers/route.js.map +2 -2
- package/dist/modules/customers/api/dashboard/widgets/new-deals/route.js +3 -1
- package/dist/modules/customers/api/dashboard/widgets/new-deals/route.js.map +2 -2
- package/dist/modules/customers/api/dashboard/widgets/next-interactions/route.js +3 -1
- package/dist/modules/customers/api/dashboard/widgets/next-interactions/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/companies/route.js +3 -1
- package/dist/modules/customers/api/deals/[id]/companies/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/people/route.js +3 -1
- package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/deals/aggregate/route.js +3 -1
- package/dist/modules/customers/api/deals/aggregate/route.js.map +2 -2
- package/dist/modules/customers/api/deals/bulk-update-owner/route.js +7 -5
- package/dist/modules/customers/api/deals/bulk-update-owner/route.js.map +2 -2
- package/dist/modules/customers/api/deals/bulk-update-stage/route.js +7 -5
- package/dist/modules/customers/api/deals/bulk-update-stage/route.js.map +2 -2
- package/dist/modules/customers/api/deals/route.js +3 -1
- package/dist/modules/customers/api/deals/route.js.map +2 -2
- package/dist/modules/customers/api/deals/summary/route.js +3 -1
- package/dist/modules/customers/api/deals/summary/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js +4 -2
- package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/[kind]/route.js +5 -3
- package/dist/modules/customers/api/dictionaries/[kind]/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/cache.js +3 -1
- package/dist/modules/customers/api/dictionaries/cache.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/context.js +3 -1
- package/dist/modules/customers/api/dictionaries/context.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/currency/route.js +3 -1
- package/dist/modules/customers/api/dictionaries/currency/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/kind-settings/route.js +4 -2
- package/dist/modules/customers/api/dictionaries/kind-settings/route.js.map +2 -2
- package/dist/modules/customers/api/entity-roles-factory.js +7 -5
- package/dist/modules/customers/api/entity-roles-factory.js.map +2 -2
- package/dist/modules/customers/api/interactions/cancel/route.js +3 -1
- package/dist/modules/customers/api/interactions/cancel/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/complete/route.js +3 -1
- package/dist/modules/customers/api/interactions/complete/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/conflicts/route.js +3 -1
- package/dist/modules/customers/api/interactions/conflicts/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/counts/route.js +3 -1
- package/dist/modules/customers/api/interactions/counts/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/route.js +7 -4
- package/dist/modules/customers/api/interactions/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/tasks/route.js +3 -1
- package/dist/modules/customers/api/interactions/tasks/route.js.map +2 -2
- package/dist/modules/customers/api/labels/assign/route.js +3 -1
- package/dist/modules/customers/api/labels/assign/route.js.map +2 -2
- package/dist/modules/customers/api/labels/route.js +6 -3
- package/dist/modules/customers/api/labels/route.js.map +2 -2
- package/dist/modules/customers/api/labels/unassign/route.js +3 -1
- package/dist/modules/customers/api/labels/unassign/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +3 -1
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/route.js +5 -3
- package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/people/route.js +5 -3
- package/dist/modules/customers/api/people/route.js.map +2 -2
- package/dist/modules/customers/api/pipeline-stages/reorder/route.js +3 -1
- package/dist/modules/customers/api/pipeline-stages/reorder/route.js.map +2 -2
- package/dist/modules/customers/api/pipeline-stages/route.js +6 -4
- package/dist/modules/customers/api/pipeline-stages/route.js.map +2 -2
- package/dist/modules/customers/api/pipelines/route.js +6 -4
- package/dist/modules/customers/api/pipelines/route.js.map +2 -2
- package/dist/modules/customers/api/settings/address-format/route.js +4 -2
- package/dist/modules/customers/api/settings/address-format/route.js.map +2 -2
- package/dist/modules/customers/api/settings/dictionary-sort-modes/route.js +4 -2
- package/dist/modules/customers/api/settings/dictionary-sort-modes/route.js.map +2 -2
- package/dist/modules/customers/api/settings/stuck-threshold/route.js +4 -2
- package/dist/modules/customers/api/settings/stuck-threshold/route.js.map +2 -2
- package/dist/modules/customers/api/tags/assign/route.js +3 -1
- package/dist/modules/customers/api/tags/assign/route.js.map +2 -2
- package/dist/modules/customers/api/tags/unassign/route.js +3 -1
- package/dist/modules/customers/api/tags/unassign/route.js.map +2 -2
- package/dist/modules/customers/api/todos/route.js +6 -4
- package/dist/modules/customers/api/todos/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +5 -3
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.js +3 -1
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js +3 -1
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/map/components/DealsMapCanvasImpl.js +4 -2
- package/dist/modules/customers/backend/customers/deals/map/components/DealsMapCanvasImpl.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +4 -2
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +5 -3
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +3 -1
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/customers/commands/dictionaries.js +3 -1
- package/dist/modules/customers/commands/dictionaries.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js +4 -2
- package/dist/modules/customers/commands/interactions.js.map +2 -2
- package/dist/modules/customers/commands/shared.js +4 -2
- package/dist/modules/customers/commands/shared.js.map +2 -2
- package/dist/modules/customers/commands/todos.js +3 -1
- package/dist/modules/customers/commands/todos.js.map +2 -2
- package/dist/modules/customers/components/DictionarySettings.js +5 -3
- package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
- package/dist/modules/customers/components/DictionarySortSettings.js +3 -1
- package/dist/modules/customers/components/DictionarySortSettings.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivitiesCard.js +3 -1
- package/dist/modules/customers/components/detail/ActivitiesCard.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivitiesDayStrip.js +3 -1
- package/dist/modules/customers/components/detail/ActivitiesDayStrip.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivitiesSection.js +6 -4
- package/dist/modules/customers/components/detail/ActivitiesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivityCard.js +3 -1
- package/dist/modules/customers/components/detail/ActivityCard.js.map +2 -2
- package/dist/modules/customers/components/detail/ChangelogTab.js +3 -1
- package/dist/modules/customers/components/detail/ChangelogTab.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyCard.js +3 -1
- package/dist/modules/customers/components/detail/CompanyCard.js.map +2 -2
- package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js +3 -1
- package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js +3 -1
- package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/InlineActivityComposer.js +3 -1
- package/dist/modules/customers/components/detail/InlineActivityComposer.js.map +2 -2
- package/dist/modules/customers/components/detail/ManageTagsDialog.js +3 -1
- package/dist/modules/customers/components/detail/ManageTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js +5 -3
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js.map +2 -2
- package/dist/modules/customers/components/detail/RolesSection.js +4 -2
- package/dist/modules/customers/components/detail/RolesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js +5 -3
- package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js.map +2 -2
- package/dist/modules/customers/components/linking/LinkEntityDialog.js +4 -2
- package/dist/modules/customers/components/linking/LinkEntityDialog.js.map +2 -2
- package/dist/modules/customers/inbox-actions.js +3 -1
- package/dist/modules/customers/inbox-actions.js.map +2 -2
- package/dist/modules/customers/lib/bulkDeals.js +3 -1
- package/dist/modules/customers/lib/bulkDeals.js.map +2 -2
- package/dist/modules/customers/lib/dealClosureNotification.js +4 -2
- package/dist/modules/customers/lib/dealClosureNotification.js.map +2 -2
- package/dist/modules/customers/lib/dealStageTransitionTable.js +3 -1
- package/dist/modules/customers/lib/dealStageTransitionTable.js.map +2 -2
- package/dist/modules/customers/lib/interactionFeatureFlags.js +3 -1
- package/dist/modules/customers/lib/interactionFeatureFlags.js.map +2 -2
- package/dist/modules/customers/lib/todoCompatibility.js +3 -1
- package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
- package/dist/modules/customers/search.js +14 -7
- package/dist/modules/customers/search.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/customer-todos/widget.client.js +3 -1
- package/dist/modules/customers/widgets/dashboard/customer-todos/widget.client.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/new-customers/widget.client.js +3 -1
- package/dist/modules/customers/widgets/dashboard/new-customers/widget.client.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/new-deals/widget.client.js +3 -1
- package/dist/modules/customers/widgets/dashboard/new-deals/widget.client.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/next-interactions/widget.client.js +3 -1
- package/dist/modules/customers/widgets/dashboard/next-interactions/widget.client.js.map +2 -2
- package/dist/modules/dashboards/api/widgets/data/batch/route.js +3 -1
- package/dist/modules/dashboards/api/widgets/data/batch/route.js.map +2 -2
- package/dist/modules/dashboards/api/widgets/data/route.js +3 -1
- package/dist/modules/dashboards/api/widgets/data/route.js.map +2 -2
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +5 -3
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/top-products/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/top-products/widget.client.js.map +2 -2
- package/dist/modules/data_sync/api/run.js +3 -1
- package/dist/modules/data_sync/api/run.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +1 -1
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +2 -2
- package/dist/modules/data_sync/lib/adapter-registry.js +11 -4
- package/dist/modules/data_sync/lib/adapter-registry.js.map +2 -2
- package/dist/modules/data_sync/lib/sync-engine.js +23 -2
- package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
- package/dist/modules/data_sync/workers/sync-export.js +3 -1
- package/dist/modules/data_sync/workers/sync-export.js.map +2 -2
- package/dist/modules/data_sync/workers/sync-import.js +3 -1
- package/dist/modules/data_sync/workers/sync-import.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +4 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js +3 -1
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js +4 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js +3 -1
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/route.js +5 -3
- package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/api/context.js +3 -1
- package/dist/modules/dictionaries/api/context.js.map +2 -2
- package/dist/modules/dictionaries/api/route.js +4 -2
- package/dist/modules/dictionaries/api/route.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionariesManager.js +5 -3
- package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js +4 -2
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryEntrySelect.js +4 -2
- package/dist/modules/dictionaries/components/DictionaryEntrySelect.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionarySelectControl.js +3 -1
- package/dist/modules/dictionaries/components/DictionarySelectControl.js.map +2 -2
- package/dist/modules/dictionaries/fields/dictionary.js +3 -1
- package/dist/modules/dictionaries/fields/dictionary.js.map +2 -2
- package/dist/modules/directory/api/organization-branding/route.js +3 -1
- package/dist/modules/directory/api/organization-branding/route.js.map +2 -2
- package/dist/modules/directory/api/organization-switcher/route.js +3 -1
- package/dist/modules/directory/api/organization-switcher/route.js.map +2 -2
- package/dist/modules/directory/commands/tenants.js +5 -3
- package/dist/modules/directory/commands/tenants.js.map +2 -2
- package/dist/modules/directory/utils/organizationScope.js +6 -4
- package/dist/modules/directory/utils/organizationScope.js.map +2 -2
- package/dist/modules/entities/api/definitions.cache.js +3 -1
- package/dist/modules/entities/api/definitions.cache.js.map +2 -2
- package/dist/modules/entities/api/definitions.js +7 -5
- package/dist/modules/entities/api/definitions.js.map +2 -2
- package/dist/modules/entities/api/records.js +4 -8
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/components/EncryptionManager.js +3 -1
- package/dist/modules/entities/components/EncryptionManager.js.map +2 -2
- package/dist/modules/entities/lib/makeActivityRoute.js +3 -1
- package/dist/modules/entities/lib/makeActivityRoute.js.map +2 -2
- package/dist/modules/feature_toggles/api/overrides/route.js +3 -1
- package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
- package/dist/modules/feature_toggles/lib/feature-flag-check.js +5 -9
- package/dist/modules/feature_toggles/lib/feature-flag-check.js.map +2 -2
- package/dist/modules/inbox_ops/api/emails/[id]/reprocess/route.js +4 -2
- package/dist/modules/inbox_ops/api/emails/[id]/reprocess/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/emails/[id]/route.js +4 -2
- package/dist/modules/inbox_ops/api/emails/[id]/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/emails/route.js +3 -1
- package/dist/modules/inbox_ops/api/emails/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/extract/route.js +3 -1
- package/dist/modules/inbox_ops/api/extract/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.js +3 -1
- package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/proposals/[id]/replies/[replyId]/send/route.js +4 -2
- package/dist/modules/inbox_ops/api/proposals/[id]/replies/[replyId]/send/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/proposals/counts/route.js +4 -2
- package/dist/modules/inbox_ops/api/proposals/counts/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/proposals/route.js +3 -1
- package/dist/modules/inbox_ops/api/proposals/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/routeHelpers.js +3 -1
- package/dist/modules/inbox_ops/api/routeHelpers.js.map +2 -2
- package/dist/modules/inbox_ops/api/settings/route.js +3 -1
- package/dist/modules/inbox_ops/api/settings/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/webhook/inbound.js +7 -5
- package/dist/modules/inbox_ops/api/webhook/inbound.js.map +2 -2
- package/dist/modules/inbox_ops/lib/cache.js +4 -2
- package/dist/modules/inbox_ops/lib/cache.js.map +2 -2
- package/dist/modules/inbox_ops/lib/catalogLookup.js +3 -1
- package/dist/modules/inbox_ops/lib/catalogLookup.js.map +2 -2
- package/dist/modules/inbox_ops/lib/eventBus.js +3 -4
- package/dist/modules/inbox_ops/lib/eventBus.js.map +2 -2
- package/dist/modules/inbox_ops/lib/messagesIntegration.js +4 -8
- package/dist/modules/inbox_ops/lib/messagesIntegration.js.map +2 -2
- package/dist/modules/inbox_ops/subscribers/executionAuditor.js +3 -1
- package/dist/modules/inbox_ops/subscribers/executionAuditor.js.map +2 -2
- package/dist/modules/inbox_ops/subscribers/extractionWorker.js +10 -8
- package/dist/modules/inbox_ops/subscribers/extractionWorker.js.map +2 -2
- package/dist/modules/inbox_ops/subscribers/proposalNotifier.js +3 -1
- package/dist/modules/inbox_ops/subscribers/proposalNotifier.js.map +2 -2
- package/dist/modules/messages/api/[id]/route.js +3 -4
- package/dist/modules/messages/api/[id]/route.js.map +2 -2
- package/dist/modules/messages/commands/actions.js +3 -1
- package/dist/modules/messages/commands/actions.js.map +2 -2
- package/dist/modules/messages/components/MessagesInboxPageClient.js +3 -1
- package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
- package/dist/modules/messages/lib/email-sender.js +3 -7
- package/dist/modules/messages/lib/email-sender.js.map +2 -2
- package/dist/modules/messages/lib/message-objects-registry.js +3 -1
- package/dist/modules/messages/lib/message-objects-registry.js.map +2 -2
- package/dist/modules/messages/lib/message-types-registry.js +3 -1
- package/dist/modules/messages/lib/message-types-registry.js.map +2 -2
- package/dist/modules/messages/workers/send-email.worker.js +6 -4
- package/dist/modules/messages/workers/send-email.worker.js.map +2 -2
- package/dist/modules/notifications/lib/notificationMapper.js +3 -4
- package/dist/modules/notifications/lib/notificationMapper.js.map +2 -2
- package/dist/modules/notifications/lib/notificationService.js +4 -5
- package/dist/modules/notifications/lib/notificationService.js.map +2 -2
- package/dist/modules/notifications/subscribers/deliver-notification.js +8 -13
- package/dist/modules/notifications/subscribers/deliver-notification.js.map +2 -2
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +3 -1
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +2 -2
- package/dist/modules/perspectives/services/perspectiveService.js +3 -3
- package/dist/modules/perspectives/services/perspectiveService.js.map +2 -2
- package/dist/modules/planner/api/access.js +3 -3
- package/dist/modules/planner/api/access.js.map +2 -2
- package/dist/modules/planner/api/availability-date-specific.js +3 -1
- package/dist/modules/planner/api/availability-date-specific.js.map +2 -2
- package/dist/modules/planner/api/availability-weekly.js +3 -1
- package/dist/modules/planner/api/availability-weekly.js.map +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js +4 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRulesEditor.js +3 -1
- package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
- package/dist/modules/progress/api/jobs/route.js +3 -1
- package/dist/modules/progress/api/jobs/route.js.map +2 -2
- package/dist/modules/query_index/components/QueryIndexesTable.js +5 -3
- package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
- package/dist/modules/query_index/lib/batch.js +4 -2
- package/dist/modules/query_index/lib/batch.js.map +2 -2
- package/dist/modules/query_index/lib/coverage.js +3 -1
- package/dist/modules/query_index/lib/coverage.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +13 -18
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/lib/reindexer.js +8 -6
- package/dist/modules/query_index/lib/reindexer.js.map +2 -2
- package/dist/modules/query_index/lib/search-tokens.js +3 -1
- package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
- package/dist/modules/query_index/subscribers/coverage_refresh.js +3 -1
- package/dist/modules/query_index/subscribers/coverage_refresh.js.map +2 -2
- package/dist/modules/resources/api/comments.js +3 -1
- package/dist/modules/resources/api/comments.js.map +2 -2
- package/dist/modules/resources/api/resources/tags/assign/route.js +3 -1
- package/dist/modules/resources/api/resources/tags/assign/route.js.map +2 -2
- package/dist/modules/resources/api/resources/tags/unassign/route.js +3 -1
- package/dist/modules/resources/api/resources/tags/unassign/route.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js +3 -1
- package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js +4 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/commands/activities.js +6 -5
- package/dist/modules/resources/commands/activities.js.map +2 -2
- package/dist/modules/resources/commands/comments.js +6 -4
- package/dist/modules/resources/commands/comments.js.map +2 -2
- package/dist/modules/resources/commands/shared.js +24 -1
- package/dist/modules/resources/commands/shared.js.map +2 -2
- package/dist/modules/sales/api/channels/route.js +3 -1
- package/dist/modules/sales/api/channels/route.js.map +2 -2
- package/dist/modules/sales/api/document-history/route.js +3 -1
- package/dist/modules/sales/api/document-history/route.js.map +2 -2
- package/dist/modules/sales/api/document-numbers/route.js +3 -1
- package/dist/modules/sales/api/document-numbers/route.js.map +2 -2
- package/dist/modules/sales/api/quotes/accept/route.js +4 -2
- package/dist/modules/sales/api/quotes/accept/route.js.map +2 -2
- package/dist/modules/sales/api/quotes/convert/route.js +3 -1
- package/dist/modules/sales/api/quotes/convert/route.js.map +2 -2
- package/dist/modules/sales/api/quotes/public/[token]/route.js +3 -1
- package/dist/modules/sales/api/quotes/public/[token]/route.js.map +2 -2
- package/dist/modules/sales/api/quotes/send/route.js +3 -1
- package/dist/modules/sales/api/quotes/send/route.js.map +2 -2
- package/dist/modules/sales/api/returns/[id]/route.js +3 -1
- package/dist/modules/sales/api/returns/[id]/route.js.map +2 -2
- package/dist/modules/sales/api/settings/document-numbers/route.js +4 -2
- package/dist/modules/sales/api/settings/document-numbers/route.js.map +2 -2
- package/dist/modules/sales/api/settings/order-editing/route.js +4 -2
- package/dist/modules/sales/api/settings/order-editing/route.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +3 -1
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js +6 -4
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +4 -2
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +20 -18
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +4 -8
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/commands/payments.js +3 -1
- package/dist/modules/sales/commands/payments.js.map +2 -2
- package/dist/modules/sales/commands/shipments.js +3 -1
- package/dist/modules/sales/commands/shipments.js.map +2 -2
- package/dist/modules/sales/components/AdjustmentKindSettings.js +5 -3
- package/dist/modules/sales/components/AdjustmentKindSettings.js.map +2 -2
- package/dist/modules/sales/components/DocumentNumberSettings.js +4 -2
- package/dist/modules/sales/components/DocumentNumberSettings.js.map +2 -2
- package/dist/modules/sales/components/OrderEditingSettings.js +4 -2
- package/dist/modules/sales/components/OrderEditingSettings.js.map +2 -2
- package/dist/modules/sales/components/PaymentMethodsSettings.js +5 -3
- package/dist/modules/sales/components/PaymentMethodsSettings.js.map +2 -2
- package/dist/modules/sales/components/ShippingMethodsSettings.js +5 -3
- package/dist/modules/sales/components/ShippingMethodsSettings.js.map +2 -2
- package/dist/modules/sales/components/StatusSettings.js +5 -3
- package/dist/modules/sales/components/StatusSettings.js.map +2 -2
- package/dist/modules/sales/components/TaxRatesSettings.js +5 -3
- package/dist/modules/sales/components/TaxRatesSettings.js.map +2 -2
- package/dist/modules/sales/components/channels/ChannelOfferForm.js +16 -14
- package/dist/modules/sales/components/channels/ChannelOfferForm.js.map +2 -2
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +4 -2
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
- package/dist/modules/sales/components/documents/AddressesSection.js +5 -3
- package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentDialog.js +3 -1
- package/dist/modules/sales/components/documents/AdjustmentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentsSection.js +5 -3
- package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +6 -4
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +8 -6
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentDialog.js +5 -3
- package/dist/modules/sales/components/documents/PaymentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js +4 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentForm.js +14 -12
- package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +5 -3
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +9 -7
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentsSection.js +4 -2
- package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
- package/dist/modules/sales/frontend/quote/[token]/page.js +4 -2
- package/dist/modules/sales/frontend/quote/[token]/page.js.map +2 -2
- package/dist/modules/sales/seed/examples.js +7 -9
- package/dist/modules/sales/seed/examples.js.map +2 -2
- package/dist/modules/sales/subscribers/quote-expiring-notification.js +3 -1
- package/dist/modules/sales/subscribers/quote-expiring-notification.js.map +2 -2
- package/dist/modules/sales/subscribers/reconcileOnAddressDelete.js +3 -1
- package/dist/modules/sales/subscribers/reconcileOnAddressDelete.js.map +2 -2
- package/dist/modules/sales/subscribers/reconcileOnCompanyDelete.js +3 -1
- package/dist/modules/sales/subscribers/reconcileOnCompanyDelete.js.map +2 -2
- package/dist/modules/sales/subscribers/reconcileOnCustomerDelete.js +3 -1
- package/dist/modules/sales/subscribers/reconcileOnCustomerDelete.js.map +2 -2
- package/dist/modules/sales/widgets/dashboard/makeDashboardWidgetRoute.js +5 -3
- package/dist/modules/sales/widgets/dashboard/makeDashboardWidgetRoute.js.map +2 -2
- package/dist/modules/sales/widgets/dashboard/new-orders/widget.client.js +3 -1
- package/dist/modules/sales/widgets/dashboard/new-orders/widget.client.js.map +2 -2
- package/dist/modules/sales/widgets/dashboard/new-quotes/widget.client.js +3 -1
- package/dist/modules/sales/widgets/dashboard/new-quotes/widget.client.js.map +2 -2
- package/dist/modules/shipping_carriers/api/tracking/route.js +5 -0
- package/dist/modules/shipping_carriers/api/tracking/route.js.map +2 -2
- package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js +3 -1
- package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/shipping-service.js +41 -19
- package/dist/modules/shipping_carriers/lib/shipping-service.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/upstream-error-response.js +3 -1
- package/dist/modules/shipping_carriers/lib/upstream-error-response.js.map +2 -2
- package/dist/modules/shipping_carriers/workers/webhook-processor.js +3 -5
- package/dist/modules/shipping_carriers/workers/webhook-processor.js.map +2 -2
- package/dist/modules/staff/api/comments.js +3 -1
- package/dist/modules/staff/api/comments.js.map +2 -2
- package/dist/modules/staff/api/leave-requests/accept/route.js +3 -1
- package/dist/modules/staff/api/leave-requests/accept/route.js.map +2 -2
- package/dist/modules/staff/api/leave-requests/reject/route.js +3 -1
- package/dist/modules/staff/api/leave-requests/reject/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/assignable/route.js +3 -1
- package/dist/modules/staff/api/team-members/assignable/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/self/route.js +4 -2
- package/dist/modules/staff/api/team-members/self/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/tags/assign/route.js +3 -1
- package/dist/modules/staff/api/team-members/tags/assign/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/tags/unassign/route.js +3 -1
- package/dist/modules/staff/api/team-members/tags/unassign/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js +3 -1
- package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/my-projects/route.js +3 -1
- package/dist/modules/staff/api/timesheets/my-projects/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/projects/kpis/route.js +3 -1
- package/dist/modules/staff/api/timesheets/projects/kpis/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js +3 -1
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js +4 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js +4 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js +3 -1
- package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js +3 -1
- package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/page.js +4 -2
- package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js +4 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +4 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js +4 -2
- package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/page.js +7 -5
- package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js +3 -1
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js +4 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
- package/dist/modules/staff/commands/timesheets-entries.js +3 -1
- package/dist/modules/staff/commands/timesheets-entries.js.map +2 -2
- package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.js +3 -1
- package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.js.map +2 -2
- package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.js +5 -3
- package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.js.map +2 -2
- package/dist/modules/sync_excel/api/import/route.js +3 -1
- package/dist/modules/sync_excel/api/import/route.js.map +2 -2
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js +5 -3
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
- package/dist/modules/translations/api/get/locales.js +3 -1
- package/dist/modules/translations/api/get/locales.js.map +2 -2
- package/dist/modules/translations/api/put/locales.js +3 -1
- package/dist/modules/translations/api/put/locales.js.map +2 -2
- package/dist/modules/translations/components/TranslationManager.js +3 -1
- package/dist/modules/translations/components/TranslationManager.js.map +2 -2
- package/dist/modules/translations/subscribers/cleanup.js +3 -1
- package/dist/modules/translations/subscribers/cleanup.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/customize/route.js +4 -2
- package/dist/modules/workflows/api/definitions/[id]/customize/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/reset-to-code/route.js +4 -2
- package/dist/modules/workflows/api/definitions/[id]/reset-to-code/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/route.js +6 -4
- package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/route.js +4 -2
- package/dist/modules/workflows/api/definitions/route.js.map +2 -2
- package/dist/modules/workflows/api/events/[id]/route.js +3 -1
- package/dist/modules/workflows/api/events/[id]/route.js.map +2 -2
- package/dist/modules/workflows/api/events/route.js +3 -1
- package/dist/modules/workflows/api/events/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/advance/route.js +3 -1
- package/dist/modules/workflows/api/instances/[id]/advance/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/cancel/route.js +3 -1
- package/dist/modules/workflows/api/instances/[id]/cancel/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/events/route.js +3 -1
- package/dist/modules/workflows/api/instances/[id]/events/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/retry/route.js +3 -1
- package/dist/modules/workflows/api/instances/[id]/retry/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/route.js +3 -1
- package/dist/modules/workflows/api/instances/[id]/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/signal/route.js +5 -7
- package/dist/modules/workflows/api/instances/[id]/signal/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/route.js +5 -3
- package/dist/modules/workflows/api/instances/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/validate-start/route.js +3 -1
- package/dist/modules/workflows/api/instances/validate-start/route.js.map +2 -2
- package/dist/modules/workflows/api/signals/route.js +3 -1
- package/dist/modules/workflows/api/signals/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/[id]/claim/route.js +3 -1
- package/dist/modules/workflows/api/tasks/[id]/claim/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/[id]/complete/route.js +3 -1
- package/dist/modules/workflows/api/tasks/[id]/complete/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/[id]/route.js +3 -1
- package/dist/modules/workflows/api/tasks/[id]/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/route.js +3 -1
- package/dist/modules/workflows/api/tasks/route.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +4 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
- package/dist/modules/workflows/backend/instances/[id]/page.js +5 -3
- package/dist/modules/workflows/backend/instances/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/[id]/page.js +3 -1
- package/dist/modules/workflows/backend/tasks/[id]/page.js.map +2 -2
- package/dist/modules/workflows/components/BusinessRulesSelector.js +5 -3
- package/dist/modules/workflows/components/BusinessRulesSelector.js.map +2 -2
- package/dist/modules/workflows/components/WorkflowSelector.js +5 -3
- package/dist/modules/workflows/components/WorkflowSelector.js.map +2 -2
- package/dist/modules/workflows/components/fields/BusinessRuleConditionsEditor.js +3 -1
- package/dist/modules/workflows/components/fields/BusinessRuleConditionsEditor.js.map +2 -2
- package/dist/modules/workflows/components/fields/StartPreConditionsEditor.js +3 -1
- package/dist/modules/workflows/components/fields/StartPreConditionsEditor.js.map +2 -2
- package/dist/modules/workflows/components/fields/WorkflowSelectorField.js +3 -1
- package/dist/modules/workflows/components/fields/WorkflowSelectorField.js.map +2 -2
- package/dist/modules/workflows/frontend/checkout-demo/page.js +8 -7
- package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
- package/dist/modules/workflows/lib/activity-executor.js +25 -21
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/dist/modules/workflows/lib/activity-worker-handler.js +8 -15
- package/dist/modules/workflows/lib/activity-worker-handler.js.map +2 -2
- package/dist/modules/workflows/lib/code-registry.js +7 -7
- package/dist/modules/workflows/lib/code-registry.js.map +2 -2
- package/dist/modules/workflows/lib/compensation-handler.js +4 -2
- package/dist/modules/workflows/lib/compensation-handler.js.map +2 -2
- package/dist/modules/workflows/lib/edgeFormTransforms.js +3 -1
- package/dist/modules/workflows/lib/edgeFormTransforms.js.map +2 -2
- package/dist/modules/workflows/lib/event-trigger-service.js +5 -3
- package/dist/modules/workflows/lib/event-trigger-service.js.map +2 -2
- package/dist/modules/workflows/lib/nodeFormTransforms.js +3 -1
- package/dist/modules/workflows/lib/nodeFormTransforms.js.map +2 -2
- package/dist/modules/workflows/lib/seeds.js +16 -2
- package/dist/modules/workflows/lib/seeds.js.map +2 -2
- package/dist/modules/workflows/lib/signal-handler.js +3 -1
- package/dist/modules/workflows/lib/signal-handler.js.map +2 -2
- package/dist/modules/workflows/lib/start-validator.js +9 -3
- package/dist/modules/workflows/lib/start-validator.js.map +2 -2
- package/dist/modules/workflows/lib/step-handler.js +3 -1
- package/dist/modules/workflows/lib/step-handler.js.map +2 -2
- package/dist/modules/workflows/lib/task-handler.js +3 -1
- package/dist/modules/workflows/lib/task-handler.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +5 -3
- package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
- package/dist/modules/workflows/lib/workflow-executor.js +27 -15
- package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
- package/dist/modules/workflows/subscribers/event-trigger.js +21 -18
- package/dist/modules/workflows/subscribers/event-trigger.js.map +2 -2
- package/dist/modules/workflows/subscribers/task-assigned-notification.js +3 -1
- package/dist/modules/workflows/subscribers/task-assigned-notification.js.map +2 -2
- package/dist/modules/workflows/workers/workflow-activities.worker.js +30 -20
- package/dist/modules/workflows/workers/workflow-activities.worker.js.map +2 -2
- package/package.json +7 -7
- package/src/bootstrap.ts +14 -11
- package/src/helpers/integration/queue-runner.ts +2 -2
- package/src/modules/api_keys/services/apiKeyService.ts +6 -3
- package/src/modules/attachments/api/image/[id]/[[...slug]]/route.ts +5 -2
- package/src/modules/attachments/api/library/[id]/route.ts +4 -1
- package/src/modules/attachments/api/route.ts +9 -6
- package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +6 -3
- package/src/modules/attachments/lib/assignmentDetails.ts +4 -1
- package/src/modules/attachments/lib/drivers/driverFactory.ts +4 -1
- package/src/modules/attachments/lib/ocrQueue.ts +11 -11
- package/src/modules/attachments/lib/ocrService.ts +7 -4
- package/src/modules/audit_logs/api/audit-logs/actions/redo/route.ts +4 -1
- package/src/modules/audit_logs/api/audit-logs/actions/undo/route.ts +4 -1
- package/src/modules/audit_logs/backend/audit-logs/page.tsx +4 -1
- package/src/modules/audit_logs/components/AuditLogsActions.tsx +5 -2
- package/src/modules/audit_logs/services/accessLogService.ts +5 -4
- package/src/modules/audit_logs/services/actionLogService.ts +5 -2
- package/src/modules/auth/api/profile/route.ts +5 -2
- package/src/modules/auth/api/reset/confirm.ts +4 -1
- package/src/modules/auth/api/reset.ts +5 -2
- package/src/modules/auth/api/roles/route.ts +4 -1
- package/src/modules/auth/api/sidebar/variants/route.ts +4 -2
- package/src/modules/auth/api/users/resend-invite/route.ts +5 -2
- package/src/modules/auth/api/users/route.ts +4 -1
- package/src/modules/auth/backend/auth/profile/page.tsx +4 -1
- package/src/modules/auth/backend/profile/change-password/page.tsx +4 -1
- package/src/modules/auth/backend/users/[id]/edit/page.tsx +6 -3
- package/src/modules/auth/backend/users/create/page.tsx +5 -2
- package/src/modules/auth/cli.ts +10 -0
- package/src/modules/auth/commands/users.ts +5 -2
- package/src/modules/auth/lib/consentIntegrity.ts +4 -4
- package/src/modules/auth/lib/setup-app.ts +10 -10
- package/src/modules/auth/lib/tenantAccess.ts +4 -1
- package/src/modules/auth/lib/tokenHash.ts +4 -4
- package/src/modules/business_rules/api/rules/route.ts +5 -2
- package/src/modules/business_rules/lib/expression-evaluator.ts +8 -6
- package/src/modules/business_rules/lib/rule-engine.ts +6 -3
- package/src/modules/business_rules/lib/rule-evaluator.ts +11 -11
- package/src/modules/business_rules/subscribers/crud-rule-trigger.ts +4 -1
- package/src/modules/business_rules/subscribers/rule-execution-failed-notification.ts +4 -1
- package/src/modules/catalog/ai-agents-context.ts +5 -5
- package/src/modules/catalog/ai-tools/_shared.ts +4 -1
- package/src/modules/catalog/ai-tools/authoring-pack.ts +4 -1
- package/src/modules/catalog/ai-tools/merchandising-pack.ts +4 -1
- package/src/modules/catalog/api/dictionaries/[key]/route.ts +4 -1
- package/src/modules/catalog/api/prices/route.ts +4 -1
- package/src/modules/catalog/api/products/route.ts +6 -3
- package/src/modules/catalog/api/settings/route.ts +5 -2
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +15 -12
- package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +9 -6
- package/src/modules/catalog/backend/catalog/products/[productId]/variants/create/page.tsx +6 -3
- package/src/modules/catalog/backend/catalog/products/create/page.tsx +6 -6
- package/src/modules/catalog/backend/catalog/products/optionSchemaClient.ts +4 -1
- package/src/modules/catalog/components/PriceKindSettings.tsx +6 -3
- package/src/modules/catalog/components/UnitPriceDisplaySettings.tsx +5 -2
- package/src/modules/catalog/inbox-actions.ts +5 -2
- package/src/modules/catalog/seed/examples.ts +5 -5
- package/src/modules/catalog/subscribers/low-stock-notification.ts +4 -1
- package/src/modules/catalog/widgets/injection/product-seo/state.ts +4 -1
- package/src/modules/communication_channels/api/get/oauth/[provider]/callback/route.ts +13 -13
- package/src/modules/communication_channels/api/post/channels/[id]/import-history/route.ts +4 -1
- package/src/modules/communication_channels/api/post/channels/[id]/push/register/route.ts +4 -1
- package/src/modules/communication_channels/api/post/webhook/[provider]/route.ts +6 -3
- package/src/modules/communication_channels/api/post/webhooks/gmail/route.ts +7 -6
- package/src/modules/communication_channels/commands/connect-credential-channel.ts +5 -10
- package/src/modules/communication_channels/commands/delete-channel.ts +4 -5
- package/src/modules/communication_channels/commands/deliver-outbound-message.ts +5 -5
- package/src/modules/communication_channels/commands/disconnect-channel.ts +4 -5
- package/src/modules/communication_channels/commands/ingest-inbound-message.ts +6 -12
- package/src/modules/communication_channels/commands/push-unregister.ts +4 -3
- package/src/modules/communication_channels/commands/reassign-conversation.ts +6 -3
- package/src/modules/communication_channels/lib/dead-letter.ts +4 -5
- package/src/modules/communication_channels/lib/email-mime.ts +5 -6
- package/src/modules/communication_channels/lib/oauth-client-config.ts +7 -3
- package/src/modules/communication_channels/lib/send-as-user.ts +4 -1
- package/src/modules/communication_channels/lib/thread-token.ts +5 -2
- package/src/modules/communication_channels/setup.ts +4 -4
- package/src/modules/communication_channels/workers/channel-import-history.ts +5 -8
- package/src/modules/communication_channels/workers/gmail-history-sync.ts +9 -18
- package/src/modules/communication_channels/workers/gmail-renew-watch.ts +6 -9
- package/src/modules/communication_channels/workers/outbound-delivery.ts +7 -12
- package/src/modules/communication_channels/workers/poll-channel.ts +8 -15
- package/src/modules/communication_channels/workers/poll-tick.ts +6 -6
- package/src/modules/communication_channels/workers/reaction-processor.ts +6 -9
- package/src/modules/configs/api/cache/route.ts +5 -2
- package/src/modules/configs/api/system-status/route.ts +5 -2
- package/src/modules/configs/api/upgrade-actions/route.ts +5 -2
- package/src/modules/configs/components/ModuleTelemetryPanel.tsx +4 -1
- package/src/modules/configs/lib/touchGeneratedBarrels.ts +1 -1
- package/src/modules/configs/services/upgradeActionsService.ts +7 -3
- package/src/modules/currencies/components/CurrencyFetchingConfig.tsx +4 -1
- package/src/modules/currencies/lib/exchangeRateFormConfig.ts +4 -1
- package/src/modules/currencies/services/providers/nbp.ts +7 -4
- package/src/modules/currencies/services/providers/raiffeisen.ts +8 -7
- package/src/modules/customer_accounts/api/domain-resolve/all.ts +7 -5
- package/src/modules/customer_accounts/api/signup.ts +5 -2
- package/src/modules/customer_accounts/lib/customerAuthServer.ts +4 -1
- package/src/modules/customer_accounts/subscribers/autoLinkCrm.ts +4 -1
- package/src/modules/customer_accounts/subscribers/autoLinkCrmReverse.ts +4 -1
- package/src/modules/customer_accounts/subscribers/unlinkOnCompanyDelete.ts +4 -1
- package/src/modules/customer_accounts/subscribers/unlinkOnPersonDelete.ts +4 -1
- package/src/modules/customers/ai-agents-context.ts +5 -5
- package/src/modules/customers/api/activities/route.ts +7 -4
- package/src/modules/customers/api/comments/route.ts +4 -1
- package/src/modules/customers/api/companies/[id]/people/route.ts +4 -1
- package/src/modules/customers/api/companies/[id]/route.ts +6 -3
- package/src/modules/customers/api/companies/route.ts +6 -3
- package/src/modules/customers/api/dashboard/widgets/customer-todos/route.ts +4 -1
- package/src/modules/customers/api/dashboard/widgets/new-customers/route.ts +4 -1
- package/src/modules/customers/api/dashboard/widgets/new-deals/route.ts +4 -1
- package/src/modules/customers/api/dashboard/widgets/next-interactions/route.ts +4 -1
- 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/aggregate/route.ts +4 -1
- package/src/modules/customers/api/deals/bulk-update-owner/route.ts +8 -5
- package/src/modules/customers/api/deals/bulk-update-stage/route.ts +8 -5
- package/src/modules/customers/api/deals/route.ts +4 -1
- package/src/modules/customers/api/deals/summary/route.ts +4 -1
- package/src/modules/customers/api/dictionaries/[kind]/[id]/route.ts +5 -2
- package/src/modules/customers/api/dictionaries/[kind]/route.ts +6 -3
- package/src/modules/customers/api/dictionaries/cache.ts +4 -1
- package/src/modules/customers/api/dictionaries/context.ts +4 -1
- package/src/modules/customers/api/dictionaries/currency/route.ts +4 -1
- package/src/modules/customers/api/dictionaries/kind-settings/route.ts +5 -2
- package/src/modules/customers/api/entity-roles-factory.ts +8 -5
- package/src/modules/customers/api/interactions/cancel/route.ts +4 -1
- package/src/modules/customers/api/interactions/complete/route.ts +4 -1
- package/src/modules/customers/api/interactions/conflicts/route.ts +4 -1
- package/src/modules/customers/api/interactions/counts/route.ts +4 -1
- package/src/modules/customers/api/interactions/route.ts +8 -4
- package/src/modules/customers/api/interactions/tasks/route.ts +4 -1
- package/src/modules/customers/api/labels/assign/route.ts +4 -1
- package/src/modules/customers/api/labels/route.ts +7 -3
- package/src/modules/customers/api/labels/unassign/route.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 +6 -3
- package/src/modules/customers/api/people/route.ts +6 -3
- package/src/modules/customers/api/pipeline-stages/reorder/route.ts +4 -1
- package/src/modules/customers/api/pipeline-stages/route.ts +7 -4
- package/src/modules/customers/api/pipelines/route.ts +7 -4
- package/src/modules/customers/api/settings/address-format/route.ts +5 -2
- package/src/modules/customers/api/settings/dictionary-sort-modes/route.ts +5 -2
- package/src/modules/customers/api/settings/stuck-threshold/route.ts +5 -2
- package/src/modules/customers/api/tags/assign/route.ts +4 -1
- package/src/modules/customers/api/tags/unassign/route.ts +4 -1
- package/src/modules/customers/api/todos/route.ts +7 -4
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +6 -3
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.ts +4 -1
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.ts +4 -1
- package/src/modules/customers/backend/customers/deals/map/components/DealsMapCanvasImpl.tsx +5 -3
- package/src/modules/customers/backend/customers/deals/page.tsx +5 -2
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +6 -3
- package/src/modules/customers/commands/deals.ts +4 -1
- package/src/modules/customers/commands/dictionaries.ts +4 -1
- package/src/modules/customers/commands/interactions.ts +5 -2
- package/src/modules/customers/commands/shared.ts +5 -2
- package/src/modules/customers/commands/todos.ts +4 -1
- package/src/modules/customers/components/DictionarySettings.tsx +6 -3
- package/src/modules/customers/components/DictionarySortSettings.tsx +4 -1
- package/src/modules/customers/components/detail/ActivitiesCard.tsx +4 -1
- package/src/modules/customers/components/detail/ActivitiesDayStrip.tsx +4 -1
- package/src/modules/customers/components/detail/ActivitiesSection.tsx +7 -4
- package/src/modules/customers/components/detail/ActivityCard.tsx +4 -1
- package/src/modules/customers/components/detail/ChangelogTab.tsx +4 -1
- package/src/modules/customers/components/detail/CompanyCard.tsx +4 -1
- package/src/modules/customers/components/detail/ConfirmDealLostDialog.tsx +4 -1
- package/src/modules/customers/components/detail/EntityTagsDialog.tsx +4 -1
- package/src/modules/customers/components/detail/InlineActivityComposer.tsx +4 -1
- package/src/modules/customers/components/detail/ManageTagsDialog.tsx +4 -1
- package/src/modules/customers/components/detail/RoleAssignmentRow.tsx +6 -3
- package/src/modules/customers/components/detail/RolesSection.tsx +5 -2
- package/src/modules/customers/components/detail/hooks/useInteractionMutations.ts +6 -3
- package/src/modules/customers/components/linking/LinkEntityDialog.tsx +5 -2
- package/src/modules/customers/inbox-actions.ts +4 -1
- package/src/modules/customers/lib/bulkDeals.ts +4 -1
- package/src/modules/customers/lib/dealClosureNotification.ts +5 -2
- package/src/modules/customers/lib/dealStageTransitionTable.ts +4 -1
- package/src/modules/customers/lib/interactionFeatureFlags.ts +5 -1
- package/src/modules/customers/lib/todoCompatibility.ts +4 -1
- package/src/modules/customers/search.ts +15 -7
- package/src/modules/customers/widgets/dashboard/customer-todos/widget.client.tsx +4 -1
- package/src/modules/customers/widgets/dashboard/new-customers/widget.client.tsx +4 -1
- package/src/modules/customers/widgets/dashboard/new-deals/widget.client.tsx +4 -1
- package/src/modules/customers/widgets/dashboard/next-interactions/widget.client.tsx +4 -1
- package/src/modules/dashboards/api/widgets/data/batch/route.ts +4 -1
- package/src/modules/dashboards/api/widgets/data/route.ts +4 -1
- package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +6 -3
- package/src/modules/dashboards/widgets/dashboard/aov-kpi/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/orders-by-status/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/orders-kpi/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/pipeline-summary/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/revenue-kpi/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/top-customers/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/top-products/widget.client.tsx +4 -1
- package/src/modules/data_sync/api/run.ts +4 -1
- package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +3 -1
- package/src/modules/data_sync/lib/adapter-registry.ts +16 -4
- package/src/modules/data_sync/lib/sync-engine.ts +31 -2
- package/src/modules/data_sync/workers/sync-export.ts +4 -1
- package/src/modules/data_sync/workers/sync-import.ts +4 -1
- package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +5 -2
- package/src/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.ts +4 -1
- package/src/modules/dictionaries/api/[dictionaryId]/entries/route.ts +5 -2
- package/src/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.ts +4 -1
- package/src/modules/dictionaries/api/[dictionaryId]/route.ts +6 -3
- package/src/modules/dictionaries/api/context.ts +4 -1
- package/src/modules/dictionaries/api/route.ts +5 -2
- package/src/modules/dictionaries/components/DictionariesManager.tsx +6 -3
- package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +5 -2
- package/src/modules/dictionaries/components/DictionaryEntrySelect.tsx +5 -2
- package/src/modules/dictionaries/components/DictionarySelectControl.tsx +4 -1
- package/src/modules/dictionaries/fields/dictionary.tsx +4 -1
- package/src/modules/directory/api/organization-branding/route.ts +4 -1
- package/src/modules/directory/api/organization-switcher/route.ts +4 -1
- package/src/modules/directory/commands/tenants.ts +6 -3
- package/src/modules/directory/utils/organizationScope.ts +7 -4
- package/src/modules/entities/api/definitions.cache.ts +4 -1
- package/src/modules/entities/api/definitions.ts +8 -5
- package/src/modules/entities/api/records.ts +5 -2
- package/src/modules/entities/components/EncryptionManager.tsx +4 -1
- package/src/modules/entities/lib/makeActivityRoute.ts +4 -1
- package/src/modules/feature_toggles/api/overrides/route.ts +4 -1
- package/src/modules/feature_toggles/lib/feature-flag-check.ts +6 -9
- package/src/modules/inbox_ops/api/emails/[id]/reprocess/route.ts +5 -2
- package/src/modules/inbox_ops/api/emails/[id]/route.ts +5 -2
- package/src/modules/inbox_ops/api/emails/route.ts +4 -1
- package/src/modules/inbox_ops/api/extract/route.ts +4 -1
- package/src/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.ts +4 -1
- package/src/modules/inbox_ops/api/proposals/[id]/replies/[replyId]/send/route.ts +5 -2
- package/src/modules/inbox_ops/api/proposals/counts/route.ts +5 -2
- package/src/modules/inbox_ops/api/proposals/route.ts +4 -1
- package/src/modules/inbox_ops/api/routeHelpers.ts +4 -1
- package/src/modules/inbox_ops/api/settings/route.ts +4 -1
- package/src/modules/inbox_ops/api/webhook/inbound.ts +8 -5
- package/src/modules/inbox_ops/lib/cache.ts +5 -2
- package/src/modules/inbox_ops/lib/catalogLookup.ts +4 -1
- package/src/modules/inbox_ops/lib/eventBus.ts +4 -4
- package/src/modules/inbox_ops/lib/messagesIntegration.ts +5 -8
- package/src/modules/inbox_ops/subscribers/executionAuditor.ts +5 -1
- package/src/modules/inbox_ops/subscribers/extractionWorker.ts +11 -8
- package/src/modules/inbox_ops/subscribers/proposalNotifier.ts +4 -1
- package/src/modules/messages/api/[id]/route.ts +4 -4
- package/src/modules/messages/commands/actions.ts +4 -1
- package/src/modules/messages/components/MessagesInboxPageClient.tsx +4 -1
- package/src/modules/messages/lib/email-sender.ts +4 -7
- package/src/modules/messages/lib/message-objects-registry.ts +4 -1
- package/src/modules/messages/lib/message-types-registry.ts +4 -1
- package/src/modules/messages/workers/send-email.worker.ts +7 -4
- package/src/modules/notifications/lib/notificationMapper.ts +4 -4
- package/src/modules/notifications/lib/notificationService.ts +4 -5
- package/src/modules/notifications/subscribers/deliver-notification.ts +9 -14
- package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +4 -1
- package/src/modules/perspectives/services/perspectiveService.ts +4 -3
- package/src/modules/planner/api/access.ts +4 -3
- package/src/modules/planner/api/availability-date-specific.ts +4 -1
- package/src/modules/planner/api/availability-weekly.ts +4 -1
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +5 -2
- package/src/modules/planner/components/AvailabilityRulesEditor.tsx +4 -1
- package/src/modules/progress/api/jobs/route.ts +4 -1
- package/src/modules/query_index/components/QueryIndexesTable.tsx +6 -3
- package/src/modules/query_index/lib/batch.ts +5 -2
- package/src/modules/query_index/lib/coverage.ts +4 -1
- package/src/modules/query_index/lib/engine.ts +14 -17
- package/src/modules/query_index/lib/reindexer.ts +9 -6
- package/src/modules/query_index/lib/search-tokens.ts +4 -2
- package/src/modules/query_index/subscribers/coverage_refresh.ts +4 -1
- package/src/modules/resources/api/comments.ts +4 -1
- package/src/modules/resources/api/resources/tags/assign/route.ts +4 -1
- package/src/modules/resources/api/resources/tags/unassign/route.ts +4 -1
- package/src/modules/resources/backend/resources/resource-types/[id]/edit/page.tsx +4 -1
- package/src/modules/resources/backend/resources/resource-types/page.tsx +5 -2
- package/src/modules/resources/commands/activities.ts +5 -4
- package/src/modules/resources/commands/comments.ts +6 -4
- package/src/modules/resources/commands/shared.ts +36 -0
- package/src/modules/sales/api/channels/route.ts +4 -1
- package/src/modules/sales/api/document-history/route.ts +4 -1
- package/src/modules/sales/api/document-numbers/route.ts +4 -1
- package/src/modules/sales/api/quotes/accept/route.ts +5 -2
- package/src/modules/sales/api/quotes/convert/route.ts +4 -1
- package/src/modules/sales/api/quotes/public/[token]/route.ts +4 -1
- package/src/modules/sales/api/quotes/send/route.ts +4 -1
- package/src/modules/sales/api/returns/[id]/route.ts +4 -1
- package/src/modules/sales/api/settings/document-numbers/route.ts +5 -2
- package/src/modules/sales/api/settings/order-editing/route.ts +5 -2
- package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +4 -1
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +7 -4
- package/src/modules/sales/backend/sales/channels/page.tsx +5 -2
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +21 -18
- package/src/modules/sales/commands/documents.ts +5 -8
- package/src/modules/sales/commands/payments.ts +4 -1
- package/src/modules/sales/commands/shipments.ts +4 -2
- package/src/modules/sales/components/AdjustmentKindSettings.tsx +6 -3
- package/src/modules/sales/components/DocumentNumberSettings.tsx +5 -2
- package/src/modules/sales/components/OrderEditingSettings.tsx +5 -2
- package/src/modules/sales/components/PaymentMethodsSettings.tsx +6 -3
- package/src/modules/sales/components/ShippingMethodsSettings.tsx +6 -3
- package/src/modules/sales/components/StatusSettings.tsx +6 -3
- package/src/modules/sales/components/TaxRatesSettings.tsx +6 -3
- package/src/modules/sales/components/channels/ChannelOfferForm.tsx +17 -14
- package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +5 -2
- package/src/modules/sales/components/documents/AddressesSection.tsx +6 -3
- package/src/modules/sales/components/documents/AdjustmentDialog.tsx +4 -1
- package/src/modules/sales/components/documents/AdjustmentsSection.tsx +6 -3
- package/src/modules/sales/components/documents/ItemsSection.tsx +7 -4
- package/src/modules/sales/components/documents/LineItemDialog.tsx +9 -6
- package/src/modules/sales/components/documents/PaymentDialog.tsx +6 -3
- package/src/modules/sales/components/documents/PaymentsSection.tsx +5 -2
- package/src/modules/sales/components/documents/SalesDocumentForm.tsx +15 -12
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +6 -3
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +10 -7
- package/src/modules/sales/components/documents/ShipmentsSection.tsx +5 -2
- package/src/modules/sales/frontend/quote/[token]/page.tsx +5 -2
- package/src/modules/sales/seed/examples.ts +8 -9
- package/src/modules/sales/subscribers/quote-expiring-notification.ts +4 -1
- package/src/modules/sales/subscribers/reconcileOnAddressDelete.ts +4 -1
- package/src/modules/sales/subscribers/reconcileOnCompanyDelete.ts +4 -1
- package/src/modules/sales/subscribers/reconcileOnCustomerDelete.ts +4 -1
- package/src/modules/sales/widgets/dashboard/makeDashboardWidgetRoute.ts +6 -3
- package/src/modules/sales/widgets/dashboard/new-orders/widget.client.tsx +274 -271
- package/src/modules/sales/widgets/dashboard/new-quotes/widget.client.tsx +280 -277
- package/src/modules/shipping_carriers/api/tracking/route.ts +5 -1
- package/src/modules/shipping_carriers/api/webhook/[provider]/route.ts +4 -1
- package/src/modules/shipping_carriers/lib/shipping-service.ts +47 -22
- package/src/modules/shipping_carriers/lib/upstream-error-response.ts +4 -1
- package/src/modules/shipping_carriers/workers/webhook-processor.ts +4 -5
- package/src/modules/staff/api/comments.ts +4 -1
- package/src/modules/staff/api/leave-requests/accept/route.ts +4 -1
- package/src/modules/staff/api/leave-requests/reject/route.ts +4 -1
- package/src/modules/staff/api/team-members/assignable/route.ts +4 -1
- package/src/modules/staff/api/team-members/self/route.ts +5 -2
- package/src/modules/staff/api/team-members/tags/assign/route.ts +4 -1
- package/src/modules/staff/api/team-members/tags/unassign/route.ts +4 -1
- package/src/modules/staff/api/timesheets/my-projects/[projectId]/route.ts +4 -1
- package/src/modules/staff/api/timesheets/my-projects/route.ts +4 -1
- package/src/modules/staff/api/timesheets/projects/kpis/route.ts +4 -1
- package/src/modules/staff/api/timesheets/time-entries/[id]/segments/route.ts +4 -1
- package/src/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.ts +5 -2
- package/src/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.ts +5 -2
- package/src/modules/staff/api/timesheets/time-entries/bulk/route.ts +4 -1
- package/src/modules/staff/api/timesheets/time-entries/start-timer/route.ts +4 -1
- package/src/modules/staff/backend/staff/team-members/page.tsx +5 -2
- package/src/modules/staff/backend/staff/team-roles/page.tsx +5 -2
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +5 -2
- package/src/modules/staff/backend/staff/teams/page.tsx +5 -2
- package/src/modules/staff/backend/staff/timesheets/page.tsx +8 -5
- package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +4 -1
- package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +5 -2
- package/src/modules/staff/commands/timesheets-entries.ts +4 -1
- package/src/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.tsx +4 -1
- package/src/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.tsx +6 -3
- package/src/modules/sync_excel/api/import/route.ts +4 -1
- package/src/modules/translations/api/[entityType]/[entityId]/route.ts +6 -3
- package/src/modules/translations/api/get/locales.ts +4 -1
- package/src/modules/translations/api/put/locales.ts +4 -1
- package/src/modules/translations/components/TranslationManager.tsx +4 -1
- package/src/modules/translations/subscribers/cleanup.ts +4 -1
- package/src/modules/workflows/api/definitions/[id]/customize/route.ts +5 -2
- package/src/modules/workflows/api/definitions/[id]/reset-to-code/route.ts +5 -2
- package/src/modules/workflows/api/definitions/[id]/route.ts +7 -4
- package/src/modules/workflows/api/definitions/route.ts +5 -2
- package/src/modules/workflows/api/events/[id]/route.ts +4 -1
- package/src/modules/workflows/api/events/route.ts +4 -1
- package/src/modules/workflows/api/instances/[id]/advance/route.ts +4 -1
- package/src/modules/workflows/api/instances/[id]/cancel/route.ts +4 -1
- package/src/modules/workflows/api/instances/[id]/events/route.ts +4 -1
- package/src/modules/workflows/api/instances/[id]/retry/route.ts +4 -1
- package/src/modules/workflows/api/instances/[id]/route.ts +4 -1
- package/src/modules/workflows/api/instances/[id]/signal/route.ts +6 -7
- package/src/modules/workflows/api/instances/route.ts +6 -3
- package/src/modules/workflows/api/instances/validate-start/route.ts +4 -1
- package/src/modules/workflows/api/signals/route.ts +4 -1
- package/src/modules/workflows/api/tasks/[id]/claim/route.ts +4 -1
- package/src/modules/workflows/api/tasks/[id]/complete/route.ts +4 -1
- package/src/modules/workflows/api/tasks/[id]/route.ts +4 -1
- package/src/modules/workflows/api/tasks/route.ts +4 -1
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +5 -2
- package/src/modules/workflows/backend/instances/[id]/page.tsx +6 -3
- package/src/modules/workflows/backend/tasks/[id]/page.tsx +4 -1
- package/src/modules/workflows/components/BusinessRulesSelector.tsx +6 -3
- package/src/modules/workflows/components/WorkflowSelector.tsx +6 -3
- package/src/modules/workflows/components/fields/BusinessRuleConditionsEditor.tsx +4 -1
- package/src/modules/workflows/components/fields/StartPreConditionsEditor.tsx +4 -1
- package/src/modules/workflows/components/fields/WorkflowSelectorField.tsx +4 -1
- package/src/modules/workflows/frontend/checkout-demo/page.tsx +9 -7
- package/src/modules/workflows/lib/activity-executor.ts +26 -21
- package/src/modules/workflows/lib/activity-worker-handler.ts +9 -15
- package/src/modules/workflows/lib/code-registry.ts +8 -7
- package/src/modules/workflows/lib/compensation-handler.ts +5 -2
- package/src/modules/workflows/lib/edgeFormTransforms.ts +4 -1
- package/src/modules/workflows/lib/event-trigger-service.ts +6 -3
- package/src/modules/workflows/lib/nodeFormTransforms.ts +4 -1
- package/src/modules/workflows/lib/seeds.ts +17 -2
- package/src/modules/workflows/lib/signal-handler.ts +4 -1
- package/src/modules/workflows/lib/start-validator.ts +10 -3
- package/src/modules/workflows/lib/step-handler.ts +4 -1
- package/src/modules/workflows/lib/task-handler.ts +4 -1
- package/src/modules/workflows/lib/transition-handler.ts +6 -3
- package/src/modules/workflows/lib/workflow-executor.ts +28 -15
- package/src/modules/workflows/subscribers/event-trigger.ts +22 -24
- package/src/modules/workflows/subscribers/task-assigned-notification.ts +4 -1
- package/src/modules/workflows/workers/workflow-activities.worker.ts +31 -20
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/attachments/lib/assignmentDetails.ts"],
|
|
4
|
-
"sourcesContent": ["import type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport type { AttachmentAssignment } from './metadata'\nimport type { CustomEntitySpec } from '@open-mercato/shared/modules/entities'\nimport { getEntityIds } from '@open-mercato/shared/lib/encryption/entityIds'\nimport { getModules } from '@open-mercato/shared/lib/i18n/server'\n\ntype AssignmentLinkSpec = {\n labelFields?: string[]\n extraFields?: string[]\n buildHref?: (record: Record<string, unknown>) => string | null | undefined\n}\n\nlet _entityLinkSpecsCache: Record<string, AssignmentLinkSpec> | null = null\n\nfunction getEntityLinkSpecs(): Record<string, AssignmentLinkSpec> {\n if (_entityLinkSpecsCache) return _entityLinkSpecsCache\n const E = getEntityIds() as any\n const specs: Record<string, AssignmentLinkSpec> = {}\n\n if (E.catalog?.catalog_product) {\n specs[E.catalog.catalog_product] = {\n labelFields: ['title', 'sku', 'handle'],\n buildHref: (record) => buildSimpleHref('/backend/catalog/products', record.id),\n }\n }\n if (E.catalog?.catalog_product_variant) {\n specs[E.catalog.catalog_product_variant] = {\n labelFields: ['name', 'sku'],\n extraFields: ['product_id'],\n buildHref: (record) => {\n const productId = readRecordValue(record, 'product_id')\n if (!productId) return null\n return `/backend/catalog/products/${encodeURIComponent(productId)}/variants/${encodeURIComponent(String(record.id ?? ''))}`\n },\n }\n }\n if (E.customers?.customer_entity) {\n specs[E.customers.customer_entity] = {\n labelFields: ['display_name'],\n extraFields: ['kind'],\n buildHref: (record) => {\n const kind = String(readRecordValue(record, 'kind') || '').toLowerCase()\n if (kind === 'company') return buildSimpleHref('/backend/customers/companies', record.id)\n if (kind === 'person') return buildSimpleHref('/backend/customers/people', record.id)\n return null\n },\n }\n }\n if (E.customers?.customer_person_profile) {\n specs[E.customers.customer_person_profile] = {\n labelFields: ['preferred_name', 'display_name', 'first_name', 'last_name'],\n extraFields: ['entity_id', 'first_name', 'last_name'],\n buildHref: (record) => {\n const entityId = readRecordValue(record, 'entity_id')\n return entityId ? buildSimpleHref('/backend/customers/people', entityId) : null\n },\n }\n }\n if (E.customers?.customer_company_profile) {\n specs[E.customers.customer_company_profile] = {\n labelFields: ['brand_name', 'display_name', 'legal_name'],\n extraFields: ['entity_id'],\n buildHref: (record) => {\n const entityId = readRecordValue(record, 'entity_id')\n return entityId ? buildSimpleHref('/backend/customers/companies', entityId) : null\n },\n }\n }\n if (E.customers?.customer_deal) {\n specs[E.customers.customer_deal] = {\n labelFields: ['title'],\n buildHref: (record) => buildSimpleHref('/backend/customers/deals', record.id),\n }\n }\n if (E.sales?.sales_channel) {\n specs[E.sales.sales_channel] = {\n labelFields: ['name', 'title'],\n buildHref: (record) => buildSimpleHref('/backend/sales/channels', record.id, '/edit'),\n }\n }\n\n _entityLinkSpecsCache = specs\n return _entityLinkSpecsCache\n}\n\nconst LIBRARY_ENTITY_ID = 'attachments:library'\nconst DEFAULT_LABEL_FIELDS = [\n 'label',\n 'title',\n 'name',\n 'display_name',\n 'displayName',\n 'subject',\n 'sku',\n 'handle',\n 'order_number',\n 'quote_number',\n 'invoice_number',\n 'email',\n 'company_name',\n 'legal_name',\n 'brand_name',\n]\n\nlet entitySpecsPromise: Promise<Map<string, CustomEntitySpec>> | null = null\n\nasync function loadEntitySpecs(): Promise<Map<string, CustomEntitySpec>> {\n if (!entitySpecsPromise) {\n entitySpecsPromise = Promise.resolve()\n .then(() => {\n const map = new Map<string, CustomEntitySpec>()\n const mods = getModules()\n for (const mod of mods) {\n const specs = ((mod as any).customEntities as CustomEntitySpec[] | undefined) ?? []\n for (const spec of specs) {\n if (spec?.id && !map.has(spec.id)) {\n map.set(spec.id, spec)\n }\n }\n }\n return map\n })\n .catch(() => new Map<string, CustomEntitySpec>())\n }\n return entitySpecsPromise\n}\n\nexport type AssignmentEnrichment = {\n label?: string\n href?: string\n}\n\nexport type AssignmentEnrichmentMap = Map<string, AssignmentEnrichment>\n\nfunction camelToSnake(value: string): string {\n return value\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/[\\s-]+/g, '_')\n .toLowerCase()\n}\n\nfunction snakeToCamel(value: string): string {\n return value.replace(/[_-](\\w)/g, (_, c: string) => c.toUpperCase())\n}\n\nfunction normalizeValue(value: unknown): string | null {\n if (value === undefined || value === null) return null\n if (typeof value === 'string') {\n const trimmed = value.trim()\n return trimmed.length ? trimmed : null\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value)\n }\n return null\n}\n\nfunction readRecordValue(record: Record<string, unknown>, field: string): string | null {\n if (!field) return null\n if (record[field] !== undefined) return normalizeValue(record[field])\n const snake = camelToSnake(field)\n if (snake !== field && record[snake] !== undefined) return normalizeValue(record[snake])\n const camel = snakeToCamel(field)\n if (camel !== field && record[camel] !== undefined) return normalizeValue(record[camel])\n return null\n}\n\nfunction buildSimpleHref(base: string, idValue: unknown, suffix: string = ''): string | null {\n const id = normalizeValue(idValue)\n if (!id) return null\n return `${base}/${encodeURIComponent(id)}${suffix}`\n}\n\nfunction isUuid(value: string | null | undefined): boolean {\n return typeof value === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value.trim())\n}\n\nfunction filterIdsForEntity(entityId: string, ids: string[]): string[] {\n const E = getEntityIds() as any\n if (entityId === E.catalog?.catalog_product_variant || entityId === E.catalog?.catalog_product) {\n return ids.filter((id) => isUuid(id))\n }\n return ids\n}\n\nfunction resolveLabelCandidates(entityId: string, linkSpec: AssignmentLinkSpec | undefined, entitySpecs: Map<string, CustomEntitySpec>): string[] {\n const candidates = new Set<string>()\n const spec = entitySpecs.get(entityId)\n if (spec?.labelField) {\n candidates.add(spec.labelField)\n candidates.add(camelToSnake(spec.labelField))\n }\n for (const field of linkSpec?.labelFields ?? []) {\n candidates.add(field)\n candidates.add(camelToSnake(field))\n }\n DEFAULT_LABEL_FIELDS.forEach((field) => {\n candidates.add(field)\n candidates.add(camelToSnake(field))\n })\n return Array.from(candidates).filter((field) => field.length > 0)\n}\n\nfunction buildLabel(\n record: Record<string, unknown>,\n entityId: string,\n linkSpec: AssignmentLinkSpec | undefined,\n entitySpecs: Map<string, CustomEntitySpec>\n): string | null {\n const candidates = resolveLabelCandidates(entityId, linkSpec, entitySpecs)\n for (const candidate of candidates) {\n const value = readRecordValue(record, candidate)\n if (value) return value\n }\n const fullName = [readRecordValue(record, 'first_name'), readRecordValue(record, 'last_name')]\n .filter((part): part is string => Boolean(part))\n .join(' ')\n .trim()\n if (fullName.length) return fullName\n return null\n}\n\nexport async function resolveAssignmentEnrichments(\n assignments: AttachmentAssignment[],\n opts: { queryEngine?: QueryEngine | null; tenantId: string; organizationId: string | null },\n): Promise<AssignmentEnrichmentMap> {\n const map: AssignmentEnrichmentMap = new Map()\n if (!assignments.length || !opts.queryEngine) return map\n const entitySpecs = await loadEntitySpecs()\n const grouped = new Map<string, Set<string>>()\n for (const assignment of assignments) {\n if (!assignment || assignment.type === LIBRARY_ENTITY_ID) continue\n const type = assignment.type?.trim()\n const id = assignment.id?.trim()\n if (!type || !id) continue\n if (!grouped.has(type)) grouped.set(type, new Set())\n grouped.get(type)!.add(id)\n }\n if (!grouped.size) return map\n\n const entityLinkSpecs = getEntityLinkSpecs()\n for (const [entityId, idsSet] of grouped.entries()) {\n const ids = filterIdsForEntity(entityId, Array.from(idsSet.values()))\n if (!ids.length) continue\n const linkSpec = entityLinkSpecs[entityId]\n const fields = new Set<string>(['id'])\n const candidates = resolveLabelCandidates(entityId, linkSpec, entitySpecs)\n candidates.forEach((field) => fields.add(field))\n for (const extra of linkSpec?.extraFields ?? []) {\n fields.add(extra)\n fields.add(camelToSnake(extra))\n }\n try {\n const result = await opts.queryEngine.query(entityId as any, {\n fields: Array.from(fields),\n filters: { id: ids.length === 1 ? { $eq: ids[0] } : { $in: ids } },\n tenantId: opts.tenantId,\n organizationId: opts.organizationId ?? undefined,\n page: { pageSize: Math.max(ids.length, 20) },\n })\n for (const record of result.items ?? []) {\n const recordId = normalizeValue((record as Record<string, unknown>).id)\n if (!recordId) continue\n const label = buildLabel(record as Record<string, unknown>, entityId, linkSpec, entitySpecs)\n const href = linkSpec?.buildHref?.(record as Record<string, unknown>) ?? null\n if (label || href) {\n map.set(`${entityId}:${recordId}`, {\n label: label ?? undefined,\n href: href ?? undefined,\n })\n }\n }\n } catch (error) {\n console.warn('[attachments] Failed to resolve assignment details for', entityId, error)\n }\n }\n return map\n}\n\nexport function applyAssignmentEnrichments(\n assignments: AttachmentAssignment[],\n enrichments: AssignmentEnrichmentMap,\n): AttachmentAssignment[] {\n if (!enrichments.size) return assignments\n return assignments.map((assignment) => {\n if (!assignment || !assignment.type || !assignment.id) return assignment\n const key = `${assignment.type}:${assignment.id}`\n const detail = enrichments.get(key)\n if (!detail) return assignment\n const next: AttachmentAssignment = { ...assignment }\n if (!next.label && detail.label) next.label = detail.label\n if (!next.href && detail.href) next.href = detail.href\n return next\n })\n}\n"],
|
|
5
|
-
"mappings": "AAGA,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;
|
|
4
|
+
"sourcesContent": ["import type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport type { AttachmentAssignment } from './metadata'\nimport type { CustomEntitySpec } from '@open-mercato/shared/modules/entities'\nimport { getEntityIds } from '@open-mercato/shared/lib/encryption/entityIds'\nimport { getModules } from '@open-mercato/shared/lib/i18n/server'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('attachments')\n\ntype AssignmentLinkSpec = {\n labelFields?: string[]\n extraFields?: string[]\n buildHref?: (record: Record<string, unknown>) => string | null | undefined\n}\n\nlet _entityLinkSpecsCache: Record<string, AssignmentLinkSpec> | null = null\n\nfunction getEntityLinkSpecs(): Record<string, AssignmentLinkSpec> {\n if (_entityLinkSpecsCache) return _entityLinkSpecsCache\n const E = getEntityIds() as any\n const specs: Record<string, AssignmentLinkSpec> = {}\n\n if (E.catalog?.catalog_product) {\n specs[E.catalog.catalog_product] = {\n labelFields: ['title', 'sku', 'handle'],\n buildHref: (record) => buildSimpleHref('/backend/catalog/products', record.id),\n }\n }\n if (E.catalog?.catalog_product_variant) {\n specs[E.catalog.catalog_product_variant] = {\n labelFields: ['name', 'sku'],\n extraFields: ['product_id'],\n buildHref: (record) => {\n const productId = readRecordValue(record, 'product_id')\n if (!productId) return null\n return `/backend/catalog/products/${encodeURIComponent(productId)}/variants/${encodeURIComponent(String(record.id ?? ''))}`\n },\n }\n }\n if (E.customers?.customer_entity) {\n specs[E.customers.customer_entity] = {\n labelFields: ['display_name'],\n extraFields: ['kind'],\n buildHref: (record) => {\n const kind = String(readRecordValue(record, 'kind') || '').toLowerCase()\n if (kind === 'company') return buildSimpleHref('/backend/customers/companies', record.id)\n if (kind === 'person') return buildSimpleHref('/backend/customers/people', record.id)\n return null\n },\n }\n }\n if (E.customers?.customer_person_profile) {\n specs[E.customers.customer_person_profile] = {\n labelFields: ['preferred_name', 'display_name', 'first_name', 'last_name'],\n extraFields: ['entity_id', 'first_name', 'last_name'],\n buildHref: (record) => {\n const entityId = readRecordValue(record, 'entity_id')\n return entityId ? buildSimpleHref('/backend/customers/people', entityId) : null\n },\n }\n }\n if (E.customers?.customer_company_profile) {\n specs[E.customers.customer_company_profile] = {\n labelFields: ['brand_name', 'display_name', 'legal_name'],\n extraFields: ['entity_id'],\n buildHref: (record) => {\n const entityId = readRecordValue(record, 'entity_id')\n return entityId ? buildSimpleHref('/backend/customers/companies', entityId) : null\n },\n }\n }\n if (E.customers?.customer_deal) {\n specs[E.customers.customer_deal] = {\n labelFields: ['title'],\n buildHref: (record) => buildSimpleHref('/backend/customers/deals', record.id),\n }\n }\n if (E.sales?.sales_channel) {\n specs[E.sales.sales_channel] = {\n labelFields: ['name', 'title'],\n buildHref: (record) => buildSimpleHref('/backend/sales/channels', record.id, '/edit'),\n }\n }\n\n _entityLinkSpecsCache = specs\n return _entityLinkSpecsCache\n}\n\nconst LIBRARY_ENTITY_ID = 'attachments:library'\nconst DEFAULT_LABEL_FIELDS = [\n 'label',\n 'title',\n 'name',\n 'display_name',\n 'displayName',\n 'subject',\n 'sku',\n 'handle',\n 'order_number',\n 'quote_number',\n 'invoice_number',\n 'email',\n 'company_name',\n 'legal_name',\n 'brand_name',\n]\n\nlet entitySpecsPromise: Promise<Map<string, CustomEntitySpec>> | null = null\n\nasync function loadEntitySpecs(): Promise<Map<string, CustomEntitySpec>> {\n if (!entitySpecsPromise) {\n entitySpecsPromise = Promise.resolve()\n .then(() => {\n const map = new Map<string, CustomEntitySpec>()\n const mods = getModules()\n for (const mod of mods) {\n const specs = ((mod as any).customEntities as CustomEntitySpec[] | undefined) ?? []\n for (const spec of specs) {\n if (spec?.id && !map.has(spec.id)) {\n map.set(spec.id, spec)\n }\n }\n }\n return map\n })\n .catch(() => new Map<string, CustomEntitySpec>())\n }\n return entitySpecsPromise\n}\n\nexport type AssignmentEnrichment = {\n label?: string\n href?: string\n}\n\nexport type AssignmentEnrichmentMap = Map<string, AssignmentEnrichment>\n\nfunction camelToSnake(value: string): string {\n return value\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/[\\s-]+/g, '_')\n .toLowerCase()\n}\n\nfunction snakeToCamel(value: string): string {\n return value.replace(/[_-](\\w)/g, (_, c: string) => c.toUpperCase())\n}\n\nfunction normalizeValue(value: unknown): string | null {\n if (value === undefined || value === null) return null\n if (typeof value === 'string') {\n const trimmed = value.trim()\n return trimmed.length ? trimmed : null\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value)\n }\n return null\n}\n\nfunction readRecordValue(record: Record<string, unknown>, field: string): string | null {\n if (!field) return null\n if (record[field] !== undefined) return normalizeValue(record[field])\n const snake = camelToSnake(field)\n if (snake !== field && record[snake] !== undefined) return normalizeValue(record[snake])\n const camel = snakeToCamel(field)\n if (camel !== field && record[camel] !== undefined) return normalizeValue(record[camel])\n return null\n}\n\nfunction buildSimpleHref(base: string, idValue: unknown, suffix: string = ''): string | null {\n const id = normalizeValue(idValue)\n if (!id) return null\n return `${base}/${encodeURIComponent(id)}${suffix}`\n}\n\nfunction isUuid(value: string | null | undefined): boolean {\n return typeof value === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value.trim())\n}\n\nfunction filterIdsForEntity(entityId: string, ids: string[]): string[] {\n const E = getEntityIds() as any\n if (entityId === E.catalog?.catalog_product_variant || entityId === E.catalog?.catalog_product) {\n return ids.filter((id) => isUuid(id))\n }\n return ids\n}\n\nfunction resolveLabelCandidates(entityId: string, linkSpec: AssignmentLinkSpec | undefined, entitySpecs: Map<string, CustomEntitySpec>): string[] {\n const candidates = new Set<string>()\n const spec = entitySpecs.get(entityId)\n if (spec?.labelField) {\n candidates.add(spec.labelField)\n candidates.add(camelToSnake(spec.labelField))\n }\n for (const field of linkSpec?.labelFields ?? []) {\n candidates.add(field)\n candidates.add(camelToSnake(field))\n }\n DEFAULT_LABEL_FIELDS.forEach((field) => {\n candidates.add(field)\n candidates.add(camelToSnake(field))\n })\n return Array.from(candidates).filter((field) => field.length > 0)\n}\n\nfunction buildLabel(\n record: Record<string, unknown>,\n entityId: string,\n linkSpec: AssignmentLinkSpec | undefined,\n entitySpecs: Map<string, CustomEntitySpec>\n): string | null {\n const candidates = resolveLabelCandidates(entityId, linkSpec, entitySpecs)\n for (const candidate of candidates) {\n const value = readRecordValue(record, candidate)\n if (value) return value\n }\n const fullName = [readRecordValue(record, 'first_name'), readRecordValue(record, 'last_name')]\n .filter((part): part is string => Boolean(part))\n .join(' ')\n .trim()\n if (fullName.length) return fullName\n return null\n}\n\nexport async function resolveAssignmentEnrichments(\n assignments: AttachmentAssignment[],\n opts: { queryEngine?: QueryEngine | null; tenantId: string; organizationId: string | null },\n): Promise<AssignmentEnrichmentMap> {\n const map: AssignmentEnrichmentMap = new Map()\n if (!assignments.length || !opts.queryEngine) return map\n const entitySpecs = await loadEntitySpecs()\n const grouped = new Map<string, Set<string>>()\n for (const assignment of assignments) {\n if (!assignment || assignment.type === LIBRARY_ENTITY_ID) continue\n const type = assignment.type?.trim()\n const id = assignment.id?.trim()\n if (!type || !id) continue\n if (!grouped.has(type)) grouped.set(type, new Set())\n grouped.get(type)!.add(id)\n }\n if (!grouped.size) return map\n\n const entityLinkSpecs = getEntityLinkSpecs()\n for (const [entityId, idsSet] of grouped.entries()) {\n const ids = filterIdsForEntity(entityId, Array.from(idsSet.values()))\n if (!ids.length) continue\n const linkSpec = entityLinkSpecs[entityId]\n const fields = new Set<string>(['id'])\n const candidates = resolveLabelCandidates(entityId, linkSpec, entitySpecs)\n candidates.forEach((field) => fields.add(field))\n for (const extra of linkSpec?.extraFields ?? []) {\n fields.add(extra)\n fields.add(camelToSnake(extra))\n }\n try {\n const result = await opts.queryEngine.query(entityId as any, {\n fields: Array.from(fields),\n filters: { id: ids.length === 1 ? { $eq: ids[0] } : { $in: ids } },\n tenantId: opts.tenantId,\n organizationId: opts.organizationId ?? undefined,\n page: { pageSize: Math.max(ids.length, 20) },\n })\n for (const record of result.items ?? []) {\n const recordId = normalizeValue((record as Record<string, unknown>).id)\n if (!recordId) continue\n const label = buildLabel(record as Record<string, unknown>, entityId, linkSpec, entitySpecs)\n const href = linkSpec?.buildHref?.(record as Record<string, unknown>) ?? null\n if (label || href) {\n map.set(`${entityId}:${recordId}`, {\n label: label ?? undefined,\n href: href ?? undefined,\n })\n }\n }\n } catch (error) {\n logger.warn('Failed to resolve assignment details', { entityId, err: error })\n }\n }\n return map\n}\n\nexport function applyAssignmentEnrichments(\n assignments: AttachmentAssignment[],\n enrichments: AssignmentEnrichmentMap,\n): AttachmentAssignment[] {\n if (!enrichments.size) return assignments\n return assignments.map((assignment) => {\n if (!assignment || !assignment.type || !assignment.id) return assignment\n const key = `${assignment.type}:${assignment.id}`\n const detail = enrichments.get(key)\n if (!detail) return assignment\n const next: AttachmentAssignment = { ...assignment }\n if (!next.label && detail.label) next.label = detail.label\n if (!next.href && detail.href) next.href = detail.href\n return next\n })\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { LocalStorageDriver } from "./localDriver.js";
|
|
2
2
|
import { LegacyPublicStorageDriver } from "./legacyPublicDriver.js";
|
|
3
3
|
import { AttachmentPartition } from "../../data/entities.js";
|
|
4
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
5
|
+
const logger = createLogger("attachments").child({ component: "storage-driver-factory" });
|
|
4
6
|
const moduleDriverRegistry = /* @__PURE__ */ new Map();
|
|
5
7
|
const moduleEnhancerRegistry = /* @__PURE__ */ new Map();
|
|
6
8
|
function registerExternalStorageDriver(key, factory) {
|
|
@@ -48,7 +50,7 @@ class StorageDriverFactory {
|
|
|
48
50
|
const partition = await this.em.findOne(AttachmentPartition, { code: partitionCode });
|
|
49
51
|
if (!partition) return this.localDriver;
|
|
50
52
|
const driverKey = partition.storageDriver ?? "local";
|
|
51
|
-
|
|
53
|
+
logger.debug("Resolving storage driver for partition", { partition: partitionCode, driverKey, moduleDrivers: [...moduleDriverRegistry.keys()], instanceDrivers: [...this.externalDrivers.keys()] });
|
|
52
54
|
let config = partition.configJson ?? {};
|
|
53
55
|
const activeEnhancer = this.credentialEnhancers.get(driverKey) ?? moduleEnhancerRegistry.get(driverKey)?.enhancer;
|
|
54
56
|
if (scope && activeEnhancer) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/attachments/lib/drivers/driverFactory.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { StorageDriver } from './types'\nimport { LocalStorageDriver } from './localDriver'\nimport { LegacyPublicStorageDriver } from './legacyPublicDriver'\nimport { AttachmentPartition } from '../../data/entities'\n\ntype DriverScope = { tenantId: string; organizationId: string }\ntype CredentialEnhancer = (config: Record<string, unknown>, scope: DriverScope) => Promise<Record<string, unknown>>\n\ntype DriverRegistration = { factory: (config: Record<string, unknown>) => StorageDriver }\ntype EnhancerRegistration = { enhancer: CredentialEnhancer }\n\nconst moduleDriverRegistry = new Map<string, DriverRegistration>()\nconst moduleEnhancerRegistry = new Map<string, EnhancerRegistration>()\n\nexport function registerExternalStorageDriver(\n key: string,\n factory: (config: Record<string, unknown>) => StorageDriver,\n): void {\n moduleDriverRegistry.set(key, { factory })\n}\n\nexport function registerExternalCredentialEnhancer(key: string, enhancer: CredentialEnhancer): void {\n moduleEnhancerRegistry.set(key, { enhancer })\n}\n\nexport class StorageDriverFactory {\n private readonly cache = new Map<string, StorageDriver>()\n private readonly localDriver = new LocalStorageDriver()\n private readonly legacyPublicDriver = new LegacyPublicStorageDriver()\n private readonly externalDrivers = new Map<string, (config: Record<string, unknown>) => StorageDriver>()\n private readonly credentialEnhancers = new Map<string, CredentialEnhancer>()\n\n constructor(private readonly em: EntityManager) {}\n\n registerDriver(key: string, factory: (config: Record<string, unknown>) => StorageDriver): void {\n this.externalDrivers.set(key, factory)\n }\n\n registerCredentialEnhancer(key: string, enhancer: CredentialEnhancer): void {\n this.credentialEnhancers.set(key, enhancer)\n }\n\n resolveForAttachment(\n storageDriver: string,\n configJson?: Record<string, unknown> | null,\n ): StorageDriver {\n switch (storageDriver) {\n case 'legacyPublic':\n return this.legacyPublicDriver\n\n case 'local':\n return this.localDriver\n\n default: {\n const externalFactory =\n this.externalDrivers.get(storageDriver) ?? moduleDriverRegistry.get(storageDriver)?.factory\n if (externalFactory) {\n const cacheKey = `${storageDriver}:${JSON.stringify(configJson ?? {})}`\n const cached = this.cache.get(cacheKey)\n if (cached) return cached\n const driver = externalFactory(configJson ?? {})\n this.cache.set(cacheKey, driver)\n return driver\n }\n return this.localDriver\n }\n }\n }\n\n async resolveForPartition(partitionCode: string, scope?: DriverScope): Promise<StorageDriver> {\n const partition = await this.em.findOne(AttachmentPartition, { code: partitionCode })\n if (!partition) return this.localDriver\n\n const driverKey = partition.storageDriver ?? 'local'\n
|
|
5
|
-
"mappings": "AAEA,SAAS,0BAA0B;AACnC,SAAS,iCAAiC;AAC1C,SAAS,2BAA2B;
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { StorageDriver } from './types'\nimport { LocalStorageDriver } from './localDriver'\nimport { LegacyPublicStorageDriver } from './legacyPublicDriver'\nimport { AttachmentPartition } from '../../data/entities'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('attachments').child({ component: 'storage-driver-factory' })\n\ntype DriverScope = { tenantId: string; organizationId: string }\ntype CredentialEnhancer = (config: Record<string, unknown>, scope: DriverScope) => Promise<Record<string, unknown>>\n\ntype DriverRegistration = { factory: (config: Record<string, unknown>) => StorageDriver }\ntype EnhancerRegistration = { enhancer: CredentialEnhancer }\n\nconst moduleDriverRegistry = new Map<string, DriverRegistration>()\nconst moduleEnhancerRegistry = new Map<string, EnhancerRegistration>()\n\nexport function registerExternalStorageDriver(\n key: string,\n factory: (config: Record<string, unknown>) => StorageDriver,\n): void {\n moduleDriverRegistry.set(key, { factory })\n}\n\nexport function registerExternalCredentialEnhancer(key: string, enhancer: CredentialEnhancer): void {\n moduleEnhancerRegistry.set(key, { enhancer })\n}\n\nexport class StorageDriverFactory {\n private readonly cache = new Map<string, StorageDriver>()\n private readonly localDriver = new LocalStorageDriver()\n private readonly legacyPublicDriver = new LegacyPublicStorageDriver()\n private readonly externalDrivers = new Map<string, (config: Record<string, unknown>) => StorageDriver>()\n private readonly credentialEnhancers = new Map<string, CredentialEnhancer>()\n\n constructor(private readonly em: EntityManager) {}\n\n registerDriver(key: string, factory: (config: Record<string, unknown>) => StorageDriver): void {\n this.externalDrivers.set(key, factory)\n }\n\n registerCredentialEnhancer(key: string, enhancer: CredentialEnhancer): void {\n this.credentialEnhancers.set(key, enhancer)\n }\n\n resolveForAttachment(\n storageDriver: string,\n configJson?: Record<string, unknown> | null,\n ): StorageDriver {\n switch (storageDriver) {\n case 'legacyPublic':\n return this.legacyPublicDriver\n\n case 'local':\n return this.localDriver\n\n default: {\n const externalFactory =\n this.externalDrivers.get(storageDriver) ?? moduleDriverRegistry.get(storageDriver)?.factory\n if (externalFactory) {\n const cacheKey = `${storageDriver}:${JSON.stringify(configJson ?? {})}`\n const cached = this.cache.get(cacheKey)\n if (cached) return cached\n const driver = externalFactory(configJson ?? {})\n this.cache.set(cacheKey, driver)\n return driver\n }\n return this.localDriver\n }\n }\n }\n\n async resolveForPartition(partitionCode: string, scope?: DriverScope): Promise<StorageDriver> {\n const partition = await this.em.findOne(AttachmentPartition, { code: partitionCode })\n if (!partition) return this.localDriver\n\n const driverKey = partition.storageDriver ?? 'local'\n logger.debug('Resolving storage driver for partition', { partition: partitionCode, driverKey, moduleDrivers: [...moduleDriverRegistry.keys()], instanceDrivers: [...this.externalDrivers.keys()] })\n let config: Record<string, unknown> = partition.configJson ?? {}\n\n const activeEnhancer =\n this.credentialEnhancers.get(driverKey) ?? moduleEnhancerRegistry.get(driverKey)?.enhancer\n if (scope && activeEnhancer) {\n config = await activeEnhancer(config, scope)\n // Skip shared cache for scope-enhanced configs (credentials are per-tenant)\n const externalFactory =\n this.externalDrivers.get(driverKey) ?? moduleDriverRegistry.get(driverKey)?.factory\n if (externalFactory) return externalFactory(config)\n }\n\n return this.resolveForAttachment(driverKey, config)\n }\n}\n"],
|
|
5
|
+
"mappings": "AAEA,SAAS,0BAA0B;AACnC,SAAS,iCAAiC;AAC1C,SAAS,2BAA2B;AACpC,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,aAAa,EAAE,MAAM,EAAE,WAAW,yBAAyB,CAAC;AAQxF,MAAM,uBAAuB,oBAAI,IAAgC;AACjE,MAAM,yBAAyB,oBAAI,IAAkC;AAE9D,SAAS,8BACd,KACA,SACM;AACN,uBAAqB,IAAI,KAAK,EAAE,QAAQ,CAAC;AAC3C;AAEO,SAAS,mCAAmC,KAAa,UAAoC;AAClG,yBAAuB,IAAI,KAAK,EAAE,SAAS,CAAC;AAC9C;AAEO,MAAM,qBAAqB;AAAA,EAOhC,YAA6B,IAAmB;AAAnB;AAN7B,SAAiB,QAAQ,oBAAI,IAA2B;AACxD,SAAiB,cAAc,IAAI,mBAAmB;AACtD,SAAiB,qBAAqB,IAAI,0BAA0B;AACpE,SAAiB,kBAAkB,oBAAI,IAAgE;AACvG,SAAiB,sBAAsB,oBAAI,IAAgC;AAAA,EAE1B;AAAA,EAEjD,eAAe,KAAa,SAAmE;AAC7F,SAAK,gBAAgB,IAAI,KAAK,OAAO;AAAA,EACvC;AAAA,EAEA,2BAA2B,KAAa,UAAoC;AAC1E,SAAK,oBAAoB,IAAI,KAAK,QAAQ;AAAA,EAC5C;AAAA,EAEA,qBACE,eACA,YACe;AACf,YAAQ,eAAe;AAAA,MACrB,KAAK;AACH,eAAO,KAAK;AAAA,MAEd,KAAK;AACH,eAAO,KAAK;AAAA,MAEd,SAAS;AACP,cAAM,kBACJ,KAAK,gBAAgB,IAAI,aAAa,KAAK,qBAAqB,IAAI,aAAa,GAAG;AACtF,YAAI,iBAAiB;AACnB,gBAAM,WAAW,GAAG,aAAa,IAAI,KAAK,UAAU,cAAc,CAAC,CAAC,CAAC;AACrE,gBAAM,SAAS,KAAK,MAAM,IAAI,QAAQ;AACtC,cAAI,OAAQ,QAAO;AACnB,gBAAM,SAAS,gBAAgB,cAAc,CAAC,CAAC;AAC/C,eAAK,MAAM,IAAI,UAAU,MAAM;AAC/B,iBAAO;AAAA,QACT;AACA,eAAO,KAAK;AAAA,MACd;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,oBAAoB,eAAuB,OAA6C;AAC5F,UAAM,YAAY,MAAM,KAAK,GAAG,QAAQ,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACpF,QAAI,CAAC,UAAW,QAAO,KAAK;AAE5B,UAAM,YAAY,UAAU,iBAAiB;AAC7C,WAAO,MAAM,0CAA0C,EAAE,WAAW,eAAe,WAAW,eAAe,CAAC,GAAG,qBAAqB,KAAK,CAAC,GAAG,iBAAiB,CAAC,GAAG,KAAK,gBAAgB,KAAK,CAAC,EAAE,CAAC;AAClM,QAAI,SAAkC,UAAU,cAAc,CAAC;AAE/D,UAAM,iBACJ,KAAK,oBAAoB,IAAI,SAAS,KAAK,uBAAuB,IAAI,SAAS,GAAG;AACpF,QAAI,SAAS,gBAAgB;AAC3B,eAAS,MAAM,eAAe,QAAQ,KAAK;AAE3C,YAAM,kBACJ,KAAK,gBAAgB,IAAI,SAAS,KAAK,qBAAqB,IAAI,SAAS,GAAG;AAC9E,UAAI,gBAAiB,QAAO,gBAAgB,MAAM;AAAA,IACpD;AAEA,WAAO,KAAK,qBAAqB,WAAW,MAAM;AAAA,EACpD;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Attachment, AttachmentPartition } from "../data/entities.js";
|
|
2
2
|
import { OcrService } from "./ocrService.js";
|
|
3
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
4
|
+
const logger = createLogger("attachments").child({ component: "ocr" });
|
|
3
5
|
async function processAttachmentOcr(em, payload, driver) {
|
|
4
6
|
const { attachmentId, storagePath, mimeType, partitionCode } = payload;
|
|
5
|
-
|
|
7
|
+
logger.info("Processing started", { attachmentId });
|
|
6
8
|
const startTime = Date.now();
|
|
7
9
|
const { filePath, cleanup } = await driver.toLocalPath(partitionCode, storagePath);
|
|
8
10
|
try {
|
|
@@ -10,7 +12,7 @@ async function processAttachmentOcr(em, payload, driver) {
|
|
|
10
12
|
const resolvedModel = partition?.ocrModel ?? process.env.OCR_MODEL ?? "gpt-4o";
|
|
11
13
|
const ocrService = new OcrService();
|
|
12
14
|
if (!ocrService.available) {
|
|
13
|
-
|
|
15
|
+
logger.warn("OPENAI_API_KEY not configured, skipping OCR", { attachmentId });
|
|
14
16
|
return;
|
|
15
17
|
}
|
|
16
18
|
const result = await ocrService.processFile({
|
|
@@ -19,17 +21,17 @@ async function processAttachmentOcr(em, payload, driver) {
|
|
|
19
21
|
model: resolvedModel
|
|
20
22
|
});
|
|
21
23
|
if (!result) {
|
|
22
|
-
|
|
24
|
+
logger.info("No content extracted", { attachmentId });
|
|
23
25
|
return;
|
|
24
26
|
}
|
|
25
27
|
const attachment = await em.findOne(Attachment, { id: attachmentId });
|
|
26
28
|
if (!attachment) {
|
|
27
|
-
|
|
29
|
+
logger.error("Attachment not found", { attachmentId });
|
|
28
30
|
return;
|
|
29
31
|
}
|
|
30
32
|
attachment.content = result.content;
|
|
31
33
|
await em.persist(attachment).flush();
|
|
32
|
-
|
|
34
|
+
logger.info("Processing completed", {
|
|
33
35
|
attachmentId,
|
|
34
36
|
pageCount: result.pageCount,
|
|
35
37
|
contentLength: result.content.length,
|
|
@@ -37,13 +39,10 @@ async function processAttachmentOcr(em, payload, driver) {
|
|
|
37
39
|
totalTimeMs: Date.now() - startTime
|
|
38
40
|
});
|
|
39
41
|
} catch (error) {
|
|
40
|
-
|
|
41
|
-
attachmentId,
|
|
42
|
-
error: error instanceof Error ? error.message : String(error)
|
|
43
|
-
});
|
|
42
|
+
logger.error("Processing failed", { attachmentId, err: error });
|
|
44
43
|
} finally {
|
|
45
44
|
await cleanup().catch((cleanupError) => {
|
|
46
|
-
|
|
45
|
+
logger.warn("Temp file cleanup failed", { err: cleanupError });
|
|
47
46
|
});
|
|
48
47
|
}
|
|
49
48
|
}
|
|
@@ -64,7 +63,7 @@ async function requestOcrProcessing(em, attachment, driver, storagePath) {
|
|
|
64
63
|
const workerEm = em.fork();
|
|
65
64
|
setImmediate(() => {
|
|
66
65
|
processAttachmentOcr(workerEm, payload, driver).catch((error) => {
|
|
67
|
-
|
|
66
|
+
logger.error("Background processing error", { err: error });
|
|
68
67
|
});
|
|
69
68
|
});
|
|
70
69
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/attachments/lib/ocrQueue.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { Attachment, AttachmentPartition } from '../data/entities'\nimport { OcrService } from './ocrService'\nimport type { StorageDriver } from './drivers/types'\n\nexport type OcrRequestedEvent = {\n attachmentId: string\n storagePath: string\n mimeType: string\n partitionCode: string\n organizationId: string | null\n tenantId: string | null\n}\n\nexport async function processAttachmentOcr(\n em: EntityManager,\n payload: OcrRequestedEvent,\n driver: StorageDriver,\n): Promise<void> {\n const { attachmentId, storagePath, mimeType, partitionCode } = payload\n\n
|
|
5
|
-
"mappings": "AACA,SAAS,YAAY,2BAA2B;AAChD,SAAS,kBAAkB;
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { Attachment, AttachmentPartition } from '../data/entities'\nimport { OcrService } from './ocrService'\nimport type { StorageDriver } from './drivers/types'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('attachments').child({ component: 'ocr' })\n\nexport type OcrRequestedEvent = {\n attachmentId: string\n storagePath: string\n mimeType: string\n partitionCode: string\n organizationId: string | null\n tenantId: string | null\n}\n\nexport async function processAttachmentOcr(\n em: EntityManager,\n payload: OcrRequestedEvent,\n driver: StorageDriver,\n): Promise<void> {\n const { attachmentId, storagePath, mimeType, partitionCode } = payload\n\n logger.info('Processing started', { attachmentId })\n const startTime = Date.now()\n\n const { filePath, cleanup } = await driver.toLocalPath(partitionCode, storagePath)\n try {\n const partition = await em.findOne(AttachmentPartition, { code: partitionCode })\n const resolvedModel = partition?.ocrModel ?? process.env.OCR_MODEL ?? 'gpt-4o'\n\n const ocrService = new OcrService()\n\n if (!ocrService.available) {\n logger.warn('OPENAI_API_KEY not configured, skipping OCR', { attachmentId })\n return\n }\n\n const result = await ocrService.processFile({\n filePath,\n mimeType,\n model: resolvedModel,\n })\n\n if (!result) {\n logger.info('No content extracted', { attachmentId })\n return\n }\n\n const attachment = await em.findOne(Attachment, { id: attachmentId })\n if (!attachment) {\n logger.error('Attachment not found', { attachmentId })\n return\n }\n\n attachment.content = result.content\n await em.persist(attachment).flush()\n\n logger.info('Processing completed', {\n attachmentId,\n pageCount: result.pageCount,\n contentLength: result.content.length,\n timeMs: result.processingTimeMs,\n totalTimeMs: Date.now() - startTime,\n })\n } catch (error) {\n logger.error('Processing failed', { attachmentId, err: error })\n } finally {\n await cleanup().catch((cleanupError) => {\n logger.warn('Temp file cleanup failed', { err: cleanupError })\n })\n }\n}\n\nexport async function requestOcrProcessing(\n em: EntityManager,\n attachment: Attachment,\n driver: StorageDriver,\n storagePath: string,\n): Promise<void> {\n const payload: OcrRequestedEvent = {\n attachmentId: attachment.id,\n storagePath,\n mimeType: attachment.mimeType,\n partitionCode: attachment.partitionCode,\n organizationId: attachment.organizationId ?? null,\n tenantId: attachment.tenantId ?? null,\n }\n\n if (typeof (em as { fork?: unknown })?.fork !== 'function') {\n throw new Error(\n '[internal] attachments OCR background processing requires an EntityManager that exposes fork(); ' +\n 'reusing the request-scoped EntityManager in the async worker would race with later request mutations.',\n )\n }\n\n const workerEm = em.fork()\n\n setImmediate(() => {\n processAttachmentOcr(workerEm, payload, driver).catch((error) => {\n logger.error('Background processing error', { err: error })\n })\n })\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,YAAY,2BAA2B;AAChD,SAAS,kBAAkB;AAE3B,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,aAAa,EAAE,MAAM,EAAE,WAAW,MAAM,CAAC;AAWrE,eAAsB,qBACpB,IACA,SACA,QACe;AACf,QAAM,EAAE,cAAc,aAAa,UAAU,cAAc,IAAI;AAE/D,SAAO,KAAK,sBAAsB,EAAE,aAAa,CAAC;AAClD,QAAM,YAAY,KAAK,IAAI;AAE3B,QAAM,EAAE,UAAU,QAAQ,IAAI,MAAM,OAAO,YAAY,eAAe,WAAW;AACjF,MAAI;AACF,UAAM,YAAY,MAAM,GAAG,QAAQ,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC/E,UAAM,gBAAgB,WAAW,YAAY,QAAQ,IAAI,aAAa;AAEtE,UAAM,aAAa,IAAI,WAAW;AAElC,QAAI,CAAC,WAAW,WAAW;AACzB,aAAO,KAAK,+CAA+C,EAAE,aAAa,CAAC;AAC3E;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,WAAW,YAAY;AAAA,MAC1C;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT,CAAC;AAED,QAAI,CAAC,QAAQ;AACX,aAAO,KAAK,wBAAwB,EAAE,aAAa,CAAC;AACpD;AAAA,IACF;AAEA,UAAM,aAAa,MAAM,GAAG,QAAQ,YAAY,EAAE,IAAI,aAAa,CAAC;AACpE,QAAI,CAAC,YAAY;AACf,aAAO,MAAM,wBAAwB,EAAE,aAAa,CAAC;AACrD;AAAA,IACF;AAEA,eAAW,UAAU,OAAO;AAC5B,UAAM,GAAG,QAAQ,UAAU,EAAE,MAAM;AAEnC,WAAO,KAAK,wBAAwB;AAAA,MAClC;AAAA,MACA,WAAW,OAAO;AAAA,MAClB,eAAe,OAAO,QAAQ;AAAA,MAC9B,QAAQ,OAAO;AAAA,MACf,aAAa,KAAK,IAAI,IAAI;AAAA,IAC5B,CAAC;AAAA,EACH,SAAS,OAAO;AACd,WAAO,MAAM,qBAAqB,EAAE,cAAc,KAAK,MAAM,CAAC;AAAA,EAChE,UAAE;AACA,UAAM,QAAQ,EAAE,MAAM,CAAC,iBAAiB;AACtC,aAAO,KAAK,4BAA4B,EAAE,KAAK,aAAa,CAAC;AAAA,IAC/D,CAAC;AAAA,EACH;AACF;AAEA,eAAsB,qBACpB,IACA,YACA,QACA,aACe;AACf,QAAM,UAA6B;AAAA,IACjC,cAAc,WAAW;AAAA,IACzB;AAAA,IACA,UAAU,WAAW;AAAA,IACrB,eAAe,WAAW;AAAA,IAC1B,gBAAgB,WAAW,kBAAkB;AAAA,IAC7C,UAAU,WAAW,YAAY;AAAA,EACnC;AAEA,MAAI,OAAQ,IAA2B,SAAS,YAAY;AAC1D,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAEA,QAAM,WAAW,GAAG,KAAK;AAEzB,eAAa,MAAM;AACjB,yBAAqB,UAAU,SAAS,MAAM,EAAE,MAAM,CAAC,UAAU;AAC/D,aAAO,MAAM,+BAA+B,EAAE,KAAK,MAAM,CAAC;AAAA,IAC5D,CAAC;AAAA,EACH,CAAC;AACH;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,6 +2,8 @@ import { generateText } from "ai";
|
|
|
2
2
|
import { createOpenAI } from "@ai-sdk/openai";
|
|
3
3
|
import fs from "fs/promises";
|
|
4
4
|
import path from "path";
|
|
5
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
6
|
+
const logger = createLogger("attachments").child({ component: "ocr-service" });
|
|
5
7
|
const DEFAULT_MODEL = "gpt-4o";
|
|
6
8
|
const OCR_IMAGE_EXTENSIONS = [".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp", ".tiff"];
|
|
7
9
|
const DEFAULT_OCR_PROMPT = `Extract all text content from this image. Preserve the structure and formatting where possible. Output the text in markdown format. If there are tables, preserve them as markdown tables. If there is no text visible, respond with an empty string.`;
|
|
@@ -168,7 +170,7 @@ ${pageContent}`);
|
|
|
168
170
|
}
|
|
169
171
|
}
|
|
170
172
|
} catch (error) {
|
|
171
|
-
|
|
173
|
+
logger.error("Failed to process PDF page", { pageNumber: page.pageNumber, err: error });
|
|
172
174
|
}
|
|
173
175
|
}
|
|
174
176
|
return {
|
|
@@ -180,14 +182,14 @@ ${pageContent}`);
|
|
|
180
182
|
async processFile(input) {
|
|
181
183
|
const { filePath, mimeType } = input;
|
|
182
184
|
if (isPdfMimeType(mimeType, filePath)) {
|
|
183
|
-
|
|
185
|
+
logger.info("Processing PDF attachment via pdfjs-dist");
|
|
184
186
|
return this.processPdf(input);
|
|
185
187
|
}
|
|
186
188
|
if (isImageMimeType(mimeType, filePath)) {
|
|
187
|
-
|
|
189
|
+
logger.info("Processing image attachment via LLM OCR");
|
|
188
190
|
return this.processImage(input);
|
|
189
191
|
}
|
|
190
|
-
|
|
192
|
+
logger.info("Unsupported file type for OCR", { mimeType: mimeType || "unknown" });
|
|
191
193
|
return null;
|
|
192
194
|
}
|
|
193
195
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/attachments/lib/ocrService.ts"],
|
|
4
|
-
"sourcesContent": ["import { generateText } from 'ai'\nimport { createOpenAI } from '@ai-sdk/openai'\nimport fs from 'fs/promises'\nimport path from 'path'\n\nexport type OcrServiceOptions = {\n apiKey?: string\n model?: string\n}\n\nexport type OcrInput = {\n filePath: string\n mimeType: string | null\n model?: string\n}\n\nexport type OcrResult = {\n content: string\n pageCount?: number\n processingTimeMs: number\n}\n\nconst DEFAULT_MODEL = 'gpt-4o'\nconst OCR_IMAGE_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp', '.tiff']\n\nconst DEFAULT_OCR_PROMPT = `Extract all text content from this image. Preserve the structure and formatting where possible. Output the text in markdown format. If there are tables, preserve them as markdown tables. If there is no text visible, respond with an empty string.`\n\nfunction isImageMimeType(mimeType: string | null, filePath?: string): boolean {\n const normalized = (mimeType || '').toLowerCase()\n if (normalized.startsWith('image/')) return true\n if (filePath) {\n const ext = path.extname(filePath).toLowerCase()\n return OCR_IMAGE_EXTENSIONS.includes(ext)\n }\n return false\n}\n\nfunction isPdfMimeType(mimeType: string | null, filePath?: string): boolean {\n const normalized = (mimeType || '').toLowerCase()\n if (normalized === 'application/pdf') return true\n if (filePath) {\n const ext = path.extname(filePath).toLowerCase()\n return ext === '.pdf'\n }\n return false\n}\n\nfunction getImageMediaType(mimeType: string | null, filePath: string): string {\n if (mimeType && mimeType.startsWith('image/')) {\n return mimeType\n }\n const ext = path.extname(filePath).toLowerCase()\n const mimeMap: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.bmp': 'image/bmp',\n '.webp': 'image/webp',\n '.tiff': 'image/tiff',\n }\n return mimeMap[ext] || 'image/png'\n}\n\nexport class OcrService {\n private readonly apiKey: string | null\n private readonly defaultModel: string\n private client: ReturnType<typeof createOpenAI> | null = null\n\n constructor(opts: OcrServiceOptions = {}) {\n this.apiKey = opts.apiKey ?? process.env.OPENAI_API_KEY ?? null\n this.defaultModel = opts.model ?? process.env.OCR_MODEL ?? DEFAULT_MODEL\n }\n\n get available(): boolean {\n return Boolean(this.apiKey)\n }\n\n private ensureClient() {\n if (!this.apiKey) {\n throw new Error('[attachments.ocr] Missing OPENAI_API_KEY environment variable')\n }\n if (!this.client) {\n this.client = createOpenAI({ apiKey: this.apiKey })\n }\n return this.client\n }\n\n private async generateTextFromImageBuffer(params: {\n imageBuffer: Buffer\n mediaType: string\n model: string\n }): Promise<string> {\n const { imageBuffer, mediaType, model } = params\n const client = this.ensureClient()\n const base64 = imageBuffer.toString('base64')\n const dataUrl = `data:${mediaType};base64,${base64}`\n\n try {\n const result = await generateText({\n model: client(model),\n messages: [\n {\n role: 'user',\n content: [\n {\n type: 'image',\n image: dataUrl,\n },\n {\n type: 'text',\n text: process.env.OCR_DEFAULT_PROMPT ?? DEFAULT_OCR_PROMPT,\n },\n ],\n },\n ],\n })\n\n return result.text.trim()\n } catch (err: any) {\n const statusCandidate =\n err?.statusCode ?? err?.status ?? err?.response?.status ?? err?.response?.statusCode\n const status =\n typeof statusCandidate === 'number'\n ? Number.isFinite(statusCandidate) ? statusCandidate : undefined\n : typeof statusCandidate === 'string'\n ? Number.parseInt(statusCandidate, 10)\n : undefined\n const apiError = err?.data?.error ?? err?.body?.error ?? err?.response?.data?.error\n const apiMessage = apiError?.message ?? err?.response?.data?.message\n const apiCode = typeof apiError?.code === 'string' ? apiError.code : undefined\n const rawMessage = typeof apiMessage === 'string'\n ? apiMessage\n : (typeof err?.message === 'string' ? err.message : 'OCR request failed')\n\n let guidance: string\n switch (apiCode) {\n case 'insufficient_quota':\n guidance = 'OpenAI usage quota exceeded. Please review your plan and billing.'\n break\n case 'invalid_api_key':\n guidance = 'Invalid OpenAI API key. Update the key and retry.'\n break\n case 'account_deactivated':\n guidance = 'OpenAI account is disabled. Contact OpenAI support or provide a different key.'\n break\n case 'rate_limit_exceeded':\n guidance = 'Rate limit exceeded. Please try again later.'\n break\n default:\n guidance = rawMessage.includes('https://')\n ? rawMessage\n : `${rawMessage}. Check OPENAI_API_KEY.`\n }\n\n const wrapped = new Error(`[attachments.ocr] ${guidance}`)\n if (typeof status === 'number' && Number.isFinite(status)) {\n const normalizedStatus = status === 401 || status === 403 ? 502 : status\n if (normalizedStatus >= 400 && normalizedStatus < 600) {\n (wrapped as any).status = normalizedStatus\n }\n }\n if (apiCode) {\n (wrapped as any).code = apiCode\n }\n (wrapped as any).cause = err\n throw wrapped\n }\n }\n\n async processImage(input: OcrInput): Promise<OcrResult> {\n const startTime = Date.now()\n const { filePath, mimeType, model } = input\n const resolvedModel = model ?? this.defaultModel\n const imageBuffer = await fs.readFile(filePath)\n\n return {\n content: await this.generateTextFromImageBuffer({\n imageBuffer,\n mediaType: getImageMediaType(mimeType, filePath),\n model: resolvedModel,\n }),\n processingTimeMs: Date.now() - startTime,\n }\n }\n\n async processPdf(input: OcrInput): Promise<OcrResult> {\n const startTime = Date.now()\n const { filePath, model } = input\n const resolvedModel = model ?? this.defaultModel\n const { preparePdfPagesForOcr } = await import('./pdfProcessing')\n const preparedPdf = await preparePdfPagesForOcr(filePath)\n\n if (preparedPdf.pageCount === 0) {\n return {\n content: '',\n pageCount: 0,\n processingTimeMs: Date.now() - startTime,\n }\n }\n\n const pageContents: string[] = []\n\n for (const page of preparedPdf.pages) {\n try {\n let pageContent = page.extractedText\n\n if (!pageContent && page.imageBuffer) {\n pageContent = await this.generateTextFromImageBuffer({\n imageBuffer: page.imageBuffer,\n mediaType: 'image/png',\n model: resolvedModel,\n })\n }\n\n if (pageContent) {\n if (preparedPdf.pageCount > 1) {\n pageContents.push(`--- Page ${page.pageNumber} ---\\n\\n${pageContent}`)\n } else {\n pageContents.push(pageContent)\n }\n }\n } catch (error) {\n
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAC7B,OAAO,QAAQ;AACf,OAAO,UAAU;
|
|
4
|
+
"sourcesContent": ["import { generateText } from 'ai'\nimport { createOpenAI } from '@ai-sdk/openai'\nimport fs from 'fs/promises'\nimport path from 'path'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('attachments').child({ component: 'ocr-service' })\n\nexport type OcrServiceOptions = {\n apiKey?: string\n model?: string\n}\n\nexport type OcrInput = {\n filePath: string\n mimeType: string | null\n model?: string\n}\n\nexport type OcrResult = {\n content: string\n pageCount?: number\n processingTimeMs: number\n}\n\nconst DEFAULT_MODEL = 'gpt-4o'\nconst OCR_IMAGE_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp', '.tiff']\n\nconst DEFAULT_OCR_PROMPT = `Extract all text content from this image. Preserve the structure and formatting where possible. Output the text in markdown format. If there are tables, preserve them as markdown tables. If there is no text visible, respond with an empty string.`\n\nfunction isImageMimeType(mimeType: string | null, filePath?: string): boolean {\n const normalized = (mimeType || '').toLowerCase()\n if (normalized.startsWith('image/')) return true\n if (filePath) {\n const ext = path.extname(filePath).toLowerCase()\n return OCR_IMAGE_EXTENSIONS.includes(ext)\n }\n return false\n}\n\nfunction isPdfMimeType(mimeType: string | null, filePath?: string): boolean {\n const normalized = (mimeType || '').toLowerCase()\n if (normalized === 'application/pdf') return true\n if (filePath) {\n const ext = path.extname(filePath).toLowerCase()\n return ext === '.pdf'\n }\n return false\n}\n\nfunction getImageMediaType(mimeType: string | null, filePath: string): string {\n if (mimeType && mimeType.startsWith('image/')) {\n return mimeType\n }\n const ext = path.extname(filePath).toLowerCase()\n const mimeMap: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.bmp': 'image/bmp',\n '.webp': 'image/webp',\n '.tiff': 'image/tiff',\n }\n return mimeMap[ext] || 'image/png'\n}\n\nexport class OcrService {\n private readonly apiKey: string | null\n private readonly defaultModel: string\n private client: ReturnType<typeof createOpenAI> | null = null\n\n constructor(opts: OcrServiceOptions = {}) {\n this.apiKey = opts.apiKey ?? process.env.OPENAI_API_KEY ?? null\n this.defaultModel = opts.model ?? process.env.OCR_MODEL ?? DEFAULT_MODEL\n }\n\n get available(): boolean {\n return Boolean(this.apiKey)\n }\n\n private ensureClient() {\n if (!this.apiKey) {\n throw new Error('[attachments.ocr] Missing OPENAI_API_KEY environment variable')\n }\n if (!this.client) {\n this.client = createOpenAI({ apiKey: this.apiKey })\n }\n return this.client\n }\n\n private async generateTextFromImageBuffer(params: {\n imageBuffer: Buffer\n mediaType: string\n model: string\n }): Promise<string> {\n const { imageBuffer, mediaType, model } = params\n const client = this.ensureClient()\n const base64 = imageBuffer.toString('base64')\n const dataUrl = `data:${mediaType};base64,${base64}`\n\n try {\n const result = await generateText({\n model: client(model),\n messages: [\n {\n role: 'user',\n content: [\n {\n type: 'image',\n image: dataUrl,\n },\n {\n type: 'text',\n text: process.env.OCR_DEFAULT_PROMPT ?? DEFAULT_OCR_PROMPT,\n },\n ],\n },\n ],\n })\n\n return result.text.trim()\n } catch (err: any) {\n const statusCandidate =\n err?.statusCode ?? err?.status ?? err?.response?.status ?? err?.response?.statusCode\n const status =\n typeof statusCandidate === 'number'\n ? Number.isFinite(statusCandidate) ? statusCandidate : undefined\n : typeof statusCandidate === 'string'\n ? Number.parseInt(statusCandidate, 10)\n : undefined\n const apiError = err?.data?.error ?? err?.body?.error ?? err?.response?.data?.error\n const apiMessage = apiError?.message ?? err?.response?.data?.message\n const apiCode = typeof apiError?.code === 'string' ? apiError.code : undefined\n const rawMessage = typeof apiMessage === 'string'\n ? apiMessage\n : (typeof err?.message === 'string' ? err.message : 'OCR request failed')\n\n let guidance: string\n switch (apiCode) {\n case 'insufficient_quota':\n guidance = 'OpenAI usage quota exceeded. Please review your plan and billing.'\n break\n case 'invalid_api_key':\n guidance = 'Invalid OpenAI API key. Update the key and retry.'\n break\n case 'account_deactivated':\n guidance = 'OpenAI account is disabled. Contact OpenAI support or provide a different key.'\n break\n case 'rate_limit_exceeded':\n guidance = 'Rate limit exceeded. Please try again later.'\n break\n default:\n guidance = rawMessage.includes('https://')\n ? rawMessage\n : `${rawMessage}. Check OPENAI_API_KEY.`\n }\n\n const wrapped = new Error(`[attachments.ocr] ${guidance}`)\n if (typeof status === 'number' && Number.isFinite(status)) {\n const normalizedStatus = status === 401 || status === 403 ? 502 : status\n if (normalizedStatus >= 400 && normalizedStatus < 600) {\n (wrapped as any).status = normalizedStatus\n }\n }\n if (apiCode) {\n (wrapped as any).code = apiCode\n }\n (wrapped as any).cause = err\n throw wrapped\n }\n }\n\n async processImage(input: OcrInput): Promise<OcrResult> {\n const startTime = Date.now()\n const { filePath, mimeType, model } = input\n const resolvedModel = model ?? this.defaultModel\n const imageBuffer = await fs.readFile(filePath)\n\n return {\n content: await this.generateTextFromImageBuffer({\n imageBuffer,\n mediaType: getImageMediaType(mimeType, filePath),\n model: resolvedModel,\n }),\n processingTimeMs: Date.now() - startTime,\n }\n }\n\n async processPdf(input: OcrInput): Promise<OcrResult> {\n const startTime = Date.now()\n const { filePath, model } = input\n const resolvedModel = model ?? this.defaultModel\n const { preparePdfPagesForOcr } = await import('./pdfProcessing')\n const preparedPdf = await preparePdfPagesForOcr(filePath)\n\n if (preparedPdf.pageCount === 0) {\n return {\n content: '',\n pageCount: 0,\n processingTimeMs: Date.now() - startTime,\n }\n }\n\n const pageContents: string[] = []\n\n for (const page of preparedPdf.pages) {\n try {\n let pageContent = page.extractedText\n\n if (!pageContent && page.imageBuffer) {\n pageContent = await this.generateTextFromImageBuffer({\n imageBuffer: page.imageBuffer,\n mediaType: 'image/png',\n model: resolvedModel,\n })\n }\n\n if (pageContent) {\n if (preparedPdf.pageCount > 1) {\n pageContents.push(`--- Page ${page.pageNumber} ---\\n\\n${pageContent}`)\n } else {\n pageContents.push(pageContent)\n }\n }\n } catch (error) {\n logger.error('Failed to process PDF page', { pageNumber: page.pageNumber, err: error })\n }\n }\n\n return {\n content: pageContents.join('\\n\\n'),\n pageCount: preparedPdf.pageCount,\n processingTimeMs: Date.now() - startTime,\n }\n }\n\n async processFile(input: OcrInput): Promise<OcrResult | null> {\n const { filePath, mimeType } = input\n\n if (isPdfMimeType(mimeType, filePath)) {\n logger.info('Processing PDF attachment via pdfjs-dist')\n return this.processPdf(input)\n }\n\n if (isImageMimeType(mimeType, filePath)) {\n logger.info('Processing image attachment via LLM OCR')\n return this.processImage(input)\n }\n\n logger.info('Unsupported file type for OCR', { mimeType: mimeType || 'unknown' })\n return null\n }\n}\n\nexport function shouldUseLlmOcr(mimeType: string | null, fileName: string): boolean {\n if (isPdfMimeType(mimeType, fileName)) return true\n return isImageMimeType(mimeType, fileName)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -4,6 +4,8 @@ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
|
4
4
|
import { resolveFeatureCheckContext, resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
|
|
5
5
|
import { serializeOperationMetadata } from "@open-mercato/shared/lib/commands/operationMetadata";
|
|
6
6
|
import { z } from "zod";
|
|
7
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
8
|
+
const logger = createLogger("audit_logs").child({ component: "redo" });
|
|
7
9
|
const metadata = {
|
|
8
10
|
POST: { requireAuth: true, requireFeatures: ["audit_logs.redo_self"] }
|
|
9
11
|
};
|
|
@@ -114,7 +116,7 @@ async function POST(req) {
|
|
|
114
116
|
}
|
|
115
117
|
return response;
|
|
116
118
|
} catch (err) {
|
|
117
|
-
|
|
119
|
+
logger.error("Redo failed", { err });
|
|
118
120
|
return NextResponse.json({ error: "Redo failed" }, { status: 400 });
|
|
119
121
|
}
|
|
120
122
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/audit_logs/api/audit-logs/actions/redo/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { getAuthFromRequest, type AuthContext } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveFeatureCheckContext, resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { CommandBus } from '@open-mercato/shared/lib/commands/command-bus'\nimport { ActionLogService } from '@open-mercato/core/modules/audit_logs/services/actionLogService'\nimport type { CommandRuntimeContext, CommandLogMetadata } from '@open-mercato/shared/lib/commands'\nimport { serializeOperationMetadata } from '@open-mercato/shared/lib/commands/operationMetadata'\nimport type { AwilixContainer } from 'awilix'\nimport type { ActionLog } from '@open-mercato/core/modules/audit_logs/data/entities'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['audit_logs.redo_self'] },\n}\n\ntype RedoRequestBody = {\n logId?: string\n}\n\nconst redoRequestSchema = z.object({\n logId: z.string().min(1).describe('Identifier of the previously undone action log'),\n})\n\nconst redoResponseSchema = z.object({\n ok: z.literal(true),\n logId: z.string().nullable().describe('Identifier of the new redo log entry, if available'),\n undoToken: z.string().nullable().describe('New undo token associated with the redone action'),\n})\n\nconst errorSchema = z.object({\n error: z.string(),\n})\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const body = (await req.json().catch(() => null)) as RedoRequestBody | null\n const logId = typeof body?.logId === 'string' ? body.logId.trim() : ''\n if (!logId) return NextResponse.json({ error: 'Invalid log id' }, { status: 400 })\n\n const container = await createRequestContainer()\n const commandBus = (container.resolve('commandBus') as CommandBus)\n const logs = (container.resolve('actionLogService') as ActionLogService)\n let rbac: RbacService | null = null\n try {\n rbac = (container.resolve('rbacService') as RbacService)\n } catch {\n rbac = null\n }\n\n const { organizationId } = await resolveFeatureCheckContext({ container, auth, request: req })\n\n const canRedoTenant = rbac\n ? await rbac.userHasAllFeatures(auth.sub, ['audit_logs.redo_tenant'], {\n tenantId: auth.tenantId ?? null,\n organizationId,\n })\n : false\n\n const scopedOrgId = canRedoTenant ? organizationId ?? null : organizationId ?? auth.orgId ?? null\n const log = await logs.findById(logId)\n\n if (!log || log.executionState !== 'undone') {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n if (log.actorUserId && log.actorUserId !== auth.sub && !canRedoTenant) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n // Fail closed on tenant scope: `audit_logs.redo_tenant` only widens scope WITHIN a\n // tenant, never across tenants, so a tenant-scoped target always requires a caller\n // bound to that same tenant. A caller whose tenantId is null (tenant-less global\n // account or unscoped API key) must never redo a tenant-scoped row. Mirrors the\n // hardened undo route (issue #2685, ported in #2931).\n if (log.tenantId && log.tenantId !== (auth.tenantId ?? null)) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n // Tenant-level redoers may redo across organizations within the tenant, so an\n // unresolved (null) caller org is allowed and only an explicit mismatch is rejected.\n // Every other caller must resolve to the target's own organization \u2014 a null caller\n // org must not bypass an org-scoped target (issue #2685, ported in #2931).\n const orgScopeMismatch = canRedoTenant\n ? Boolean(log.organizationId && scopedOrgId && log.organizationId !== scopedOrgId)\n : Boolean(log.organizationId && log.organizationId !== scopedOrgId)\n if (orgScopeMismatch) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n\n const lookupActorId = canRedoTenant ? (log.actorUserId ?? auth.sub) : auth.sub\n const latestUndoneOrganizationId = log.organizationId ?? null\n const latestUndone = await logs.latestUndoneForActor(lookupActorId, {\n tenantId: auth.tenantId ?? null,\n organizationId: latestUndoneOrganizationId,\n })\n if (!latestUndone || latestUndone.id !== log.id) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n\n try {\n const ctx = await createRuntimeContext(container, auth, req)\n const contextRecord = log.contextJson && typeof log.contextJson === 'object' ? (log.contextJson as Record<string, unknown>) : null\n const cacheAliasesRaw = Array.isArray(contextRecord?.cacheAliases as unknown[])\n ? (contextRecord!.cacheAliases as unknown[])\n : []\n const cacheAliases = cacheAliasesRaw\n .filter((value): value is string => typeof value === 'string' && value.trim().length > 0)\n .map((value) => value.trim())\n const metadataContext: Record<string, unknown> = {\n historyAction: 'redo',\n sourceLogId: log.id,\n sourceCommandId: log.commandId,\n }\n if (cacheAliases.length) metadataContext.cacheAliases = cacheAliases\n const metadata: CommandLogMetadata = {\n tenantId: log.tenantId,\n organizationId: log.organizationId,\n actorUserId: auth.sub,\n actionLabel: log.actionLabel,\n resourceKind: log.resourceKind,\n resourceId: log.resourceId,\n context: metadataContext,\n }\n const resolvedInput = resolveRedoInput(log.commandPayload, log)\n if (!resolvedInput) {\n return NextResponse.json({ error: 'Redo data unavailable for this action' }, { status: 400 })\n }\n const commandInput = resolvedInput\n const { logEntry } = await commandBus.execute(log.commandId, {\n input: commandInput,\n ctx,\n metadata,\n redoLogEntry: log,\n })\n await logs.markRedone(log.id)\n const actionLog = asActionLog(logEntry)\n const response = NextResponse.json({\n ok: true,\n logId: actionLog?.id ?? null,\n undoToken: actionLog?.undoToken ?? null,\n })\n if (actionLog?.undoToken && actionLog.id) {\n const createdAt = actionLog.createdAt instanceof Date\n ? actionLog.createdAt.toISOString()\n : (typeof actionLog.createdAt === 'string' ? actionLog.createdAt : new Date().toISOString())\n response.headers.set('x-om-operation', serializeOperationMetadata({\n id: actionLog.id,\n undoToken: actionLog.undoToken,\n commandId: actionLog.commandId ?? log.commandId,\n actionLabel: actionLog.actionLabel ?? log.actionLabel ?? null,\n resourceKind: typeof actionLog.resourceKind === 'string' ? actionLog.resourceKind : log.resourceKind ?? null,\n resourceId: typeof actionLog.resourceId === 'string' ? actionLog.resourceId : log.resourceId ?? null,\n executedAt: createdAt,\n }))\n }\n return response\n } catch (err) {\n console.error('Redo failed', err)\n return NextResponse.json({ error: 'Redo failed' }, { status: 400 })\n }\n}\n\nasync function createRuntimeContext(container: AwilixContainer, auth: AuthContext, request: Request): Promise<CommandRuntimeContext> {\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request })\n return {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: scope.selectedId,\n organizationIds: scope.filterIds,\n request,\n }\n}\n\nfunction asActionLog(entry: unknown): ActionLog | null {\n if (!entry || typeof entry !== 'object') return null\n if (typeof (entry as { id?: unknown }).id !== 'string') return null\n return entry as ActionLog\n}\n\nfunction resolveRedoInput(payload: unknown, log: ActionLog): unknown | null {\n if (payload && typeof payload === 'object' && !Array.isArray(payload) && '__redoInput' in payload) {\n const envelope = payload as { __redoInput?: unknown }\n return envelope.__redoInput ?? {}\n }\n const updateFallback = deriveUpdateInput(log)\n if (updateFallback) return updateFallback\n return null\n}\n\nfunction deriveUpdateInput(log: ActionLog): Record<string, unknown> | null {\n if (!log.commandId.endsWith('.update')) return null\n if (!log.resourceId) return null\n const changes = log.changesJson\n if (!changes || typeof changes !== 'object' || Array.isArray(changes)) return { id: log.resourceId }\n const payload: Record<string, unknown> = { id: log.resourceId }\n for (const [key, value] of Object.entries(changes)) {\n if (value && typeof value === 'object' && !Array.isArray(value) && 'to' in value) {\n payload[key] = (value as Record<string, unknown>).to\n } else {\n payload[key] = value\n }\n }\n return payload\n}\n\nexport const openApi: OpenApiRouteDoc = {\n summary: 'Redo a previously undone action',\n description: 'Replays the command associated with a recently undone action, reapplying the change and issuing a fresh undo token.',\n methods: {\n POST: {\n summary: 'Redo by action log id',\n description:\n 'Redoes the latest undone command owned by the caller. Requires the action to still be eligible for redo within tenant and organization scope.',\n requestBody: {\n contentType: 'application/json',\n schema: redoRequestSchema,\n },\n responses: [\n { status: 200, description: 'Redo executed successfully', schema: redoResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Log not eligible for redo', schema: errorSchema },\n { status: 401, description: 'Authentication required', schema: errorSchema },\n { status: 403, description: 'Redo blocked by scope checks', schema: errorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,0BAA4C;AACrD,SAAS,8BAA8B;AACvC,SAAS,4BAA4B,0CAA0C;AAK/E,SAAS,kCAAkC;AAG3C,SAAS,SAAS;
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { getAuthFromRequest, type AuthContext } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveFeatureCheckContext, resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { CommandBus } from '@open-mercato/shared/lib/commands/command-bus'\nimport { ActionLogService } from '@open-mercato/core/modules/audit_logs/services/actionLogService'\nimport type { CommandRuntimeContext, CommandLogMetadata } from '@open-mercato/shared/lib/commands'\nimport { serializeOperationMetadata } from '@open-mercato/shared/lib/commands/operationMetadata'\nimport type { AwilixContainer } from 'awilix'\nimport type { ActionLog } from '@open-mercato/core/modules/audit_logs/data/entities'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('audit_logs').child({ component: 'redo' })\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['audit_logs.redo_self'] },\n}\n\ntype RedoRequestBody = {\n logId?: string\n}\n\nconst redoRequestSchema = z.object({\n logId: z.string().min(1).describe('Identifier of the previously undone action log'),\n})\n\nconst redoResponseSchema = z.object({\n ok: z.literal(true),\n logId: z.string().nullable().describe('Identifier of the new redo log entry, if available'),\n undoToken: z.string().nullable().describe('New undo token associated with the redone action'),\n})\n\nconst errorSchema = z.object({\n error: z.string(),\n})\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const body = (await req.json().catch(() => null)) as RedoRequestBody | null\n const logId = typeof body?.logId === 'string' ? body.logId.trim() : ''\n if (!logId) return NextResponse.json({ error: 'Invalid log id' }, { status: 400 })\n\n const container = await createRequestContainer()\n const commandBus = (container.resolve('commandBus') as CommandBus)\n const logs = (container.resolve('actionLogService') as ActionLogService)\n let rbac: RbacService | null = null\n try {\n rbac = (container.resolve('rbacService') as RbacService)\n } catch {\n rbac = null\n }\n\n const { organizationId } = await resolveFeatureCheckContext({ container, auth, request: req })\n\n const canRedoTenant = rbac\n ? await rbac.userHasAllFeatures(auth.sub, ['audit_logs.redo_tenant'], {\n tenantId: auth.tenantId ?? null,\n organizationId,\n })\n : false\n\n const scopedOrgId = canRedoTenant ? organizationId ?? null : organizationId ?? auth.orgId ?? null\n const log = await logs.findById(logId)\n\n if (!log || log.executionState !== 'undone') {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n if (log.actorUserId && log.actorUserId !== auth.sub && !canRedoTenant) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n // Fail closed on tenant scope: `audit_logs.redo_tenant` only widens scope WITHIN a\n // tenant, never across tenants, so a tenant-scoped target always requires a caller\n // bound to that same tenant. A caller whose tenantId is null (tenant-less global\n // account or unscoped API key) must never redo a tenant-scoped row. Mirrors the\n // hardened undo route (issue #2685, ported in #2931).\n if (log.tenantId && log.tenantId !== (auth.tenantId ?? null)) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n // Tenant-level redoers may redo across organizations within the tenant, so an\n // unresolved (null) caller org is allowed and only an explicit mismatch is rejected.\n // Every other caller must resolve to the target's own organization \u2014 a null caller\n // org must not bypass an org-scoped target (issue #2685, ported in #2931).\n const orgScopeMismatch = canRedoTenant\n ? Boolean(log.organizationId && scopedOrgId && log.organizationId !== scopedOrgId)\n : Boolean(log.organizationId && log.organizationId !== scopedOrgId)\n if (orgScopeMismatch) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n\n const lookupActorId = canRedoTenant ? (log.actorUserId ?? auth.sub) : auth.sub\n const latestUndoneOrganizationId = log.organizationId ?? null\n const latestUndone = await logs.latestUndoneForActor(lookupActorId, {\n tenantId: auth.tenantId ?? null,\n organizationId: latestUndoneOrganizationId,\n })\n if (!latestUndone || latestUndone.id !== log.id) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n\n try {\n const ctx = await createRuntimeContext(container, auth, req)\n const contextRecord = log.contextJson && typeof log.contextJson === 'object' ? (log.contextJson as Record<string, unknown>) : null\n const cacheAliasesRaw = Array.isArray(contextRecord?.cacheAliases as unknown[])\n ? (contextRecord!.cacheAliases as unknown[])\n : []\n const cacheAliases = cacheAliasesRaw\n .filter((value): value is string => typeof value === 'string' && value.trim().length > 0)\n .map((value) => value.trim())\n const metadataContext: Record<string, unknown> = {\n historyAction: 'redo',\n sourceLogId: log.id,\n sourceCommandId: log.commandId,\n }\n if (cacheAliases.length) metadataContext.cacheAliases = cacheAliases\n const metadata: CommandLogMetadata = {\n tenantId: log.tenantId,\n organizationId: log.organizationId,\n actorUserId: auth.sub,\n actionLabel: log.actionLabel,\n resourceKind: log.resourceKind,\n resourceId: log.resourceId,\n context: metadataContext,\n }\n const resolvedInput = resolveRedoInput(log.commandPayload, log)\n if (!resolvedInput) {\n return NextResponse.json({ error: 'Redo data unavailable for this action' }, { status: 400 })\n }\n const commandInput = resolvedInput\n const { logEntry } = await commandBus.execute(log.commandId, {\n input: commandInput,\n ctx,\n metadata,\n redoLogEntry: log,\n })\n await logs.markRedone(log.id)\n const actionLog = asActionLog(logEntry)\n const response = NextResponse.json({\n ok: true,\n logId: actionLog?.id ?? null,\n undoToken: actionLog?.undoToken ?? null,\n })\n if (actionLog?.undoToken && actionLog.id) {\n const createdAt = actionLog.createdAt instanceof Date\n ? actionLog.createdAt.toISOString()\n : (typeof actionLog.createdAt === 'string' ? actionLog.createdAt : new Date().toISOString())\n response.headers.set('x-om-operation', serializeOperationMetadata({\n id: actionLog.id,\n undoToken: actionLog.undoToken,\n commandId: actionLog.commandId ?? log.commandId,\n actionLabel: actionLog.actionLabel ?? log.actionLabel ?? null,\n resourceKind: typeof actionLog.resourceKind === 'string' ? actionLog.resourceKind : log.resourceKind ?? null,\n resourceId: typeof actionLog.resourceId === 'string' ? actionLog.resourceId : log.resourceId ?? null,\n executedAt: createdAt,\n }))\n }\n return response\n } catch (err) {\n logger.error('Redo failed', { err })\n return NextResponse.json({ error: 'Redo failed' }, { status: 400 })\n }\n}\n\nasync function createRuntimeContext(container: AwilixContainer, auth: AuthContext, request: Request): Promise<CommandRuntimeContext> {\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request })\n return {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: scope.selectedId,\n organizationIds: scope.filterIds,\n request,\n }\n}\n\nfunction asActionLog(entry: unknown): ActionLog | null {\n if (!entry || typeof entry !== 'object') return null\n if (typeof (entry as { id?: unknown }).id !== 'string') return null\n return entry as ActionLog\n}\n\nfunction resolveRedoInput(payload: unknown, log: ActionLog): unknown | null {\n if (payload && typeof payload === 'object' && !Array.isArray(payload) && '__redoInput' in payload) {\n const envelope = payload as { __redoInput?: unknown }\n return envelope.__redoInput ?? {}\n }\n const updateFallback = deriveUpdateInput(log)\n if (updateFallback) return updateFallback\n return null\n}\n\nfunction deriveUpdateInput(log: ActionLog): Record<string, unknown> | null {\n if (!log.commandId.endsWith('.update')) return null\n if (!log.resourceId) return null\n const changes = log.changesJson\n if (!changes || typeof changes !== 'object' || Array.isArray(changes)) return { id: log.resourceId }\n const payload: Record<string, unknown> = { id: log.resourceId }\n for (const [key, value] of Object.entries(changes)) {\n if (value && typeof value === 'object' && !Array.isArray(value) && 'to' in value) {\n payload[key] = (value as Record<string, unknown>).to\n } else {\n payload[key] = value\n }\n }\n return payload\n}\n\nexport const openApi: OpenApiRouteDoc = {\n summary: 'Redo a previously undone action',\n description: 'Replays the command associated with a recently undone action, reapplying the change and issuing a fresh undo token.',\n methods: {\n POST: {\n summary: 'Redo by action log id',\n description:\n 'Redoes the latest undone command owned by the caller. Requires the action to still be eligible for redo within tenant and organization scope.',\n requestBody: {\n contentType: 'application/json',\n schema: redoRequestSchema,\n },\n responses: [\n { status: 200, description: 'Redo executed successfully', schema: redoResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Log not eligible for redo', schema: errorSchema },\n { status: 401, description: 'Authentication required', schema: errorSchema },\n { status: 403, description: 'Redo blocked by scope checks', schema: errorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["metadata"]
|
|
7
7
|
}
|
|
@@ -3,6 +3,8 @@ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
|
3
3
|
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
4
4
|
import { resolveFeatureCheckContext, resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
7
|
+
const logger = createLogger("audit_logs").child({ component: "undo" });
|
|
6
8
|
const metadata = {
|
|
7
9
|
POST: { requireAuth: true, requireFeatures: ["audit_logs.undo_self"] }
|
|
8
10
|
};
|
|
@@ -77,7 +79,7 @@ async function POST(req) {
|
|
|
77
79
|
await commandBus.undo(undoToken, ctx);
|
|
78
80
|
return NextResponse.json({ ok: true, logId: target.id });
|
|
79
81
|
} catch (err) {
|
|
80
|
-
|
|
82
|
+
logger.error("Undo failed", { err });
|
|
81
83
|
return NextResponse.json({ error: "Undo failed" }, { status: 400 });
|
|
82
84
|
}
|
|
83
85
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/audit_logs/api/audit-logs/actions/undo/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { getAuthFromRequest, type AuthContext } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveFeatureCheckContext, resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { CommandBus } from '@open-mercato/shared/lib/commands/command-bus'\nimport { ActionLogService } from '@open-mercato/core/modules/audit_logs/services/actionLogService'\nimport type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport type { AwilixContainer } from 'awilix'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['audit_logs.undo_self'] },\n}\n\ntype UndoRequestBody = {\n undoToken?: string\n}\n\nconst undoRequestSchema = z.object({\n undoToken: z.string().min(1).describe('Undo token issued by the action log entry'),\n})\n\nconst undoResponseSchema = z.object({\n ok: z.literal(true),\n logId: z.string().describe('Identifier of the action log that was undone'),\n})\n\nconst errorSchema = z.object({\n error: z.string(),\n})\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const body = (await req.json().catch(() => null)) as UndoRequestBody | null\n const undoToken = body?.undoToken?.trim()\n if (!undoToken) return NextResponse.json({ error: 'Invalid undo token' }, { status: 400 })\n\n const container = await createRequestContainer()\n const commandBus = (container.resolve('commandBus') as CommandBus)\n const logs = (container.resolve('actionLogService') as ActionLogService)\n let rbac: RbacService | null = null\n try {\n rbac = (container.resolve('rbacService') as RbacService)\n } catch {\n rbac = null\n }\n\n const { organizationId } = await resolveFeatureCheckContext({ container, auth, request: req })\n\n const canUndoTenant = rbac\n ? await rbac.userHasAllFeatures(auth.sub, ['audit_logs.undo_tenant'], {\n tenantId: auth.tenantId ?? null,\n organizationId,\n })\n : false\n\n const target = await logs.findByUndoToken(undoToken)\n if (!target || target.executionState !== 'done') {\n return NextResponse.json({ error: 'Undo token not available' }, { status: 400 })\n }\n if (target.actorUserId && target.actorUserId !== auth.sub && !canUndoTenant) {\n return NextResponse.json({ error: 'Undo token not available' }, { status: 400 })\n }\n // Fail closed on tenant scope: `audit_logs.undo_tenant` only widens scope WITHIN a\n // tenant, never across tenants, so a tenant-scoped target always requires a caller\n // bound to that same tenant. A caller whose tenantId is null (tenant-less global\n // account or unscoped API key) must never undo a tenant-scoped row (issue #2685).\n if (target.tenantId && target.tenantId !== (auth.tenantId ?? null)) {\n return NextResponse.json({ error: 'Undo token not available' }, { status: 400 })\n }\n const scopedOrgId = canUndoTenant ? organizationId ?? null : organizationId ?? auth.orgId ?? null\n // Tenant-level undoers may undo across organizations within the tenant, so an\n // unresolved (null) caller org is allowed and only an explicit mismatch is rejected.\n // Every other caller must resolve to the target's own organization \u2014 a null caller\n // org must not bypass an org-scoped target (issue #2685).\n const orgScopeMismatch = canUndoTenant\n ? Boolean(target.organizationId && scopedOrgId && target.organizationId !== scopedOrgId)\n : Boolean(target.organizationId && target.organizationId !== scopedOrgId)\n if (orgScopeMismatch) {\n return NextResponse.json({ error: 'Undo token not available' }, { status: 400 })\n }\n\n const lookupActorId = canUndoTenant ? (target.actorUserId ?? auth.sub) : auth.sub\n // Scope the latest-undoable re-lookup to the target row's own organization, not\n // the caller's currently-resolved org. The actor/tenant/org guards above already\n // authorized the caller for this row; reusing the caller's scope here breaks undo\n // for tenant-level rows (organization create/update/delete/reparent log with a\n // null organization_id) whenever the caller resolves to a concrete home org, so\n // the lookup never matches and returns \"Undo token not available\" (issue #2398).\n const lookupOrgId = target.organizationId ?? null\n let latest = null\n if (target.resourceKind || target.resourceId) {\n latest = await logs.latestUndoableForResource({\n actorUserId: lookupActorId,\n tenantId: auth.tenantId ?? null,\n organizationId: lookupOrgId,\n resourceKind: target.resourceKind ?? undefined,\n resourceId: target.resourceId ?? undefined,\n })\n }\n if (!latest) {\n latest = await logs.latestUndoableForActor(lookupActorId, {\n tenantId: auth.tenantId ?? null,\n organizationId: lookupOrgId,\n })\n }\n if (!latest || latest.id !== target.id) {\n return NextResponse.json({ error: 'Undo token not available' }, { status: 400 })\n }\n\n try {\n const ctx = await createRuntimeContext(container, auth, req)\n await commandBus.undo(undoToken, ctx)\n return NextResponse.json({ ok: true, logId: target.id })\n } catch (err) {\n
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,0BAA4C;AACrD,SAAS,8BAA8B;AACvC,SAAS,4BAA4B,0CAA0C;AAM/E,SAAS,SAAS;
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { getAuthFromRequest, type AuthContext } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveFeatureCheckContext, resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { CommandBus } from '@open-mercato/shared/lib/commands/command-bus'\nimport { ActionLogService } from '@open-mercato/core/modules/audit_logs/services/actionLogService'\nimport type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport type { AwilixContainer } from 'awilix'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('audit_logs').child({ component: 'undo' })\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['audit_logs.undo_self'] },\n}\n\ntype UndoRequestBody = {\n undoToken?: string\n}\n\nconst undoRequestSchema = z.object({\n undoToken: z.string().min(1).describe('Undo token issued by the action log entry'),\n})\n\nconst undoResponseSchema = z.object({\n ok: z.literal(true),\n logId: z.string().describe('Identifier of the action log that was undone'),\n})\n\nconst errorSchema = z.object({\n error: z.string(),\n})\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const body = (await req.json().catch(() => null)) as UndoRequestBody | null\n const undoToken = body?.undoToken?.trim()\n if (!undoToken) return NextResponse.json({ error: 'Invalid undo token' }, { status: 400 })\n\n const container = await createRequestContainer()\n const commandBus = (container.resolve('commandBus') as CommandBus)\n const logs = (container.resolve('actionLogService') as ActionLogService)\n let rbac: RbacService | null = null\n try {\n rbac = (container.resolve('rbacService') as RbacService)\n } catch {\n rbac = null\n }\n\n const { organizationId } = await resolveFeatureCheckContext({ container, auth, request: req })\n\n const canUndoTenant = rbac\n ? await rbac.userHasAllFeatures(auth.sub, ['audit_logs.undo_tenant'], {\n tenantId: auth.tenantId ?? null,\n organizationId,\n })\n : false\n\n const target = await logs.findByUndoToken(undoToken)\n if (!target || target.executionState !== 'done') {\n return NextResponse.json({ error: 'Undo token not available' }, { status: 400 })\n }\n if (target.actorUserId && target.actorUserId !== auth.sub && !canUndoTenant) {\n return NextResponse.json({ error: 'Undo token not available' }, { status: 400 })\n }\n // Fail closed on tenant scope: `audit_logs.undo_tenant` only widens scope WITHIN a\n // tenant, never across tenants, so a tenant-scoped target always requires a caller\n // bound to that same tenant. A caller whose tenantId is null (tenant-less global\n // account or unscoped API key) must never undo a tenant-scoped row (issue #2685).\n if (target.tenantId && target.tenantId !== (auth.tenantId ?? null)) {\n return NextResponse.json({ error: 'Undo token not available' }, { status: 400 })\n }\n const scopedOrgId = canUndoTenant ? organizationId ?? null : organizationId ?? auth.orgId ?? null\n // Tenant-level undoers may undo across organizations within the tenant, so an\n // unresolved (null) caller org is allowed and only an explicit mismatch is rejected.\n // Every other caller must resolve to the target's own organization \u2014 a null caller\n // org must not bypass an org-scoped target (issue #2685).\n const orgScopeMismatch = canUndoTenant\n ? Boolean(target.organizationId && scopedOrgId && target.organizationId !== scopedOrgId)\n : Boolean(target.organizationId && target.organizationId !== scopedOrgId)\n if (orgScopeMismatch) {\n return NextResponse.json({ error: 'Undo token not available' }, { status: 400 })\n }\n\n const lookupActorId = canUndoTenant ? (target.actorUserId ?? auth.sub) : auth.sub\n // Scope the latest-undoable re-lookup to the target row's own organization, not\n // the caller's currently-resolved org. The actor/tenant/org guards above already\n // authorized the caller for this row; reusing the caller's scope here breaks undo\n // for tenant-level rows (organization create/update/delete/reparent log with a\n // null organization_id) whenever the caller resolves to a concrete home org, so\n // the lookup never matches and returns \"Undo token not available\" (issue #2398).\n const lookupOrgId = target.organizationId ?? null\n let latest = null\n if (target.resourceKind || target.resourceId) {\n latest = await logs.latestUndoableForResource({\n actorUserId: lookupActorId,\n tenantId: auth.tenantId ?? null,\n organizationId: lookupOrgId,\n resourceKind: target.resourceKind ?? undefined,\n resourceId: target.resourceId ?? undefined,\n })\n }\n if (!latest) {\n latest = await logs.latestUndoableForActor(lookupActorId, {\n tenantId: auth.tenantId ?? null,\n organizationId: lookupOrgId,\n })\n }\n if (!latest || latest.id !== target.id) {\n return NextResponse.json({ error: 'Undo token not available' }, { status: 400 })\n }\n\n try {\n const ctx = await createRuntimeContext(container, auth, req)\n await commandBus.undo(undoToken, ctx)\n return NextResponse.json({ ok: true, logId: target.id })\n } catch (err) {\n logger.error('Undo failed', { err })\n return NextResponse.json({ error: 'Undo failed' }, { status: 400 })\n }\n}\n\nasync function createRuntimeContext(container: AwilixContainer, auth: AuthContext, request: Request): Promise<CommandRuntimeContext> {\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request })\n return {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: scope.selectedId,\n organizationIds: scope.filterIds,\n request,\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n summary: 'Undo a recent action',\n description: 'Executes the undo operation for the most recent undoable action belonging to the caller.',\n methods: {\n POST: {\n summary: 'Undo action by token',\n description:\n 'Replays the undo handler registered for a command. The provided undo token must match the latest undoable log entry accessible to the caller.',\n requestBody: {\n contentType: 'application/json',\n schema: undoRequestSchema,\n },\n responses: [\n { status: 200, description: 'Undo applied successfully', schema: undoResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid or unavailable undo token', schema: errorSchema },\n { status: 401, description: 'Authentication required', schema: errorSchema },\n { status: 403, description: 'Undo blocked by organization or tenant scope', schema: errorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -7,6 +7,8 @@ import { Button } from "@open-mercato/ui/primitives/button";
|
|
|
7
7
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
8
8
|
import { AuditLogsActions } from "../../components/AuditLogsActions.js";
|
|
9
9
|
import { AccessLogsTable } from "../../components/AccessLogsTable.js";
|
|
10
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
11
|
+
const logger = createLogger("audit_logs").child({ component: "audit-logs-page" });
|
|
10
12
|
const DEFAULT_PAGE_SIZE = 50;
|
|
11
13
|
function AuditLogsPage() {
|
|
12
14
|
const t = useT();
|
|
@@ -84,7 +86,7 @@ function AuditLogsPage() {
|
|
|
84
86
|
try {
|
|
85
87
|
await loadAll(actionPage, actionPageSize, accessPageNum, accessPageSizeNum);
|
|
86
88
|
} catch (err) {
|
|
87
|
-
|
|
89
|
+
logger.error("Failed to load audit logs", { err });
|
|
88
90
|
setError(t("audit_logs.error.load"));
|
|
89
91
|
} finally {
|
|
90
92
|
setLoading(false);
|