@open-mercato/core 0.6.1-develop.3276.1.1fcd145078 → 0.6.1-develop.3287.1.450f4ffb56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +2 -2
- package/dist/generated/entities/domain_mapping/index.js +31 -0
- package/dist/generated/entities/domain_mapping/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +2 -1
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +16 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/helpers/integration/auth.js +1 -1
- package/dist/helpers/integration/auth.js.map +2 -2
- package/dist/helpers/integration/authUi.js +1 -1
- package/dist/helpers/integration/authUi.js.map +2 -2
- package/dist/helpers/integration/salesUi.js +18 -17
- package/dist/helpers/integration/salesUi.js.map +2 -2
- package/dist/modules/auth/frontend/login.js +4 -4
- package/dist/modules/auth/frontend/login.js.map +2 -2
- package/dist/modules/auth/frontend/reset/[token]/page.js +5 -5
- package/dist/modules/auth/frontend/reset/[token]/page.js.map +2 -2
- package/dist/modules/auth/frontend/reset.js +2 -2
- package/dist/modules/auth/frontend/reset.js.map +2 -2
- package/dist/modules/customer_accounts/acl.js +2 -1
- package/dist/modules/customer_accounts/acl.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/domain-mappings/[id]/health-check.js +110 -0
- package/dist/modules/customer_accounts/api/admin/domain-mappings/[id]/health-check.js.map +7 -0
- package/dist/modules/customer_accounts/api/admin/domain-mappings/[id]/verify.js +114 -0
- package/dist/modules/customer_accounts/api/admin/domain-mappings/[id]/verify.js.map +7 -0
- package/dist/modules/customer_accounts/api/admin/domain-mappings.js +271 -0
- package/dist/modules/customer_accounts/api/admin/domain-mappings.js.map +7 -0
- package/dist/modules/customer_accounts/api/domain-check.js +70 -0
- package/dist/modules/customer_accounts/api/domain-check.js.map +7 -0
- package/dist/modules/customer_accounts/api/domain-resolve/all.js +128 -0
- package/dist/modules/customer_accounts/api/domain-resolve/all.js.map +7 -0
- package/dist/modules/customer_accounts/api/domain-resolve.js +84 -0
- package/dist/modules/customer_accounts/api/domain-resolve.js.map +7 -0
- package/dist/modules/customer_accounts/api/login.js +14 -3
- package/dist/modules/customer_accounts/api/login.js.map +2 -2
- package/dist/modules/customer_accounts/api/magic-link/request.js +14 -3
- package/dist/modules/customer_accounts/api/magic-link/request.js.map +2 -2
- package/dist/modules/customer_accounts/api/password/reset-request.js +14 -3
- package/dist/modules/customer_accounts/api/password/reset-request.js.map +2 -2
- package/dist/modules/customer_accounts/api/signup.js +32 -5
- package/dist/modules/customer_accounts/api/signup.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Actions.js +48 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Actions.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Diagnostics.js +43 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Diagnostics.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/DnsConfig.js +53 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/DnsConfig.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/DomainPanel.js +69 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/DomainPanel.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/OrgSwitcher.js +31 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/OrgSwitcher.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/RegisterDialog.js +147 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/RegisterDialog.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/StatusBadgeSection.js +39 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/StatusBadgeSection.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Stepper.js +60 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Stepper.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/domainStatusMap.js +11 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/domainStatusMap.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/types.js +1 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/types.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.js +361 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.meta.js +28 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.meta.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js +4 -3
- package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +6 -5
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
- package/dist/modules/customer_accounts/data/enrichers.js +78 -12
- package/dist/modules/customer_accounts/data/enrichers.js.map +2 -2
- package/dist/modules/customer_accounts/data/entities.js +85 -2
- package/dist/modules/customer_accounts/data/entities.js.map +2 -2
- package/dist/modules/customer_accounts/data/guards.js +130 -0
- package/dist/modules/customer_accounts/data/guards.js.map +7 -0
- package/dist/modules/customer_accounts/data/validators.js +19 -0
- package/dist/modules/customer_accounts/data/validators.js.map +2 -2
- package/dist/modules/customer_accounts/di.js +23 -1
- package/dist/modules/customer_accounts/di.js.map +2 -2
- package/dist/modules/customer_accounts/events.js +9 -2
- package/dist/modules/customer_accounts/events.js.map +2 -2
- package/dist/modules/customer_accounts/lib/customerAuthServer.js +27 -7
- package/dist/modules/customer_accounts/lib/customerAuthServer.js.map +2 -2
- package/dist/modules/customer_accounts/lib/customerUrl.js +48 -0
- package/dist/modules/customer_accounts/lib/customerUrl.js.map +7 -0
- package/dist/modules/customer_accounts/lib/hostname.js +55 -0
- package/dist/modules/customer_accounts/lib/hostname.js.map +7 -0
- package/dist/modules/customer_accounts/lib/platformDomains.js +7 -0
- package/dist/modules/customer_accounts/lib/platformDomains.js.map +7 -0
- package/dist/modules/customer_accounts/lib/proxyRanges.js +71 -0
- package/dist/modules/customer_accounts/lib/proxyRanges.js.map +7 -0
- package/dist/modules/customer_accounts/lib/rateLimiter.js +7 -0
- package/dist/modules/customer_accounts/lib/rateLimiter.js.map +2 -2
- package/dist/modules/customer_accounts/lib/resolveTenantContext.js +63 -0
- package/dist/modules/customer_accounts/lib/resolveTenantContext.js.map +7 -0
- package/dist/modules/customer_accounts/lib/secretCompare.js +13 -0
- package/dist/modules/customer_accounts/lib/secretCompare.js.map +7 -0
- package/dist/modules/customer_accounts/migrations/Migration20260430120000_customer_accounts.js +37 -0
- package/dist/modules/customer_accounts/migrations/Migration20260430120000_customer_accounts.js.map +7 -0
- package/dist/modules/customer_accounts/notifications.client.js +76 -0
- package/dist/modules/customer_accounts/notifications.client.js.map +2 -2
- package/dist/modules/customer_accounts/notifications.js +76 -0
- package/dist/modules/customer_accounts/notifications.js.map +2 -2
- package/dist/modules/customer_accounts/services/domainMappingService.js +497 -0
- package/dist/modules/customer_accounts/services/domainMappingService.js.map +7 -0
- package/dist/modules/customer_accounts/setup.js +48 -1
- package/dist/modules/customer_accounts/setup.js.map +2 -2
- package/dist/modules/customer_accounts/subscribers/invalidateDomainCache.js +29 -0
- package/dist/modules/customer_accounts/subscribers/invalidateDomainCache.js.map +7 -0
- package/dist/modules/customer_accounts/subscribers/notifyDomainActivated.js +29 -0
- package/dist/modules/customer_accounts/subscribers/notifyDomainActivated.js.map +7 -0
- package/dist/modules/customer_accounts/subscribers/notifyDomainDnsFailed.js +30 -0
- package/dist/modules/customer_accounts/subscribers/notifyDomainDnsFailed.js.map +7 -0
- package/dist/modules/customer_accounts/subscribers/notifyDomainTlsFailed.js +31 -0
- package/dist/modules/customer_accounts/subscribers/notifyDomainTlsFailed.js.map +7 -0
- package/dist/modules/customer_accounts/subscribers/notifyDomainVerified.js +29 -0
- package/dist/modules/customer_accounts/subscribers/notifyDomainVerified.js.map +7 -0
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +2 -2
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +2 -2
- package/dist/modules/customer_accounts/workers/domainTlsRetryWorker.js +67 -0
- package/dist/modules/customer_accounts/workers/domainTlsRetryWorker.js.map +7 -0
- package/dist/modules/customer_accounts/workers/domainVerificationWorker.js +34 -0
- package/dist/modules/customer_accounts/workers/domainVerificationWorker.js.map +7 -0
- package/dist/modules/customers/api/companies/route.js +4 -9
- package/dist/modules/customers/api/companies/route.js.map +2 -2
- package/dist/modules/customers/api/deals/route.js +4 -9
- package/dist/modules/customers/api/deals/route.js.map +2 -2
- package/dist/modules/customers/api/people/route.js +4 -9
- package/dist/modules/customers/api/people/route.js.map +2 -2
- package/dist/modules/customers/api/utils.js +0 -12
- package/dist/modules/customers/api/utils.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +361 -284
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +378 -473
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js +368 -286
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/components/detail/assignableStaff.js +15 -1
- package/dist/modules/customers/components/detail/assignableStaff.js.map +2 -2
- package/dist/modules/customers/components/formConfig.js +2 -2
- package/dist/modules/customers/components/formConfig.js.map +2 -2
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js +188 -36
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js.map +2 -2
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.js +2 -2
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.js.map +2 -2
- package/dist/modules/customers/widgets/injection-table.js +6 -0
- package/dist/modules/customers/widgets/injection-table.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/[id]/page.js +2 -3
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/perspectives/services/perspectiveService.js +16 -2
- package/dist/modules/perspectives/services/perspectiveService.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js +5 -3
- package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.js +3 -3
- package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.js +4 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +31 -8
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +3 -5
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/components/ProviderFieldInput.js +2 -2
- package/dist/modules/sales/components/ProviderFieldInput.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentForm.js +3 -4
- package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/shipment-wizard/components/ConfigureStep.js +3 -4
- package/dist/modules/shipping_carriers/lib/shipment-wizard/components/ConfigureStep.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/[id]/page.js +2 -2
- package/dist/modules/workflows/backend/tasks/[id]/page.js.map +2 -2
- package/dist/modules/workflows/frontend/checkout-demo/page.js +2 -2
- package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
- package/generated/entities/domain_mapping/index.ts +14 -0
- package/generated/entities.ids.generated.ts +2 -1
- package/generated/entity-fields-registry.ts +16 -0
- package/package.json +5 -5
- package/src/helpers/integration/auth.ts +1 -1
- package/src/helpers/integration/authUi.ts +1 -1
- package/src/helpers/integration/salesUi.ts +27 -23
- package/src/modules/auth/frontend/login.tsx +4 -3
- package/src/modules/auth/frontend/reset/[token]/page.tsx +4 -4
- package/src/modules/auth/frontend/reset.tsx +2 -2
- package/src/modules/customer_accounts/acl.ts +1 -0
- package/src/modules/customer_accounts/api/admin/domain-mappings/[id]/health-check.ts +119 -0
- package/src/modules/customer_accounts/api/admin/domain-mappings/[id]/verify.ts +123 -0
- package/src/modules/customer_accounts/api/admin/domain-mappings.ts +303 -0
- package/src/modules/customer_accounts/api/domain-check.ts +83 -0
- package/src/modules/customer_accounts/api/domain-resolve/all.ts +139 -0
- package/src/modules/customer_accounts/api/domain-resolve.ts +91 -0
- package/src/modules/customer_accounts/api/login.ts +14 -3
- package/src/modules/customer_accounts/api/magic-link/request.ts +14 -3
- package/src/modules/customer_accounts/api/password/reset-request.ts +15 -3
- package/src/modules/customer_accounts/api/signup.ts +36 -5
- package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Actions.tsx +70 -0
- package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Diagnostics.tsx +66 -0
- package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/DnsConfig.tsx +78 -0
- package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/DomainPanel.tsx +90 -0
- package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/OrgSwitcher.tsx +43 -0
- package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/RegisterDialog.tsx +178 -0
- package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/StatusBadgeSection.tsx +56 -0
- package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Stepper.tsx +69 -0
- package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/domainStatusMap.ts +10 -0
- package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/types.ts +31 -0
- package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/page.meta.ts +26 -0
- package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/page.tsx +411 -0
- package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/page.tsx +3 -2
- package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +5 -4
- package/src/modules/customer_accounts/data/enrichers.ts +95 -12
- package/src/modules/customer_accounts/data/entities.ts +80 -1
- package/src/modules/customer_accounts/data/guards.ts +155 -0
- package/src/modules/customer_accounts/data/validators.ts +26 -0
- package/src/modules/customer_accounts/di.ts +35 -1
- package/src/modules/customer_accounts/events.ts +8 -1
- package/src/modules/customer_accounts/i18n/de.json +78 -0
- package/src/modules/customer_accounts/i18n/en.json +78 -0
- package/src/modules/customer_accounts/i18n/es.json +78 -0
- package/src/modules/customer_accounts/i18n/pl.json +78 -0
- package/src/modules/customer_accounts/lib/customerAuthServer.ts +44 -8
- package/src/modules/customer_accounts/lib/customerUrl.ts +72 -0
- package/src/modules/customer_accounts/lib/hostname.ts +76 -0
- package/src/modules/customer_accounts/lib/platformDomains.ts +14 -0
- package/src/modules/customer_accounts/lib/proxyRanges.ts +85 -0
- package/src/modules/customer_accounts/lib/rateLimiter.ts +10 -0
- package/src/modules/customer_accounts/lib/resolveTenantContext.ts +96 -0
- package/src/modules/customer_accounts/lib/secretCompare.ts +20 -0
- package/src/modules/customer_accounts/migrations/.snapshot-open-mercato.json +341 -0
- package/src/modules/customer_accounts/migrations/Migration20260430120000_customer_accounts.ts +38 -0
- package/src/modules/customer_accounts/notifications.client.ts +76 -0
- package/src/modules/customer_accounts/notifications.ts +76 -0
- package/src/modules/customer_accounts/services/domainMappingService.ts +632 -0
- package/src/modules/customer_accounts/setup.ts +81 -1
- package/src/modules/customer_accounts/subscribers/invalidateDomainCache.ts +35 -0
- package/src/modules/customer_accounts/subscribers/notifyDomainActivated.ts +32 -0
- package/src/modules/customer_accounts/subscribers/notifyDomainDnsFailed.ts +33 -0
- package/src/modules/customer_accounts/subscribers/notifyDomainTlsFailed.ts +34 -0
- package/src/modules/customer_accounts/subscribers/notifyDomainVerified.ts +32 -0
- package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +2 -2
- package/src/modules/customer_accounts/workers/domainTlsRetryWorker.ts +84 -0
- package/src/modules/customer_accounts/workers/domainVerificationWorker.ts +45 -0
- package/src/modules/customers/api/companies/route.ts +4 -9
- package/src/modules/customers/api/deals/route.ts +4 -9
- package/src/modules/customers/api/people/route.ts +4 -9
- package/src/modules/customers/api/utils.ts +0 -14
- package/src/modules/customers/backend/customers/companies/page.tsx +321 -237
- package/src/modules/customers/backend/customers/deals/page.tsx +321 -455
- package/src/modules/customers/backend/customers/people/page.tsx +331 -240
- package/src/modules/customers/components/detail/assignableStaff.ts +21 -0
- package/src/modules/customers/components/formConfig.tsx +2 -2
- package/src/modules/customers/i18n/de.json +31 -0
- package/src/modules/customers/i18n/en.json +31 -0
- package/src/modules/customers/i18n/es.json +31 -0
- package/src/modules/customers/i18n/pl.json +31 -0
- package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.tsx +197 -40
- package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.ts +13 -7
- package/src/modules/customers/widgets/injection-table.ts +6 -0
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +2 -2
- package/src/modules/perspectives/services/perspectiveService.ts +30 -2
- package/src/modules/portal/frontend/[orgSlug]/portal/login/page.tsx +5 -3
- package/src/modules/portal/frontend/[orgSlug]/portal/reset-password/page.tsx +3 -3
- package/src/modules/portal/frontend/[orgSlug]/portal/signup/page.tsx +4 -2
- package/src/modules/query_index/lib/engine.ts +46 -8
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +3 -5
- package/src/modules/sales/components/ProviderFieldInput.tsx +2 -2
- package/src/modules/sales/components/documents/SalesDocumentForm.tsx +2 -3
- package/src/modules/shipping_carriers/lib/shipment-wizard/components/ConfigureStep.tsx +3 -4
- package/src/modules/workflows/backend/tasks/[id]/page.tsx +2 -2
- package/src/modules/workflows/frontend/checkout-demo/page.tsx +2 -2
|
@@ -15,6 +15,76 @@ interface SeedScope {
|
|
|
15
15
|
organizationId: string
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
type SchedulerServiceLike = {
|
|
19
|
+
register: (registration: {
|
|
20
|
+
id: string
|
|
21
|
+
name: string
|
|
22
|
+
description?: string
|
|
23
|
+
scopeType: 'system'
|
|
24
|
+
scheduleType: 'interval'
|
|
25
|
+
scheduleValue: string
|
|
26
|
+
timezone?: string
|
|
27
|
+
targetType: 'queue'
|
|
28
|
+
targetQueue: string
|
|
29
|
+
targetPayload?: Record<string, unknown>
|
|
30
|
+
sourceType: 'module'
|
|
31
|
+
sourceModule: string
|
|
32
|
+
isEnabled?: boolean
|
|
33
|
+
}) => Promise<void>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Stable, deterministic UUIDs for the two domain-routing system schedules so
|
|
37
|
+
// re-running setup re-upserts the same rows instead of creating duplicates.
|
|
38
|
+
const DOMAIN_VERIFICATION_SCHEDULE_ID = '5e9ef5fc-1f4d-5b3d-8b58-8e1a5a4d1001'
|
|
39
|
+
const DOMAIN_TLS_RETRY_SCHEDULE_ID = '5e9ef5fc-1f4d-5b3d-8b58-8e1a5a4d1002'
|
|
40
|
+
|
|
41
|
+
function intervalSecondsFromEnv(envName: string, fallbackSeconds: number): string {
|
|
42
|
+
const parsed = Number.parseInt(process.env[envName] ?? '', 10)
|
|
43
|
+
const seconds = Number.isFinite(parsed) && parsed > 0 ? parsed : fallbackSeconds
|
|
44
|
+
return `${seconds}s`
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function registerDomainSchedules(
|
|
48
|
+
container: { hasRegistration?: (name: string) => boolean; resolve: (name: string) => unknown },
|
|
49
|
+
): Promise<void> {
|
|
50
|
+
if (typeof container.hasRegistration !== 'function' || !container.hasRegistration('schedulerService')) {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
const schedulerService = container.resolve('schedulerService') as SchedulerServiceLike
|
|
54
|
+
|
|
55
|
+
await schedulerService.register({
|
|
56
|
+
id: DOMAIN_VERIFICATION_SCHEDULE_ID,
|
|
57
|
+
name: 'Custom domain — DNS auto-verification',
|
|
58
|
+
description:
|
|
59
|
+
'Re-runs DNS verification for custom-domain mappings stuck in pending or dns_failed, and triggers TLS health checks on success.',
|
|
60
|
+
scopeType: 'system',
|
|
61
|
+
scheduleType: 'interval',
|
|
62
|
+
scheduleValue: intervalSecondsFromEnv('DOMAIN_AUTO_VERIFY_INTERVAL_SECONDS', 300),
|
|
63
|
+
timezone: 'UTC',
|
|
64
|
+
targetType: 'queue',
|
|
65
|
+
targetQueue: 'domain-verification',
|
|
66
|
+
sourceType: 'module',
|
|
67
|
+
sourceModule: 'customer_accounts',
|
|
68
|
+
isEnabled: true,
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
await schedulerService.register({
|
|
72
|
+
id: DOMAIN_TLS_RETRY_SCHEDULE_ID,
|
|
73
|
+
name: 'Custom domain — TLS retry',
|
|
74
|
+
description:
|
|
75
|
+
'Retries TLS certificate provisioning for verified or tls_failed custom-domain mappings, with batch cap and adaptive backoff on Let\'s Encrypt rate limits.',
|
|
76
|
+
scopeType: 'system',
|
|
77
|
+
scheduleType: 'interval',
|
|
78
|
+
scheduleValue: intervalSecondsFromEnv('DOMAIN_TLS_RETRY_INTERVAL_SECONDS', 1800),
|
|
79
|
+
timezone: 'UTC',
|
|
80
|
+
targetType: 'queue',
|
|
81
|
+
targetQueue: 'domain-tls-retry',
|
|
82
|
+
sourceType: 'module',
|
|
83
|
+
sourceModule: 'customer_accounts',
|
|
84
|
+
isEnabled: true,
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
18
88
|
const DEFAULT_ROLES = [
|
|
19
89
|
{
|
|
20
90
|
name: 'Portal Admin',
|
|
@@ -155,7 +225,7 @@ export const setup: ModuleSetupConfig = {
|
|
|
155
225
|
await seedDefaultRoles(em, { tenantId, organizationId })
|
|
156
226
|
},
|
|
157
227
|
|
|
158
|
-
async seedDefaults({ em, tenantId, organizationId }) {
|
|
228
|
+
async seedDefaults({ em, tenantId, organizationId, container }) {
|
|
159
229
|
await seedDefaultRoles(em, { tenantId, organizationId })
|
|
160
230
|
// Merge defaultCustomerRoleFeatures from all enabled modules
|
|
161
231
|
try {
|
|
@@ -165,6 +235,16 @@ export const setup: ModuleSetupConfig = {
|
|
|
165
235
|
} catch {
|
|
166
236
|
// Modules may not be registered yet during initial setup
|
|
167
237
|
}
|
|
238
|
+
|
|
239
|
+
// System-scoped schedules: register is idempotent, so re-running setup
|
|
240
|
+
// (or running it for additional tenants) just upserts the same two rows.
|
|
241
|
+
try {
|
|
242
|
+
await registerDomainSchedules(
|
|
243
|
+
container as { hasRegistration?: (name: string) => boolean; resolve: (name: string) => unknown },
|
|
244
|
+
)
|
|
245
|
+
} catch {
|
|
246
|
+
// Scheduler may not be installed in this deployment; ignore.
|
|
247
|
+
}
|
|
168
248
|
},
|
|
169
249
|
|
|
170
250
|
async seedExamples({ em, tenantId, organizationId }) {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
type CacheService = {
|
|
2
|
+
deleteByTags(tags: string[]): Promise<number>
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export const metadata = {
|
|
6
|
+
event: 'customer_accounts.domain_mapping.*',
|
|
7
|
+
persistent: false,
|
|
8
|
+
id: 'customer_accounts:invalidate-domain-cache',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default async function handle(
|
|
12
|
+
payload: unknown,
|
|
13
|
+
ctx: { resolve: <T = unknown>(name: string) => T },
|
|
14
|
+
): Promise<void> {
|
|
15
|
+
const data = (payload ?? {}) as Record<string, unknown>
|
|
16
|
+
const hostname = typeof data.hostname === 'string' ? data.hostname : null
|
|
17
|
+
const organizationId = typeof data.organizationId === 'string' ? data.organizationId : null
|
|
18
|
+
|
|
19
|
+
let cache: CacheService | null = null
|
|
20
|
+
try {
|
|
21
|
+
cache = ctx.resolve<CacheService>('cache')
|
|
22
|
+
} catch {
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
if (!cache) return
|
|
26
|
+
|
|
27
|
+
const tags = ['domain_routing']
|
|
28
|
+
if (hostname) tags.push(`domain_routing:${hostname}`)
|
|
29
|
+
if (organizationId) tags.push(`domain_routing:org:${organizationId}`)
|
|
30
|
+
try {
|
|
31
|
+
await cache.deleteByTags(tags)
|
|
32
|
+
} catch {
|
|
33
|
+
// Best-effort cache invalidation. TTL is the backstop.
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { EventBus } from '@open-mercato/events/types'
|
|
2
|
+
|
|
3
|
+
export const metadata = {
|
|
4
|
+
event: 'customer_accounts.domain_mapping.activated',
|
|
5
|
+
persistent: true,
|
|
6
|
+
id: 'customer_accounts:notify-domain-activated',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default async function handle(
|
|
10
|
+
payload: unknown,
|
|
11
|
+
ctx: { resolve: <T = unknown>(name: string) => T },
|
|
12
|
+
): Promise<void> {
|
|
13
|
+
const data = (payload ?? {}) as Record<string, unknown>
|
|
14
|
+
const id = typeof data.id === 'string' ? data.id : null
|
|
15
|
+
const tenantId = typeof data.tenantId === 'string' ? data.tenantId : null
|
|
16
|
+
const organizationId = typeof data.organizationId === 'string' ? data.organizationId : null
|
|
17
|
+
const hostname = typeof data.hostname === 'string' ? data.hostname : ''
|
|
18
|
+
if (!id || !tenantId || !organizationId) return
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const eventBus = ctx.resolve<EventBus>('eventBus')
|
|
22
|
+
await eventBus.emitEvent('notifications.create', {
|
|
23
|
+
type: 'customer_accounts.domain_mapping.activated',
|
|
24
|
+
tenantId,
|
|
25
|
+
organizationId,
|
|
26
|
+
sourceEntityId: id,
|
|
27
|
+
data: { hostname },
|
|
28
|
+
})
|
|
29
|
+
} catch {
|
|
30
|
+
// Notifications module may be absent — best-effort.
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { EventBus } from '@open-mercato/events/types'
|
|
2
|
+
|
|
3
|
+
export const metadata = {
|
|
4
|
+
event: 'customer_accounts.domain_mapping.dns_failed',
|
|
5
|
+
persistent: true,
|
|
6
|
+
id: 'customer_accounts:notify-domain-dns-failed',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default async function handle(
|
|
10
|
+
payload: unknown,
|
|
11
|
+
ctx: { resolve: <T = unknown>(name: string) => T },
|
|
12
|
+
): Promise<void> {
|
|
13
|
+
const data = (payload ?? {}) as Record<string, unknown>
|
|
14
|
+
const id = typeof data.id === 'string' ? data.id : null
|
|
15
|
+
const tenantId = typeof data.tenantId === 'string' ? data.tenantId : null
|
|
16
|
+
const organizationId = typeof data.organizationId === 'string' ? data.organizationId : null
|
|
17
|
+
const hostname = typeof data.hostname === 'string' ? data.hostname : ''
|
|
18
|
+
const reason = typeof data.reason === 'string' ? data.reason : ''
|
|
19
|
+
if (!id || !tenantId || !organizationId) return
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const eventBus = ctx.resolve<EventBus>('eventBus')
|
|
23
|
+
await eventBus.emitEvent('notifications.create', {
|
|
24
|
+
type: 'customer_accounts.domain_mapping.dns_failed',
|
|
25
|
+
tenantId,
|
|
26
|
+
organizationId,
|
|
27
|
+
sourceEntityId: id,
|
|
28
|
+
data: { hostname, reason },
|
|
29
|
+
})
|
|
30
|
+
} catch {
|
|
31
|
+
// Notifications module may be absent — best-effort.
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { EventBus } from '@open-mercato/events/types'
|
|
2
|
+
|
|
3
|
+
export const metadata = {
|
|
4
|
+
event: 'customer_accounts.domain_mapping.tls_failed',
|
|
5
|
+
persistent: true,
|
|
6
|
+
id: 'customer_accounts:notify-domain-tls-failed',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default async function handle(
|
|
10
|
+
payload: unknown,
|
|
11
|
+
ctx: { resolve: <T = unknown>(name: string) => T },
|
|
12
|
+
): Promise<void> {
|
|
13
|
+
const data = (payload ?? {}) as Record<string, unknown>
|
|
14
|
+
const id = typeof data.id === 'string' ? data.id : null
|
|
15
|
+
const tenantId = typeof data.tenantId === 'string' ? data.tenantId : null
|
|
16
|
+
const organizationId = typeof data.organizationId === 'string' ? data.organizationId : null
|
|
17
|
+
const hostname = typeof data.hostname === 'string' ? data.hostname : ''
|
|
18
|
+
const reason = typeof data.reason === 'string' ? data.reason : ''
|
|
19
|
+
const retryCount = typeof data.retryCount === 'number' ? data.retryCount : 0
|
|
20
|
+
if (!id || !tenantId || !organizationId) return
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const eventBus = ctx.resolve<EventBus>('eventBus')
|
|
24
|
+
await eventBus.emitEvent('notifications.create', {
|
|
25
|
+
type: 'customer_accounts.domain_mapping.tls_failed',
|
|
26
|
+
tenantId,
|
|
27
|
+
organizationId,
|
|
28
|
+
sourceEntityId: id,
|
|
29
|
+
data: { hostname, reason, retryCount },
|
|
30
|
+
})
|
|
31
|
+
} catch {
|
|
32
|
+
// Notifications module may be absent — best-effort.
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { EventBus } from '@open-mercato/events/types'
|
|
2
|
+
|
|
3
|
+
export const metadata = {
|
|
4
|
+
event: 'customer_accounts.domain_mapping.verified',
|
|
5
|
+
persistent: true,
|
|
6
|
+
id: 'customer_accounts:notify-domain-verified',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default async function handle(
|
|
10
|
+
payload: unknown,
|
|
11
|
+
ctx: { resolve: <T = unknown>(name: string) => T },
|
|
12
|
+
): Promise<void> {
|
|
13
|
+
const data = (payload ?? {}) as Record<string, unknown>
|
|
14
|
+
const id = typeof data.id === 'string' ? data.id : null
|
|
15
|
+
const tenantId = typeof data.tenantId === 'string' ? data.tenantId : null
|
|
16
|
+
const organizationId = typeof data.organizationId === 'string' ? data.organizationId : null
|
|
17
|
+
const hostname = typeof data.hostname === 'string' ? data.hostname : ''
|
|
18
|
+
if (!id || !tenantId || !organizationId) return
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const eventBus = ctx.resolve<EventBus>('eventBus')
|
|
22
|
+
await eventBus.emitEvent('notifications.create', {
|
|
23
|
+
type: 'customer_accounts.domain_mapping.verified',
|
|
24
|
+
tenantId,
|
|
25
|
+
organizationId,
|
|
26
|
+
sourceEntityId: id,
|
|
27
|
+
data: { hostname },
|
|
28
|
+
})
|
|
29
|
+
} catch {
|
|
30
|
+
// Notifications module may be absent — best-effort.
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -6,6 +6,7 @@ import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
|
|
|
6
6
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
7
7
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
8
8
|
import { Input } from '@open-mercato/ui/primitives/input'
|
|
9
|
+
import { EmailInput } from '@open-mercato/ui/primitives/email-input'
|
|
9
10
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
10
11
|
|
|
11
12
|
interface AccountStatusData {
|
|
@@ -168,9 +169,8 @@ function InviteForm({ personEntityId, onSuccess }: { personEntityId: string; onS
|
|
|
168
169
|
<label htmlFor="invite-email" className="block text-xs font-medium text-muted-foreground mb-1">
|
|
169
170
|
{t('common.email', 'Email')}
|
|
170
171
|
</label>
|
|
171
|
-
<
|
|
172
|
+
<EmailInput
|
|
172
173
|
id="invite-email"
|
|
173
|
-
type="email"
|
|
174
174
|
size="sm"
|
|
175
175
|
value={email}
|
|
176
176
|
onChange={(event) => setEmail(event.target.value)}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { JobContext, QueuedJob, WorkerMeta } from '@open-mercato/queue'
|
|
2
|
+
import type { DomainMappingService } from '@open-mercato/core/modules/customer_accounts/services/domainMappingService'
|
|
3
|
+
|
|
4
|
+
export const metadata: WorkerMeta = {
|
|
5
|
+
queue: 'domain-tls-retry',
|
|
6
|
+
id: 'customer_accounts:domain-tls-retry',
|
|
7
|
+
concurrency: 1,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type HandlerContext = JobContext & {
|
|
11
|
+
resolve: <T = unknown>(name: string) => T
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function parseInt32(value: string | undefined, fallback: number): number {
|
|
15
|
+
const parsed = Number.parseInt(value ?? '', 10)
|
|
16
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return fallback
|
|
17
|
+
return parsed
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function parseFloat01(value: string | undefined, fallback: number): number {
|
|
21
|
+
const parsed = Number.parseFloat(value ?? '')
|
|
22
|
+
if (!Number.isFinite(parsed) || parsed <= 0 || parsed > 1) return fallback
|
|
23
|
+
return parsed
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// In-process adaptive-backoff state. Worker is concurrency=1, so a single
|
|
27
|
+
// process owns this state. Surviving restarts is unnecessary because the
|
|
28
|
+
// scheduler will simply re-evaluate on the next tick. See spec
|
|
29
|
+
// "Phase 5 → Worker-level backoff" for the contract.
|
|
30
|
+
let backoffMultiplier = 1
|
|
31
|
+
let nextEligibleAt = 0
|
|
32
|
+
|
|
33
|
+
const BACKOFF_CAP_HOURS = 6
|
|
34
|
+
|
|
35
|
+
export default async function handle(_job: QueuedJob, ctx: HandlerContext): Promise<void> {
|
|
36
|
+
const baseIntervalSeconds = parseInt32(process.env.DOMAIN_TLS_RETRY_INTERVAL_SECONDS, 1800)
|
|
37
|
+
const batchSize = parseInt32(process.env.DOMAIN_TLS_RETRY_BATCH, 50)
|
|
38
|
+
const maxRetries = parseInt32(process.env.DOMAIN_TLS_MAX_RETRIES, 6)
|
|
39
|
+
const failureThreshold = parseFloat01(process.env.DOMAIN_TLS_RETRY_FAILURE_THRESHOLD, 0.8)
|
|
40
|
+
const capSeconds = BACKOFF_CAP_HOURS * 3600
|
|
41
|
+
const maxMultiplier = Math.max(1, Math.floor(capSeconds / baseIntervalSeconds))
|
|
42
|
+
|
|
43
|
+
if (Date.now() < nextEligibleAt) return
|
|
44
|
+
|
|
45
|
+
const service = ctx.resolve<DomainMappingService>('domainMappingService')
|
|
46
|
+
const candidates = await service.findPendingTls({ maxRetries, batchSize })
|
|
47
|
+
if (candidates.length === 0) {
|
|
48
|
+
backoffMultiplier = 1
|
|
49
|
+
nextEligibleAt = 0
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let attempted = 0
|
|
54
|
+
let failed = 0
|
|
55
|
+
for (const mapping of candidates) {
|
|
56
|
+
attempted += 1
|
|
57
|
+
try {
|
|
58
|
+
const updated = await service.healthCheck(mapping.id)
|
|
59
|
+
if (updated.status !== 'active') failed += 1
|
|
60
|
+
} catch {
|
|
61
|
+
failed += 1
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (attempted === 0) return
|
|
66
|
+
const failureRate = failed / attempted
|
|
67
|
+
|
|
68
|
+
if (failureRate >= failureThreshold) {
|
|
69
|
+
backoffMultiplier = Math.min(backoffMultiplier * 2, maxMultiplier)
|
|
70
|
+
nextEligibleAt = Date.now() + backoffMultiplier * baseIntervalSeconds * 1000
|
|
71
|
+
} else {
|
|
72
|
+
backoffMultiplier = 1
|
|
73
|
+
nextEligibleAt = 0
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Test-only export so unit tests can reset state between runs.
|
|
78
|
+
export const __testing__ = {
|
|
79
|
+
reset: () => {
|
|
80
|
+
backoffMultiplier = 1
|
|
81
|
+
nextEligibleAt = 0
|
|
82
|
+
},
|
|
83
|
+
getState: () => ({ backoffMultiplier, nextEligibleAt }),
|
|
84
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { JobContext, QueuedJob, WorkerMeta } from '@open-mercato/queue'
|
|
2
|
+
import type { DomainMappingService } from '@open-mercato/core/modules/customer_accounts/services/domainMappingService'
|
|
3
|
+
|
|
4
|
+
export const metadata: WorkerMeta = {
|
|
5
|
+
queue: 'domain-verification',
|
|
6
|
+
id: 'customer_accounts:domain-verification',
|
|
7
|
+
concurrency: 1,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type HandlerContext = JobContext & {
|
|
11
|
+
resolve: <T = unknown>(name: string) => T
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function parseSeconds(value: string | undefined, fallback: number): number {
|
|
15
|
+
const parsed = Number.parseInt(value ?? '', 10)
|
|
16
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return fallback
|
|
17
|
+
return parsed
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default async function handle(_job: QueuedJob, ctx: HandlerContext): Promise<void> {
|
|
21
|
+
const service = ctx.resolve<DomainMappingService>('domainMappingService')
|
|
22
|
+
|
|
23
|
+
const intervalSeconds = parseSeconds(process.env.DOMAIN_AUTO_VERIFY_INTERVAL_SECONDS, 300)
|
|
24
|
+
const olderThanMs = intervalSeconds * 1000
|
|
25
|
+
|
|
26
|
+
const candidates = await service.findPendingVerification({ olderThanMs })
|
|
27
|
+
if (candidates.length === 0) return
|
|
28
|
+
|
|
29
|
+
for (const mapping of candidates) {
|
|
30
|
+
try {
|
|
31
|
+
const result = await service.verify(mapping.id)
|
|
32
|
+
if (result.domainMapping.status === 'verified') {
|
|
33
|
+
try {
|
|
34
|
+
await service.healthCheck(mapping.id)
|
|
35
|
+
} catch {
|
|
36
|
+
// healthCheck emits its own events on failure; swallow here so one
|
|
37
|
+
// bad domain doesn't poison the rest of the batch.
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
} catch {
|
|
41
|
+
// verify() emits dns_failed events on negative results. A thrown error
|
|
42
|
+
// here is unexpected (e.g. DB blip) — skip and let the next tick retry.
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -14,7 +14,6 @@ import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
|
|
|
14
14
|
import {
|
|
15
15
|
applyEntityIdExclusion,
|
|
16
16
|
applyEntityIdRestriction,
|
|
17
|
-
consumeAdvancedFilterState,
|
|
18
17
|
findMatchingEntityIdsWithQueryEngine,
|
|
19
18
|
findMatchingEntityIdsBySearchTokensAcrossSources,
|
|
20
19
|
withScopedPayload,
|
|
@@ -27,7 +26,7 @@ import {
|
|
|
27
26
|
import { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'
|
|
28
27
|
import { parseBooleanToken } from '@open-mercato/shared/lib/boolean'
|
|
29
28
|
import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
30
|
-
import {
|
|
29
|
+
import { consumeAdvancedFilterState, mergeAdvancedFilterTree } from '@open-mercato/shared/lib/crud/advanced-filter-integration'
|
|
31
30
|
import {
|
|
32
31
|
createCustomersCrudOpenApi,
|
|
33
32
|
createPagedListResponseSchema,
|
|
@@ -119,8 +118,7 @@ const crud = makeCrudRoute({
|
|
|
119
118
|
updatedAt: 'updated_at',
|
|
120
119
|
},
|
|
121
120
|
buildFilters: async (query, ctx) => {
|
|
122
|
-
const
|
|
123
|
-
const advancedFilterState = consumeAdvancedFilterState(query)
|
|
121
|
+
const advancedFilterTree = consumeAdvancedFilterState(query)
|
|
124
122
|
const filters: Record<string, unknown> = { kind: { $eq: 'company' } }
|
|
125
123
|
if (query.id) filters.id = { $eq: query.id }
|
|
126
124
|
if (query.search) {
|
|
@@ -313,11 +311,8 @@ const crud = makeCrudRoute({
|
|
|
313
311
|
console.warn('[customers.companies.list] custom field filter resolution failed; falling back to base filters', err)
|
|
314
312
|
}
|
|
315
313
|
}
|
|
316
|
-
if (ctx &&
|
|
317
|
-
const advancedFilters =
|
|
318
|
-
{ ...filters },
|
|
319
|
-
advancedQuery as Record<string, unknown>,
|
|
320
|
-
)
|
|
314
|
+
if (ctx && advancedFilterTree) {
|
|
315
|
+
const advancedFilters = mergeAdvancedFilterTree({ ...filters }, advancedFilterTree)
|
|
321
316
|
const matchedIds = await findMatchingEntityIdsWithQueryEngine({
|
|
322
317
|
ctx,
|
|
323
318
|
entityId: E.customers.customer_entity,
|
|
@@ -7,7 +7,6 @@ import { E } from '#generated/entities.ids.generated'
|
|
|
7
7
|
import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
|
|
8
8
|
import {
|
|
9
9
|
applyEntityIdRestriction,
|
|
10
|
-
consumeAdvancedFilterState,
|
|
11
10
|
findMatchingEntityIdsWithQueryEngine,
|
|
12
11
|
findMatchingEntityIdsBySearchTokensAcrossSources,
|
|
13
12
|
parseScopedCommandInput,
|
|
@@ -20,7 +19,7 @@ import {
|
|
|
20
19
|
} from '../openapi'
|
|
21
20
|
import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
22
21
|
import { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'
|
|
23
|
-
import {
|
|
22
|
+
import { consumeAdvancedFilterState, mergeAdvancedFilterTree } from '@open-mercato/shared/lib/crud/advanced-filter-integration'
|
|
24
23
|
|
|
25
24
|
const rawBodySchema = z.object({}).passthrough()
|
|
26
25
|
|
|
@@ -133,8 +132,7 @@ const crud = makeCrudRoute<unknown, unknown, DealListQuery>({
|
|
|
133
132
|
},
|
|
134
133
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
135
134
|
buildFilters: async (query: any, ctx) => {
|
|
136
|
-
const
|
|
137
|
-
const advancedFilterState = consumeAdvancedFilterState(query)
|
|
135
|
+
const advancedFilterTree = consumeAdvancedFilterState(query)
|
|
138
136
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
139
137
|
const filters: Record<string, any> = {}
|
|
140
138
|
if (query.search) {
|
|
@@ -182,11 +180,8 @@ const crud = makeCrudRoute<unknown, unknown, DealListQuery>({
|
|
|
182
180
|
if (query.pipelineStageId) {
|
|
183
181
|
filters.pipeline_stage_id = { $eq: query.pipelineStageId }
|
|
184
182
|
}
|
|
185
|
-
if (ctx &&
|
|
186
|
-
const advancedFilters =
|
|
187
|
-
{ ...filters },
|
|
188
|
-
advancedQuery as Record<string, unknown>,
|
|
189
|
-
)
|
|
183
|
+
if (ctx && advancedFilterTree) {
|
|
184
|
+
const advancedFilters = mergeAdvancedFilterTree({ ...filters }, advancedFilterTree)
|
|
190
185
|
const matchedIds = await findMatchingEntityIdsWithQueryEngine({
|
|
191
186
|
ctx,
|
|
192
187
|
entityId: E.customers.customer_deal,
|
|
@@ -14,7 +14,6 @@ import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
|
|
|
14
14
|
import {
|
|
15
15
|
applyEntityIdExclusion,
|
|
16
16
|
applyEntityIdRestriction,
|
|
17
|
-
consumeAdvancedFilterState,
|
|
18
17
|
findMatchingEntityIdsWithQueryEngine,
|
|
19
18
|
findMatchingEntityIdsBySearchTokensAcrossSources,
|
|
20
19
|
withScopedPayload,
|
|
@@ -23,7 +22,7 @@ import { buildCustomFieldFiltersFromQuery, extractAllCustomFieldEntries, splitCu
|
|
|
23
22
|
import { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'
|
|
24
23
|
import { parseBooleanToken } from '@open-mercato/shared/lib/boolean'
|
|
25
24
|
import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
26
|
-
import {
|
|
25
|
+
import { consumeAdvancedFilterState, mergeAdvancedFilterTree } from '@open-mercato/shared/lib/crud/advanced-filter-integration'
|
|
27
26
|
import {
|
|
28
27
|
createCustomersCrudOpenApi,
|
|
29
28
|
createPagedListResponseSchema,
|
|
@@ -112,8 +111,7 @@ const crud = makeCrudRoute({
|
|
|
112
111
|
updatedAt: 'updated_at',
|
|
113
112
|
},
|
|
114
113
|
buildFilters: async (query, ctx) => {
|
|
115
|
-
const
|
|
116
|
-
const advancedFilterState = consumeAdvancedFilterState(query)
|
|
114
|
+
const advancedFilterTree = consumeAdvancedFilterState(query)
|
|
117
115
|
const filters: Record<string, unknown> = { kind: { $eq: 'person' } }
|
|
118
116
|
if (query.id) filters.id = { $eq: query.id }
|
|
119
117
|
if (query.search) {
|
|
@@ -304,11 +302,8 @@ const crud = makeCrudRoute({
|
|
|
304
302
|
console.warn('[customers.people.list] custom field filter resolution failed; falling back to base filters', err)
|
|
305
303
|
}
|
|
306
304
|
}
|
|
307
|
-
if (ctx &&
|
|
308
|
-
const advancedFilters =
|
|
309
|
-
{ ...filters },
|
|
310
|
-
advancedQuery as Record<string, unknown>,
|
|
311
|
-
)
|
|
305
|
+
if (ctx && advancedFilterTree) {
|
|
306
|
+
const advancedFilters = mergeAdvancedFilterTree({ ...filters }, advancedFilterTree)
|
|
312
307
|
const matchedIds = await findMatchingEntityIdsWithQueryEngine({
|
|
313
308
|
ctx,
|
|
314
309
|
entityId: E.customers.customer_entity,
|
|
@@ -6,7 +6,6 @@ import type { EntityId } from '@open-mercato/shared/modules/entities'
|
|
|
6
6
|
import type { QueryCustomFieldSource, QueryJoinEdge, QueryEngine } from '@open-mercato/shared/lib/query/types'
|
|
7
7
|
import { resolveSearchConfig } from '@open-mercato/shared/lib/search/config'
|
|
8
8
|
import { tokenizeText } from '@open-mercato/shared/lib/search/tokenize'
|
|
9
|
-
import { deserializeAdvancedFilter } from '@open-mercato/shared/lib/query/advanced-filter'
|
|
10
9
|
import { SortDir } from '@open-mercato/shared/lib/query/types'
|
|
11
10
|
|
|
12
11
|
const { withScopedPayload, parseScopedCommandInput } = createScopedApiHelpers({
|
|
@@ -278,19 +277,6 @@ export function applyEntityIdExclusion(
|
|
|
278
277
|
}
|
|
279
278
|
}
|
|
280
279
|
|
|
281
|
-
export function consumeAdvancedFilterState(query: Record<string, unknown>) {
|
|
282
|
-
const state = deserializeAdvancedFilter(query)
|
|
283
|
-
if (!state) return null
|
|
284
|
-
|
|
285
|
-
for (const key of Object.keys(query)) {
|
|
286
|
-
if (key.startsWith('filter[')) {
|
|
287
|
-
delete query[key]
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
return state
|
|
292
|
-
}
|
|
293
|
-
|
|
294
280
|
export async function findMatchingEntityIdsWithQueryEngine({
|
|
295
281
|
ctx,
|
|
296
282
|
entityId,
|