@open-mercato/core 0.5.1-develop.2691.d8a0934b37 → 0.5.1-develop.2694.732417c5ec
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/modules/api_keys/data/entities.js +1 -1
- package/dist/modules/api_keys/data/entities.js.map +1 -1
- package/dist/modules/api_keys/services/apiKeyService.js +5 -5
- package/dist/modules/api_keys/services/apiKeyService.js.map +2 -2
- package/dist/modules/attachments/api/library/[id]/route.js +1 -1
- package/dist/modules/attachments/api/library/[id]/route.js.map +2 -2
- package/dist/modules/attachments/api/library/route.js +7 -9
- package/dist/modules/attachments/api/library/route.js.map +2 -2
- package/dist/modules/attachments/api/partitions/route.js +3 -3
- package/dist/modules/attachments/api/partitions/route.js.map +2 -2
- package/dist/modules/attachments/api/route.js +6 -5
- package/dist/modules/attachments/api/route.js.map +2 -2
- package/dist/modules/attachments/api/transfer/route.js +1 -1
- package/dist/modules/attachments/api/transfer/route.js.map +2 -2
- package/dist/modules/attachments/data/entities.js +2 -1
- package/dist/modules/attachments/data/entities.js.map +2 -2
- package/dist/modules/attachments/lib/ocrQueue.js +1 -1
- package/dist/modules/attachments/lib/ocrQueue.js.map +2 -2
- package/dist/modules/audit_logs/api/audit-logs/actions/export/route.js.map +2 -2
- package/dist/modules/audit_logs/api/audit-logs/actions/route.js.map +2 -2
- package/dist/modules/audit_logs/data/entities.js +1 -1
- package/dist/modules/audit_logs/data/entities.js.map +1 -1
- package/dist/modules/audit_logs/services/actionLogService.js +77 -70
- package/dist/modules/audit_logs/services/actionLogService.js.map +2 -2
- package/dist/modules/auth/api/roles/acl/route.js +1 -1
- package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
- package/dist/modules/auth/api/users/acl/route.js +2 -2
- package/dist/modules/auth/api/users/acl/route.js.map +2 -2
- package/dist/modules/auth/api/users/resend-invite/route.js +1 -1
- package/dist/modules/auth/api/users/resend-invite/route.js.map +2 -2
- package/dist/modules/auth/cli.js +12 -6
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/auth/commands/users.js +1 -1
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/auth/data/entities.js +1 -1
- package/dist/modules/auth/data/entities.js.map +2 -2
- package/dist/modules/auth/lib/setup-app.js +3 -3
- package/dist/modules/auth/lib/setup-app.js.map +2 -2
- package/dist/modules/auth/services/authService.js +2 -2
- package/dist/modules/auth/services/authService.js.map +2 -2
- package/dist/modules/business_rules/api/rules/route.js +3 -3
- package/dist/modules/business_rules/api/rules/route.js.map +2 -2
- package/dist/modules/business_rules/api/sets/[id]/members/route.js +7 -4
- package/dist/modules/business_rules/api/sets/[id]/members/route.js.map +2 -2
- package/dist/modules/business_rules/api/sets/route.js +3 -3
- package/dist/modules/business_rules/api/sets/route.js.map +2 -2
- package/dist/modules/business_rules/cli.js +1 -1
- package/dist/modules/business_rules/cli.js.map +2 -2
- package/dist/modules/business_rules/data/entities.js +2 -9
- package/dist/modules/business_rules/data/entities.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-engine.js +1 -1
- package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
- package/dist/modules/catalog/api/option-schemas/route.js +0 -1
- package/dist/modules/catalog/api/option-schemas/route.js.map +2 -2
- package/dist/modules/catalog/data/entities.js +2 -11
- package/dist/modules/catalog/data/entities.js.map +2 -2
- package/dist/modules/configs/data/entities.js +2 -1
- package/dist/modules/configs/data/entities.js.map +2 -2
- package/dist/modules/currencies/commands/fetch-configs.js +3 -3
- package/dist/modules/currencies/commands/fetch-configs.js.map +2 -2
- package/dist/modules/currencies/data/entities.js +1 -1
- package/dist/modules/currencies/data/entities.js.map +2 -2
- package/dist/modules/customer_accounts/api/signup.js +1 -1
- package/dist/modules/customer_accounts/api/signup.js.map +2 -2
- package/dist/modules/customer_accounts/data/entities.js +1 -1
- package/dist/modules/customer_accounts/data/entities.js.map +2 -2
- package/dist/modules/customer_accounts/services/customerInvitationService.js +1 -1
- package/dist/modules/customer_accounts/services/customerInvitationService.js.map +2 -2
- package/dist/modules/customer_accounts/services/customerSessionService.js +1 -1
- package/dist/modules/customer_accounts/services/customerSessionService.js.map +2 -2
- package/dist/modules/customer_accounts/services/customerTokenService.js +12 -7
- package/dist/modules/customer_accounts/services/customerTokenService.js.map +2 -2
- package/dist/modules/customers/api/interactions/conflicts/route.js +19 -17
- package/dist/modules/customers/api/interactions/conflicts/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/counts/route.js +7 -6
- package/dist/modules/customers/api/interactions/counts/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/route.js +28 -42
- package/dist/modules/customers/api/interactions/route.js.map +2 -2
- package/dist/modules/customers/api/utils.js +29 -24
- package/dist/modules/customers/api/utils.js.map +2 -2
- package/dist/modules/customers/cli.js +45 -40
- package/dist/modules/customers/cli.js.map +2 -2
- package/dist/modules/customers/commands/dictionaries.js +1 -1
- package/dist/modules/customers/commands/dictionaries.js.map +2 -2
- package/dist/modules/customers/commands/tags.js +1 -1
- package/dist/modules/customers/commands/tags.js.map +2 -2
- package/dist/modules/customers/data/entities.js +2 -12
- package/dist/modules/customers/data/entities.js.map +2 -2
- package/dist/modules/customers/lib/interactionProjection.js +18 -15
- package/dist/modules/customers/lib/interactionProjection.js.map +2 -2
- package/dist/modules/customers/lib/personCompanyLinkTable.js +6 -8
- package/dist/modules/customers/lib/personCompanyLinkTable.js.map +2 -2
- package/dist/modules/dashboards/api/roles/widgets/route.js +1 -1
- package/dist/modules/dashboards/api/roles/widgets/route.js.map +2 -2
- package/dist/modules/dashboards/api/users/widgets/route.js +1 -1
- package/dist/modules/dashboards/api/users/widgets/route.js.map +2 -2
- package/dist/modules/dashboards/data/entities.js +1 -1
- package/dist/modules/dashboards/data/entities.js.map +1 -1
- package/dist/modules/data_sync/api/mappings/route.js +1 -1
- package/dist/modules/data_sync/api/mappings/route.js.map +2 -2
- package/dist/modules/data_sync/data/entities.js +2 -1
- package/dist/modules/data_sync/data/entities.js.map +2 -2
- package/dist/modules/data_sync/lib/id-mapping.js +1 -1
- package/dist/modules/data_sync/lib/id-mapping.js.map +2 -2
- package/dist/modules/data_sync/lib/sync-run-service.js +1 -1
- package/dist/modules/data_sync/lib/sync-run-service.js.map +2 -2
- package/dist/modules/dictionaries/commands/factory.js +1 -1
- package/dist/modules/dictionaries/commands/factory.js.map +2 -2
- package/dist/modules/dictionaries/data/entities.js +2 -9
- package/dist/modules/dictionaries/data/entities.js.map +2 -2
- package/dist/modules/directory/commands/organizations.js +4 -4
- package/dist/modules/directory/commands/organizations.js.map +2 -2
- package/dist/modules/directory/data/entities.js +2 -1
- package/dist/modules/directory/data/entities.js.map +2 -2
- package/dist/modules/entities/api/definitions.js +2 -2
- package/dist/modules/entities/api/definitions.js.map +2 -2
- package/dist/modules/entities/api/encryption.js +2 -2
- package/dist/modules/entities/api/encryption.js.map +2 -2
- package/dist/modules/entities/api/relations/options.js +2 -2
- package/dist/modules/entities/api/relations/options.js.map +2 -2
- package/dist/modules/entities/cli.js +4 -4
- package/dist/modules/entities/cli.js.map +2 -2
- package/dist/modules/entities/data/entities.js +1 -1
- package/dist/modules/entities/data/entities.js.map +2 -2
- package/dist/modules/entities/lib/field-definitions.js +2 -2
- package/dist/modules/entities/lib/field-definitions.js.map +2 -2
- package/dist/modules/entities/lib/register.js +1 -1
- package/dist/modules/entities/lib/register.js.map +2 -2
- package/dist/modules/feature_toggles/data/entities.js +2 -9
- package/dist/modules/feature_toggles/data/entities.js.map +2 -2
- package/dist/modules/inbox_ops/api/proposals/counts/route.js +3 -6
- package/dist/modules/inbox_ops/api/proposals/counts/route.js.map +2 -2
- package/dist/modules/inbox_ops/data/entities.js +2 -8
- package/dist/modules/inbox_ops/data/entities.js.map +2 -2
- package/dist/modules/inbox_ops/lib/messagesIntegration.js +6 -6
- package/dist/modules/inbox_ops/lib/messagesIntegration.js.map +2 -2
- package/dist/modules/integrations/data/entities.js +2 -1
- package/dist/modules/integrations/data/entities.js.map +2 -2
- package/dist/modules/integrations/lib/credentials-service.js +1 -1
- package/dist/modules/integrations/lib/credentials-service.js.map +2 -2
- package/dist/modules/integrations/lib/log-service.js +1 -1
- package/dist/modules/integrations/lib/log-service.js.map +2 -2
- package/dist/modules/integrations/lib/state-service.js +1 -1
- package/dist/modules/integrations/lib/state-service.js.map +2 -2
- package/dist/modules/messages/api/route.js +90 -93
- package/dist/modules/messages/api/route.js.map +2 -2
- package/dist/modules/messages/api/unread-count/route.js +8 -7
- package/dist/modules/messages/api/unread-count/route.js.map +2 -2
- package/dist/modules/messages/commands/confirmations.js +1 -1
- package/dist/modules/messages/commands/confirmations.js.map +2 -2
- package/dist/modules/messages/commands/messages.js +3 -3
- package/dist/modules/messages/commands/messages.js.map +2 -2
- package/dist/modules/messages/data/entities.js +2 -1
- package/dist/modules/messages/data/entities.js.map +2 -2
- package/dist/modules/messages/lib/email-sender.js +1 -1
- package/dist/modules/messages/lib/email-sender.js.map +2 -2
- package/dist/modules/messages/lib/searchLookup.js +8 -8
- package/dist/modules/messages/lib/searchLookup.js.map +2 -2
- package/dist/modules/messages/lib/tokenConsumption.js +9 -4
- package/dist/modules/messages/lib/tokenConsumption.js.map +2 -2
- package/dist/modules/notifications/data/entities.js +2 -1
- package/dist/modules/notifications/data/entities.js.map +2 -2
- package/dist/modules/notifications/lib/notificationRecipients.js +15 -5
- package/dist/modules/notifications/lib/notificationRecipients.js.map +2 -2
- package/dist/modules/notifications/lib/notificationService.js +39 -34
- package/dist/modules/notifications/lib/notificationService.js.map +2 -2
- package/dist/modules/notifications/workers/create-notification.worker.js +14 -13
- package/dist/modules/notifications/workers/create-notification.worker.js.map +2 -2
- package/dist/modules/payment_gateways/api/transactions/route.js +2 -2
- package/dist/modules/payment_gateways/api/transactions/route.js.map +2 -2
- package/dist/modules/payment_gateways/data/entities.js +2 -1
- package/dist/modules/payment_gateways/data/entities.js.map +2 -2
- package/dist/modules/payment_gateways/lib/gateway-service.js +1 -1
- package/dist/modules/payment_gateways/lib/gateway-service.js.map +2 -2
- package/dist/modules/payment_gateways/lib/webhook-utils.js +2 -2
- package/dist/modules/payment_gateways/lib/webhook-utils.js.map +2 -2
- package/dist/modules/perspectives/data/entities.js +1 -1
- package/dist/modules/perspectives/data/entities.js.map +2 -2
- package/dist/modules/planner/data/entities.js +1 -1
- package/dist/modules/planner/data/entities.js.map +2 -2
- package/dist/modules/progress/data/entities.js +2 -1
- package/dist/modules/progress/data/entities.js.map +2 -2
- package/dist/modules/progress/lib/progressServiceImpl.js +1 -1
- package/dist/modules/progress/lib/progressServiceImpl.js.map +2 -2
- package/dist/modules/query_index/api/status.js +66 -57
- package/dist/modules/query_index/api/status.js.map +2 -2
- package/dist/modules/query_index/cli.js +39 -24
- package/dist/modules/query_index/cli.js.map +2 -2
- package/dist/modules/query_index/data/entities.js +1 -1
- package/dist/modules/query_index/data/entities.js.map +2 -2
- package/dist/modules/query_index/di.js +25 -13
- package/dist/modules/query_index/di.js.map +2 -2
- package/dist/modules/query_index/lib/batch.js +31 -33
- package/dist/modules/query_index/lib/batch.js.map +2 -2
- package/dist/modules/query_index/lib/coverage.js +63 -50
- package/dist/modules/query_index/lib/coverage.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +592 -588
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/lib/indexer.js +74 -47
- package/dist/modules/query_index/lib/indexer.js.map +2 -2
- package/dist/modules/query_index/lib/jobs.js +37 -24
- package/dist/modules/query_index/lib/jobs.js.map +2 -2
- package/dist/modules/query_index/lib/purge.js +19 -11
- package/dist/modules/query_index/lib/purge.js.map +2 -2
- package/dist/modules/query_index/lib/reindexer.js +47 -44
- package/dist/modules/query_index/lib/reindexer.js.map +2 -2
- package/dist/modules/query_index/lib/search-tokens.js +47 -25
- package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
- package/dist/modules/query_index/lib/stale.js +14 -12
- package/dist/modules/query_index/lib/stale.js.map +2 -2
- package/dist/modules/query_index/lib/subscriber-scope.js +2 -2
- package/dist/modules/query_index/lib/subscriber-scope.js.map +2 -2
- package/dist/modules/query_index/subscribers/delete_one.js +3 -2
- package/dist/modules/query_index/subscribers/delete_one.js.map +2 -2
- package/dist/modules/resources/commands/tag-assignments.js +1 -1
- package/dist/modules/resources/commands/tag-assignments.js.map +2 -2
- package/dist/modules/resources/commands/tags.js +1 -1
- package/dist/modules/resources/commands/tags.js.map +2 -2
- package/dist/modules/resources/data/entities.js +2 -1
- package/dist/modules/resources/data/entities.js.map +2 -2
- package/dist/modules/sales/commands/documentAddresses.js +2 -2
- package/dist/modules/sales/commands/documentAddresses.js.map +2 -2
- package/dist/modules/sales/commands/notes.js.map +2 -2
- package/dist/modules/sales/commands/tags.js +1 -1
- package/dist/modules/sales/commands/tags.js.map +2 -2
- package/dist/modules/sales/data/enrichers.js +9 -8
- package/dist/modules/sales/data/enrichers.js.map +2 -2
- package/dist/modules/sales/data/entities.js +2 -11
- package/dist/modules/sales/data/entities.js.map +2 -2
- package/dist/modules/shipping_carriers/data/entities.js +2 -1
- package/dist/modules/shipping_carriers/data/entities.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/shipping-service.js +1 -1
- package/dist/modules/shipping_carriers/lib/shipping-service.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/webhook-utils.js +2 -2
- package/dist/modules/shipping_carriers/lib/webhook-utils.js.map +2 -2
- package/dist/modules/staff/data/entities.js +1 -1
- package/dist/modules/staff/data/entities.js.map +2 -2
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js +3 -5
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
- package/dist/modules/translations/api/context.js +2 -2
- package/dist/modules/translations/api/context.js.map +2 -2
- package/dist/modules/translations/commands/translations.js +46 -39
- package/dist/modules/translations/commands/translations.js.map +2 -2
- package/dist/modules/translations/components/TranslationManager.js +19 -10
- package/dist/modules/translations/components/TranslationManager.js.map +2 -2
- package/dist/modules/translations/data/entities.js +1 -1
- package/dist/modules/translations/data/entities.js.map +2 -2
- package/dist/modules/translations/lib/apply.js +4 -4
- package/dist/modules/translations/lib/apply.js.map +2 -2
- package/dist/modules/translations/lib/batch.js +3 -2
- package/dist/modules/translations/lib/batch.js.map +2 -2
- package/dist/modules/translations/subscribers/cleanup.js +3 -5
- package/dist/modules/translations/subscribers/cleanup.js.map +2 -2
- package/dist/modules/workflows/api/definitions/route.js +1 -1
- package/dist/modules/workflows/api/definitions/route.js.map +2 -2
- package/dist/modules/workflows/cli.js +5 -5
- package/dist/modules/workflows/cli.js.map +2 -2
- package/dist/modules/workflows/data/entities.js +2 -1
- package/dist/modules/workflows/data/entities.js.map +2 -2
- package/dist/modules/workflows/lib/event-logger.js +2 -2
- package/dist/modules/workflows/lib/event-logger.js.map +2 -2
- package/dist/modules/workflows/lib/seeds.js +16 -1
- package/dist/modules/workflows/lib/seeds.js.map +2 -2
- package/dist/modules/workflows/lib/step-handler.js +3 -3
- package/dist/modules/workflows/lib/step-handler.js.map +2 -2
- package/dist/modules/workflows/lib/task-handler.js +1 -1
- package/dist/modules/workflows/lib/task-handler.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +1 -1
- package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
- package/dist/modules/workflows/lib/workflow-executor.js +2 -2
- package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
- package/jest.config.cjs +4 -2
- package/package.json +3 -3
- package/src/modules/api_keys/data/entities.ts +1 -1
- package/src/modules/api_keys/services/apiKeyService.ts +5 -5
- package/src/modules/attachments/api/library/[id]/route.ts +1 -1
- package/src/modules/attachments/api/library/route.ts +10 -12
- package/src/modules/attachments/api/partitions/route.ts +3 -3
- package/src/modules/attachments/api/route.ts +10 -8
- package/src/modules/attachments/api/transfer/route.ts +1 -1
- package/src/modules/attachments/data/entities.ts +2 -1
- package/src/modules/attachments/lib/ocrQueue.ts +1 -1
- package/src/modules/audit_logs/api/audit-logs/actions/export/route.ts +4 -4
- package/src/modules/audit_logs/api/audit-logs/actions/route.ts +4 -4
- package/src/modules/audit_logs/data/entities.ts +1 -1
- package/src/modules/audit_logs/services/actionLogService.ts +96 -87
- package/src/modules/auth/api/roles/acl/route.ts +1 -1
- package/src/modules/auth/api/users/acl/route.ts +2 -2
- package/src/modules/auth/api/users/resend-invite/route.ts +1 -1
- package/src/modules/auth/cli.ts +46 -40
- package/src/modules/auth/commands/users.ts +1 -1
- package/src/modules/auth/data/entities.ts +1 -1
- package/src/modules/auth/lib/setup-app.ts +3 -3
- package/src/modules/auth/services/authService.ts +2 -2
- package/src/modules/business_rules/api/rules/route.ts +3 -3
- package/src/modules/business_rules/api/sets/[id]/members/route.ts +7 -4
- package/src/modules/business_rules/api/sets/route.ts +3 -3
- package/src/modules/business_rules/cli.ts +1 -1
- package/src/modules/business_rules/data/entities.ts +2 -9
- package/src/modules/business_rules/lib/rule-engine.ts +1 -1
- package/src/modules/catalog/api/option-schemas/route.ts +0 -1
- package/src/modules/catalog/data/entities.ts +2 -11
- package/src/modules/configs/data/entities.ts +2 -1
- package/src/modules/currencies/commands/fetch-configs.ts +3 -3
- package/src/modules/currencies/data/entities.ts +1 -1
- package/src/modules/customer_accounts/api/signup.ts +1 -1
- package/src/modules/customer_accounts/data/entities.ts +1 -1
- package/src/modules/customer_accounts/services/customerInvitationService.ts +1 -1
- package/src/modules/customer_accounts/services/customerSessionService.ts +1 -1
- package/src/modules/customer_accounts/services/customerTokenService.ts +26 -15
- package/src/modules/customers/api/interactions/conflicts/route.ts +26 -23
- package/src/modules/customers/api/interactions/counts/route.ts +13 -11
- package/src/modules/customers/api/interactions/route.ts +32 -44
- package/src/modules/customers/api/utils.ts +45 -37
- package/src/modules/customers/cli.ts +88 -67
- package/src/modules/customers/commands/dictionaries.ts +1 -1
- package/src/modules/customers/commands/tags.ts +1 -1
- package/src/modules/customers/data/entities.ts +2 -12
- package/src/modules/customers/lib/interactionProjection.ts +36 -25
- package/src/modules/customers/lib/personCompanyLinkTable.ts +13 -18
- package/src/modules/dashboards/api/roles/widgets/route.ts +1 -1
- package/src/modules/dashboards/api/users/widgets/route.ts +1 -1
- package/src/modules/dashboards/data/entities.ts +1 -1
- package/src/modules/data_sync/api/mappings/route.ts +1 -1
- package/src/modules/data_sync/data/entities.ts +2 -1
- package/src/modules/data_sync/lib/id-mapping.ts +1 -1
- package/src/modules/data_sync/lib/sync-run-service.ts +1 -1
- package/src/modules/dictionaries/commands/factory.ts +1 -1
- package/src/modules/dictionaries/data/entities.ts +2 -9
- package/src/modules/directory/commands/organizations.ts +4 -4
- package/src/modules/directory/data/entities.ts +2 -1
- package/src/modules/entities/api/definitions.ts +2 -2
- package/src/modules/entities/api/encryption.ts +2 -2
- package/src/modules/entities/api/relations/options.ts +8 -3
- package/src/modules/entities/cli.ts +4 -4
- package/src/modules/entities/data/entities.ts +1 -1
- package/src/modules/entities/lib/field-definitions.ts +2 -2
- package/src/modules/entities/lib/register.ts +1 -1
- package/src/modules/feature_toggles/data/entities.ts +2 -9
- package/src/modules/inbox_ops/api/proposals/counts/route.ts +10 -10
- package/src/modules/inbox_ops/data/entities.ts +2 -8
- package/src/modules/inbox_ops/lib/messagesIntegration.ts +12 -11
- package/src/modules/integrations/data/entities.ts +2 -1
- package/src/modules/integrations/lib/credentials-service.ts +1 -1
- package/src/modules/integrations/lib/log-service.ts +1 -1
- package/src/modules/integrations/lib/state-service.ts +1 -1
- package/src/modules/messages/api/route.ts +134 -123
- package/src/modules/messages/api/unread-count/route.ts +19 -16
- package/src/modules/messages/commands/confirmations.ts +1 -1
- package/src/modules/messages/commands/messages.ts +3 -3
- package/src/modules/messages/data/entities.ts +2 -1
- package/src/modules/messages/lib/email-sender.ts +1 -1
- package/src/modules/messages/lib/searchLookup.ts +16 -13
- package/src/modules/messages/lib/tokenConsumption.ts +16 -8
- package/src/modules/notifications/data/entities.ts +2 -1
- package/src/modules/notifications/lib/notificationRecipients.ts +42 -26
- package/src/modules/notifications/lib/notificationService.ts +53 -42
- package/src/modules/notifications/workers/create-notification.worker.ts +20 -17
- package/src/modules/payment_gateways/api/transactions/route.ts +2 -2
- package/src/modules/payment_gateways/data/entities.ts +2 -1
- package/src/modules/payment_gateways/lib/gateway-service.ts +1 -1
- package/src/modules/payment_gateways/lib/webhook-utils.ts +2 -2
- package/src/modules/perspectives/data/entities.ts +1 -1
- package/src/modules/planner/data/entities.ts +1 -1
- package/src/modules/progress/data/entities.ts +2 -1
- package/src/modules/progress/lib/progressServiceImpl.ts +1 -1
- package/src/modules/query_index/api/status.ts +85 -71
- package/src/modules/query_index/cli.ts +51 -31
- package/src/modules/query_index/data/entities.ts +1 -1
- package/src/modules/query_index/di.ts +41 -16
- package/src/modules/query_index/lib/batch.ts +68 -55
- package/src/modules/query_index/lib/coverage.ts +115 -88
- package/src/modules/query_index/lib/engine.ts +1036 -1096
- package/src/modules/query_index/lib/indexer.ts +115 -79
- package/src/modules/query_index/lib/jobs.ts +51 -31
- package/src/modules/query_index/lib/purge.ts +25 -19
- package/src/modules/query_index/lib/reindexer.ts +97 -84
- package/src/modules/query_index/lib/search-tokens.ts +67 -36
- package/src/modules/query_index/lib/stale.ts +14 -17
- package/src/modules/query_index/lib/subscriber-scope.ts +6 -5
- package/src/modules/query_index/subscribers/delete_one.ts +9 -6
- package/src/modules/resources/commands/tag-assignments.ts +1 -1
- package/src/modules/resources/commands/tags.ts +1 -1
- package/src/modules/resources/data/entities.ts +2 -1
- package/src/modules/sales/commands/documentAddresses.ts +2 -2
- package/src/modules/sales/commands/notes.ts +1 -1
- package/src/modules/sales/commands/tags.ts +1 -1
- package/src/modules/sales/data/enrichers.ts +17 -13
- package/src/modules/sales/data/entities.ts +2 -11
- package/src/modules/shipping_carriers/data/entities.ts +2 -1
- package/src/modules/shipping_carriers/lib/shipping-service.ts +1 -1
- package/src/modules/shipping_carriers/lib/webhook-utils.ts +2 -2
- package/src/modules/staff/data/entities.ts +1 -1
- package/src/modules/translations/api/[entityType]/[entityId]/route.ts +14 -11
- package/src/modules/translations/api/context.ts +4 -4
- package/src/modules/translations/commands/translations.ts +116 -81
- package/src/modules/translations/components/TranslationManager.tsx +23 -14
- package/src/modules/translations/data/entities.ts +1 -1
- package/src/modules/translations/i18n/de.json +1 -0
- package/src/modules/translations/i18n/en.json +1 -0
- package/src/modules/translations/i18n/es.json +1 -0
- package/src/modules/translations/i18n/pl.json +1 -0
- package/src/modules/translations/lib/apply.ts +6 -6
- package/src/modules/translations/lib/batch.ts +9 -7
- package/src/modules/translations/subscribers/cleanup.ts +10 -11
- package/src/modules/workflows/api/definitions/route.ts +1 -1
- package/src/modules/workflows/cli.ts +5 -5
- package/src/modules/workflows/data/entities.ts +2 -1
- package/src/modules/workflows/lib/event-logger.ts +2 -2
- package/src/modules/workflows/lib/seeds.ts +16 -1
- package/src/modules/workflows/lib/step-handler.ts +3 -3
- package/src/modules/workflows/lib/task-handler.ts +1 -1
- package/src/modules/workflows/lib/transition-handler.ts +1 -1
- package/src/modules/workflows/lib/workflow-executor.ts +2 -2
|
@@ -2,6 +2,7 @@ import { NextResponse } from "next/server";
|
|
|
2
2
|
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
3
3
|
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
4
4
|
import { getEntityIds } from "@open-mercato/shared/lib/encryption/entityIds";
|
|
5
|
+
import { sql } from "kysely";
|
|
5
6
|
import { readCoverageSnapshot, refreshCoverageSnapshot } from "../lib/coverage.js";
|
|
6
7
|
import { queryIndexTag, queryIndexErrorSchema, queryIndexStatusResponseSchema } from "./openapi.js";
|
|
7
8
|
import { flattenSystemEntityIds } from "@open-mercato/shared/lib/entities/system-entities";
|
|
@@ -14,7 +15,7 @@ async function GET(req) {
|
|
|
14
15
|
if (!auth) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
15
16
|
const container = await createRequestContainer();
|
|
16
17
|
const em = container.resolve("em");
|
|
17
|
-
const
|
|
18
|
+
const db = em.getKysely();
|
|
18
19
|
const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req });
|
|
19
20
|
const organizationId = scope.selectedId ?? auth.orgId ?? null;
|
|
20
21
|
const tenantId = typeof scope.tenantId === "string" && scope.tenantId.trim().length > 0 ? scope.tenantId.trim() : typeof auth.tenantId === "string" && auth.tenantId.trim().length > 0 ? auth.tenantId.trim() : null;
|
|
@@ -79,19 +80,22 @@ async function GET(req) {
|
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
try {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
83
|
+
let cfQuery = db.selectFrom("custom_field_defs").select(["entity_id"]).distinct().where("is_active", "=", true);
|
|
84
|
+
if (tenantId != null) {
|
|
85
|
+
cfQuery = cfQuery.where((eb) => eb.or([
|
|
86
|
+
eb("tenant_id", "=", tenantId),
|
|
87
|
+
eb("tenant_id", "is", null)
|
|
88
|
+
]));
|
|
89
|
+
} else {
|
|
90
|
+
cfQuery = cfQuery.where("tenant_id", "is", null);
|
|
91
|
+
}
|
|
92
|
+
if (Array.isArray(organizationScopeIds)) {
|
|
93
|
+
cfQuery = cfQuery.where((eb) => eb.or([
|
|
94
|
+
eb("organization_id", "in", organizationScopeIds),
|
|
95
|
+
eb("organization_id", "is", null)
|
|
96
|
+
]));
|
|
97
|
+
}
|
|
98
|
+
const cfRows = await cfQuery.execute();
|
|
95
99
|
const enabled = new Set((cfRows || []).map((r) => String(r.entity_id)));
|
|
96
100
|
entityIds = entityIds.filter((id) => enabled.has(id));
|
|
97
101
|
} catch {
|
|
@@ -100,19 +104,16 @@ async function GET(req) {
|
|
|
100
104
|
const COVERAGE_STALE_MS = 6e4;
|
|
101
105
|
async function fetchJobSummary(entityType, tenantIdParam, organizationIdParam) {
|
|
102
106
|
try {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
qb.whereRaw("organization_id is not distinct from ?", [null]);
|
|
114
|
-
}
|
|
115
|
-
}).orderBy("started_at", "desc");
|
|
107
|
+
let jobQuery = db.selectFrom("entity_index_jobs").selectAll().where("entity_type", "=", entityType).where(sql`tenant_id is not distinct from ${tenantIdParam ?? null}`);
|
|
108
|
+
if (organizationIdParam != null) {
|
|
109
|
+
jobQuery = jobQuery.where((eb) => eb.or([
|
|
110
|
+
eb("organization_id", "=", organizationIdParam),
|
|
111
|
+
eb("organization_id", "is", null)
|
|
112
|
+
]));
|
|
113
|
+
} else {
|
|
114
|
+
jobQuery = jobQuery.where(sql`organization_id is not distinct from ${null}`);
|
|
115
|
+
}
|
|
116
|
+
const rows = await jobQuery.orderBy("started_at", "desc").execute();
|
|
116
117
|
if (!rows.length) {
|
|
117
118
|
return { status: "idle", partitions: [] };
|
|
118
119
|
}
|
|
@@ -221,12 +222,12 @@ async function GET(req) {
|
|
|
221
222
|
withDeleted: false
|
|
222
223
|
};
|
|
223
224
|
const ensureSnapshot = async () => {
|
|
224
|
-
let snapshot = await readCoverageSnapshot(
|
|
225
|
+
let snapshot = await readCoverageSnapshot(db, scope2);
|
|
225
226
|
const refreshedAt = snapshot?.refreshed_at instanceof Date ? snapshot.refreshed_at : snapshot?.refreshed_at ? new Date(snapshot.refreshed_at) : null;
|
|
226
227
|
const stale = !snapshot || !refreshedAt || Date.now() - refreshedAt.getTime() > COVERAGE_STALE_MS;
|
|
227
228
|
if (forceRefresh || stale) {
|
|
228
229
|
await refreshCoverageSnapshot(em, scope2).catch(() => void 0);
|
|
229
|
-
snapshot = await readCoverageSnapshot(
|
|
230
|
+
snapshot = await readCoverageSnapshot(db, scope2);
|
|
230
231
|
}
|
|
231
232
|
const finalRefreshed = snapshot?.refreshed_at instanceof Date ? snapshot.refreshed_at : snapshot?.refreshed_at ? new Date(snapshot.refreshed_at) : null;
|
|
232
233
|
if (!snapshot || !finalRefreshed || Date.now() - finalRefreshed.getTime() > COVERAGE_STALE_MS) {
|
|
@@ -290,20 +291,24 @@ async function GET(req) {
|
|
|
290
291
|
} catch {
|
|
291
292
|
}
|
|
292
293
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
294
|
+
let errorQuery = db.selectFrom("indexer_error_logs").selectAll();
|
|
295
|
+
if (tenantId != null) {
|
|
296
|
+
errorQuery = errorQuery.where((eb) => eb.or([
|
|
297
|
+
eb("tenant_id", "=", tenantId),
|
|
298
|
+
eb("tenant_id", "is", null)
|
|
299
|
+
]));
|
|
300
|
+
} else {
|
|
301
|
+
errorQuery = errorQuery.where("tenant_id", "is", null);
|
|
302
|
+
}
|
|
303
|
+
if (Array.isArray(organizationScopeIds) && organizationScopeIds.length) {
|
|
304
|
+
errorQuery = errorQuery.where((eb) => eb.or([
|
|
305
|
+
eb("organization_id", "is", null),
|
|
306
|
+
eb("organization_id", "in", organizationScopeIds)
|
|
307
|
+
]));
|
|
308
|
+
} else {
|
|
309
|
+
errorQuery = errorQuery.where("organization_id", "is", null);
|
|
310
|
+
}
|
|
311
|
+
const errorRows = await errorQuery.orderBy("occurred_at", "desc").limit(100).execute();
|
|
307
312
|
const errors = errorRows.map((row) => {
|
|
308
313
|
const occurredAt = row.occurred_at instanceof Date ? row.occurred_at : row.occurred_at ? new Date(row.occurred_at) : null;
|
|
309
314
|
return {
|
|
@@ -320,20 +325,24 @@ async function GET(req) {
|
|
|
320
325
|
occurredAt: occurredAt ? occurredAt.toISOString() : (/* @__PURE__ */ new Date()).toISOString()
|
|
321
326
|
};
|
|
322
327
|
});
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
328
|
+
let logsQuery = db.selectFrom("indexer_status_logs").selectAll();
|
|
329
|
+
if (tenantId != null) {
|
|
330
|
+
logsQuery = logsQuery.where((eb) => eb.or([
|
|
331
|
+
eb("tenant_id", "=", tenantId),
|
|
332
|
+
eb("tenant_id", "is", null)
|
|
333
|
+
]));
|
|
334
|
+
} else {
|
|
335
|
+
logsQuery = logsQuery.where("tenant_id", "is", null);
|
|
336
|
+
}
|
|
337
|
+
if (Array.isArray(organizationScopeIds) && organizationScopeIds.length) {
|
|
338
|
+
logsQuery = logsQuery.where((eb) => eb.or([
|
|
339
|
+
eb("organization_id", "is", null),
|
|
340
|
+
eb("organization_id", "in", organizationScopeIds)
|
|
341
|
+
]));
|
|
342
|
+
} else {
|
|
343
|
+
logsQuery = logsQuery.where("organization_id", "is", null);
|
|
344
|
+
}
|
|
345
|
+
const logRows = await logsQuery.orderBy("occurred_at", "desc").limit(100).execute();
|
|
337
346
|
const logs = logRows.map((row) => {
|
|
338
347
|
const occurredAt = row.occurred_at instanceof Date ? row.occurred_at : row.occurred_at ? new Date(row.occurred_at) : null;
|
|
339
348
|
const level = row.level === "warn" ? "warn" : "info";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/query_index/api/status.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { getEntityIds } from '@open-mercato/shared/lib/encryption/entityIds'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { readCoverageSnapshot, refreshCoverageSnapshot } from '../lib/coverage'\nimport type { FullTextSearchStrategy } from '@open-mercato/search/strategies'\nimport type { SearchModuleConfig } from '@open-mercato/shared/modules/search'\nimport type { OpenApiMethodDoc, OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { queryIndexTag, queryIndexErrorSchema, queryIndexStatusResponseSchema } from './openapi'\nimport { flattenSystemEntityIds } from '@open-mercato/shared/lib/entities/system-entities'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['query_index.status.view'] },\n}\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const container = await createRequestContainer()\n const em = container.resolve('em') as EntityManager\n const knex = (em as any).getConnection().getKnex()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n\n const organizationId = scope.selectedId ?? auth.orgId ?? null\n const tenantId = typeof scope.tenantId === 'string' && scope.tenantId.trim().length > 0\n ? scope.tenantId.trim()\n : (typeof auth.tenantId === 'string' && auth.tenantId.trim().length > 0 ? auth.tenantId.trim() : null)\n if (!tenantId) {\n return NextResponse.json({ error: 'Tenant context is required' }, { status: 400 })\n }\n\n const organizationFilter =\n scope.filterIds === null\n ? null\n : Array.isArray(scope.filterIds) && scope.filterIds.length > 0\n ? scope.filterIds\n : organizationId\n ? [organizationId]\n : []\n\n if (Array.isArray(organizationFilter) && organizationFilter.length === 0) {\n return NextResponse.json({ error: 'Organization access denied' }, { status: 403 })\n }\n\n const organizationScopeIds = organizationFilter === null\n ? null\n : Array.from(\n new Set(\n organizationFilter.filter(\n (value): value is string => typeof value === 'string' && value.length > 0,\n ),\n ),\n )\n\n if (Array.isArray(organizationScopeIds) && organizationScopeIds.length === 0) {\n return NextResponse.json({ error: 'Organization access denied' }, { status: 403 })\n }\n\n const url = new URL(req.url)\n const forceRefresh = url.searchParams.has('refresh') && url.searchParams.get('refresh') !== '0'\n\n const generatedIds = flattenSystemEntityIds(getEntityIds() as Record<string, Record<string, string>>)\n const generated = generatedIds.map((entityId) => ({ entityId, label: entityId }))\n\n const byId = new Map<string, { entityId: string; label: string }>()\n for (const g of generated) byId.set(g.entityId, g)\n\n let entityIds = generatedIds.slice()\n\n // Resolve search module configs to determine vector-enabled entities\n // Entities with buildSource defined are vector-search enabled\n let searchModuleConfigs: SearchModuleConfig[] = []\n try {\n searchModuleConfigs = container.resolve('searchModuleConfigs') as SearchModuleConfig[]\n } catch {\n // Search module configs not available\n }\n\n const vectorEnabledEntities = new Set<string>()\n const fulltextEnabledEntities = new Set<string>()\n for (const moduleConfig of searchModuleConfigs) {\n for (const entity of moduleConfig.entities ?? []) {\n if (entity.enabled !== false) {\n // Vector: entities with buildSource defined\n if (typeof entity.buildSource === 'function') {\n vectorEnabledEntities.add(entity.entityId)\n }\n // Fulltext: entities with fieldPolicy defined\n if (entity.fieldPolicy && typeof entity.fieldPolicy === 'object') {\n fulltextEnabledEntities.add(entity.entityId)\n }\n }\n }\n }\n\n // Resolve fulltext strategy for entity counts\n let fulltextStrategy: FullTextSearchStrategy | null = null\n try {\n const searchStrategies = container.resolve('searchStrategies') as unknown[]\n fulltextStrategy = (searchStrategies?.find(\n (s: unknown) => (s as { id?: string })?.id === 'fulltext',\n ) as FullTextSearchStrategy) ?? null\n } catch {\n fulltextStrategy = null\n }\n\n // Fetch fulltext entity counts\n let fulltextEntityCounts: Record<string, number> | null = null\n if (fulltextStrategy) {\n try {\n fulltextEntityCounts = await fulltextStrategy.getEntityCounts(tenantId)\n } catch {\n fulltextEntityCounts = null\n }\n }\n\n // Limit to entities that have active custom field definitions in current scope\n try {\n const cfRows = await knex('custom_field_defs')\n .distinct('entity_id')\n .where({ is_active: true })\n .modify((qb: any) => {\n if (tenantId != null) {\n qb.andWhere((b: any) => b.where({ tenant_id: tenantId }).orWhereNull('tenant_id'))\n } else {\n qb.andWhere((b: any) => b.whereNull('tenant_id'))\n }\n if (Array.isArray(organizationScopeIds)) {\n qb.andWhere((b: any) => {\n b.whereIn('organization_id', organizationScopeIds)\n b.orWhereNull('organization_id')\n })\n }\n })\n const enabled = new Set<string>((cfRows || []).map((r: any) => String(r.entity_id)))\n entityIds = entityIds.filter((id) => enabled.has(id))\n } catch {}\n\n const HEARTBEAT_STALE_MS = 60_000\n const COVERAGE_STALE_MS = 60_000\n\n async function fetchJobSummary(entityType: string, tenantIdParam: string | null, organizationIdParam: string | null) {\n try {\n const rows = await knex('entity_index_jobs')\n .where({ entity_type: entityType })\n .andWhere((qb: any) => {\n if (tenantIdParam != null) {\n qb.whereRaw('tenant_id is not distinct from ?', [tenantIdParam])\n } else {\n qb.whereRaw('tenant_id is not distinct from ?', [null])\n }\n })\n .andWhere((qb: any) => {\n if (organizationIdParam != null) {\n qb.whereRaw('organization_id is not distinct from ?', [organizationIdParam]).orWhereNull('organization_id')\n } else {\n qb.whereRaw('organization_id is not distinct from ?', [null])\n }\n })\n .orderBy('started_at', 'desc')\n\n if (!rows.length) {\n return { status: 'idle' as const, partitions: [] as any[] }\n }\n\n const preferOrg =\n organizationIdParam != null && rows.some((row: any) => row.organization_id === organizationIdParam)\n const pickPreferred = <T extends { startedTs: number; tenantMatch: boolean; orgMatch: boolean }>(\n existing: T | null,\n candidate: T,\n ): T => {\n if (!existing) return candidate\n if (preferOrg) {\n if (candidate.orgMatch && !existing.orgMatch) return candidate\n if (!candidate.orgMatch && existing.orgMatch) return existing\n }\n if (candidate.tenantMatch && !existing.tenantMatch) return candidate\n if (!candidate.tenantMatch && existing.tenantMatch) return existing\n return candidate.startedTs > existing.startedTs ? candidate : existing\n }\n\n const partitionRows = new Map<string, { row: any; startedTs: number; tenantMatch: boolean; orgMatch: boolean }>()\n let scopeRow: { row: any; startedTs: number; tenantMatch: boolean; orgMatch: boolean } | null = null\n for (const row of rows) {\n const key = String(row.partition_index ?? '__null__')\n const startedTs = row.started_at ? new Date(row.started_at).getTime() : 0\n const tenantMatch = tenantIdParam != null ? row.tenant_id === tenantIdParam : true\n const orgMatch = organizationIdParam != null ? row.organization_id === organizationIdParam : row.organization_id == null\n const candidate = { row, startedTs, tenantMatch, orgMatch }\n if (row.partition_index == null) {\n scopeRow = pickPreferred(scopeRow, candidate)\n continue\n }\n const existing = partitionRows.get(key)\n partitionRows.set(key, pickPreferred(existing ?? null, candidate))\n }\n\n const partitions = Array.from(partitionRows.values())\n .filter((entry) => !preferOrg || entry.orgMatch)\n .map(({ row }) => {\n const heartbeatDate = row.heartbeat_at ? new Date(row.heartbeat_at) : null\n const startedDate = row.started_at ? new Date(row.started_at) : null\n const finishedDate = row.finished_at ? new Date(row.finished_at) : null\n const stalled =\n !finishedDate && (!heartbeatDate || Date.now() - heartbeatDate.getTime() > HEARTBEAT_STALE_MS)\n const state = finishedDate\n ? 'completed'\n : stalled\n ? 'stalled'\n : (row.status as string) || 'reindexing'\n return {\n partitionIndex: row.partition_index ?? null,\n partitionCount: row.partition_count ?? null,\n status: state,\n startedAt: startedDate ? startedDate.toISOString() : null,\n finishedAt: finishedDate ? finishedDate.toISOString() : null,\n heartbeatAt: heartbeatDate ? heartbeatDate.toISOString() : null,\n processedCount: row.processed_count ?? null,\n totalCount: row.total_count ?? null,\n }\n })\n .sort((a, b) => (a.partitionIndex ?? 0) - (b.partitionIndex ?? 0))\n const activePartitions = partitions.filter((p) => !p.finishedAt)\n const runningPartitions = activePartitions.filter(\n (p) => p.status === 'reindexing' || p.status === 'purging',\n )\n const stalledPartitions = activePartitions.filter((p) => p.status === 'stalled')\n let status: 'idle' | 'reindexing' | 'purging' | 'stalled' = 'idle'\n if (activePartitions.length) {\n if (runningPartitions.length) {\n status = runningPartitions.some((p) => p.status === 'purging') ? 'purging' : 'reindexing'\n } else if (stalledPartitions.length) {\n status = 'stalled'\n }\n }\n\n const startedAt = activePartitions[0]?.startedAt ?? partitions[0]?.startedAt ?? null\n const finishedAt = status === 'idle' ? (partitions.find((p) => p.finishedAt)?.finishedAt ?? null) : null\n const heartbeatAt = activePartitions[0]?.heartbeatAt ?? partitions[0]?.heartbeatAt ?? null\n const jobTotalCount = partitions.reduce((sum, p) => sum + (p.totalCount ?? 0), 0)\n const processedSum = partitions.reduce((sum, p) => sum + (p.processedCount ?? 0), 0)\n const processedCount = jobTotalCount ? Math.min(jobTotalCount, processedSum) : processedSum || null\n const scopeCandidate = !preferOrg || !scopeRow || scopeRow.orgMatch ? scopeRow : null\n\n return {\n status,\n startedAt,\n finishedAt,\n heartbeatAt,\n processedCount: jobTotalCount ? processedCount : scopeCandidate?.row?.processed_count ?? null,\n totalCount: jobTotalCount ? jobTotalCount : scopeCandidate?.row?.total_count ?? null,\n partitions,\n scope: scopeCandidate\n ? {\n status: (() => {\n const heartbeatDate = scopeCandidate!.row.heartbeat_at ? new Date(scopeCandidate!.row.heartbeat_at) : null\n const finishedDate = scopeCandidate!.row.finished_at ? new Date(scopeCandidate!.row.finished_at) : null\n if (finishedDate) return 'completed'\n if (\n !heartbeatDate ||\n Date.now() - heartbeatDate.getTime() > HEARTBEAT_STALE_MS\n ) {\n return 'stalled'\n }\n return (scopeCandidate!.row.status as string) || 'reindexing'\n })(),\n processedCount: scopeCandidate.row.processed_count ?? null,\n totalCount: scopeCandidate.row.total_count ?? null,\n }\n : null,\n }\n } catch {\n return { status: 'idle' as const, partitions: [] as any[] }\n }\n }\n\n const normalizeCount = (value: unknown): number | null => {\n if (value == null) return null\n if (typeof value === 'number') return Number.isFinite(value) ? value : null\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : null\n }\n\n const coverageSnapshots: Array<Awaited<ReturnType<typeof readCoverageSnapshot>>> = []\n const entitiesNeedingRefresh = new Set<string>()\n for (const entityId of entityIds) {\n const scope = {\n entityType: entityId,\n tenantId: tenantId ?? null,\n organizationId,\n withDeleted: false,\n } as const\n const ensureSnapshot = async () => {\n let snapshot = await readCoverageSnapshot(knex, scope)\n const refreshedAt = snapshot?.refreshed_at instanceof Date\n ? snapshot.refreshed_at\n : snapshot?.refreshed_at\n ? new Date(snapshot.refreshed_at)\n : null\n const stale = !snapshot || !refreshedAt || (Date.now() - refreshedAt.getTime() > COVERAGE_STALE_MS)\n if (forceRefresh || stale) {\n await refreshCoverageSnapshot(em, scope).catch(() => undefined)\n snapshot = await readCoverageSnapshot(knex, scope)\n }\n const finalRefreshed = snapshot?.refreshed_at instanceof Date\n ? snapshot.refreshed_at\n : snapshot?.refreshed_at\n ? new Date(snapshot.refreshed_at)\n : null\n if (!snapshot || !finalRefreshed || (Date.now() - finalRefreshed.getTime() > COVERAGE_STALE_MS)) {\n entitiesNeedingRefresh.add(entityId)\n }\n return snapshot\n }\n coverageSnapshots.push(await ensureSnapshot())\n }\n\n const jobs = await Promise.all(entityIds.map((eid) => fetchJobSummary(eid, tenantId, organizationId)))\n\n const items: any[] = []\n for (let idx = 0; idx < entityIds.length; idx += 1) {\n const eid = entityIds[idx]\n let coverage = coverageSnapshots[idx]\n\n const refreshedAt = coverage?.refreshed_at instanceof Date ? coverage.refreshed_at : coverage?.refreshed_at ? new Date(coverage.refreshed_at) : null\n const isStale = !coverage || !refreshedAt || (Date.now() - refreshedAt.getTime() > COVERAGE_STALE_MS)\n if (isStale) entitiesNeedingRefresh.add(eid)\n\n const job = jobs[idx]\n const label = (byId.get(eid)?.label) || eid\n const baseCountNumber = normalizeCount(coverage?.baseCount)\n const indexCountNumber = normalizeCount(coverage?.indexedCount)\n const vectorEnabled = vectorEnabledEntities.has(eid)\n const vectorCountNumber = vectorEnabled ? normalizeCount((coverage as any)?.vectorIndexedCount ?? (coverage as any)?.vector_indexed_count) : null\n const fulltextEnabled = fulltextEnabledEntities.has(eid)\n const fulltextCountNumber = fulltextEnabled ? (fulltextEntityCounts?.[eid] ?? 0) : null\n const ok = (() => {\n if (baseCountNumber == null || indexCountNumber == null) return false\n if (baseCountNumber !== indexCountNumber) return false\n if (!vectorEnabled) return true\n return vectorCountNumber != null && vectorCountNumber === baseCountNumber\n })()\n items.push({\n entityId: eid,\n label,\n baseCount: baseCountNumber,\n indexCount: indexCountNumber,\n vectorCount: vectorEnabled ? vectorCountNumber : null,\n vectorEnabled,\n fulltextCount: fulltextCountNumber,\n fulltextEnabled,\n ok,\n job,\n refreshedAt: refreshedAt ?? null,\n })\n }\n\n if (!forceRefresh) {\n try {\n const eventBus = container.resolve('eventBus')\n if (entitiesNeedingRefresh.size > 0) {\n await Promise.all(\n Array.from(entitiesNeedingRefresh).map((entityId) =>\n eventBus\n .emitEvent('query_index.coverage.refresh', {\n entityType: entityId,\n tenantId: tenantId ?? null,\n organizationId,\n delayMs: 0,\n })\n .catch(() => undefined)\n )\n )\n }\n } catch {}\n }\n\n const errorRows = await knex('indexer_error_logs')\n .modify((qb: any) => {\n if (tenantId != null) {\n qb.where((inner: any) => {\n inner.where('tenant_id', tenantId).orWhereNull('tenant_id')\n })\n } else {\n qb.whereNull('tenant_id')\n }\n })\n .andWhere((qb: any) => {\n qb.whereNull('organization_id')\n if (Array.isArray(organizationScopeIds) && organizationScopeIds.length) {\n qb.orWhereIn('organization_id', organizationScopeIds)\n }\n })\n .orderBy('occurred_at', 'desc')\n .limit(100)\n\n const errors = errorRows.map((row: any) => {\n const occurredAt = row.occurred_at instanceof Date ? row.occurred_at : row.occurred_at ? new Date(row.occurred_at) : null\n return {\n id: String(row.id),\n source: String(row.source ?? ''),\n handler: String(row.handler ?? ''),\n entityType: row.entity_type ?? null,\n recordId: row.record_id ?? null,\n tenantId: row.tenant_id ?? null,\n organizationId: row.organization_id ?? null,\n message: String(row.message ?? ''),\n stack: row.stack ?? null,\n payload: row.payload ?? null,\n occurredAt: occurredAt ? occurredAt.toISOString() : new Date().toISOString(),\n }\n })\n\n const logRows = await knex('indexer_status_logs')\n .modify((qb: any) => {\n if (tenantId != null) {\n qb.where((inner: any) => {\n inner.where('tenant_id', tenantId).orWhereNull('tenant_id')\n })\n } else {\n qb.whereNull('tenant_id')\n }\n })\n .andWhere((qb: any) => {\n qb.whereNull('organization_id')\n if (Array.isArray(organizationScopeIds) && organizationScopeIds.length) {\n qb.orWhereIn('organization_id', organizationScopeIds)\n }\n })\n .orderBy('occurred_at', 'desc')\n .limit(100)\n\n const logs = logRows.map((row: any) => {\n const occurredAt = row.occurred_at instanceof Date ? row.occurred_at : row.occurred_at ? new Date(row.occurred_at) : null\n const level = row.level === 'warn' ? 'warn' : 'info'\n return {\n id: String(row.id),\n source: String(row.source ?? ''),\n handler: String(row.handler ?? ''),\n level,\n entityType: row.entity_type ?? null,\n recordId: row.record_id ?? null,\n tenantId: row.tenant_id ?? null,\n organizationId: row.organization_id ?? null,\n message: String(row.message ?? ''),\n details: row.details ?? null,\n occurredAt: occurredAt ? occurredAt.toISOString() : new Date().toISOString(),\n }\n })\n\n const response = NextResponse.json({ items, errors, logs })\n const partial = items.find((item) => {\n if (item.baseCount == null || item.indexCount == null) return true\n return item.baseCount !== item.indexCount\n })\n if (partial) {\n response.headers.set(\n 'x-om-partial-index',\n JSON.stringify({\n type: 'partial_index',\n entity: partial.entityId,\n entityLabel: partial.label ?? partial.entityId,\n baseCount: partial.baseCount,\n indexedCount: partial.indexCount,\n scope: organizationId,\n })\n )\n }\n return response\n}\n\nconst queryIndexStatusDoc: OpenApiMethodDoc = {\n summary: 'Inspect query index coverage',\n description: 'Returns entity counts comparing base tables with the query index along with the latest job status.',\n tags: [queryIndexTag],\n responses: [\n { status: 200, description: 'Current query index status.', schema: queryIndexStatusResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Tenant or organization context required', schema: queryIndexErrorSchema },\n { status: 401, description: 'Authentication required', schema: queryIndexErrorSchema },\n ],\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: queryIndexTag,\n summary: 'Query index status',\n methods: {\n GET: queryIndexStatusDoc,\n },\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { getEntityIds } from '@open-mercato/shared/lib/encryption/entityIds'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { sql } from 'kysely'\nimport { readCoverageSnapshot, refreshCoverageSnapshot } from '../lib/coverage'\nimport type { FullTextSearchStrategy } from '@open-mercato/search/strategies'\nimport type { SearchModuleConfig } from '@open-mercato/shared/modules/search'\nimport type { OpenApiMethodDoc, OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { queryIndexTag, queryIndexErrorSchema, queryIndexStatusResponseSchema } from './openapi'\nimport { flattenSystemEntityIds } from '@open-mercato/shared/lib/entities/system-entities'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['query_index.status.view'] },\n}\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const container = await createRequestContainer()\n const em = container.resolve('em') as EntityManager\n const db = (em as any).getKysely()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n\n const organizationId = scope.selectedId ?? auth.orgId ?? null\n const tenantId = typeof scope.tenantId === 'string' && scope.tenantId.trim().length > 0\n ? scope.tenantId.trim()\n : (typeof auth.tenantId === 'string' && auth.tenantId.trim().length > 0 ? auth.tenantId.trim() : null)\n if (!tenantId) {\n return NextResponse.json({ error: 'Tenant context is required' }, { status: 400 })\n }\n\n const organizationFilter =\n scope.filterIds === null\n ? null\n : Array.isArray(scope.filterIds) && scope.filterIds.length > 0\n ? scope.filterIds\n : organizationId\n ? [organizationId]\n : []\n\n if (Array.isArray(organizationFilter) && organizationFilter.length === 0) {\n return NextResponse.json({ error: 'Organization access denied' }, { status: 403 })\n }\n\n const organizationScopeIds = organizationFilter === null\n ? null\n : Array.from(\n new Set(\n organizationFilter.filter(\n (value): value is string => typeof value === 'string' && value.length > 0,\n ),\n ),\n )\n\n if (Array.isArray(organizationScopeIds) && organizationScopeIds.length === 0) {\n return NextResponse.json({ error: 'Organization access denied' }, { status: 403 })\n }\n\n const url = new URL(req.url)\n const forceRefresh = url.searchParams.has('refresh') && url.searchParams.get('refresh') !== '0'\n\n const generatedIds = flattenSystemEntityIds(getEntityIds() as Record<string, Record<string, string>>)\n const generated = generatedIds.map((entityId) => ({ entityId, label: entityId }))\n\n const byId = new Map<string, { entityId: string; label: string }>()\n for (const g of generated) byId.set(g.entityId, g)\n\n let entityIds = generatedIds.slice()\n\n // Resolve search module configs to determine vector-enabled entities\n // Entities with buildSource defined are vector-search enabled\n let searchModuleConfigs: SearchModuleConfig[] = []\n try {\n searchModuleConfigs = container.resolve('searchModuleConfigs') as SearchModuleConfig[]\n } catch {\n // Search module configs not available\n }\n\n const vectorEnabledEntities = new Set<string>()\n const fulltextEnabledEntities = new Set<string>()\n for (const moduleConfig of searchModuleConfigs) {\n for (const entity of moduleConfig.entities ?? []) {\n if (entity.enabled !== false) {\n // Vector: entities with buildSource defined\n if (typeof entity.buildSource === 'function') {\n vectorEnabledEntities.add(entity.entityId)\n }\n // Fulltext: entities with fieldPolicy defined\n if (entity.fieldPolicy && typeof entity.fieldPolicy === 'object') {\n fulltextEnabledEntities.add(entity.entityId)\n }\n }\n }\n }\n\n // Resolve fulltext strategy for entity counts\n let fulltextStrategy: FullTextSearchStrategy | null = null\n try {\n const searchStrategies = container.resolve('searchStrategies') as unknown[]\n fulltextStrategy = (searchStrategies?.find(\n (s: unknown) => (s as { id?: string })?.id === 'fulltext',\n ) as FullTextSearchStrategy) ?? null\n } catch {\n fulltextStrategy = null\n }\n\n // Fetch fulltext entity counts\n let fulltextEntityCounts: Record<string, number> | null = null\n if (fulltextStrategy) {\n try {\n fulltextEntityCounts = await fulltextStrategy.getEntityCounts(tenantId)\n } catch {\n fulltextEntityCounts = null\n }\n }\n\n // Limit to entities that have active custom field definitions in current scope\n try {\n let cfQuery = db\n .selectFrom('custom_field_defs' as any)\n .select(['entity_id' as any])\n .distinct()\n .where('is_active' as any, '=', true)\n if (tenantId != null) {\n cfQuery = cfQuery.where((eb: any) => eb.or([\n eb('tenant_id' as any, '=', tenantId),\n eb('tenant_id' as any, 'is', null),\n ]))\n } else {\n cfQuery = cfQuery.where('tenant_id' as any, 'is', null as any)\n }\n if (Array.isArray(organizationScopeIds)) {\n cfQuery = cfQuery.where((eb: any) => eb.or([\n eb('organization_id' as any, 'in', organizationScopeIds),\n eb('organization_id' as any, 'is', null),\n ]))\n }\n const cfRows = await cfQuery.execute() as Array<{ entity_id: string }>\n const enabled = new Set<string>((cfRows || []).map((r) => String(r.entity_id)))\n entityIds = entityIds.filter((id) => enabled.has(id))\n } catch {}\n\n const HEARTBEAT_STALE_MS = 60_000\n const COVERAGE_STALE_MS = 60_000\n\n async function fetchJobSummary(entityType: string, tenantIdParam: string | null, organizationIdParam: string | null) {\n try {\n let jobQuery = db\n .selectFrom('entity_index_jobs' as any)\n .selectAll()\n .where('entity_type' as any, '=', entityType)\n .where(sql<boolean>`tenant_id is not distinct from ${tenantIdParam ?? null}`)\n if (organizationIdParam != null) {\n jobQuery = jobQuery.where((eb: any) => eb.or([\n eb('organization_id' as any, '=', organizationIdParam),\n eb('organization_id' as any, 'is', null),\n ]))\n } else {\n jobQuery = jobQuery.where(sql<boolean>`organization_id is not distinct from ${null}`)\n }\n const rows = await jobQuery\n .orderBy('started_at' as any, 'desc')\n .execute() as Array<Record<string, any>>\n\n if (!rows.length) {\n return { status: 'idle' as const, partitions: [] as any[] }\n }\n\n const preferOrg =\n organizationIdParam != null && rows.some((row: any) => row.organization_id === organizationIdParam)\n const pickPreferred = <T extends { startedTs: number; tenantMatch: boolean; orgMatch: boolean }>(\n existing: T | null,\n candidate: T,\n ): T => {\n if (!existing) return candidate\n if (preferOrg) {\n if (candidate.orgMatch && !existing.orgMatch) return candidate\n if (!candidate.orgMatch && existing.orgMatch) return existing\n }\n if (candidate.tenantMatch && !existing.tenantMatch) return candidate\n if (!candidate.tenantMatch && existing.tenantMatch) return existing\n return candidate.startedTs > existing.startedTs ? candidate : existing\n }\n\n const partitionRows = new Map<string, { row: any; startedTs: number; tenantMatch: boolean; orgMatch: boolean }>()\n let scopeRow: { row: any; startedTs: number; tenantMatch: boolean; orgMatch: boolean } | null = null\n for (const row of rows) {\n const key = String(row.partition_index ?? '__null__')\n const startedTs = row.started_at ? new Date(row.started_at).getTime() : 0\n const tenantMatch = tenantIdParam != null ? row.tenant_id === tenantIdParam : true\n const orgMatch = organizationIdParam != null ? row.organization_id === organizationIdParam : row.organization_id == null\n const candidate = { row, startedTs, tenantMatch, orgMatch }\n if (row.partition_index == null) {\n scopeRow = pickPreferred(scopeRow, candidate)\n continue\n }\n const existing = partitionRows.get(key)\n partitionRows.set(key, pickPreferred(existing ?? null, candidate))\n }\n\n const partitions = Array.from(partitionRows.values())\n .filter((entry) => !preferOrg || entry.orgMatch)\n .map(({ row }) => {\n const heartbeatDate = row.heartbeat_at ? new Date(row.heartbeat_at) : null\n const startedDate = row.started_at ? new Date(row.started_at) : null\n const finishedDate = row.finished_at ? new Date(row.finished_at) : null\n const stalled =\n !finishedDate && (!heartbeatDate || Date.now() - heartbeatDate.getTime() > HEARTBEAT_STALE_MS)\n const state = finishedDate\n ? 'completed'\n : stalled\n ? 'stalled'\n : (row.status as string) || 'reindexing'\n return {\n partitionIndex: row.partition_index ?? null,\n partitionCount: row.partition_count ?? null,\n status: state,\n startedAt: startedDate ? startedDate.toISOString() : null,\n finishedAt: finishedDate ? finishedDate.toISOString() : null,\n heartbeatAt: heartbeatDate ? heartbeatDate.toISOString() : null,\n processedCount: row.processed_count ?? null,\n totalCount: row.total_count ?? null,\n }\n })\n .sort((a, b) => (a.partitionIndex ?? 0) - (b.partitionIndex ?? 0))\n const activePartitions = partitions.filter((p) => !p.finishedAt)\n const runningPartitions = activePartitions.filter(\n (p) => p.status === 'reindexing' || p.status === 'purging',\n )\n const stalledPartitions = activePartitions.filter((p) => p.status === 'stalled')\n let status: 'idle' | 'reindexing' | 'purging' | 'stalled' = 'idle'\n if (activePartitions.length) {\n if (runningPartitions.length) {\n status = runningPartitions.some((p) => p.status === 'purging') ? 'purging' : 'reindexing'\n } else if (stalledPartitions.length) {\n status = 'stalled'\n }\n }\n\n const startedAt = activePartitions[0]?.startedAt ?? partitions[0]?.startedAt ?? null\n const finishedAt = status === 'idle' ? (partitions.find((p) => p.finishedAt)?.finishedAt ?? null) : null\n const heartbeatAt = activePartitions[0]?.heartbeatAt ?? partitions[0]?.heartbeatAt ?? null\n const jobTotalCount = partitions.reduce((sum, p) => sum + (p.totalCount ?? 0), 0)\n const processedSum = partitions.reduce((sum, p) => sum + (p.processedCount ?? 0), 0)\n const processedCount = jobTotalCount ? Math.min(jobTotalCount, processedSum) : processedSum || null\n const scopeCandidate = !preferOrg || !scopeRow || scopeRow.orgMatch ? scopeRow : null\n\n return {\n status,\n startedAt,\n finishedAt,\n heartbeatAt,\n processedCount: jobTotalCount ? processedCount : scopeCandidate?.row?.processed_count ?? null,\n totalCount: jobTotalCount ? jobTotalCount : scopeCandidate?.row?.total_count ?? null,\n partitions,\n scope: scopeCandidate\n ? {\n status: (() => {\n const heartbeatDate = scopeCandidate!.row.heartbeat_at ? new Date(scopeCandidate!.row.heartbeat_at) : null\n const finishedDate = scopeCandidate!.row.finished_at ? new Date(scopeCandidate!.row.finished_at) : null\n if (finishedDate) return 'completed'\n if (\n !heartbeatDate ||\n Date.now() - heartbeatDate.getTime() > HEARTBEAT_STALE_MS\n ) {\n return 'stalled'\n }\n return (scopeCandidate!.row.status as string) || 'reindexing'\n })(),\n processedCount: scopeCandidate.row.processed_count ?? null,\n totalCount: scopeCandidate.row.total_count ?? null,\n }\n : null,\n }\n } catch {\n return { status: 'idle' as const, partitions: [] as any[] }\n }\n }\n\n const normalizeCount = (value: unknown): number | null => {\n if (value == null) return null\n if (typeof value === 'number') return Number.isFinite(value) ? value : null\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : null\n }\n\n const coverageSnapshots: Array<Awaited<ReturnType<typeof readCoverageSnapshot>>> = []\n const entitiesNeedingRefresh = new Set<string>()\n for (const entityId of entityIds) {\n const scope = {\n entityType: entityId,\n tenantId: tenantId ?? null,\n organizationId,\n withDeleted: false,\n } as const\n const ensureSnapshot = async () => {\n let snapshot = await readCoverageSnapshot(db, scope)\n const refreshedAt = snapshot?.refreshed_at instanceof Date\n ? snapshot.refreshed_at\n : snapshot?.refreshed_at\n ? new Date(snapshot.refreshed_at)\n : null\n const stale = !snapshot || !refreshedAt || (Date.now() - refreshedAt.getTime() > COVERAGE_STALE_MS)\n if (forceRefresh || stale) {\n await refreshCoverageSnapshot(em, scope).catch(() => undefined)\n snapshot = await readCoverageSnapshot(db, scope)\n }\n const finalRefreshed = snapshot?.refreshed_at instanceof Date\n ? snapshot.refreshed_at\n : snapshot?.refreshed_at\n ? new Date(snapshot.refreshed_at)\n : null\n if (!snapshot || !finalRefreshed || (Date.now() - finalRefreshed.getTime() > COVERAGE_STALE_MS)) {\n entitiesNeedingRefresh.add(entityId)\n }\n return snapshot\n }\n coverageSnapshots.push(await ensureSnapshot())\n }\n\n const jobs = await Promise.all(entityIds.map((eid) => fetchJobSummary(eid, tenantId, organizationId)))\n\n const items: any[] = []\n for (let idx = 0; idx < entityIds.length; idx += 1) {\n const eid = entityIds[idx]\n let coverage = coverageSnapshots[idx]\n\n const refreshedAt = coverage?.refreshed_at instanceof Date ? coverage.refreshed_at : coverage?.refreshed_at ? new Date(coverage.refreshed_at) : null\n const isStale = !coverage || !refreshedAt || (Date.now() - refreshedAt.getTime() > COVERAGE_STALE_MS)\n if (isStale) entitiesNeedingRefresh.add(eid)\n\n const job = jobs[idx]\n const label = (byId.get(eid)?.label) || eid\n const baseCountNumber = normalizeCount(coverage?.baseCount)\n const indexCountNumber = normalizeCount(coverage?.indexedCount)\n const vectorEnabled = vectorEnabledEntities.has(eid)\n const vectorCountNumber = vectorEnabled ? normalizeCount((coverage as any)?.vectorIndexedCount ?? (coverage as any)?.vector_indexed_count) : null\n const fulltextEnabled = fulltextEnabledEntities.has(eid)\n const fulltextCountNumber = fulltextEnabled ? (fulltextEntityCounts?.[eid] ?? 0) : null\n const ok = (() => {\n if (baseCountNumber == null || indexCountNumber == null) return false\n if (baseCountNumber !== indexCountNumber) return false\n if (!vectorEnabled) return true\n return vectorCountNumber != null && vectorCountNumber === baseCountNumber\n })()\n items.push({\n entityId: eid,\n label,\n baseCount: baseCountNumber,\n indexCount: indexCountNumber,\n vectorCount: vectorEnabled ? vectorCountNumber : null,\n vectorEnabled,\n fulltextCount: fulltextCountNumber,\n fulltextEnabled,\n ok,\n job,\n refreshedAt: refreshedAt ?? null,\n })\n }\n\n if (!forceRefresh) {\n try {\n const eventBus = container.resolve('eventBus')\n if (entitiesNeedingRefresh.size > 0) {\n await Promise.all(\n Array.from(entitiesNeedingRefresh).map((entityId) =>\n eventBus\n .emitEvent('query_index.coverage.refresh', {\n entityType: entityId,\n tenantId: tenantId ?? null,\n organizationId,\n delayMs: 0,\n })\n .catch(() => undefined)\n )\n )\n }\n } catch {}\n }\n\n let errorQuery = db\n .selectFrom('indexer_error_logs' as any)\n .selectAll()\n if (tenantId != null) {\n errorQuery = errorQuery.where((eb: any) => eb.or([\n eb('tenant_id' as any, '=', tenantId),\n eb('tenant_id' as any, 'is', null),\n ]))\n } else {\n errorQuery = errorQuery.where('tenant_id' as any, 'is', null as any)\n }\n if (Array.isArray(organizationScopeIds) && organizationScopeIds.length) {\n errorQuery = errorQuery.where((eb: any) => eb.or([\n eb('organization_id' as any, 'is', null),\n eb('organization_id' as any, 'in', organizationScopeIds),\n ]))\n } else {\n errorQuery = errorQuery.where('organization_id' as any, 'is', null as any)\n }\n const errorRows = await errorQuery\n .orderBy('occurred_at' as any, 'desc')\n .limit(100)\n .execute() as Array<Record<string, any>>\n\n const errors = errorRows.map((row: any) => {\n const occurredAt = row.occurred_at instanceof Date ? row.occurred_at : row.occurred_at ? new Date(row.occurred_at) : null\n return {\n id: String(row.id),\n source: String(row.source ?? ''),\n handler: String(row.handler ?? ''),\n entityType: row.entity_type ?? null,\n recordId: row.record_id ?? null,\n tenantId: row.tenant_id ?? null,\n organizationId: row.organization_id ?? null,\n message: String(row.message ?? ''),\n stack: row.stack ?? null,\n payload: row.payload ?? null,\n occurredAt: occurredAt ? occurredAt.toISOString() : new Date().toISOString(),\n }\n })\n\n let logsQuery = db\n .selectFrom('indexer_status_logs' as any)\n .selectAll()\n if (tenantId != null) {\n logsQuery = logsQuery.where((eb: any) => eb.or([\n eb('tenant_id' as any, '=', tenantId),\n eb('tenant_id' as any, 'is', null),\n ]))\n } else {\n logsQuery = logsQuery.where('tenant_id' as any, 'is', null as any)\n }\n if (Array.isArray(organizationScopeIds) && organizationScopeIds.length) {\n logsQuery = logsQuery.where((eb: any) => eb.or([\n eb('organization_id' as any, 'is', null),\n eb('organization_id' as any, 'in', organizationScopeIds),\n ]))\n } else {\n logsQuery = logsQuery.where('organization_id' as any, 'is', null as any)\n }\n const logRows = await logsQuery\n .orderBy('occurred_at' as any, 'desc')\n .limit(100)\n .execute() as Array<Record<string, any>>\n\n const logs = logRows.map((row: any) => {\n const occurredAt = row.occurred_at instanceof Date ? row.occurred_at : row.occurred_at ? new Date(row.occurred_at) : null\n const level = row.level === 'warn' ? 'warn' : 'info'\n return {\n id: String(row.id),\n source: String(row.source ?? ''),\n handler: String(row.handler ?? ''),\n level,\n entityType: row.entity_type ?? null,\n recordId: row.record_id ?? null,\n tenantId: row.tenant_id ?? null,\n organizationId: row.organization_id ?? null,\n message: String(row.message ?? ''),\n details: row.details ?? null,\n occurredAt: occurredAt ? occurredAt.toISOString() : new Date().toISOString(),\n }\n })\n\n const response = NextResponse.json({ items, errors, logs })\n const partial = items.find((item) => {\n if (item.baseCount == null || item.indexCount == null) return true\n return item.baseCount !== item.indexCount\n })\n if (partial) {\n response.headers.set(\n 'x-om-partial-index',\n JSON.stringify({\n type: 'partial_index',\n entity: partial.entityId,\n entityLabel: partial.label ?? partial.entityId,\n baseCount: partial.baseCount,\n indexedCount: partial.indexCount,\n scope: organizationId,\n })\n )\n }\n return response\n}\n\nconst queryIndexStatusDoc: OpenApiMethodDoc = {\n summary: 'Inspect query index coverage',\n description: 'Returns entity counts comparing base tables with the query index along with the latest job status.',\n tags: [queryIndexTag],\n responses: [\n { status: 200, description: 'Current query index status.', schema: queryIndexStatusResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Tenant or organization context required', schema: queryIndexErrorSchema },\n { status: 401, description: 'Authentication required', schema: queryIndexErrorSchema },\n ],\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: queryIndexTag,\n summary: 'Query index status',\n methods: {\n GET: queryIndexStatusDoc,\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["scope"]
|
|
7
7
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
2
|
+
import { sql } from "kysely";
|
|
2
3
|
import { createProgressBar } from "@open-mercato/shared/lib/cli/progress";
|
|
3
4
|
import { resolveTenantEncryptionService } from "@open-mercato/shared/lib/encryption/customFieldValues";
|
|
4
5
|
import { decryptIndexDocForSearch, encryptIndexDocForStorage } from "@open-mercato/shared/lib/encryption/indexDoc";
|
|
@@ -116,7 +117,7 @@ const DEFAULT_BATCH_SIZE = 200;
|
|
|
116
117
|
async function rebuildEntityIndexes(options) {
|
|
117
118
|
const {
|
|
118
119
|
em,
|
|
119
|
-
|
|
120
|
+
db,
|
|
120
121
|
entityType,
|
|
121
122
|
tableName,
|
|
122
123
|
orgOverride,
|
|
@@ -159,25 +160,37 @@ async function rebuildEntityIndexes(options) {
|
|
|
159
160
|
return doc;
|
|
160
161
|
}
|
|
161
162
|
};
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
163
|
+
const applyFilters = (q) => {
|
|
164
|
+
let chain = q;
|
|
165
|
+
if (!global) {
|
|
166
|
+
if (orgOverride !== void 0 && supportsOrgFilter) {
|
|
167
|
+
chain = chain.where("organization_id", "=", orgOverride);
|
|
168
|
+
}
|
|
169
|
+
if (tenantOverride !== void 0 && supportsTenantFilter) {
|
|
170
|
+
chain = chain.where("tenant_id", "=", tenantOverride);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (!includeDeleted && supportsDeletedFilter) {
|
|
174
|
+
chain = chain.where("deleted_at", "is", null);
|
|
175
|
+
}
|
|
176
|
+
return chain;
|
|
177
|
+
};
|
|
169
178
|
if (recordId) {
|
|
170
|
-
const row = await
|
|
179
|
+
const row = await applyFilters(
|
|
180
|
+
db.selectFrom(tableName).selectAll()
|
|
181
|
+
).where("id", "=", recordId).executeTakeFirst();
|
|
171
182
|
if (!row) return { processed: 0, matched: 0 };
|
|
172
183
|
const bar2 = createProgressBar(progressLabel ?? `Rebuilding ${entityType}`, 1);
|
|
173
|
-
await upsertIndexBatch(
|
|
184
|
+
await upsertIndexBatch(db, entityType, [row], { orgId: orgOverride, tenantId: tenantOverride }, { encryptDoc, decryptDoc });
|
|
174
185
|
bar2.update(1);
|
|
175
186
|
bar2.complete();
|
|
176
187
|
return { processed: 1, matched: 1 };
|
|
177
188
|
}
|
|
178
|
-
const countRow = await
|
|
179
|
-
|
|
180
|
-
|
|
189
|
+
const countRow = await applyFilters(
|
|
190
|
+
db.selectFrom(tableName).select(sql`count(*)`.as("count"))
|
|
191
|
+
).executeTakeFirst();
|
|
192
|
+
const totalRaw = countRow?.count;
|
|
193
|
+
const total = totalRaw != null ? Number(totalRaw) : 0;
|
|
181
194
|
const effectiveOffset = Math.max(0, offset);
|
|
182
195
|
const matchedWithoutLimit = Math.max(0, total - effectiveOffset);
|
|
183
196
|
const limitValue = toPositiveInt(limit);
|
|
@@ -191,9 +204,11 @@ async function rebuildEntityIndexes(options) {
|
|
|
191
204
|
let remaining = limitValue;
|
|
192
205
|
while (processed < intended) {
|
|
193
206
|
const chunkLimit = remaining !== void 0 ? Math.min(batchSize, remaining) : batchSize;
|
|
194
|
-
const chunk = await
|
|
207
|
+
const chunk = await applyFilters(
|
|
208
|
+
db.selectFrom(tableName).selectAll().orderBy("id").limit(chunkLimit).offset(cursorOffset)
|
|
209
|
+
).execute();
|
|
195
210
|
if (!chunk.length) break;
|
|
196
|
-
await upsertIndexBatch(
|
|
211
|
+
await upsertIndexBatch(db, entityType, chunk, {
|
|
197
212
|
orgId: orgOverride,
|
|
198
213
|
tenantId: tenantOverride
|
|
199
214
|
}, { encryptDoc, decryptDoc });
|
|
@@ -209,10 +224,10 @@ async function rebuildEntityIndexes(options) {
|
|
|
209
224
|
bar.complete();
|
|
210
225
|
return { processed, matched: intended };
|
|
211
226
|
}
|
|
212
|
-
async function getColumnSet(
|
|
227
|
+
async function getColumnSet(db, tableName) {
|
|
213
228
|
try {
|
|
214
|
-
const
|
|
215
|
-
return new Set(
|
|
229
|
+
const rows = await db.selectFrom("information_schema.columns").select(["column_name"]).where(sql`table_schema = current_schema()`).where("table_name", "=", tableName).execute();
|
|
230
|
+
return new Set(rows.map((row) => String(row.column_name).toLowerCase()));
|
|
216
231
|
} catch {
|
|
217
232
|
return /* @__PURE__ */ new Set();
|
|
218
233
|
}
|
|
@@ -247,9 +262,9 @@ const rebuild = {
|
|
|
247
262
|
const container = await createRequestContainer();
|
|
248
263
|
const em = container.resolve("em");
|
|
249
264
|
try {
|
|
250
|
-
const
|
|
265
|
+
const db = em.getKysely();
|
|
251
266
|
const tableName = resolveEntityTableName(em, entity);
|
|
252
|
-
const columns = await getColumnSet(
|
|
267
|
+
const columns = await getColumnSet(db, tableName);
|
|
253
268
|
const supportsOrg = columns.has("organization_id");
|
|
254
269
|
const supportsTenant = columns.has("tenant_id");
|
|
255
270
|
const supportsDeleted = columns.has("deleted_at");
|
|
@@ -264,7 +279,7 @@ const rebuild = {
|
|
|
264
279
|
}
|
|
265
280
|
const result = await rebuildEntityIndexes({
|
|
266
281
|
em,
|
|
267
|
-
|
|
282
|
+
db,
|
|
268
283
|
entityType: entity,
|
|
269
284
|
tableName,
|
|
270
285
|
orgOverride: orgId,
|
|
@@ -343,7 +358,7 @@ const rebuildAll = {
|
|
|
343
358
|
const container = await createRequestContainer();
|
|
344
359
|
const em = container.resolve("em");
|
|
345
360
|
try {
|
|
346
|
-
const
|
|
361
|
+
const db = em.getKysely();
|
|
347
362
|
const { getEntityIds } = await import("@open-mercato/shared/lib/encryption/entityIds");
|
|
348
363
|
const entityIds = flattenSystemEntityIds(getEntityIds());
|
|
349
364
|
if (!entityIds.length) {
|
|
@@ -354,7 +369,7 @@ const rebuildAll = {
|
|
|
354
369
|
for (let idx = 0; idx < entityIds.length; idx += 1) {
|
|
355
370
|
const entity = entityIds[idx];
|
|
356
371
|
const tableName = resolveEntityTableName(em, entity);
|
|
357
|
-
const columns = await getColumnSet(
|
|
372
|
+
const columns = await getColumnSet(db, tableName);
|
|
358
373
|
const supportsOrg = columns.has("organization_id");
|
|
359
374
|
const supportsTenant = columns.has("tenant_id");
|
|
360
375
|
const supportsDeleted = columns.has("deleted_at");
|
|
@@ -379,7 +394,7 @@ const rebuildAll = {
|
|
|
379
394
|
console.log(`[${idx + 1}/${entityIds.length}] Rebuilding ${entity}${scopeLabel}`);
|
|
380
395
|
const result = await rebuildEntityIndexes({
|
|
381
396
|
em,
|
|
382
|
-
|
|
397
|
+
db,
|
|
383
398
|
entityType: entity,
|
|
384
399
|
tableName,
|
|
385
400
|
orgOverride: orgId,
|