@open-mercato/core 0.8.1-develop.7296.1.2111d779db → 0.9.0
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/AGENTS.md +4 -5
- package/dist/generated/entities/availability_policy/index.js +41 -0
- package/dist/generated/entities/availability_policy/index.js.map +7 -0
- package/dist/generated/entities/communication_channel/index.js +3 -1
- package/dist/generated/entities/communication_channel/index.js.map +2 -2
- package/dist/generated/entities/customer_email_conversation_share/index.js +21 -0
- package/dist/generated/entities/customer_email_conversation_share/index.js.map +7 -0
- package/dist/generated/entities/customer_group/index.js +33 -0
- package/dist/generated/entities/customer_group/index.js.map +7 -0
- package/dist/generated/entities/customer_group_membership/index.js +29 -0
- package/dist/generated/entities/customer_group_membership/index.js.map +7 -0
- package/dist/generated/entities/customer_group_terms/index.js +33 -0
- package/dist/generated/entities/customer_group_terms/index.js.map +7 -0
- package/dist/generated/entities/customer_interaction/index.js +2 -0
- package/dist/generated/entities/customer_interaction/index.js.map +2 -2
- package/dist/generated/entities/form/index.js +35 -0
- package/dist/generated/entities/form/index.js.map +7 -0
- package/dist/generated/entities/form_access_audit/index.js +21 -0
- package/dist/generated/entities/form_access_audit/index.js.map +7 -0
- package/dist/generated/entities/form_attachment/index.js +29 -0
- package/dist/generated/entities/form_attachment/index.js.map +7 -0
- package/dist/generated/entities/form_consent_record/index.js +37 -0
- package/dist/generated/entities/form_consent_record/index.js.map +7 -0
- package/dist/generated/entities/form_distribution/index.js +47 -0
- package/dist/generated/entities/form_distribution/index.js.map +7 -0
- package/dist/generated/entities/form_invitation/index.js +49 -0
- package/dist/generated/entities/form_invitation/index.js.map +7 -0
- package/dist/generated/entities/form_submission/index.js +39 -0
- package/dist/generated/entities/form_submission/index.js.map +7 -0
- package/dist/generated/entities/form_submission_actor/index.js +23 -0
- package/dist/generated/entities/form_submission_actor/index.js.map +7 -0
- package/dist/generated/entities/form_submission_revision/index.js +29 -0
- package/dist/generated/entities/form_submission_revision/index.js.map +7 -0
- package/dist/generated/entities/form_version/index.js +37 -0
- package/dist/generated/entities/form_version/index.js.map +7 -0
- package/dist/generated/entities/forms_encryption_key/index.js +15 -0
- package/dist/generated/entities/forms_encryption_key/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +27 -2
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +269 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/helpers/integration/communicationChannelsFixtures.js +16 -0
- package/dist/helpers/integration/communicationChannelsFixtures.js.map +2 -2
- package/dist/helpers/integration/customerGroupsFixtures.js +88 -0
- package/dist/helpers/integration/customerGroupsFixtures.js.map +7 -0
- package/dist/helpers/integration/formsFixtures.js +448 -0
- package/dist/helpers/integration/formsFixtures.js.map +7 -0
- package/dist/modules/api_docs/api/get/version.js +19 -7
- package/dist/modules/api_docs/api/get/version.js.map +2 -2
- package/dist/modules/api_keys/api/keys/route.js +74 -169
- package/dist/modules/api_keys/api/keys/route.js.map +2 -2
- package/dist/modules/api_keys/backend/api-keys/create/page.js +1 -1
- package/dist/modules/api_keys/backend/api-keys/create/page.js.map +2 -2
- package/dist/modules/api_keys/commands/keys.js +140 -0
- package/dist/modules/api_keys/commands/keys.js.map +7 -0
- package/dist/modules/api_keys/services/apiKeyService.js +72 -43
- package/dist/modules/api_keys/services/apiKeyService.js.map +2 -2
- package/dist/modules/attachments/api/file/[id]/route.js +9 -2
- package/dist/modules/attachments/api/file/[id]/route.js.map +2 -2
- package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js +6 -2
- package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js.map +2 -2
- package/dist/modules/attachments/api/route.js +10 -4
- package/dist/modules/attachments/api/route.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentLibrary.js +16 -6
- package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
- package/dist/modules/attachments/lib/access.js +1 -3
- package/dist/modules/attachments/lib/access.js.map +2 -2
- package/dist/modules/attachments/lib/requestScope.js +13 -4
- package/dist/modules/attachments/lib/requestScope.js.map +2 -2
- package/dist/modules/audit_logs/api/audit-logs/actions/export/route.js +6 -1
- package/dist/modules/audit_logs/api/audit-logs/actions/export/route.js.map +2 -2
- package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js +36 -6
- package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js.map +3 -3
- package/dist/modules/audit_logs/api/audit-logs/actions/route.js +6 -1
- package/dist/modules/audit_logs/api/audit-logs/actions/route.js.map +2 -2
- package/dist/modules/audit_logs/api/audit-logs/actions/undo/route.js +34 -4
- package/dist/modules/audit_logs/api/audit-logs/actions/undo/route.js.map +2 -2
- package/dist/modules/audit_logs/data/validators.js +1 -0
- package/dist/modules/audit_logs/data/validators.js.map +2 -2
- package/dist/modules/audit_logs/lib/actorSubject.js +65 -0
- package/dist/modules/audit_logs/lib/actorSubject.js.map +7 -0
- package/dist/modules/audit_logs/lib/replayAuthorization.js +41 -0
- package/dist/modules/audit_logs/lib/replayAuthorization.js.map +7 -0
- package/dist/modules/audit_logs/services/actionLogService.js +162 -39
- package/dist/modules/audit_logs/services/actionLogService.js.map +3 -3
- package/dist/modules/auth/api/features.js +1 -1
- package/dist/modules/auth/api/features.js.map +2 -2
- package/dist/modules/auth/cli.js +29 -17
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/auth/commands/acl.js +25 -36
- package/dist/modules/auth/commands/acl.js.map +2 -2
- package/dist/modules/auth/commands/interceptors.js +22 -0
- package/dist/modules/auth/commands/interceptors.js.map +7 -0
- package/dist/modules/auth/commands/roles.js +421 -147
- package/dist/modules/auth/commands/roles.js.map +2 -2
- package/dist/modules/auth/commands/users.js +543 -69
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/auth/lib/authorizationStateLocks.js +249 -0
- package/dist/modules/auth/lib/authorizationStateLocks.js.map +7 -0
- package/dist/modules/auth/lib/commandReplay.js +144 -0
- package/dist/modules/auth/lib/commandReplay.js.map +7 -0
- package/dist/modules/auth/lib/executionPrincipal.js +32 -25
- package/dist/modules/auth/lib/executionPrincipal.js.map +2 -2
- package/dist/modules/auth/lib/grantChecks.js +7 -2
- package/dist/modules/auth/lib/grantChecks.js.map +2 -2
- package/dist/modules/auth/lib/setup-app.js +85 -49
- package/dist/modules/auth/lib/setup-app.js.map +2 -2
- package/dist/modules/auth/lib/tokenHash.js +13 -1
- package/dist/modules/auth/lib/tokenHash.js.map +2 -2
- package/dist/modules/auth/services/rbacService.js +386 -5
- package/dist/modules/auth/services/rbacService.js.map +3 -3
- package/dist/modules/availability/acl.js +16 -0
- package/dist/modules/availability/acl.js.map +7 -0
- package/dist/modules/availability/api/check/route.js +115 -0
- package/dist/modules/availability/api/check/route.js.map +7 -0
- package/dist/modules/availability/api/openapi.js +27 -0
- package/dist/modules/availability/api/openapi.js.map +7 -0
- package/dist/modules/availability/api/policies/resolve-preview/route.js +72 -0
- package/dist/modules/availability/api/policies/resolve-preview/route.js.map +7 -0
- package/dist/modules/availability/api/policies/route.js +203 -0
- package/dist/modules/availability/api/policies/route.js.map +7 -0
- package/dist/modules/availability/backend/availability/check/page.js +186 -0
- package/dist/modules/availability/backend/availability/check/page.js.map +7 -0
- package/dist/modules/availability/backend/availability/check/page.meta.js +16 -0
- package/dist/modules/availability/backend/availability/check/page.meta.js.map +7 -0
- package/dist/modules/availability/backend/availability/policies/ResolutionPreviewPanel.js +83 -0
- package/dist/modules/availability/backend/availability/policies/ResolutionPreviewPanel.js.map +7 -0
- package/dist/modules/availability/backend/availability/policies/ScopeFields.js +53 -0
- package/dist/modules/availability/backend/availability/policies/ScopeFields.js.map +7 -0
- package/dist/modules/availability/backend/availability/policies/StockManagedField.js +32 -0
- package/dist/modules/availability/backend/availability/policies/StockManagedField.js.map +7 -0
- package/dist/modules/availability/backend/availability/policies/[id]/page.js +168 -0
- package/dist/modules/availability/backend/availability/policies/[id]/page.js.map +7 -0
- package/dist/modules/availability/backend/availability/policies/[id]/page.meta.js +12 -0
- package/dist/modules/availability/backend/availability/policies/[id]/page.meta.js.map +7 -0
- package/dist/modules/availability/backend/availability/policies/create/page.js +122 -0
- package/dist/modules/availability/backend/availability/policies/create/page.js.map +7 -0
- package/dist/modules/availability/backend/availability/policies/create/page.meta.js +12 -0
- package/dist/modules/availability/backend/availability/policies/create/page.meta.js.map +7 -0
- package/dist/modules/availability/backend/availability/policies/formGroups.js +77 -0
- package/dist/modules/availability/backend/availability/policies/formGroups.js.map +7 -0
- package/dist/modules/availability/backend/availability/policies/page.js +207 -0
- package/dist/modules/availability/backend/availability/policies/page.js.map +7 -0
- package/dist/modules/availability/backend/availability/policies/page.meta.js +16 -0
- package/dist/modules/availability/backend/availability/policies/page.meta.js.map +7 -0
- package/dist/modules/availability/backend/availability/policies/policyPayload.js +28 -0
- package/dist/modules/availability/backend/availability/policies/policyPayload.js.map +7 -0
- package/dist/modules/availability/commands/policies.js +364 -0
- package/dist/modules/availability/commands/policies.js.map +7 -0
- package/dist/modules/availability/commands/scope.js +19 -0
- package/dist/modules/availability/commands/scope.js.map +7 -0
- package/dist/modules/availability/data/entities.js +94 -0
- package/dist/modules/availability/data/entities.js.map +7 -0
- package/dist/modules/availability/data/validators.js +59 -0
- package/dist/modules/availability/data/validators.js.map +7 -0
- package/dist/modules/availability/di.js +50 -0
- package/dist/modules/availability/di.js.map +7 -0
- package/dist/modules/availability/events.js +18 -0
- package/dist/modules/availability/events.js.map +7 -0
- package/dist/modules/availability/index.js +15 -0
- package/dist/modules/availability/index.js.map +7 -0
- package/dist/modules/availability/lib/catalogTarget.js +42 -0
- package/dist/modules/availability/lib/catalogTarget.js.map +7 -0
- package/dist/modules/availability/lib/organizationScope.js +33 -0
- package/dist/modules/availability/lib/organizationScope.js.map +7 -0
- package/dist/modules/availability/lib/policyResolution.js +150 -0
- package/dist/modules/availability/lib/policyResolution.js.map +7 -0
- package/dist/modules/availability/lib/tryResolve.js +11 -0
- package/dist/modules/availability/lib/tryResolve.js.map +7 -0
- package/dist/modules/availability/migrations/Migration20260922095844_availability.js +16 -0
- package/dist/modules/availability/migrations/Migration20260922095844_availability.js.map +7 -0
- package/dist/modules/availability/migrations/Migration20260930120000_availability.js +20 -0
- package/dist/modules/availability/migrations/Migration20260930120000_availability.js.map +7 -0
- package/dist/modules/availability/setup.js +12 -0
- package/dist/modules/availability/setup.js.map +7 -0
- package/dist/modules/catalog/api/categories/bulk-create/route.js +124 -0
- package/dist/modules/catalog/api/categories/bulk-create/route.js.map +7 -0
- package/dist/modules/catalog/api/categories/route.js +56 -8
- package/dist/modules/catalog/api/categories/route.js.map +2 -2
- package/dist/modules/catalog/api/products/bulk-create/route.js +124 -0
- package/dist/modules/catalog/api/products/bulk-create/route.js.map +7 -0
- package/dist/modules/catalog/api/products/route.js +55 -31
- package/dist/modules/catalog/api/products/route.js.map +3 -3
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +3 -6
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/create/page.js +12 -4
- package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
- package/dist/modules/catalog/commands/categories.js +1 -0
- package/dist/modules/catalog/commands/categories.js.map +2 -2
- package/dist/modules/catalog/commands/products.js +5 -2
- package/dist/modules/catalog/commands/products.js.map +2 -2
- package/dist/modules/catalog/components/PriceKindSettings.js +5 -19
- package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
- package/dist/modules/catalog/components/prices/PriceScopeSelectors.js +2 -2
- package/dist/modules/catalog/components/prices/PriceScopeSelectors.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductUomSection.js +26 -29
- package/dist/modules/catalog/components/products/ProductUomSection.js.map +2 -2
- package/dist/modules/catalog/components/products/productForm.js +3 -2
- package/dist/modules/catalog/components/products/productForm.js.map +2 -2
- package/dist/modules/catalog/data/validators.js +15 -0
- package/dist/modules/catalog/data/validators.js.map +2 -2
- package/dist/modules/catalog/di.js +3 -2
- package/dist/modules/catalog/di.js.map +2 -2
- package/dist/modules/catalog/events.js +9 -3
- package/dist/modules/catalog/events.js.map +2 -2
- package/dist/modules/catalog/lib/bulkCreateCategories.js +237 -0
- package/dist/modules/catalog/lib/bulkCreateCategories.js.map +7 -0
- package/dist/modules/catalog/lib/bulkCreateCheckpoint.js +82 -0
- package/dist/modules/catalog/lib/bulkCreateCheckpoint.js.map +7 -0
- package/dist/modules/catalog/lib/bulkCreateMutationGuards.js +39 -0
- package/dist/modules/catalog/lib/bulkCreateMutationGuards.js.map +7 -0
- package/dist/modules/catalog/lib/bulkCreateProducts.js +241 -0
- package/dist/modules/catalog/lib/bulkCreateProducts.js.map +7 -0
- package/dist/modules/catalog/lib/bulkDelete.js +10 -11
- package/dist/modules/catalog/lib/bulkDelete.js.map +2 -2
- package/dist/modules/catalog/lib/catalogQueue.js +14 -0
- package/dist/modules/catalog/lib/catalogQueue.js.map +7 -0
- package/dist/modules/catalog/lib/currencyOptions.js +25 -0
- package/dist/modules/catalog/lib/currencyOptions.js.map +7 -0
- package/dist/modules/catalog/lib/productSearch.js +8 -0
- package/dist/modules/catalog/lib/productSearch.js.map +7 -0
- package/dist/modules/catalog/lib/seeds.js +2 -42
- package/dist/modules/catalog/lib/seeds.js.map +2 -2
- package/dist/modules/catalog/lib/unitLabels.js +53 -0
- package/dist/modules/catalog/lib/unitLabels.js.map +7 -0
- package/dist/modules/catalog/migrations/Migration20260914120000.js +29 -0
- package/dist/modules/catalog/migrations/Migration20260914120000.js.map +7 -0
- package/dist/modules/catalog/migrations/Migration20260914120100.js +28 -0
- package/dist/modules/catalog/migrations/Migration20260914120100.js.map +7 -0
- package/dist/modules/catalog/workers/catalog-category-bulk-create.js +40 -0
- package/dist/modules/catalog/workers/catalog-category-bulk-create.js.map +7 -0
- package/dist/modules/catalog/workers/catalog-product-bulk-create.js +40 -0
- package/dist/modules/catalog/workers/catalog-product-bulk-create.js.map +7 -0
- package/dist/modules/communication_channels/acl.js +8 -0
- package/dist/modules/communication_channels/acl.js.map +2 -2
- package/dist/modules/communication_channels/api/get/me/channels/route.js +4 -0
- package/dist/modules/communication_channels/api/get/me/channels/route.js.map +2 -2
- package/dist/modules/communication_channels/api/get/oauth/[provider]/callback/route.js +22 -0
- package/dist/modules/communication_channels/api/get/oauth/[provider]/callback/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/channels/[id]/import-history/route.js +4 -4
- package/dist/modules/communication_channels/api/post/channels/[id]/import-history/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js +2 -1
- package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/test-seed/route.js +90 -20
- package/dist/modules/communication_channels/api/post/test-seed/route.js.map +3 -3
- package/dist/modules/communication_channels/api/put/channels/[id]/visibility/route.js +137 -0
- package/dist/modules/communication_channels/api/put/channels/[id]/visibility/route.js.map +7 -0
- package/dist/modules/communication_channels/backend/profile/communication-channels/page.js +175 -107
- package/dist/modules/communication_channels/backend/profile/communication-channels/page.js.map +2 -2
- package/dist/modules/communication_channels/commands/ingest-inbound-message.js +2 -1
- package/dist/modules/communication_channels/commands/ingest-inbound-message.js.map +2 -2
- package/dist/modules/communication_channels/commands/set-channel-visibility.js +88 -0
- package/dist/modules/communication_channels/commands/set-channel-visibility.js.map +7 -0
- package/dist/modules/communication_channels/data/enrichers.js +18 -9
- package/dist/modules/communication_channels/data/enrichers.js.map +2 -2
- package/dist/modules/communication_channels/data/entities.js +4 -0
- package/dist/modules/communication_channels/data/entities.js.map +2 -2
- package/dist/modules/communication_channels/di.js +9 -1
- package/dist/modules/communication_channels/di.js.map +2 -2
- package/dist/modules/communication_channels/events.js +7 -0
- package/dist/modules/communication_channels/events.js.map +2 -2
- package/dist/modules/communication_channels/index.js +1 -1
- package/dist/modules/communication_channels/index.js.map +1 -1
- package/dist/modules/communication_channels/lib/access-control.js +2 -1
- package/dist/modules/communication_channels/lib/access-control.js.map +2 -2
- package/dist/modules/communication_channels/lib/channel-thread-access.js +60 -0
- package/dist/modules/communication_channels/lib/channel-thread-access.js.map +7 -0
- package/dist/modules/communication_channels/lib/credential-refresh.js +11 -2
- package/dist/modules/communication_channels/lib/credential-refresh.js.map +2 -2
- package/dist/modules/communication_channels/lib/inbound-message-origin.js +18 -0
- package/dist/modules/communication_channels/lib/inbound-message-origin.js.map +7 -0
- package/dist/modules/communication_channels/lib/oauth-state.js +37 -0
- package/dist/modules/communication_channels/lib/oauth-state.js.map +2 -2
- package/dist/modules/communication_channels/lib/outbound-delivery-intent.js +12 -0
- package/dist/modules/communication_channels/lib/outbound-delivery-intent.js.map +7 -0
- package/dist/modules/communication_channels/lib/send-as-user.js +1 -1
- package/dist/modules/communication_channels/lib/send-as-user.js.map +2 -2
- package/dist/modules/communication_channels/migrations/Migration20260825141000_communication_channels.js +14 -0
- package/dist/modules/communication_channels/migrations/Migration20260825141000_communication_channels.js.map +7 -0
- package/dist/modules/communication_channels/setup.js +6 -2
- package/dist/modules/communication_channels/setup.js.map +2 -2
- package/dist/modules/communication_channels/subscribers/outbound-bridge.js +8 -2
- package/dist/modules/communication_channels/subscribers/outbound-bridge.js.map +2 -2
- package/dist/modules/communication_channels/workers/gmail-history-sync.js +1 -1
- package/dist/modules/communication_channels/workers/gmail-history-sync.js.map +2 -2
- package/dist/modules/communication_channels/workers/poll-channel.js +1 -1
- package/dist/modules/communication_channels/workers/poll-channel.js.map +2 -2
- package/dist/modules/communication_channels/workers/reaction-processor.js +2 -2
- package/dist/modules/communication_channels/workers/reaction-processor.js.map +2 -2
- package/dist/modules/configs/api/upgrade-actions/route.js +2 -1
- package/dist/modules/configs/api/upgrade-actions/route.js.map +2 -2
- package/dist/modules/configs/cli.js +2 -2
- package/dist/modules/configs/cli.js.map +2 -2
- package/dist/modules/configs/lib/upgrade-actions.js +28 -6
- package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
- package/dist/modules/configs/services/upgradeActionsService.js +44 -30
- package/dist/modules/configs/services/upgradeActionsService.js.map +2 -2
- package/dist/modules/currencies/api/currencies/route.js +11 -5
- package/dist/modules/currencies/api/currencies/route.js.map +2 -2
- package/dist/modules/currencies/api/exchange-rates/route.js +11 -5
- package/dist/modules/currencies/api/exchange-rates/route.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/users/[id]/sessions/[sessionId].js +78 -0
- package/dist/modules/customer_accounts/api/admin/users/[id]/sessions/[sessionId].js.map +7 -0
- package/dist/modules/customer_groups/acl.js +14 -0
- package/dist/modules/customer_groups/acl.js.map +7 -0
- package/dist/modules/customer_groups/api/customer-groups/[id]/terms/route.js +266 -0
- package/dist/modules/customer_groups/api/customer-groups/[id]/terms/route.js.map +7 -0
- package/dist/modules/customer_groups/api/customer-groups/crud.js +473 -0
- package/dist/modules/customer_groups/api/customer-groups/crud.js.map +7 -0
- package/dist/modules/customer_groups/api/customer-groups/explain-terms/route.js +143 -0
- package/dist/modules/customer_groups/api/customer-groups/explain-terms/route.js.map +7 -0
- package/dist/modules/customer_groups/api/customer-groups/memberships/crud.js +383 -0
- package/dist/modules/customer_groups/api/customer-groups/memberships/crud.js.map +7 -0
- package/dist/modules/customer_groups/api/customer-groups/memberships/route.js +66 -0
- package/dist/modules/customer_groups/api/customer-groups/memberships/route.js.map +7 -0
- package/dist/modules/customer_groups/api/customer-groups/price-kinds/route.js +90 -0
- package/dist/modules/customer_groups/api/customer-groups/price-kinds/route.js.map +7 -0
- package/dist/modules/customer_groups/api/customer-groups/reconcile/adopt/route.js +133 -0
- package/dist/modules/customer_groups/api/customer-groups/reconcile/adopt/route.js.map +7 -0
- package/dist/modules/customer_groups/api/customer-groups/reconcile/route.js +80 -0
- package/dist/modules/customer_groups/api/customer-groups/reconcile/route.js.map +7 -0
- package/dist/modules/customer_groups/api/customer-groups/reorder/route.js +127 -0
- package/dist/modules/customer_groups/api/customer-groups/reorder/route.js.map +7 -0
- package/dist/modules/customer_groups/api/customer-groups/route.js +62 -0
- package/dist/modules/customer_groups/api/customer-groups/route.js.map +7 -0
- package/dist/modules/customer_groups/api/openapi.js +27 -0
- package/dist/modules/customer_groups/api/openapi.js.map +7 -0
- package/dist/modules/customer_groups/backend/customer-groups/[id]/edit/page.js +328 -0
- package/dist/modules/customer_groups/backend/customer-groups/[id]/edit/page.js.map +7 -0
- package/dist/modules/customer_groups/backend/customer-groups/[id]/edit/page.meta.js +16 -0
- package/dist/modules/customer_groups/backend/customer-groups/[id]/edit/page.meta.js.map +7 -0
- package/dist/modules/customer_groups/backend/customer-groups/create/page.js +249 -0
- package/dist/modules/customer_groups/backend/customer-groups/create/page.js.map +7 -0
- package/dist/modules/customer_groups/backend/customer-groups/create/page.meta.js +27 -0
- package/dist/modules/customer_groups/backend/customer-groups/create/page.meta.js.map +7 -0
- package/dist/modules/customer_groups/backend/customer-groups/orphans/page.js +139 -0
- package/dist/modules/customer_groups/backend/customer-groups/orphans/page.js.map +7 -0
- package/dist/modules/customer_groups/backend/customer-groups/orphans/page.meta.js +16 -0
- package/dist/modules/customer_groups/backend/customer-groups/orphans/page.meta.js.map +7 -0
- package/dist/modules/customer_groups/backend/customer-groups/page.js +368 -0
- package/dist/modules/customer_groups/backend/customer-groups/page.js.map +7 -0
- package/dist/modules/customer_groups/backend/customer-groups/page.meta.js +15 -0
- package/dist/modules/customer_groups/backend/customer-groups/page.meta.js.map +7 -0
- package/dist/modules/customer_groups/cli.js +72 -0
- package/dist/modules/customer_groups/cli.js.map +7 -0
- package/dist/modules/customer_groups/commands/reorderGroups.js +96 -0
- package/dist/modules/customer_groups/commands/reorderGroups.js.map +7 -0
- package/dist/modules/customer_groups/components/CustomerGroupDefaultField.js +41 -0
- package/dist/modules/customer_groups/components/CustomerGroupDefaultField.js.map +7 -0
- package/dist/modules/customer_groups/components/CustomerGroupParentField.js +156 -0
- package/dist/modules/customer_groups/components/CustomerGroupParentField.js.map +7 -0
- package/dist/modules/customer_groups/components/CustomerGroupTermsPriceKindField.js +94 -0
- package/dist/modules/customer_groups/components/CustomerGroupTermsPriceKindField.js.map +7 -0
- package/dist/modules/customer_groups/components/CustomerGroupTermsSection.js +199 -0
- package/dist/modules/customer_groups/components/CustomerGroupTermsSection.js.map +7 -0
- package/dist/modules/customer_groups/components/GroupPickerField.js +116 -0
- package/dist/modules/customer_groups/components/GroupPickerField.js.map +7 -0
- package/dist/modules/customer_groups/components/OrphanBanner.js +75 -0
- package/dist/modules/customer_groups/components/OrphanBanner.js.map +7 -0
- package/dist/modules/customer_groups/components/customerGroupTree.js +57 -0
- package/dist/modules/customer_groups/components/customerGroupTree.js.map +7 -0
- package/dist/modules/customer_groups/data/entities.js +226 -0
- package/dist/modules/customer_groups/data/entities.js.map +7 -0
- package/dist/modules/customer_groups/data/validators.js +153 -0
- package/dist/modules/customer_groups/data/validators.js.map +7 -0
- package/dist/modules/customer_groups/di.js +20 -0
- package/dist/modules/customer_groups/di.js.map +7 -0
- package/dist/modules/customer_groups/events.js +22 -0
- package/dist/modules/customer_groups/events.js.map +7 -0
- package/dist/modules/customer_groups/index.js +15 -0
- package/dist/modules/customer_groups/index.js.map +7 -0
- package/dist/modules/customer_groups/lib/createConflictRecheck.js +29 -0
- package/dist/modules/customer_groups/lib/createConflictRecheck.js.map +7 -0
- package/dist/modules/customer_groups/lib/customerScope.js +81 -0
- package/dist/modules/customer_groups/lib/customerScope.js.map +7 -0
- package/dist/modules/customer_groups/lib/groupEvents.js +31 -0
- package/dist/modules/customer_groups/lib/groupEvents.js.map +7 -0
- package/dist/modules/customer_groups/lib/priceKindScope.js +50 -0
- package/dist/modules/customer_groups/lib/priceKindScope.js.map +7 -0
- package/dist/modules/customer_groups/lib/reconcile.js +161 -0
- package/dist/modules/customer_groups/lib/reconcile.js.map +7 -0
- package/dist/modules/customer_groups/migrations/Migration20260922095316_customer_groups.js +27 -0
- package/dist/modules/customer_groups/migrations/Migration20260922095316_customer_groups.js.map +7 -0
- package/dist/modules/customer_groups/migrations/Migration20260922103033_customer_groups.js +19 -0
- package/dist/modules/customer_groups/migrations/Migration20260922103033_customer_groups.js.map +7 -0
- package/dist/modules/customer_groups/migrations/Migration20260922105444_customer_groups.js +19 -0
- package/dist/modules/customer_groups/migrations/Migration20260922105444_customer_groups.js.map +7 -0
- package/dist/modules/customer_groups/migrations/Migration20260923193330_customer_groups.js +19 -0
- package/dist/modules/customer_groups/migrations/Migration20260923193330_customer_groups.js.map +7 -0
- package/dist/modules/customer_groups/migrations/Migration20260929083000_customer_groups.js +20 -0
- package/dist/modules/customer_groups/migrations/Migration20260929083000_customer_groups.js.map +7 -0
- package/dist/modules/customer_groups/services/customerGroupsService.js +190 -0
- package/dist/modules/customer_groups/services/customerGroupsService.js.map +7 -0
- package/dist/modules/customer_groups/setup.js +13 -0
- package/dist/modules/customer_groups/setup.js.map +7 -0
- package/dist/modules/customer_groups/widgets/injection/group-picker-field/widget.js +31 -0
- package/dist/modules/customer_groups/widgets/injection/group-picker-field/widget.js.map +7 -0
- package/dist/modules/customer_groups/widgets/injection/person-groups-explain-terms.js +166 -0
- package/dist/modules/customer_groups/widgets/injection/person-groups-explain-terms.js.map +7 -0
- package/dist/modules/customer_groups/widgets/injection/person-groups-tab/widget.js +17 -0
- package/dist/modules/customer_groups/widgets/injection/person-groups-tab/widget.js.map +7 -0
- package/dist/modules/customer_groups/widgets/injection/person-groups-tab.js +457 -0
- package/dist/modules/customer_groups/widgets/injection/person-groups-tab.js.map +7 -0
- package/dist/modules/customer_groups/widgets/injection-table.js +33 -0
- package/dist/modules/customer_groups/widgets/injection-table.js.map +7 -0
- package/dist/modules/customers/acl.js +13 -0
- package/dist/modules/customers/acl.js.map +2 -2
- package/dist/modules/customers/api/activities/route.js +9 -1
- package/dist/modules/customers/api/activities/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/people/route.js +2 -1
- package/dist/modules/customers/api/companies/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/route.js +19 -7
- package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/companies/route.js +2 -1
- package/dist/modules/customers/api/deals/[id]/companies/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/people/route.js +2 -1
- package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/deals/map/route.js +7 -2
- package/dist/modules/customers/api/deals/map/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/context.js +2 -1
- package/dist/modules/customers/api/dictionaries/context.js.map +2 -2
- package/dist/modules/customers/api/entity-roles-factory.js +3 -2
- package/dist/modules/customers/api/entity-roles-factory.js.map +2 -2
- package/dist/modules/customers/api/interactions/[id]/visibility/route.js +2 -1
- package/dist/modules/customers/api/interactions/[id]/visibility/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/cancel/route.js +2 -1
- package/dist/modules/customers/api/interactions/cancel/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/complete/route.js +2 -1
- package/dist/modules/customers/api/interactions/complete/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/conflicts/route.js +10 -6
- package/dist/modules/customers/api/interactions/conflicts/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/counts/route.js +24 -4
- package/dist/modules/customers/api/interactions/counts/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/route.js +31 -8
- package/dist/modules/customers/api/interactions/route.js.map +2 -2
- package/dist/modules/customers/api/labels/assign/route.js +2 -1
- package/dist/modules/customers/api/labels/assign/route.js.map +2 -2
- package/dist/modules/customers/api/labels/route.js +3 -2
- package/dist/modules/customers/api/labels/route.js.map +2 -2
- package/dist/modules/customers/api/labels/unassign/route.js +2 -1
- package/dist/modules/customers/api/labels/unassign/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/context.js +7 -2
- package/dist/modules/customers/api/people/[id]/companies/context.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/email-share/route.js +218 -0
- package/dist/modules/customers/api/people/[id]/email-share/route.js.map +7 -0
- package/dist/modules/customers/api/people/[id]/email-threads/route.js +11 -2
- package/dist/modules/customers/api/people/[id]/email-threads/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/emails/route.js +2 -1
- package/dist/modules/customers/api/people/[id]/emails/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/route.js +20 -19
- package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/people/check-phone/route.js +2 -1
- package/dist/modules/customers/api/people/check-phone/route.js.map +2 -2
- package/dist/modules/customers/api/pipeline-stages/reorder/route.js +3 -2
- package/dist/modules/customers/api/pipeline-stages/reorder/route.js.map +2 -2
- package/dist/modules/customers/api/pipeline-stages/route.js +3 -3
- package/dist/modules/customers/api/pipeline-stages/route.js.map +2 -2
- package/dist/modules/customers/api/pipelines/route.js +3 -3
- package/dist/modules/customers/api/pipelines/route.js.map +2 -2
- package/dist/modules/customers/api/settings/address-format/route.js +2 -1
- package/dist/modules/customers/api/settings/address-format/route.js.map +2 -2
- package/dist/modules/customers/api/settings/dictionary-sort-modes/route.js +2 -1
- package/dist/modules/customers/api/settings/dictionary-sort-modes/route.js.map +2 -2
- package/dist/modules/customers/api/settings/stuck-threshold/route.js +2 -1
- package/dist/modules/customers/api/settings/stuck-threshold/route.js.map +2 -2
- package/dist/modules/customers/api/tags/assign/route.js +2 -1
- package/dist/modules/customers/api/tags/assign/route.js.map +2 -2
- package/dist/modules/customers/api/tags/unassign/route.js +2 -1
- package/dist/modules/customers/api/tags/unassign/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/[id]/page.js +4 -2
- package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js +6 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +6 -1
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/components/ReassignOwnerDialog.js +93 -0
- package/dist/modules/customers/backend/customers/deals/components/ReassignOwnerDialog.js.map +7 -0
- package/dist/modules/customers/backend/customers/deals/page.js +111 -1
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/[id]/page.js +4 -2
- package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
- package/dist/modules/customers/commands/addresses.js +83 -15
- package/dist/modules/customers/commands/addresses.js.map +2 -2
- package/dist/modules/customers/commands/companies.js +24 -5
- package/dist/modules/customers/commands/companies.js.map +2 -2
- package/dist/modules/customers/commands/emailConversationShares.js +177 -0
- package/dist/modules/customers/commands/emailConversationShares.js.map +7 -0
- package/dist/modules/customers/commands/index.js +1 -0
- package/dist/modules/customers/commands/index.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js +48 -23
- package/dist/modules/customers/commands/interactions.js.map +3 -3
- package/dist/modules/customers/commands/people.js +3 -2
- package/dist/modules/customers/commands/people.js.map +2 -2
- package/dist/modules/customers/commands/shared.js +4 -0
- package/dist/modules/customers/commands/shared.js.map +2 -2
- package/dist/modules/customers/components/calendar/types.js.map +1 -1
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js +3 -11
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
- package/dist/modules/customers/components/detail/DealForm.js +66 -2
- package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
- package/dist/modules/customers/components/detail/DealOwnerSelect.js +96 -0
- package/dist/modules/customers/components/detail/DealOwnerSelect.js.map +7 -0
- package/dist/modules/customers/components/detail/DealsSection.js +8 -14
- package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonEmailShareControl.js +190 -0
- package/dist/modules/customers/components/detail/PersonEmailShareControl.js.map +7 -0
- package/dist/modules/customers/components/detail/PersonEmailThreadsTab.js +17 -0
- package/dist/modules/customers/components/detail/PersonEmailThreadsTab.js.map +2 -2
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +5 -2
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/create/CreateDealForm.js +19 -0
- package/dist/modules/customers/components/detail/create/CreateDealForm.js.map +2 -2
- package/dist/modules/customers/components/detail/create/DealDetailsFields.js +11 -0
- package/dist/modules/customers/components/detail/create/DealDetailsFields.js.map +2 -2
- package/dist/modules/customers/components/detail/create/DealSectionCard.js +2 -2
- package/dist/modules/customers/components/detail/create/DealSectionCard.js.map +2 -2
- package/dist/modules/customers/components/detail/create/dealFormTypes.js +1 -0
- package/dist/modules/customers/components/detail/create/dealFormTypes.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +1 -1
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
- package/dist/modules/customers/components/formConfig.js +2 -0
- package/dist/modules/customers/components/formConfig.js.map +2 -2
- package/dist/modules/customers/components/linking/LinkEntityDialog.js +8 -0
- package/dist/modules/customers/components/linking/LinkEntityDialog.js.map +2 -2
- package/dist/modules/customers/data/enrichers.js +40 -2
- package/dist/modules/customers/data/enrichers.js.map +2 -2
- package/dist/modules/customers/data/entities.js +56 -0
- package/dist/modules/customers/data/entities.js.map +2 -2
- package/dist/modules/customers/data/validators.js +11 -0
- package/dist/modules/customers/data/validators.js.map +2 -2
- package/dist/modules/customers/events.js +6 -1
- package/dist/modules/customers/events.js.map +2 -2
- package/dist/modules/customers/lib/assignableStaff.js +14 -0
- package/dist/modules/customers/lib/assignableStaff.js.map +2 -2
- package/dist/modules/customers/lib/calendar/editorPayload.js +17 -13
- package/dist/modules/customers/lib/calendar/editorPayload.js.map +2 -2
- package/dist/modules/customers/lib/calendar/mapItem.js +1 -0
- package/dist/modules/customers/lib/calendar/mapItem.js.map +2 -2
- package/dist/modules/customers/lib/conversationShares.js +126 -0
- package/dist/modules/customers/lib/conversationShares.js.map +7 -0
- package/dist/modules/customers/lib/dealsOrganizationScope.js +5 -3
- package/dist/modules/customers/lib/dealsOrganizationScope.js.map +2 -2
- package/dist/modules/customers/lib/interactionRequestContext.js +2 -1
- package/dist/modules/customers/lib/interactionRequestContext.js.map +2 -2
- package/dist/modules/customers/lib/link-channel-message-handler.js +19 -9
- package/dist/modules/customers/lib/link-channel-message-handler.js.map +2 -2
- package/dist/modules/customers/lib/personDetailCacheTags.js +32 -0
- package/dist/modules/customers/lib/personDetailCacheTags.js.map +7 -0
- package/dist/modules/customers/lib/personEmailThreads.js +26 -5
- package/dist/modules/customers/lib/personEmailThreads.js.map +2 -2
- package/dist/modules/customers/lib/reassignDealOwner.js +25 -0
- package/dist/modules/customers/lib/reassignDealOwner.js.map +7 -0
- package/dist/modules/customers/lib/userNames.js +26 -0
- package/dist/modules/customers/lib/userNames.js.map +7 -0
- package/dist/modules/customers/lib/visibilityFilter.js +70 -2
- package/dist/modules/customers/lib/visibilityFilter.js.map +2 -2
- package/dist/modules/customers/migrations/Migration20260825120000_customers.js +18 -0
- package/dist/modules/customers/migrations/Migration20260825120000_customers.js.map +7 -0
- package/dist/modules/customers/migrations/Migration20260825140000_customers.js +27 -0
- package/dist/modules/customers/migrations/Migration20260825140000_customers.js.map +7 -0
- package/dist/modules/customers/setup.js +1 -0
- package/dist/modules/customers/setup.js.map +2 -2
- package/dist/modules/customers/subscribers/channel-visibility-changed.js +16 -0
- package/dist/modules/customers/subscribers/channel-visibility-changed.js.map +7 -0
- package/dist/modules/dashboards/api/widgets/data/batch/route.js +3 -8
- package/dist/modules/dashboards/api/widgets/data/batch/route.js.map +2 -2
- package/dist/modules/dashboards/api/widgets/data/route.js +10 -15
- package/dist/modules/dashboards/api/widgets/data/route.js.map +2 -2
- package/dist/modules/dashboards/lib/aggregations.js +1 -1
- package/dist/modules/dashboards/lib/aggregations.js.map +2 -2
- package/dist/modules/dashboards/lib/widgetScope.js +2 -7
- package/dist/modules/dashboards/lib/widgetScope.js.map +2 -2
- package/dist/modules/data_sync/api/runs/[id]/cancel.js +4 -1
- package/dist/modules/data_sync/api/runs/[id]/cancel.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +497 -329
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +248 -113
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +3 -3
- package/dist/modules/data_sync/components/useDataSyncRunAccess.js +17 -0
- package/dist/modules/data_sync/components/useDataSyncRunAccess.js.map +7 -0
- package/dist/modules/data_sync/lib/resume-point.js +21 -0
- package/dist/modules/data_sync/lib/resume-point.js.map +7 -0
- package/dist/modules/data_sync/lib/start-run.js +52 -2
- package/dist/modules/data_sync/lib/start-run.js.map +2 -2
- package/dist/modules/data_sync/lib/sync-run-service.js +22 -33
- package/dist/modules/data_sync/lib/sync-run-service.js.map +3 -3
- package/dist/modules/devices/api/[id]/route.js +3 -2
- package/dist/modules/devices/api/[id]/route.js.map +2 -2
- package/dist/modules/devices/api/admin/devices/route.js +2 -1
- package/dist/modules/devices/api/admin/devices/route.js.map +2 -2
- package/dist/modules/devices/api/route.js +2 -1
- package/dist/modules/devices/api/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/api/context.js +2 -1
- package/dist/modules/dictionaries/api/context.js.map +2 -2
- package/dist/modules/dictionaries/api/route.js +4 -0
- package/dist/modules/dictionaries/api/route.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionariesManager.js +101 -89
- package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
- package/dist/modules/dictionaries/data/validators.js +3 -1
- package/dist/modules/dictionaries/data/validators.js.map +2 -2
- package/dist/modules/directory/api/organization-branding/route.js +10 -1
- package/dist/modules/directory/api/organization-branding/route.js.map +2 -2
- package/dist/modules/directory/api/organizations/route.js +1 -1
- package/dist/modules/directory/api/organizations/route.js.map +1 -1
- package/dist/modules/directory/backend/directory/branding/page.js +17 -4
- package/dist/modules/directory/backend/directory/branding/page.js.map +3 -3
- package/dist/modules/directory/commands/organizations.js +136 -74
- package/dist/modules/directory/commands/organizations.js.map +2 -2
- package/dist/modules/directory/lib/hierarchy.js +19 -1
- package/dist/modules/directory/lib/hierarchy.js.map +2 -2
- package/dist/modules/directory/utils/organizationScope.js +66 -12
- package/dist/modules/directory/utils/organizationScope.js.map +2 -2
- package/dist/modules/directory/utils/organizationScopeFilter.js +7 -4
- package/dist/modules/directory/utils/organizationScopeFilter.js.map +2 -2
- package/dist/modules/directory/utils/organizationScopeGuard.js +6 -2
- package/dist/modules/directory/utils/organizationScopeGuard.js.map +2 -2
- package/dist/modules/entities/api/encryption.js +68 -25
- package/dist/modules/entities/api/encryption.js.map +2 -2
- package/dist/modules/entities/api/records.js +9 -8
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/cli.js +33 -22
- package/dist/modules/entities/cli.js.map +2 -2
- package/dist/modules/entities/data/entities.js +8 -0
- package/dist/modules/entities/data/entities.js.map +2 -2
- package/dist/modules/entities/lib/definition-scope.js +3 -1
- package/dist/modules/entities/lib/definition-scope.js.map +2 -2
- package/dist/modules/entities/lib/encryption-maps.js +117 -0
- package/dist/modules/entities/lib/encryption-maps.js.map +7 -0
- package/dist/modules/entities/lib/helpers.js +30 -6
- package/dist/modules/entities/lib/helpers.js.map +2 -2
- package/dist/modules/entities/migrations/Migration20260910120000.js +17 -0
- package/dist/modules/entities/migrations/Migration20260910120000.js.map +7 -0
- package/dist/modules/entities/migrations/Migration20261004120000_encryption_map_scope_uniqueness.js +130 -0
- package/dist/modules/entities/migrations/Migration20261004120000_encryption_map_scope_uniqueness.js.map +7 -0
- package/dist/modules/eudr/api/dashboard/widgets/compliance-overview/route.js +2 -1
- package/dist/modules/eudr/api/dashboard/widgets/compliance-overview/route.js.map +2 -2
- package/dist/modules/eudr/api/plots/import/route.js +2 -1
- package/dist/modules/eudr/api/plots/import/route.js.map +2 -2
- package/dist/modules/eudr/api/product-mappings/suggestions/apply/route.js +2 -1
- package/dist/modules/eudr/api/product-mappings/suggestions/apply/route.js.map +2 -2
- package/dist/modules/eudr/api/product-mappings/suggestions/route.js +2 -1
- package/dist/modules/eudr/api/product-mappings/suggestions/route.js.map +2 -2
- package/dist/modules/eudr/api/reports/annual/route.js +2 -1
- package/dist/modules/eudr/api/reports/annual/route.js.map +2 -2
- package/dist/modules/eudr/api/statements/[id]/export/route.js +2 -1
- package/dist/modules/eudr/api/statements/[id]/export/route.js.map +2 -2
- package/dist/modules/eudr/api/statements/[id]/readiness/route.js +2 -1
- package/dist/modules/eudr/api/statements/[id]/readiness/route.js.map +2 -2
- package/dist/modules/eudr/api/suppliers/compliance/route.js +2 -1
- package/dist/modules/eudr/api/suppliers/compliance/route.js.map +2 -2
- package/dist/modules/feature_toggles/commands/global.js +13 -13
- package/dist/modules/feature_toggles/commands/global.js.map +2 -2
- package/dist/modules/feature_toggles/lib/feature-flag-check.js +8 -2
- package/dist/modules/feature_toggles/lib/feature-flag-check.js.map +2 -2
- package/dist/modules/forms/acl.js +14 -0
- package/dist/modules/forms/acl.js.map +7 -0
- package/dist/modules/forms/api/[id]/analytics/route.js +113 -0
- package/dist/modules/forms/api/[id]/analytics/route.js.map +7 -0
- package/dist/modules/forms/api/[id]/distributions/route.js +176 -0
- package/dist/modules/forms/api/[id]/distributions/route.js.map +7 -0
- package/dist/modules/forms/api/[id]/route.js +225 -0
- package/dist/modules/forms/api/[id]/route.js.map +7 -0
- package/dist/modules/forms/api/[id]/run/context/route.js +115 -0
- package/dist/modules/forms/api/[id]/run/context/route.js.map +7 -0
- package/dist/modules/forms/api/[id]/run/submissions/route.js +109 -0
- package/dist/modules/forms/api/[id]/run/submissions/route.js.map +7 -0
- package/dist/modules/forms/api/[id]/submissions/route.js +83 -0
- package/dist/modules/forms/api/[id]/submissions/route.js.map +7 -0
- package/dist/modules/forms/api/[id]/theme-logo/route.js +117 -0
- package/dist/modules/forms/api/[id]/theme-logo/route.js.map +7 -0
- package/dist/modules/forms/api/[id]/versions/[versionId]/diff/route.js +125 -0
- package/dist/modules/forms/api/[id]/versions/[versionId]/diff/route.js.map +7 -0
- package/dist/modules/forms/api/[id]/versions/[versionId]/publish/route.js +99 -0
- package/dist/modules/forms/api/[id]/versions/[versionId]/publish/route.js.map +7 -0
- package/dist/modules/forms/api/[id]/versions/[versionId]/route.js +176 -0
- package/dist/modules/forms/api/[id]/versions/[versionId]/route.js.map +7 -0
- package/dist/modules/forms/api/[id]/versions/fork/route.js +92 -0
- package/dist/modules/forms/api/[id]/versions/fork/route.js.map +7 -0
- package/dist/modules/forms/api/attachment-helpers.js +111 -0
- package/dist/modules/forms/api/attachment-helpers.js.map +7 -0
- package/dist/modules/forms/api/by-key/[key]/active/route.js +140 -0
- package/dist/modules/forms/api/by-key/[key]/active/route.js.map +7 -0
- package/dist/modules/forms/api/distributions/[distributionId]/invitations/[invitationId]/route.js +84 -0
- package/dist/modules/forms/api/distributions/[distributionId]/invitations/[invitationId]/route.js.map +7 -0
- package/dist/modules/forms/api/distributions/[distributionId]/invitations/[invitationId]/send/route.js +88 -0
- package/dist/modules/forms/api/distributions/[distributionId]/invitations/[invitationId]/send/route.js.map +7 -0
- package/dist/modules/forms/api/distributions/[distributionId]/invitations/route.js +183 -0
- package/dist/modules/forms/api/distributions/[distributionId]/invitations/route.js.map +7 -0
- package/dist/modules/forms/api/distributions/[distributionId]/route.js +191 -0
- package/dist/modules/forms/api/distributions/[distributionId]/route.js.map +7 -0
- package/dist/modules/forms/api/form-submissions/[id]/attachments/route.js +91 -0
- package/dist/modules/forms/api/form-submissions/[id]/attachments/route.js.map +7 -0
- package/dist/modules/forms/api/form-submissions/[id]/resume-token/route.js +110 -0
- package/dist/modules/forms/api/form-submissions/[id]/resume-token/route.js.map +7 -0
- package/dist/modules/forms/api/form-submissions/[id]/route.js +146 -0
- package/dist/modules/forms/api/form-submissions/[id]/route.js.map +7 -0
- package/dist/modules/forms/api/form-submissions/[id]/submit/route.js +74 -0
- package/dist/modules/forms/api/form-submissions/[id]/submit/route.js.map +7 -0
- package/dist/modules/forms/api/form-submissions/by-subject/[subject_type]/[subject_id]/route.js +76 -0
- package/dist/modules/forms/api/form-submissions/by-subject/[subject_type]/[subject_id]/route.js.map +7 -0
- package/dist/modules/forms/api/form-submissions/route.js +113 -0
- package/dist/modules/forms/api/form-submissions/route.js.map +7 -0
- package/dist/modules/forms/api/helpers.js +124 -0
- package/dist/modules/forms/api/helpers.js.map +7 -0
- package/dist/modules/forms/api/public/distributions/[slug]/embed-policy/route.js +47 -0
- package/dist/modules/forms/api/public/distributions/[slug]/embed-policy/route.js.map +7 -0
- package/dist/modules/forms/api/public/distributions/[slug]/route.js +81 -0
- package/dist/modules/forms/api/public/distributions/[slug]/route.js.map +7 -0
- package/dist/modules/forms/api/public/embed-loader/route.js +116 -0
- package/dist/modules/forms/api/public/embed-loader/route.js.map +7 -0
- package/dist/modules/forms/api/public/invitations/[token]/route.js +87 -0
- package/dist/modules/forms/api/public/invitations/[token]/route.js.map +7 -0
- package/dist/modules/forms/api/public/rate-limit.js +54 -0
- package/dist/modules/forms/api/public/rate-limit.js.map +7 -0
- package/dist/modules/forms/api/public/start/route.js +142 -0
- package/dist/modules/forms/api/public/start/route.js.map +7 -0
- package/dist/modules/forms/api/public/submissions/[id]/attachments/[attachmentId]/route.js +67 -0
- package/dist/modules/forms/api/public/submissions/[id]/attachments/[attachmentId]/route.js.map +7 -0
- package/dist/modules/forms/api/public/submissions/[id]/attachments/route.js +85 -0
- package/dist/modules/forms/api/public/submissions/[id]/attachments/route.js.map +7 -0
- package/dist/modules/forms/api/public/submissions/[id]/pdf/route.js +72 -0
- package/dist/modules/forms/api/public/submissions/[id]/pdf/route.js.map +7 -0
- package/dist/modules/forms/api/public/submissions/[id]/route.js +154 -0
- package/dist/modules/forms/api/public/submissions/[id]/route.js.map +7 -0
- package/dist/modules/forms/api/public/submissions/[id]/submit/route.js +127 -0
- package/dist/modules/forms/api/public/submissions/[id]/submit/route.js.map +7 -0
- package/dist/modules/forms/api/route.js +216 -0
- package/dist/modules/forms/api/route.js.map +7 -0
- package/dist/modules/forms/api/runtime-helpers.js +149 -0
- package/dist/modules/forms/api/runtime-helpers.js.map +7 -0
- package/dist/modules/forms/api/subjects/[subjectType]/[subjectId]/consents/route.js +137 -0
- package/dist/modules/forms/api/subjects/[subjectType]/[subjectId]/consents/route.js.map +7 -0
- package/dist/modules/forms/api/subjects/[subjectType]/[subjectId]/export/route.js +101 -0
- package/dist/modules/forms/api/subjects/[subjectType]/[subjectId]/export/route.js.map +7 -0
- package/dist/modules/forms/api/submissions/[submissionId]/access-audit/route.js +76 -0
- package/dist/modules/forms/api/submissions/[submissionId]/access-audit/route.js.map +7 -0
- package/dist/modules/forms/api/submissions/[submissionId]/actors/[actorId]/route.js +56 -0
- package/dist/modules/forms/api/submissions/[submissionId]/actors/[actorId]/route.js.map +7 -0
- package/dist/modules/forms/api/submissions/[submissionId]/actors/route.js +76 -0
- package/dist/modules/forms/api/submissions/[submissionId]/actors/route.js.map +7 -0
- package/dist/modules/forms/api/submissions/[submissionId]/anonymize/route.js +107 -0
- package/dist/modules/forms/api/submissions/[submissionId]/anonymize/route.js.map +7 -0
- package/dist/modules/forms/api/submissions/[submissionId]/attachments/[attachmentId]/route.js +73 -0
- package/dist/modules/forms/api/submissions/[submissionId]/attachments/[attachmentId]/route.js.map +7 -0
- package/dist/modules/forms/api/submissions/[submissionId]/export/route.js +90 -0
- package/dist/modules/forms/api/submissions/[submissionId]/export/route.js.map +7 -0
- package/dist/modules/forms/api/submissions/[submissionId]/pdf/route.js +91 -0
- package/dist/modules/forms/api/submissions/[submissionId]/pdf/route.js.map +7 -0
- package/dist/modules/forms/api/submissions/[submissionId]/reopen/route.js +55 -0
- package/dist/modules/forms/api/submissions/[submissionId]/reopen/route.js.map +7 -0
- package/dist/modules/forms/api/submissions/[submissionId]/revisions/route.js +61 -0
- package/dist/modules/forms/api/submissions/[submissionId]/revisions/route.js.map +7 -0
- package/dist/modules/forms/api/submissions/[submissionId]/route.js +75 -0
- package/dist/modules/forms/api/submissions/[submissionId]/route.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/FormStudio.js +2811 -0
- package/dist/modules/forms/backend/forms/[id]/FormStudio.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/analytics/page.js +214 -0
- package/dist/modules/forms/backend/forms/[id]/analytics/page.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/analytics/page.meta.js +19 -0
- package/dist/modules/forms/backend/forms/[id]/analytics/page.meta.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/distributions/page.js +12 -0
- package/dist/modules/forms/backend/forms/[id]/distributions/page.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/distributions/page.meta.js +19 -0
- package/dist/modules/forms/backend/forms/[id]/distributions/page.meta.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/history/page.js +152 -0
- package/dist/modules/forms/backend/forms/[id]/history/page.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/history/page.meta.js +15 -0
- package/dist/modules/forms/backend/forms/[id]/history/page.meta.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/page.js +13 -0
- package/dist/modules/forms/backend/forms/[id]/page.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/page.meta.js +15 -0
- package/dist/modules/forms/backend/forms/[id]/page.meta.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/YesNoRow.js +51 -0
- package/dist/modules/forms/backend/forms/[id]/studio/YesNoRow.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/autosave-guard.js +21 -0
- package/dist/modules/forms/backend/forms/[id]/studio/autosave-guard.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/DragOverlayCard.js +18 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/DragOverlayCard.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/DropIndicator.js +41 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/DropIndicator.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/FieldRow.js +277 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/FieldRow.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/FormCanvas.js +196 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/FormCanvas.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/GridSlot.js +151 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/GridSlot.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/SectionContainer.js +340 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/SectionContainer.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/grid-collision.js +24 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/grid-collision.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/keyboard-coordinates.js +91 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/keyboard-coordinates.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/overlay-size.js +11 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/overlay-size.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/resize-math.js +27 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/resize-math.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/row-layout.js +80 -0
- package/dist/modules/forms/backend/forms/[id]/studio/canvas/row-layout.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/logic/ConditionBuilder.js +210 -0
- package/dist/modules/forms/backend/forms/[id]/studio/logic/ConditionBuilder.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/logic/HiddenFieldsPanel.js +91 -0
- package/dist/modules/forms/backend/forms/[id]/studio/logic/HiddenFieldsPanel.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/logic/JumpsEditor.js +201 -0
- package/dist/modules/forms/backend/forms/[id]/studio/logic/JumpsEditor.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/logic/RecallTokenPicker.js +66 -0
- package/dist/modules/forms/backend/forms/[id]/studio/logic/RecallTokenPicker.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/logic/VariablesPanel.js +223 -0
- package/dist/modules/forms/backend/forms/[id]/studio/logic/VariablesPanel.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/logic/condition-model.js +151 -0
- package/dist/modules/forms/backend/forms/[id]/studio/logic/condition-model.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/lucide-icons.js +88 -0
- package/dist/modules/forms/backend/forms/[id]/studio/lucide-icons.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/palette/FormAppearancePanel.js +493 -0
- package/dist/modules/forms/backend/forms/[id]/studio/palette/FormAppearancePanel.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/palette/FormPalettePanel.js +44 -0
- package/dist/modules/forms/backend/forms/[id]/studio/palette/FormPalettePanel.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/palette/InputParametersTab.js +350 -0
- package/dist/modules/forms/backend/forms/[id]/studio/palette/InputParametersTab.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/palette/PaletteCard.js +40 -0
- package/dist/modules/forms/backend/forms/[id]/studio/palette/PaletteCard.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/palette/RolesEditor.js +202 -0
- package/dist/modules/forms/backend/forms/[id]/studio/palette/RolesEditor.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/palette/entries.js +66 -0
- package/dist/modules/forms/backend/forms/[id]/studio/palette/entries.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/preview/PreviewSurface.js +1200 -0
- package/dist/modules/forms/backend/forms/[id]/studio/preview/PreviewSurface.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/preview/ViewportFrame.js +34 -0
- package/dist/modules/forms/backend/forms/[id]/studio/preview/ViewportFrame.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/recall.js +76 -0
- package/dist/modules/forms/backend/forms/[id]/studio/recall.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/schema-helpers.js +1693 -0
- package/dist/modules/forms/backend/forms/[id]/studio/schema-helpers.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/style/BackgroundControl.js +127 -0
- package/dist/modules/forms/backend/forms/[id]/studio/style/BackgroundControl.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/style/ColorControl.js +181 -0
- package/dist/modules/forms/backend/forms/[id]/studio/style/ColorControl.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/style/contrast.js +75 -0
- package/dist/modules/forms/backend/forms/[id]/studio/style/contrast.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/style/presets.js +91 -0
- package/dist/modules/forms/backend/forms/[id]/studio/style/presets.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/type-label.js +11 -0
- package/dist/modules/forms/backend/forms/[id]/studio/type-label.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/types.js +1 -0
- package/dist/modules/forms/backend/forms/[id]/studio/types.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/undo-controller.js +43 -0
- package/dist/modules/forms/backend/forms/[id]/studio/undo-controller.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/FileConstraintsEditor.js +74 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/FileConstraintsEditor.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/GroupConfigEditor.js +134 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/GroupConfigEditor.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/LengthRangeEditor.js +61 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/LengthRangeEditor.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/MatrixColumnsEditor.js +149 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/MatrixColumnsEditor.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/MatrixRowsEditor.js +168 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/MatrixRowsEditor.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/MessageOverridesEditor.js +64 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/MessageOverridesEditor.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/NpsAnchorsEditor.js +52 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/NpsAnchorsEditor.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/NumberRangeEditor.js +59 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/NumberRangeEditor.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/OpinionIconSelect.js +31 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/OpinionIconSelect.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/PatternEditor.js +105 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/PatternEditor.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/RankingExhaustiveSwitch.js +15 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/RankingExhaustiveSwitch.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/SignatureConfigEditor.js +75 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/SignatureConfigEditor.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/ValidationPanel.js +293 -0
- package/dist/modules/forms/backend/forms/[id]/studio/validation/ValidationPanel.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/submissions/components/RowBadges.js +42 -0
- package/dist/modules/forms/backend/forms/[id]/submissions/components/RowBadges.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/submissions/components/SubmissionDrawer.js +473 -0
- package/dist/modules/forms/backend/forms/[id]/submissions/components/SubmissionDrawer.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/submissions/components/formSummary.js +9 -0
- package/dist/modules/forms/backend/forms/[id]/submissions/components/formSummary.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/submissions/page.js +205 -0
- package/dist/modules/forms/backend/forms/[id]/submissions/page.js.map +7 -0
- package/dist/modules/forms/backend/forms/[id]/submissions/page.meta.js +12 -0
- package/dist/modules/forms/backend/forms/[id]/submissions/page.meta.js.map +7 -0
- package/dist/modules/forms/backend/forms/create/page.js +101 -0
- package/dist/modules/forms/backend/forms/create/page.js.map +7 -0
- package/dist/modules/forms/backend/forms/create/page.meta.js +15 -0
- package/dist/modules/forms/backend/forms/create/page.meta.js.map +7 -0
- package/dist/modules/forms/backend/forms/page.js +227 -0
- package/dist/modules/forms/backend/forms/page.js.map +7 -0
- package/dist/modules/forms/backend/forms/page.meta.js +33 -0
- package/dist/modules/forms/backend/forms/page.meta.js.map +7 -0
- package/dist/modules/forms/commands/distribution.js +421 -0
- package/dist/modules/forms/commands/distribution.js.map +7 -0
- package/dist/modules/forms/commands/form-version.js +645 -0
- package/dist/modules/forms/commands/form-version.js.map +7 -0
- package/dist/modules/forms/commands/form.js +411 -0
- package/dist/modules/forms/commands/form.js.map +7 -0
- package/dist/modules/forms/commands/index.js +11 -0
- package/dist/modules/forms/commands/index.js.map +7 -0
- package/dist/modules/forms/commands/invitation.js +333 -0
- package/dist/modules/forms/commands/invitation.js.map +7 -0
- package/dist/modules/forms/commands/shared.js +151 -0
- package/dist/modules/forms/commands/shared.js.map +7 -0
- package/dist/modules/forms/commands/submission.js +139 -0
- package/dist/modules/forms/commands/submission.js.map +7 -0
- package/dist/modules/forms/data/entities.js +654 -0
- package/dist/modules/forms/data/entities.js.map +7 -0
- package/dist/modules/forms/data/validators.js +254 -0
- package/dist/modules/forms/data/validators.js.map +7 -0
- package/dist/modules/forms/di.js +199 -0
- package/dist/modules/forms/di.js.map +7 -0
- package/dist/modules/forms/encryption.js +15 -0
- package/dist/modules/forms/encryption.js.map +7 -0
- package/dist/modules/forms/events-payloads.js +81 -0
- package/dist/modules/forms/events-payloads.js.map +7 -0
- package/dist/modules/forms/events.js +33 -0
- package/dist/modules/forms/events.js.map +7 -0
- package/dist/modules/forms/extension-points.js +36 -0
- package/dist/modules/forms/extension-points.js.map +7 -0
- package/dist/modules/forms/frontend/[orgSlug]/portal/forms/[key]/page.js +33 -0
- package/dist/modules/forms/frontend/[orgSlug]/portal/forms/[key]/page.js.map +7 -0
- package/dist/modules/forms/frontend/[orgSlug]/portal/forms/[key]/page.meta.js +11 -0
- package/dist/modules/forms/frontend/[orgSlug]/portal/forms/[key]/page.meta.js.map +7 -0
- package/dist/modules/forms/frontend/[orgSlug]/portal/submissions/[id]/continue/page.js +41 -0
- package/dist/modules/forms/frontend/[orgSlug]/portal/submissions/[id]/continue/page.js.map +7 -0
- package/dist/modules/forms/frontend/[orgSlug]/portal/submissions/[id]/continue/page.meta.js +11 -0
- package/dist/modules/forms/frontend/[orgSlug]/portal/submissions/[id]/continue/page.meta.js.map +7 -0
- package/dist/modules/forms/frontend/embed/[slug]/page.js +105 -0
- package/dist/modules/forms/frontend/embed/[slug]/page.js.map +7 -0
- package/dist/modules/forms/frontend/embed/[slug]/page.meta.js +11 -0
- package/dist/modules/forms/frontend/embed/[slug]/page.meta.js.map +7 -0
- package/dist/modules/forms/frontend/f/[slug]/page.js +12 -0
- package/dist/modules/forms/frontend/f/[slug]/page.js.map +7 -0
- package/dist/modules/forms/frontend/f/[slug]/page.meta.js +11 -0
- package/dist/modules/forms/frontend/f/[slug]/page.meta.js.map +7 -0
- package/dist/modules/forms/frontend/forms/[id]/run/page.js +62 -0
- package/dist/modules/forms/frontend/forms/[id]/run/page.js.map +7 -0
- package/dist/modules/forms/frontend/forms/[id]/run/page.meta.js +11 -0
- package/dist/modules/forms/frontend/forms/[id]/run/page.meta.js.map +7 -0
- package/dist/modules/forms/frontend/i/[token]/page.js +12 -0
- package/dist/modules/forms/frontend/i/[token]/page.js.map +7 -0
- package/dist/modules/forms/frontend/i/[token]/page.meta.js +11 -0
- package/dist/modules/forms/frontend/i/[token]/page.meta.js.map +7 -0
- package/dist/modules/forms/index.js +20 -0
- package/dist/modules/forms/index.js.map +7 -0
- package/dist/modules/forms/lib/embed-frame-policy.js +68 -0
- package/dist/modules/forms/lib/embed-frame-policy.js.map +7 -0
- package/dist/modules/forms/lib/form-definition-slicing.js +38 -0
- package/dist/modules/forms/lib/form-definition-slicing.js.map +7 -0
- package/dist/modules/forms/lib/log-redaction.js +38 -0
- package/dist/modules/forms/lib/log-redaction.js.map +7 -0
- package/dist/modules/forms/lib/navigable-url.js +24 -0
- package/dist/modules/forms/lib/navigable-url.js.map +7 -0
- package/dist/modules/forms/lib/retention.js +20 -0
- package/dist/modules/forms/lib/retention.js.map +7 -0
- package/dist/modules/forms/lib/runtime-principal.js +59 -0
- package/dist/modules/forms/lib/runtime-principal.js.map +7 -0
- package/dist/modules/forms/migrations/Migration20260508135459_forms.js +17 -0
- package/dist/modules/forms/migrations/Migration20260508135459_forms.js.map +7 -0
- package/dist/modules/forms/migrations/Migration20260508140932_forms.js +23 -0
- package/dist/modules/forms/migrations/Migration20260508140932_forms.js.map +7 -0
- package/dist/modules/forms/migrations/Migration20260508155737_forms.js +15 -0
- package/dist/modules/forms/migrations/Migration20260508155737_forms.js.map +7 -0
- package/dist/modules/forms/migrations/Migration20260520120000_forms.js +23 -0
- package/dist/modules/forms/migrations/Migration20260520120000_forms.js.map +7 -0
- package/dist/modules/forms/migrations/Migration20260521090000_forms.js +13 -0
- package/dist/modules/forms/migrations/Migration20260521090000_forms.js.map +7 -0
- package/dist/modules/forms/migrations/Migration20260521120000_forms.js +17 -0
- package/dist/modules/forms/migrations/Migration20260521120000_forms.js.map +7 -0
- package/dist/modules/forms/runner/FormRunner.js +786 -0
- package/dist/modules/forms/runner/FormRunner.js.map +7 -0
- package/dist/modules/forms/runner/MatrixField.js +150 -0
- package/dist/modules/forms/runner/MatrixField.js.map +7 -0
- package/dist/modules/forms/runner/RankingField.js +131 -0
- package/dist/modules/forms/runner/RankingField.js.map +7 -0
- package/dist/modules/forms/runner/ScaleField.js +78 -0
- package/dist/modules/forms/runner/ScaleField.js.map +7 -0
- package/dist/modules/forms/runner/SignatureField.js +132 -0
- package/dist/modules/forms/runner/SignatureField.js.map +7 -0
- package/dist/modules/forms/runner/tamper-check.js +85 -0
- package/dist/modules/forms/runner/tamper-check.js.map +7 -0
- package/dist/modules/forms/schema/address-countries.js +43 -0
- package/dist/modules/forms/schema/address-countries.js.map +7 -0
- package/dist/modules/forms/schema/field-type-patterns.js +15 -0
- package/dist/modules/forms/schema/field-type-patterns.js.map +7 -0
- package/dist/modules/forms/schema/field-type-registry-advanced.js +32 -0
- package/dist/modules/forms/schema/field-type-registry-advanced.js.map +7 -0
- package/dist/modules/forms/schema/field-type-registry.js +625 -0
- package/dist/modules/forms/schema/field-type-registry.js.map +7 -0
- package/dist/modules/forms/schema/file-field.js +64 -0
- package/dist/modules/forms/schema/file-field.js.map +7 -0
- package/dist/modules/forms/schema/group-field.js +143 -0
- package/dist/modules/forms/schema/group-field.js.map +7 -0
- package/dist/modules/forms/schema/jsonlogic-grammar.js +66 -0
- package/dist/modules/forms/schema/jsonlogic-grammar.js.map +7 -0
- package/dist/modules/forms/schema/jsonschema-extensions.js +739 -0
- package/dist/modules/forms/schema/jsonschema-extensions.js.map +7 -0
- package/dist/modules/forms/schema/layout-catalog.js +38 -0
- package/dist/modules/forms/schema/layout-catalog.js.map +7 -0
- package/dist/modules/forms/schema/signature-field.js +67 -0
- package/dist/modules/forms/schema/signature-field.js.map +7 -0
- package/dist/modules/forms/schema/style-extensions.js +77 -0
- package/dist/modules/forms/schema/style-extensions.js.map +7 -0
- package/dist/modules/forms/schema/style-validators.js +181 -0
- package/dist/modules/forms/schema/style-validators.js.map +7 -0
- package/dist/modules/forms/services/access-audit-logger.js +179 -0
- package/dist/modules/forms/services/access-audit-logger.js.map +7 -0
- package/dist/modules/forms/services/analytics-service.js +306 -0
- package/dist/modules/forms/services/analytics-service.js.map +7 -0
- package/dist/modules/forms/services/anonymize-service.js +123 -0
- package/dist/modules/forms/services/anonymize-service.js.map +7 -0
- package/dist/modules/forms/services/attachment-service.js +123 -0
- package/dist/modules/forms/services/attachment-service.js.map +7 -0
- package/dist/modules/forms/services/captcha-verifier.js +76 -0
- package/dist/modules/forms/services/captcha-verifier.js.map +7 -0
- package/dist/modules/forms/services/consent-record-service.js +96 -0
- package/dist/modules/forms/services/consent-record-service.js.map +7 -0
- package/dist/modules/forms/services/distribution-service.js +366 -0
- package/dist/modules/forms/services/distribution-service.js.map +7 -0
- package/dist/modules/forms/services/distribution-token.js +93 -0
- package/dist/modules/forms/services/distribution-token.js.map +7 -0
- package/dist/modules/forms/services/encryption-service.js +328 -0
- package/dist/modules/forms/services/encryption-service.js.map +7 -0
- package/dist/modules/forms/services/export-service.js +210 -0
- package/dist/modules/forms/services/export-service.js.map +7 -0
- package/dist/modules/forms/services/field-validation-service.js +168 -0
- package/dist/modules/forms/services/field-validation-service.js.map +7 -0
- package/dist/modules/forms/services/form-logic-evaluator.js +517 -0
- package/dist/modules/forms/services/form-logic-evaluator.js.map +7 -0
- package/dist/modules/forms/services/form-version-compiler.js +518 -0
- package/dist/modules/forms/services/form-version-compiler.js.map +7 -0
- package/dist/modules/forms/services/form-version-differ.js +89 -0
- package/dist/modules/forms/services/form-version-differ.js.map +7 -0
- package/dist/modules/forms/services/jsonlogic-evaluator.js +171 -0
- package/dist/modules/forms/services/jsonlogic-evaluator.js.map +7 -0
- package/dist/modules/forms/services/pdf-snapshot-service.js +526 -0
- package/dist/modules/forms/services/pdf-snapshot-service.js.map +7 -0
- package/dist/modules/forms/services/prefill-resolver.js +53 -0
- package/dist/modules/forms/services/prefill-resolver.js.map +7 -0
- package/dist/modules/forms/services/role-policy-service.js +55 -0
- package/dist/modules/forms/services/role-policy-service.js.map +7 -0
- package/dist/modules/forms/services/style-compiler.js +234 -0
- package/dist/modules/forms/services/style-compiler.js.map +7 -0
- package/dist/modules/forms/services/submission-service.js +858 -0
- package/dist/modules/forms/services/submission-service.js.map +7 -0
- package/dist/modules/forms/services/upload-scanner.js +9 -0
- package/dist/modules/forms/services/upload-scanner.js.map +7 -0
- package/dist/modules/forms/services/upload-validation.js +54 -0
- package/dist/modules/forms/services/upload-validation.js.map +7 -0
- package/dist/modules/forms/services/visibility-resolver.js +30 -0
- package/dist/modules/forms/services/visibility-resolver.js.map +7 -0
- package/dist/modules/forms/setup.js +18 -0
- package/dist/modules/forms/setup.js.map +7 -0
- package/dist/modules/forms/subscribers/forms-consent-projector.js +58 -0
- package/dist/modules/forms/subscribers/forms-consent-projector.js.map +7 -0
- package/dist/modules/forms/subscribers/forms-pdf-snapshot.js +68 -0
- package/dist/modules/forms/subscribers/forms-pdf-snapshot.js.map +7 -0
- package/dist/modules/forms/subscribers/forms-webhook-bridge-anonymized.js +29 -0
- package/dist/modules/forms/subscribers/forms-webhook-bridge-anonymized.js.map +7 -0
- package/dist/modules/forms/subscribers/forms-webhook-bridge.js +35 -0
- package/dist/modules/forms/subscribers/forms-webhook-bridge.js.map +7 -0
- package/dist/modules/forms/subscribers/invitation-email.js +100 -0
- package/dist/modules/forms/subscribers/invitation-email.js.map +7 -0
- package/dist/modules/forms/translations.js +10 -0
- package/dist/modules/forms/translations.js.map +7 -0
- package/dist/modules/forms/ui/admin/forms/[id]/distributions/CreateDistributionDialog.js +376 -0
- package/dist/modules/forms/ui/admin/forms/[id]/distributions/CreateDistributionDialog.js.map +7 -0
- package/dist/modules/forms/ui/admin/forms/[id]/distributions/DistributionsPanel.js +313 -0
- package/dist/modules/forms/ui/admin/forms/[id]/distributions/DistributionsPanel.js.map +7 -0
- package/dist/modules/forms/ui/admin/forms/[id]/distributions/EmbedSettingsDialog.js +263 -0
- package/dist/modules/forms/ui/admin/forms/[id]/distributions/EmbedSettingsDialog.js.map +7 -0
- package/dist/modules/forms/ui/admin/forms/[id]/distributions/RecipientsTable.js +373 -0
- package/dist/modules/forms/ui/admin/forms/[id]/distributions/RecipientsTable.js.map +7 -0
- package/dist/modules/forms/ui/public/EmbeddedForm.js +166 -0
- package/dist/modules/forms/ui/public/EmbeddedForm.js.map +7 -0
- package/dist/modules/forms/ui/public/FormRunner.js +359 -0
- package/dist/modules/forms/ui/public/FormRunner.js.map +7 -0
- package/dist/modules/forms/ui/public/FormTrigger.js +45 -0
- package/dist/modules/forms/ui/public/FormTrigger.js.map +7 -0
- package/dist/modules/forms/ui/public/PublicFormRunnerPage.js +14 -0
- package/dist/modules/forms/ui/public/PublicFormRunnerPage.js.map +7 -0
- package/dist/modules/forms/ui/public/components/CompletionScreen.js +55 -0
- package/dist/modules/forms/ui/public/components/CompletionScreen.js.map +7 -0
- package/dist/modules/forms/ui/public/components/LocaleSwitch.js +28 -0
- package/dist/modules/forms/ui/public/components/LocaleSwitch.js.map +7 -0
- package/dist/modules/forms/ui/public/components/ResumeGate.js +52 -0
- package/dist/modules/forms/ui/public/components/ResumeGate.js.map +7 -0
- package/dist/modules/forms/ui/public/components/ReviewStep.js +90 -0
- package/dist/modules/forms/ui/public/components/ReviewStep.js.map +7 -0
- package/dist/modules/forms/ui/public/components/SaveIndicator.js +65 -0
- package/dist/modules/forms/ui/public/components/SaveIndicator.js.map +7 -0
- package/dist/modules/forms/ui/public/components/SectionStepper.js +52 -0
- package/dist/modules/forms/ui/public/components/SectionStepper.js.map +7 -0
- package/dist/modules/forms/ui/public/index.js +38 -0
- package/dist/modules/forms/ui/public/index.js.map +7 -0
- package/dist/modules/forms/ui/public/renderers/index.js +737 -0
- package/dist/modules/forms/ui/public/renderers/index.js.map +7 -0
- package/dist/modules/forms/ui/public/state/logic-derivation.js +42 -0
- package/dist/modules/forms/ui/public/state/logic-derivation.js.map +7 -0
- package/dist/modules/forms/ui/public/state/runtime-client.js +306 -0
- package/dist/modules/forms/ui/public/state/runtime-client.js.map +7 -0
- package/dist/modules/forms/ui/public/state/useAutosave.js +64 -0
- package/dist/modules/forms/ui/public/state/useAutosave.js.map +7 -0
- package/dist/modules/forms/ui/public/state/useFormRunner.js +394 -0
- package/dist/modules/forms/ui/public/state/useFormRunner.js.map +7 -0
- package/dist/modules/forms/ui/public/style/LogoHeader.js +33 -0
- package/dist/modules/forms/ui/public/style/LogoHeader.js.map +7 -0
- package/dist/modules/forms/ui/public/style/applyStyle.js +12 -0
- package/dist/modules/forms/ui/public/style/applyStyle.js.map +7 -0
- package/dist/modules/forms/ui/public/types.js +18 -0
- package/dist/modules/forms/ui/public/types.js.map +7 -0
- package/dist/modules/forms/widgets/injection/access-audit-panel/widget.js +100 -0
- package/dist/modules/forms/widgets/injection/access-audit-panel/widget.js.map +7 -0
- package/dist/modules/forms/widgets/injection/anonymize-button/widget.js +148 -0
- package/dist/modules/forms/widgets/injection/anonymize-button/widget.js.map +7 -0
- package/dist/modules/forms/widgets/injection/audit-format.js +33 -0
- package/dist/modules/forms/widgets/injection/audit-format.js.map +7 -0
- package/dist/modules/forms/widgets/injection/context.js +5 -0
- package/dist/modules/forms/widgets/injection/context.js.map +7 -0
- package/dist/modules/forms/widgets/injection/embedded-form/widget.js +52 -0
- package/dist/modules/forms/widgets/injection/embedded-form/widget.js.map +7 -0
- package/dist/modules/forms/widgets/injection/pdf-download-button/widget.js +83 -0
- package/dist/modules/forms/widgets/injection/pdf-download-button/widget.js.map +7 -0
- package/dist/modules/forms/widgets/injection/self-audit-footer/widget.js +38 -0
- package/dist/modules/forms/widgets/injection/self-audit-footer/widget.js.map +7 -0
- package/dist/modules/forms/widgets/injection-table.js +32 -0
- package/dist/modules/forms/widgets/injection-table.js.map +7 -0
- package/dist/modules/forms/workers/pdf-snapshot.js +60 -0
- package/dist/modules/forms/workers/pdf-snapshot.js.map +7 -0
- package/dist/modules/forms/workers/retention-purge.js +112 -0
- package/dist/modules/forms/workers/retention-purge.js.map +7 -0
- package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.js +7 -1
- package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.js.map +2 -2
- package/dist/modules/inbox_ops/data/validators.js +2 -2
- package/dist/modules/inbox_ops/data/validators.js.map +2 -2
- package/dist/modules/inbox_ops/lib/llmProvider.js +5 -1
- package/dist/modules/inbox_ops/lib/llmProvider.js.map +2 -2
- package/dist/modules/inbox_ops/widgets/notifications/ProposalCreatedRenderer.js +2 -2
- package/dist/modules/inbox_ops/widgets/notifications/ProposalCreatedRenderer.js.map +2 -2
- package/dist/modules/integrations/di.js +3 -1
- package/dist/modules/integrations/di.js.map +2 -2
- package/dist/modules/integrations/lib/credentials-service.js +29 -36
- package/dist/modules/integrations/lib/credentials-service.js.map +2 -2
- package/dist/modules/messages/api/[id]/attachments/route.js +7 -3
- package/dist/modules/messages/api/[id]/attachments/route.js.map +2 -2
- package/dist/modules/messages/api/[id]/forward-preview/route.js +4 -3
- package/dist/modules/messages/api/[id]/forward-preview/route.js.map +2 -2
- package/dist/modules/messages/api/[id]/route.js +29 -3
- package/dist/modules/messages/api/[id]/route.js.map +2 -2
- package/dist/modules/messages/api/route.js +91 -2
- package/dist/modules/messages/api/route.js.map +2 -2
- package/dist/modules/messages/commands/messages.js +40 -6
- package/dist/modules/messages/commands/messages.js.map +2 -2
- package/dist/modules/messages/components/ComposeMessagePageClient.js +24 -1
- package/dist/modules/messages/components/ComposeMessagePageClient.js.map +2 -2
- package/dist/modules/messages/data/validators.js +11 -1
- package/dist/modules/messages/data/validators.js.map +2 -2
- package/dist/modules/messages/lib/channelThreadAccess.js +30 -0
- package/dist/modules/messages/lib/channelThreadAccess.js.map +7 -0
- package/dist/modules/messages/lib/composeSenderDelegation.js +87 -0
- package/dist/modules/messages/lib/composeSenderDelegation.js.map +7 -0
- package/dist/modules/messages/lib/composeSenderOptions.js +24 -0
- package/dist/modules/messages/lib/composeSenderOptions.js.map +7 -0
- package/dist/modules/messages/lib/email-sender.js +1 -11
- package/dist/modules/messages/lib/email-sender.js.map +2 -2
- package/dist/modules/messages/lib/forwarding.js +4 -4
- package/dist/modules/messages/lib/forwarding.js.map +2 -2
- package/dist/modules/messages/lib/markdownEmailBody.js +15 -0
- package/dist/modules/messages/lib/markdownEmailBody.js.map +7 -0
- package/dist/modules/messages/lib/messageSourceEntityTypes.js +7 -0
- package/dist/modules/messages/lib/messageSourceEntityTypes.js.map +7 -0
- package/dist/modules/messages/lib/routeHelpers.js +43 -0
- package/dist/modules/messages/lib/routeHelpers.js.map +2 -2
- package/dist/modules/messages/subscribers/message-notification.js +30 -1
- package/dist/modules/messages/subscribers/message-notification.js.map +2 -2
- package/dist/modules/notifications/api/[id]/action/route.js +2 -1
- package/dist/modules/notifications/api/[id]/action/route.js.map +2 -2
- package/dist/modules/notifications/api/openapi.js +2 -1
- package/dist/modules/notifications/api/openapi.js.map +2 -2
- package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js +47 -28
- package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js.map +2 -2
- package/dist/modules/notifications/lib/deliveryConfig.js +27 -2
- package/dist/modules/notifications/lib/deliveryConfig.js.map +2 -2
- package/dist/modules/notifications/lib/notificationMapper.js +3 -1
- package/dist/modules/notifications/lib/notificationMapper.js.map +2 -2
- package/dist/modules/notifications/lib/safeHref.js +4 -0
- package/dist/modules/notifications/lib/safeHref.js.map +2 -2
- package/dist/modules/planner/api/availability-date-specific.js +2 -1
- package/dist/modules/planner/api/availability-date-specific.js.map +2 -2
- package/dist/modules/planner/api/availability-weekly.js +2 -1
- package/dist/modules/planner/api/availability-weekly.js.map +2 -2
- package/dist/modules/progress/api/active/route.js +14 -2
- package/dist/modules/progress/api/active/route.js.map +2 -2
- package/dist/modules/progress/api/jobs/[id]/route.js +38 -22
- package/dist/modules/progress/api/jobs/[id]/route.js.map +2 -2
- package/dist/modules/progress/api/jobs/route.js +20 -6
- package/dist/modules/progress/api/jobs/route.js.map +2 -2
- package/dist/modules/progress/api/requestScope.js +32 -0
- package/dist/modules/progress/api/requestScope.js.map +7 -0
- package/dist/modules/progress/lib/organizationScope.js +10 -0
- package/dist/modules/progress/lib/organizationScope.js.map +7 -0
- package/dist/modules/progress/lib/progressService.js.map +2 -2
- package/dist/modules/progress/lib/progressServiceImpl.js +48 -15
- package/dist/modules/progress/lib/progressServiceImpl.js.map +2 -2
- package/dist/modules/push_notifications/api/custom-send/route.js +4 -1
- package/dist/modules/push_notifications/api/custom-send/route.js.map +2 -2
- package/dist/modules/query_index/api/status.js +5 -3
- package/dist/modules/query_index/api/status.js.map +2 -2
- package/dist/modules/query_index/di.js +2 -1
- package/dist/modules/query_index/di.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +2 -1
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/lib/request-encryption.js +16 -0
- package/dist/modules/query_index/lib/request-encryption.js.map +7 -0
- package/dist/modules/query_index/lib/search-tokens.js +31 -1
- package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
- package/dist/modules/resources/api/resources/tags/assign/route.js +2 -1
- package/dist/modules/resources/api/resources/tags/assign/route.js.map +2 -2
- package/dist/modules/resources/api/resources/tags/unassign/route.js +2 -1
- package/dist/modules/resources/api/resources/tags/unassign/route.js.map +2 -2
- package/dist/modules/resources/commands/activities.js +2 -2
- package/dist/modules/resources/commands/activities.js.map +2 -2
- package/dist/modules/sales/api/document-history/route.js +5 -1
- package/dist/modules/sales/api/document-history/route.js.map +2 -2
- package/dist/modules/sales/api/document-numbers/route.js +2 -1
- package/dist/modules/sales/api/document-numbers/route.js.map +2 -2
- package/dist/modules/sales/api/quotes/convert/route.js +2 -1
- package/dist/modules/sales/api/quotes/convert/route.js.map +2 -2
- package/dist/modules/sales/api/quotes/send/route.js +2 -1
- package/dist/modules/sales/api/quotes/send/route.js.map +2 -2
- package/dist/modules/sales/api/settings/document-numbers/route.js +7 -1
- package/dist/modules/sales/api/settings/document-numbers/route.js.map +2 -2
- package/dist/modules/sales/api/settings/order-editing/route.js +7 -1
- package/dist/modules/sales/api/settings/order-editing/route.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +354 -138
- package/dist/modules/sales/commands/documents.js.map +3 -3
- package/dist/modules/sales/commands/payments.js +2 -1
- package/dist/modules/sales/commands/payments.js.map +2 -2
- package/dist/modules/sales/commands/settings.js +25 -5
- package/dist/modules/sales/commands/settings.js.map +2 -2
- package/dist/modules/sales/commands/shipments.js +2 -1
- package/dist/modules/sales/commands/shipments.js.map +2 -2
- package/dist/modules/sales/components/DocumentNumberSettings.js +32 -21
- package/dist/modules/sales/components/DocumentNumberSettings.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +49 -11
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/lib/lineSnapshots.js +19 -0
- package/dist/modules/sales/lib/lineSnapshots.js.map +2 -2
- package/dist/modules/sales/setup.js +4 -4
- package/dist/modules/sales/setup.js.map +2 -2
- package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js +2 -2
- package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js.map +2 -2
- package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js +2 -2
- package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js.map +2 -2
- package/dist/modules/staff/api/leave-requests/accept/route.js +2 -1
- package/dist/modules/staff/api/leave-requests/accept/route.js.map +2 -2
- package/dist/modules/staff/api/leave-requests/reject/route.js +2 -1
- package/dist/modules/staff/api/leave-requests/reject/route.js.map +2 -2
- package/dist/modules/staff/api/leave-requests.js +2 -1
- package/dist/modules/staff/api/leave-requests.js.map +2 -2
- package/dist/modules/staff/api/team-members/self/route.js +2 -1
- package/dist/modules/staff/api/team-members/self/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/tags/assign/route.js +2 -1
- package/dist/modules/staff/api/team-members/tags/assign/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/tags/unassign/route.js +2 -1
- package/dist/modules/staff/api/team-members/tags/unassign/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.js +12 -11
- package/dist/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.js.map +2 -2
- package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js +2 -1
- package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/my-projects/route.js +2 -1
- package/dist/modules/staff/api/timesheets/my-projects/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/my-work/route.js +2 -1
- package/dist/modules/staff/api/timesheets/my-work/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/projects/kpis/route.js +2 -1
- package/dist/modules/staff/api/timesheets/projects/kpis/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/reports/[id]/close/route.js +2 -1
- package/dist/modules/staff/api/timesheets/reports/[id]/close/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/reports/[id]/export/route.js +3 -2
- package/dist/modules/staff/api/timesheets/reports/[id]/export/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/reports/[id]/sheet/route.js +3 -2
- package/dist/modules/staff/api/timesheets/reports/[id]/sheet/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/reports/[id]/unlock/route.js +3 -2
- package/dist/modules/staff/api/timesheets/reports/[id]/unlock/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/reports/preview/route.js +2 -1
- package/dist/modules/staff/api/timesheets/reports/preview/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/reports/shared.js +2 -1
- package/dist/modules/staff/api/timesheets/reports/shared.js.map +2 -2
- package/dist/modules/staff/api/timesheets/settings/reapply-rounding/route.js +2 -1
- package/dist/modules/staff/api/timesheets/settings/reapply-rounding/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/tags/entry-assignments/route.js +2 -1
- package/dist/modules/staff/api/timesheets/tags/entry-assignments/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/tags/task-assignments/route.js +2 -1
- package/dist/modules/staff/api/timesheets/tags/task-assignments/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js +2 -1
- package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/tasks/[id]/status/route.js +2 -1
- package/dist/modules/staff/api/timesheets/tasks/[id]/status/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.js +3 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js +2 -1
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js +2 -1
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js +2 -1
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js +2 -1
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js +2 -1
- package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/copy-day/route.js +3 -2
- package/dist/modules/staff/api/timesheets/time-entries/copy-day/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/overlaps/route.js +2 -1
- package/dist/modules/staff/api/timesheets/time-entries/overlaps/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js +3 -2
- package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.js +3 -2
- package/dist/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-projects/route.js +2 -1
- package/dist/modules/staff/api/timesheets/time-projects/route.js.map +2 -2
- package/dist/modules/staff/commands/activities.js +2 -2
- package/dist/modules/staff/commands/activities.js.map +2 -2
- package/dist/modules/staff/commands/timesheets-entries.js.map +2 -2
- package/dist/modules/staff/commands/timesheets-reports.js +55 -14
- package/dist/modules/staff/commands/timesheets-reports.js.map +2 -2
- package/dist/modules/staff/lib/timesheets-reports/buildReportSheet.js +2 -1
- package/dist/modules/staff/lib/timesheets-reports/buildReportSheet.js.map +2 -2
- package/dist/modules/staff/lib/timesheets-reports/loadReportData.js +32 -3
- package/dist/modules/staff/lib/timesheets-reports/loadReportData.js.map +2 -2
- package/dist/modules/staff/lib/timesheets-reports/reportPeriod.js +16 -0
- package/dist/modules/staff/lib/timesheets-reports/reportPeriod.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-ui/CalendarPicker.js +15 -10
- package/dist/modules/staff/lib/timesheets-ui/CalendarPicker.js.map +2 -2
- package/dist/modules/sync_excel/api/import/route.js +35 -12
- package/dist/modules/sync_excel/api/import/route.js.map +2 -2
- package/dist/modules/sync_excel/api/upload/route.js +29 -4
- package/dist/modules/sync_excel/api/upload/route.js.map +2 -2
- package/dist/modules/translations/api/context.js +2 -1
- package/dist/modules/translations/api/context.js.map +2 -2
- package/dist/modules/warranty_claims/api/ai/assess/route.js +2 -1
- package/dist/modules/warranty_claims/api/ai/assess/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/ai/draft-reply/route.js +2 -1
- package/dist/modules/warranty_claims/api/ai/draft-reply/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/ai/suggest/route.js +2 -1
- package/dist/modules/warranty_claims/api/ai/suggest/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/assign/route.js +2 -1
- package/dist/modules/warranty_claims/api/assign/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/credit-memo/route.js +2 -1
- package/dist/modules/warranty_claims/api/credit-memo/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/entitlement/route.js +2 -1
- package/dist/modules/warranty_claims/api/entitlement/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/events/route.js +2 -1
- package/dist/modules/warranty_claims/api/events/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/external/claims/route.js +2 -1
- package/dist/modules/warranty_claims/api/external/claims/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/receiving/route.js +2 -1
- package/dist/modules/warranty_claims/api/receiving/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/replacement-order/route.js +2 -1
- package/dist/modules/warranty_claims/api/replacement-order/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/return-label/route.js +2 -1
- package/dist/modules/warranty_claims/api/return-label/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/risk/route.js +2 -1
- package/dist/modules/warranty_claims/api/risk/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/sales-return/route.js +2 -1
- package/dist/modules/warranty_claims/api/sales-return/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/settings-general/route.js +2 -1
- package/dist/modules/warranty_claims/api/settings-general/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/stats/route.js +9 -5
- package/dist/modules/warranty_claims/api/stats/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/submit/route.js +2 -1
- package/dist/modules/warranty_claims/api/submit/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/transition/route.js +2 -1
- package/dist/modules/warranty_claims/api/transition/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/vendor-recovery/route.js +2 -1
- package/dist/modules/warranty_claims/api/vendor-recovery/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/vendor-recovery-suggestions/route.js +2 -1
- package/dist/modules/warranty_claims/api/vendor-recovery-suggestions/route.js.map +2 -2
- package/dist/modules/warranty_claims/widgets/notifications/WarrantyClaimNotificationRenderer.js +1 -1
- package/dist/modules/warranty_claims/widgets/notifications/WarrantyClaimNotificationRenderer.js.map +2 -2
- package/dist/modules/wms/api/dashboard/operational/route.js +2 -1
- package/dist/modules/wms/api/dashboard/operational/route.js.map +2 -2
- package/dist/modules/wms/api/inventory/cycle-count/route.js +1 -0
- package/dist/modules/wms/api/inventory/cycle-count/route.js.map +2 -2
- package/dist/modules/wms/api/inventory/helpers.js +2 -1
- package/dist/modules/wms/api/inventory/helpers.js.map +2 -2
- package/dist/modules/wms/api/inventory/import/helpers.js +2 -1
- package/dist/modules/wms/api/inventory/import/helpers.js.map +2 -2
- package/dist/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.js +2 -1
- package/dist/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.js.map +2 -2
- package/dist/modules/wms/commands/inventory-actions.js +39 -1
- package/dist/modules/wms/commands/inventory-actions.js.map +2 -2
- package/dist/modules/wms/components/backend/CycleCountWizardDialog.js +14 -1
- package/dist/modules/wms/components/backend/CycleCountWizardDialog.js.map +2 -2
- package/dist/modules/wms/di.js +5 -0
- package/dist/modules/wms/di.js.map +2 -2
- package/dist/modules/wms/lib/availabilityCache.js +86 -0
- package/dist/modules/wms/lib/availabilityCache.js.map +7 -0
- package/dist/modules/wms/lib/availabilityCalculation.js +212 -0
- package/dist/modules/wms/lib/availabilityCalculation.js.map +7 -0
- package/dist/modules/wms/lib/availabilityProvider.js +24 -0
- package/dist/modules/wms/lib/availabilityProvider.js.map +7 -0
- package/dist/modules/wms/lib/loadOperationalDashboard.js +42 -5
- package/dist/modules/wms/lib/loadOperationalDashboard.js.map +2 -2
- package/dist/modules/wms/lib/lowStockBalanceFilter.js +23 -10
- package/dist/modules/wms/lib/lowStockBalanceFilter.js.map +2 -2
- package/dist/modules/wms/lib/sqlInClause.js +9 -0
- package/dist/modules/wms/lib/sqlInClause.js.map +7 -0
- package/dist/modules/wms/lib/tryResolve.js +11 -0
- package/dist/modules/wms/lib/tryResolve.js.map +7 -0
- package/dist/modules/wms/subscribers/invalidate-availability-cache-policy.js +14 -0
- package/dist/modules/wms/subscribers/invalidate-availability-cache-policy.js.map +7 -0
- package/dist/modules/wms/subscribers/invalidate-availability-cache-profile.js +14 -0
- package/dist/modules/wms/subscribers/invalidate-availability-cache-profile.js.map +7 -0
- package/dist/modules/wms/subscribers/invalidate-availability-cache.js +16 -0
- package/dist/modules/wms/subscribers/invalidate-availability-cache.js.map +7 -0
- package/dist/modules/wms/widgets/notifications/WmsLowStockRenderer.js +2 -2
- package/dist/modules/wms/widgets/notifications/WmsLowStockRenderer.js.map +2 -2
- package/dist/modules/wms/widgets/notifications/WmsReservationShortfallRenderer.js +4 -3
- package/dist/modules/wms/widgets/notifications/WmsReservationShortfallRenderer.js.map +2 -2
- package/dist/modules/workflows/api/commands/route.js +4 -1
- package/dist/modules/workflows/api/commands/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/callers/route.js +4 -1
- package/dist/modules/workflows/api/definitions/[id]/callers/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/context-schema/route.js +4 -2
- package/dist/modules/workflows/api/definitions/[id]/context-schema/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/customize/route.js +4 -1
- package/dist/modules/workflows/api/definitions/[id]/customize/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/draft/route.js +6 -1
- package/dist/modules/workflows/api/definitions/[id]/draft/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/publish/route.js +6 -1
- package/dist/modules/workflows/api/definitions/[id]/publish/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/reset-to-code/route.js +4 -1
- package/dist/modules/workflows/api/definitions/[id]/reset-to-code/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/route.js +5 -3
- package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/test-step/route.js +4 -2
- package/dist/modules/workflows/api/definitions/[id]/test-step/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/generate/route.js +4 -1
- package/dist/modules/workflows/api/definitions/generate/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/route.js +4 -2
- package/dist/modules/workflows/api/definitions/route.js.map +2 -2
- package/dist/modules/workflows/api/endpoints/route.js +4 -1
- package/dist/modules/workflows/api/endpoints/route.js.map +2 -2
- package/dist/modules/workflows/api/functions/route.js +4 -1
- package/dist/modules/workflows/api/functions/route.js.map +2 -2
- package/dist/modules/workflows/api/grantable-features/route.js +2 -1
- package/dist/modules/workflows/api/grantable-features/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/advance/route.js +4 -1
- package/dist/modules/workflows/api/instances/[id]/advance/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/cancel/route.js +4 -1
- package/dist/modules/workflows/api/instances/[id]/cancel/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/context/route.js +2 -1
- package/dist/modules/workflows/api/instances/[id]/context/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/rerun-step/route.js +4 -1
- package/dist/modules/workflows/api/instances/[id]/rerun-step/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/retry/route.js +4 -1
- package/dist/modules/workflows/api/instances/[id]/retry/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/signal/route.js +4 -1
- package/dist/modules/workflows/api/instances/[id]/signal/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/step-through/route.js +4 -2
- package/dist/modules/workflows/api/instances/[id]/step-through/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/route.js +4 -2
- package/dist/modules/workflows/api/instances/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/validate-start/route.js +4 -1
- package/dist/modules/workflows/api/instances/validate-start/route.js.map +2 -2
- package/dist/modules/workflows/api/rule-usage/route.js +4 -1
- package/dist/modules/workflows/api/rule-usage/route.js.map +2 -2
- package/dist/modules/workflows/api/signals/route.js +4 -1
- package/dist/modules/workflows/api/signals/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/[id]/claim/route.js +4 -1
- package/dist/modules/workflows/api/tasks/[id]/claim/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/[id]/complete/route.js +4 -1
- package/dist/modules/workflows/api/tasks/[id]/complete/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/[id]/reassign/route.js +2 -1
- package/dist/modules/workflows/api/tasks/[id]/reassign/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/[id]/unclaim/route.js +4 -1
- package/dist/modules/workflows/api/tasks/[id]/unclaim/route.js.map +2 -2
- package/dist/modules/workflows/api/templates/route.js +4 -1
- package/dist/modules/workflows/api/templates/route.js.map +2 -2
- package/dist/modules/workflows/api/work-inbox/next/route.js +4 -1
- package/dist/modules/workflows/api/work-inbox/next/route.js.map +2 -2
- package/dist/modules/workflows/lib/activity-executor.js +87 -20
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/dist/modules/workflows/lib/activity-types.js +4 -4
- package/dist/modules/workflows/lib/activity-types.js.map +2 -2
- package/dist/modules/workflows/lib/activity-worker-handler.js +16 -11
- package/dist/modules/workflows/lib/activity-worker-handler.js.map +2 -2
- package/dist/modules/workflows/lib/event-trigger-service.js +8 -1
- package/dist/modules/workflows/lib/event-trigger-service.js.map +2 -2
- package/dist/modules/workflows/lib/step-handler.js +4 -4
- package/dist/modules/workflows/lib/step-handler.js.map +2 -2
- package/dist/test-utils/transactionalEntityManagerDouble.js +37 -0
- package/dist/test-utils/transactionalEntityManagerDouble.js.map +7 -0
- package/generated/entities/availability_policy/index.ts +19 -0
- package/generated/entities/communication_channel/index.ts +1 -0
- package/generated/entities/customer_email_conversation_share/index.ts +9 -0
- package/generated/entities/customer_group/index.ts +15 -0
- package/generated/entities/customer_group_membership/index.ts +13 -0
- package/generated/entities/customer_group_terms/index.ts +15 -0
- package/generated/entities/customer_interaction/index.ts +1 -0
- package/generated/entities/form/index.ts +16 -0
- package/generated/entities/form_access_audit/index.ts +9 -0
- package/generated/entities/form_attachment/index.ts +13 -0
- package/generated/entities/form_consent_record/index.ts +17 -0
- package/generated/entities/form_distribution/index.ts +22 -0
- package/generated/entities/form_invitation/index.ts +23 -0
- package/generated/entities/form_submission/index.ts +18 -0
- package/generated/entities/form_submission_actor/index.ts +10 -0
- package/generated/entities/form_submission_revision/index.ts +13 -0
- package/generated/entities/form_version/index.ts +17 -0
- package/generated/entities/forms_encryption_key/index.ts +6 -0
- package/generated/entities.ids.generated.ts +27 -2
- package/generated/entity-fields-registry.ts +269 -0
- package/package.json +19 -9
- package/src/helpers/integration/communicationChannelsFixtures.ts +43 -0
- package/src/helpers/integration/customerGroupsFixtures.ts +171 -0
- package/src/helpers/integration/formsFixtures.ts +757 -0
- package/src/modules/api_docs/api/get/version.ts +28 -11
- package/src/modules/api_keys/api/keys/route.ts +89 -199
- package/src/modules/api_keys/backend/api-keys/create/page.tsx +2 -2
- package/src/modules/api_keys/commands/keys.ts +172 -0
- package/src/modules/api_keys/i18n/de.json +1 -0
- package/src/modules/api_keys/i18n/en.json +1 -0
- package/src/modules/api_keys/i18n/es.json +1 -0
- package/src/modules/api_keys/i18n/ko.json +1 -0
- package/src/modules/api_keys/i18n/pl.json +1 -0
- package/src/modules/api_keys/services/apiKeyService.ts +82 -49
- package/src/modules/attachments/api/file/[id]/route.ts +9 -4
- package/src/modules/attachments/api/image/[id]/[[...slug]]/route.ts +6 -4
- package/src/modules/attachments/api/route.ts +10 -4
- package/src/modules/attachments/components/AttachmentLibrary.tsx +16 -5
- package/src/modules/attachments/lib/access.ts +1 -3
- package/src/modules/attachments/lib/requestScope.ts +35 -3
- package/src/modules/audit_logs/api/audit-logs/actions/export/route.ts +6 -1
- package/src/modules/audit_logs/api/audit-logs/actions/redo/route.ts +41 -6
- package/src/modules/audit_logs/api/audit-logs/actions/route.ts +6 -1
- package/src/modules/audit_logs/api/audit-logs/actions/undo/route.ts +39 -4
- package/src/modules/audit_logs/data/validators.ts +1 -0
- package/src/modules/audit_logs/lib/actorSubject.ts +82 -0
- package/src/modules/audit_logs/lib/replayAuthorization.ts +61 -0
- package/src/modules/audit_logs/services/actionLogService.ts +191 -47
- package/src/modules/auth/api/features.ts +1 -1
- package/src/modules/auth/cli.ts +31 -17
- package/src/modules/auth/commands/acl.ts +26 -36
- package/src/modules/auth/commands/interceptors.ts +23 -0
- package/src/modules/auth/commands/roles.ts +475 -148
- package/src/modules/auth/commands/users.ts +693 -81
- package/src/modules/auth/i18n/de.json +22 -0
- package/src/modules/auth/i18n/en.json +22 -0
- package/src/modules/auth/i18n/es.json +22 -0
- package/src/modules/auth/i18n/ko.json +22 -0
- package/src/modules/auth/i18n/pl.json +22 -0
- package/src/modules/auth/lib/authorizationStateLocks.ts +340 -0
- package/src/modules/auth/lib/commandReplay.ts +194 -0
- package/src/modules/auth/lib/executionPrincipal.ts +36 -28
- package/src/modules/auth/lib/grantChecks.ts +10 -2
- package/src/modules/auth/lib/setup-app.ts +97 -50
- package/src/modules/auth/lib/tokenHash.ts +16 -1
- package/src/modules/auth/services/rbacService.ts +578 -6
- package/src/modules/availability/acl.ts +12 -0
- package/src/modules/availability/api/check/route.ts +136 -0
- package/src/modules/availability/api/openapi.ts +28 -0
- package/src/modules/availability/api/policies/resolve-preview/route.ts +83 -0
- package/src/modules/availability/api/policies/route.ts +243 -0
- package/src/modules/availability/backend/availability/check/page.meta.ts +12 -0
- package/src/modules/availability/backend/availability/check/page.tsx +226 -0
- package/src/modules/availability/backend/availability/policies/ResolutionPreviewPanel.tsx +112 -0
- package/src/modules/availability/backend/availability/policies/ScopeFields.tsx +55 -0
- package/src/modules/availability/backend/availability/policies/StockManagedField.tsx +37 -0
- package/src/modules/availability/backend/availability/policies/[id]/page.meta.ts +8 -0
- package/src/modules/availability/backend/availability/policies/[id]/page.tsx +202 -0
- package/src/modules/availability/backend/availability/policies/create/page.meta.ts +8 -0
- package/src/modules/availability/backend/availability/policies/create/page.tsx +134 -0
- package/src/modules/availability/backend/availability/policies/formGroups.ts +83 -0
- package/src/modules/availability/backend/availability/policies/page.meta.ts +12 -0
- package/src/modules/availability/backend/availability/policies/page.tsx +232 -0
- package/src/modules/availability/backend/availability/policies/policyPayload.ts +29 -0
- package/src/modules/availability/commands/policies.ts +430 -0
- package/src/modules/availability/commands/scope.ts +26 -0
- package/src/modules/availability/data/entities.ts +93 -0
- package/src/modules/availability/data/validators.ts +87 -0
- package/src/modules/availability/di.ts +68 -0
- package/src/modules/availability/events.ts +17 -0
- package/src/modules/availability/i18n/de.json +93 -0
- package/src/modules/availability/i18n/en.json +93 -0
- package/src/modules/availability/i18n/es.json +93 -0
- package/src/modules/availability/i18n/ko.json +93 -0
- package/src/modules/availability/i18n/pl.json +93 -0
- package/src/modules/availability/index.ts +13 -0
- package/src/modules/availability/lib/catalogTarget.ts +72 -0
- package/src/modules/availability/lib/organizationScope.ts +55 -0
- package/src/modules/availability/lib/policyResolution.ts +289 -0
- package/src/modules/availability/lib/tryResolve.ts +8 -0
- package/src/modules/availability/migrations/.snapshot-open-mercato.json +375 -0
- package/src/modules/availability/migrations/Migration20260922095844_availability.ts +13 -0
- package/src/modules/availability/migrations/Migration20260930120000_availability.ts +22 -0
- package/src/modules/availability/setup.ts +10 -0
- package/src/modules/catalog/api/categories/bulk-create/route.ts +133 -0
- package/src/modules/catalog/api/categories/route.ts +70 -8
- package/src/modules/catalog/api/products/bulk-create/route.ts +133 -0
- package/src/modules/catalog/api/products/route.ts +55 -24
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +9 -16
- package/src/modules/catalog/backend/catalog/products/create/page.tsx +16 -10
- package/src/modules/catalog/commands/categories.ts +1 -0
- package/src/modules/catalog/commands/products.ts +11 -7
- package/src/modules/catalog/components/PriceKindSettings.tsx +6 -20
- package/src/modules/catalog/components/prices/PriceScopeSelectors.tsx +2 -2
- package/src/modules/catalog/components/products/ProductUomSection.tsx +26 -37
- package/src/modules/catalog/components/products/productForm.ts +6 -4
- package/src/modules/catalog/data/validators.ts +22 -0
- package/src/modules/catalog/di.ts +2 -1
- package/src/modules/catalog/events.ts +9 -3
- package/src/modules/catalog/i18n/de.json +40 -0
- package/src/modules/catalog/i18n/en.json +40 -0
- package/src/modules/catalog/i18n/es.json +40 -0
- package/src/modules/catalog/i18n/ko.json +40 -0
- package/src/modules/catalog/i18n/pl.json +40 -0
- package/src/modules/catalog/lib/bulkCreateCategories.ts +349 -0
- package/src/modules/catalog/lib/bulkCreateCheckpoint.ts +176 -0
- package/src/modules/catalog/lib/bulkCreateMutationGuards.ts +62 -0
- package/src/modules/catalog/lib/bulkCreateProducts.ts +340 -0
- package/src/modules/catalog/lib/bulkDelete.ts +10 -14
- package/src/modules/catalog/lib/catalogQueue.ts +14 -0
- package/src/modules/catalog/lib/currencyOptions.ts +28 -0
- package/src/modules/catalog/lib/productSearch.ts +16 -0
- package/src/modules/catalog/lib/seeds.ts +2 -43
- package/src/modules/catalog/lib/unitLabels.ts +52 -0
- package/src/modules/catalog/migrations/Migration20260914120000.ts +51 -0
- package/src/modules/catalog/migrations/Migration20260914120100.ts +50 -0
- package/src/modules/catalog/workers/catalog-category-bulk-create.ts +48 -0
- package/src/modules/catalog/workers/catalog-product-bulk-create.ts +48 -0
- package/src/modules/communication_channels/acl.ts +8 -0
- package/src/modules/communication_channels/api/get/me/channels/route.ts +4 -0
- package/src/modules/communication_channels/api/get/oauth/[provider]/callback/route.ts +23 -0
- package/src/modules/communication_channels/api/post/channels/[id]/import-history/route.ts +3 -4
- package/src/modules/communication_channels/api/post/channels/[id]/test-send/route.ts +9 -1
- package/src/modules/communication_channels/api/post/test-seed/route.ts +109 -24
- package/src/modules/communication_channels/api/put/channels/[id]/visibility/route.ts +165 -0
- package/src/modules/communication_channels/backend/profile/communication-channels/page.tsx +247 -129
- package/src/modules/communication_channels/commands/ingest-inbound-message.ts +2 -1
- package/src/modules/communication_channels/commands/set-channel-visibility.ts +138 -0
- package/src/modules/communication_channels/data/enrichers.ts +42 -19
- package/src/modules/communication_channels/data/entities.ts +21 -0
- package/src/modules/communication_channels/di.ts +9 -0
- package/src/modules/communication_channels/events.ts +7 -0
- package/src/modules/communication_channels/i18n/de.json +13 -3
- package/src/modules/communication_channels/i18n/en.json +13 -3
- package/src/modules/communication_channels/i18n/es.json +13 -3
- package/src/modules/communication_channels/i18n/ko.json +13 -3
- package/src/modules/communication_channels/i18n/pl.json +13 -3
- package/src/modules/communication_channels/index.ts +1 -1
- package/src/modules/communication_channels/lib/access-control.ts +4 -1
- package/src/modules/communication_channels/lib/adapter.ts +16 -6
- package/src/modules/communication_channels/lib/channel-thread-access.ts +133 -0
- package/src/modules/communication_channels/lib/credential-refresh.ts +27 -5
- package/src/modules/communication_channels/lib/inbound-message-origin.ts +62 -0
- package/src/modules/communication_channels/lib/oauth-state.ts +96 -1
- package/src/modules/communication_channels/lib/outbound-delivery-intent.ts +57 -0
- package/src/modules/communication_channels/lib/send-as-user.ts +2 -2
- package/src/modules/communication_channels/migrations/.snapshot-open-mercato.json +18 -1
- package/src/modules/communication_channels/migrations/Migration20260825141000_communication_channels.ts +22 -0
- package/src/modules/communication_channels/setup.ts +4 -0
- package/src/modules/communication_channels/subscribers/outbound-bridge.ts +34 -9
- package/src/modules/communication_channels/workers/gmail-history-sync.ts +1 -1
- package/src/modules/communication_channels/workers/poll-channel.ts +1 -1
- package/src/modules/communication_channels/workers/reaction-processor.ts +2 -2
- package/src/modules/configs/api/upgrade-actions/route.ts +2 -1
- package/src/modules/configs/cli.ts +2 -2
- package/src/modules/configs/i18n/de.json +2 -0
- package/src/modules/configs/i18n/en.json +2 -0
- package/src/modules/configs/i18n/es.json +2 -0
- package/src/modules/configs/i18n/ko.json +2 -0
- package/src/modules/configs/i18n/pl.json +2 -0
- package/src/modules/configs/lib/upgrade-actions.ts +29 -6
- package/src/modules/configs/services/upgradeActionsService.ts +45 -30
- package/src/modules/currencies/api/currencies/route.ts +11 -5
- package/src/modules/currencies/api/exchange-rates/route.ts +11 -5
- package/src/modules/customer_accounts/AGENTS.md +1 -0
- package/src/modules/customer_accounts/api/admin/users/[id]/sessions/[sessionId].ts +89 -0
- package/src/modules/customer_groups/acl.ts +10 -0
- package/src/modules/customer_groups/api/customer-groups/[id]/terms/route.ts +355 -0
- package/src/modules/customer_groups/api/customer-groups/crud.ts +627 -0
- package/src/modules/customer_groups/api/customer-groups/explain-terms/route.ts +195 -0
- package/src/modules/customer_groups/api/customer-groups/memberships/crud.ts +525 -0
- package/src/modules/customer_groups/api/customer-groups/memberships/route.ts +65 -0
- package/src/modules/customer_groups/api/customer-groups/price-kinds/route.ts +99 -0
- package/src/modules/customer_groups/api/customer-groups/reconcile/adopt/route.ts +150 -0
- package/src/modules/customer_groups/api/customer-groups/reconcile/route.ts +90 -0
- package/src/modules/customer_groups/api/customer-groups/reorder/route.ts +147 -0
- package/src/modules/customer_groups/api/customer-groups/route.ts +65 -0
- package/src/modules/customer_groups/api/openapi.ts +28 -0
- package/src/modules/customer_groups/backend/customer-groups/[id]/edit/page.meta.ts +12 -0
- package/src/modules/customer_groups/backend/customer-groups/[id]/edit/page.tsx +392 -0
- package/src/modules/customer_groups/backend/customer-groups/create/page.meta.ts +25 -0
- package/src/modules/customer_groups/backend/customer-groups/create/page.tsx +279 -0
- package/src/modules/customer_groups/backend/customer-groups/orphans/page.meta.ts +12 -0
- package/src/modules/customer_groups/backend/customer-groups/orphans/page.tsx +216 -0
- package/src/modules/customer_groups/backend/customer-groups/page.meta.ts +11 -0
- package/src/modules/customer_groups/backend/customer-groups/page.tsx +484 -0
- package/src/modules/customer_groups/cli.ts +87 -0
- package/src/modules/customer_groups/commands/reorderGroups.ts +163 -0
- package/src/modules/customer_groups/components/CustomerGroupDefaultField.tsx +55 -0
- package/src/modules/customer_groups/components/CustomerGroupParentField.tsx +194 -0
- package/src/modules/customer_groups/components/CustomerGroupTermsPriceKindField.tsx +112 -0
- package/src/modules/customer_groups/components/CustomerGroupTermsSection.tsx +277 -0
- package/src/modules/customer_groups/components/GroupPickerField.tsx +142 -0
- package/src/modules/customer_groups/components/OrphanBanner.tsx +92 -0
- package/src/modules/customer_groups/components/customerGroupTree.ts +84 -0
- package/src/modules/customer_groups/data/entities.ts +244 -0
- package/src/modules/customer_groups/data/validators.ts +232 -0
- package/src/modules/customer_groups/di.ts +25 -0
- package/src/modules/customer_groups/events.ts +22 -0
- package/src/modules/customer_groups/i18n/de.json +199 -0
- package/src/modules/customer_groups/i18n/en.json +199 -0
- package/src/modules/customer_groups/i18n/es.json +199 -0
- package/src/modules/customer_groups/i18n/ko.json +199 -0
- package/src/modules/customer_groups/i18n/pl.json +199 -0
- package/src/modules/customer_groups/index.ts +13 -0
- package/src/modules/customer_groups/lib/createConflictRecheck.ts +39 -0
- package/src/modules/customer_groups/lib/customerScope.ts +145 -0
- package/src/modules/customer_groups/lib/groupEvents.ts +50 -0
- package/src/modules/customer_groups/lib/priceKindScope.ts +65 -0
- package/src/modules/customer_groups/lib/reconcile.ts +299 -0
- package/src/modules/customer_groups/migrations/.snapshot-open-mercato.json +905 -0
- package/src/modules/customer_groups/migrations/Migration20260922095316_customer_groups.ts +26 -0
- package/src/modules/customer_groups/migrations/Migration20260922103033_customer_groups.ts +22 -0
- package/src/modules/customer_groups/migrations/Migration20260922105444_customer_groups.ts +17 -0
- package/src/modules/customer_groups/migrations/Migration20260923193330_customer_groups.ts +20 -0
- package/src/modules/customer_groups/migrations/Migration20260929083000_customer_groups.ts +21 -0
- package/src/modules/customer_groups/services/customerGroupsService.ts +358 -0
- package/src/modules/customer_groups/setup.ts +11 -0
- package/src/modules/customer_groups/widgets/injection/group-picker-field/widget.ts +41 -0
- package/src/modules/customer_groups/widgets/injection/person-groups-explain-terms.tsx +227 -0
- package/src/modules/customer_groups/widgets/injection/person-groups-tab/widget.ts +21 -0
- package/src/modules/customer_groups/widgets/injection/person-groups-tab.tsx +573 -0
- package/src/modules/customer_groups/widgets/injection-table.ts +35 -0
- package/src/modules/customers/acl.ts +13 -0
- package/src/modules/customers/api/activities/route.ts +10 -0
- package/src/modules/customers/api/companies/[id]/people/route.ts +2 -1
- package/src/modules/customers/api/companies/[id]/route.ts +20 -6
- package/src/modules/customers/api/deals/[id]/companies/route.ts +2 -1
- package/src/modules/customers/api/deals/[id]/people/route.ts +2 -1
- package/src/modules/customers/api/deals/map/route.ts +11 -10
- package/src/modules/customers/api/dictionaries/context.ts +2 -1
- package/src/modules/customers/api/entity-roles-factory.ts +3 -2
- package/src/modules/customers/api/interactions/[id]/visibility/route.ts +2 -1
- package/src/modules/customers/api/interactions/cancel/route.ts +2 -1
- package/src/modules/customers/api/interactions/complete/route.ts +2 -1
- package/src/modules/customers/api/interactions/conflicts/route.ts +10 -10
- package/src/modules/customers/api/interactions/counts/route.ts +25 -7
- package/src/modules/customers/api/interactions/route.ts +34 -10
- package/src/modules/customers/api/labels/assign/route.ts +2 -1
- package/src/modules/customers/api/labels/route.ts +3 -2
- package/src/modules/customers/api/labels/unassign/route.ts +2 -1
- package/src/modules/customers/api/people/[id]/companies/context.ts +11 -2
- package/src/modules/customers/api/people/[id]/email-share/route.ts +276 -0
- package/src/modules/customers/api/people/[id]/email-threads/route.ts +14 -1
- package/src/modules/customers/api/people/[id]/emails/route.ts +2 -1
- package/src/modules/customers/api/people/[id]/route.ts +31 -22
- package/src/modules/customers/api/people/check-phone/route.ts +2 -1
- package/src/modules/customers/api/pipeline-stages/reorder/route.ts +3 -2
- package/src/modules/customers/api/pipeline-stages/route.ts +3 -3
- package/src/modules/customers/api/pipelines/route.ts +3 -3
- package/src/modules/customers/api/settings/address-format/route.ts +2 -1
- package/src/modules/customers/api/settings/dictionary-sort-modes/route.ts +2 -1
- package/src/modules/customers/api/settings/stuck-threshold/route.ts +2 -1
- package/src/modules/customers/api/tags/assign/route.ts +2 -1
- package/src/modules/customers/api/tags/unassign/route.ts +2 -1
- package/src/modules/customers/backend/customers/companies/[id]/page.tsx +4 -2
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.ts +10 -6
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +6 -1
- package/src/modules/customers/backend/customers/deals/components/ReassignOwnerDialog.tsx +115 -0
- package/src/modules/customers/backend/customers/deals/page.tsx +121 -1
- package/src/modules/customers/backend/customers/people/[id]/page.tsx +4 -2
- package/src/modules/customers/commands/addresses.ts +117 -15
- package/src/modules/customers/commands/companies.ts +26 -5
- package/src/modules/customers/commands/emailConversationShares.ts +261 -0
- package/src/modules/customers/commands/index.ts +1 -0
- package/src/modules/customers/commands/interactions.ts +61 -21
- package/src/modules/customers/commands/people.ts +3 -2
- package/src/modules/customers/commands/shared.ts +4 -0
- package/src/modules/customers/components/calendar/types.ts +1 -1
- package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +3 -11
- package/src/modules/customers/components/detail/DealForm.tsx +111 -2
- package/src/modules/customers/components/detail/DealOwnerSelect.tsx +161 -0
- package/src/modules/customers/components/detail/DealsSection.tsx +8 -14
- package/src/modules/customers/components/detail/PersonEmailShareControl.tsx +273 -0
- package/src/modules/customers/components/detail/PersonEmailThreadsTab.tsx +26 -0
- package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +10 -2
- package/src/modules/customers/components/detail/create/CreateDealForm.tsx +30 -0
- package/src/modules/customers/components/detail/create/DealDetailsFields.tsx +12 -0
- package/src/modules/customers/components/detail/create/DealSectionCard.tsx +7 -2
- package/src/modules/customers/components/detail/create/dealFormTypes.ts +3 -0
- package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +16 -4
- package/src/modules/customers/components/formConfig.tsx +3 -0
- package/src/modules/customers/components/linking/LinkEntityDialog.tsx +8 -0
- package/src/modules/customers/data/enrichers.ts +64 -5
- package/src/modules/customers/data/entities.ts +105 -1
- package/src/modules/customers/data/validators.ts +22 -0
- package/src/modules/customers/events.ts +5 -0
- package/src/modules/customers/i18n/de.json +28 -5
- package/src/modules/customers/i18n/en.json +23 -0
- package/src/modules/customers/i18n/es.json +23 -0
- package/src/modules/customers/i18n/ko.json +23 -0
- package/src/modules/customers/i18n/pl.json +23 -0
- package/src/modules/customers/lib/assignableStaff.ts +17 -0
- package/src/modules/customers/lib/calendar/editorPayload.ts +20 -13
- package/src/modules/customers/lib/calendar/mapItem.ts +1 -0
- package/src/modules/customers/lib/conversationShares.ts +250 -0
- package/src/modules/customers/lib/dealsOrganizationScope.ts +5 -3
- package/src/modules/customers/lib/interactionRequestContext.ts +2 -1
- package/src/modules/customers/lib/link-channel-message-handler.ts +27 -4
- package/src/modules/customers/lib/personDetailCacheTags.ts +68 -0
- package/src/modules/customers/lib/personEmailThreads.ts +61 -6
- package/src/modules/customers/lib/reassignDealOwner.ts +51 -0
- package/src/modules/customers/lib/userNames.ts +39 -0
- package/src/modules/customers/lib/visibilityFilter.ts +170 -3
- package/src/modules/customers/migrations/.snapshot-open-mercato.json +240 -0
- package/src/modules/customers/migrations/Migration20260825120000_customers.ts +19 -0
- package/src/modules/customers/migrations/Migration20260825140000_customers.ts +41 -0
- package/src/modules/customers/setup.ts +1 -0
- package/src/modules/customers/subscribers/channel-visibility-changed.ts +50 -0
- package/src/modules/dashboards/api/widgets/data/batch/route.ts +3 -8
- package/src/modules/dashboards/api/widgets/data/route.ts +12 -18
- package/src/modules/dashboards/lib/aggregations.ts +1 -1
- package/src/modules/dashboards/lib/widgetScope.ts +2 -7
- package/src/modules/data_sync/AGENTS.md +35 -1
- package/src/modules/data_sync/api/runs/[id]/cancel.ts +5 -1
- package/src/modules/data_sync/backend/data-sync/page.tsx +292 -19
- package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +205 -21
- package/src/modules/data_sync/components/useDataSyncRunAccess.ts +27 -0
- package/src/modules/data_sync/i18n/de.json +24 -0
- package/src/modules/data_sync/i18n/en.json +24 -0
- package/src/modules/data_sync/i18n/es.json +24 -0
- package/src/modules/data_sync/i18n/ko.json +24 -0
- package/src/modules/data_sync/i18n/pl.json +24 -0
- package/src/modules/data_sync/lib/adapter.ts +37 -0
- package/src/modules/data_sync/lib/resume-point.ts +63 -0
- package/src/modules/data_sync/lib/start-run.ts +61 -2
- package/src/modules/data_sync/lib/sync-run-service.ts +27 -34
- package/src/modules/devices/api/[id]/route.ts +3 -2
- package/src/modules/devices/api/admin/devices/route.ts +2 -1
- package/src/modules/devices/api/route.ts +2 -1
- package/src/modules/dictionaries/api/[dictionaryId]/route.ts +3 -5
- package/src/modules/dictionaries/api/context.ts +2 -1
- package/src/modules/dictionaries/api/route.ts +4 -0
- package/src/modules/dictionaries/components/DictionariesManager.tsx +12 -4
- package/src/modules/dictionaries/data/validators.ts +9 -1
- package/src/modules/dictionaries/i18n/de.json +3 -3
- package/src/modules/dictionaries/i18n/en.json +3 -3
- package/src/modules/dictionaries/i18n/es.json +3 -3
- package/src/modules/dictionaries/i18n/ko.json +3 -3
- package/src/modules/dictionaries/i18n/pl.json +3 -3
- package/src/modules/directory/api/organization-branding/route.ts +10 -1
- package/src/modules/directory/api/organizations/route.ts +1 -1
- package/src/modules/directory/backend/directory/branding/page.tsx +24 -2
- package/src/modules/directory/commands/organizations.ts +173 -80
- package/src/modules/directory/i18n/de.json +1 -0
- package/src/modules/directory/i18n/en.json +1 -0
- package/src/modules/directory/i18n/es.json +1 -0
- package/src/modules/directory/i18n/ko.json +1 -0
- package/src/modules/directory/i18n/pl.json +1 -0
- package/src/modules/directory/lib/hierarchy.ts +22 -1
- package/src/modules/directory/utils/organizationScope.ts +102 -15
- package/src/modules/directory/utils/organizationScopeFilter.ts +6 -3
- package/src/modules/directory/utils/organizationScopeGuard.ts +9 -5
- package/src/modules/entities/api/encryption.ts +73 -27
- package/src/modules/entities/api/records.ts +9 -8
- package/src/modules/entities/cli.ts +46 -24
- package/src/modules/entities/data/entities.ts +15 -0
- package/src/modules/entities/lib/definition-scope.ts +5 -1
- package/src/modules/entities/lib/encryption-maps.ts +164 -0
- package/src/modules/entities/lib/helpers.ts +95 -8
- package/src/modules/entities/migrations/.snapshot-open-mercato.json +21 -0
- package/src/modules/entities/migrations/.snapshot-openmercato.json +12 -0
- package/src/modules/entities/migrations/Migration20260910120000.ts +42 -0
- package/src/modules/entities/migrations/Migration20261004120000_encryption_map_scope_uniqueness.ts +130 -0
- package/src/modules/eudr/api/dashboard/widgets/compliance-overview/route.ts +2 -1
- package/src/modules/eudr/api/plots/import/route.ts +2 -1
- package/src/modules/eudr/api/product-mappings/suggestions/apply/route.ts +2 -1
- package/src/modules/eudr/api/product-mappings/suggestions/route.ts +2 -1
- package/src/modules/eudr/api/reports/annual/route.ts +2 -1
- package/src/modules/eudr/api/statements/[id]/export/route.ts +2 -1
- package/src/modules/eudr/api/statements/[id]/readiness/route.ts +2 -1
- package/src/modules/eudr/api/suppliers/compliance/route.ts +2 -1
- package/src/modules/eudr/i18n/de.json +1 -0
- package/src/modules/eudr/i18n/en.json +1 -0
- package/src/modules/eudr/i18n/es.json +1 -0
- package/src/modules/eudr/i18n/ko.json +1 -0
- package/src/modules/eudr/i18n/pl.json +1 -0
- package/src/modules/feature_toggles/commands/global.ts +18 -15
- package/src/modules/feature_toggles/lib/feature-flag-check.ts +8 -3
- package/src/modules/forms/acl.ts +10 -0
- package/src/modules/forms/api/[id]/analytics/route.ts +137 -0
- package/src/modules/forms/api/[id]/distributions/route.ts +192 -0
- package/src/modules/forms/api/[id]/route.ts +245 -0
- package/src/modules/forms/api/[id]/run/context/route.ts +142 -0
- package/src/modules/forms/api/[id]/run/submissions/route.ts +147 -0
- package/src/modules/forms/api/[id]/submissions/route.ts +100 -0
- package/src/modules/forms/api/[id]/theme-logo/route.ts +147 -0
- package/src/modules/forms/api/[id]/versions/[versionId]/diff/route.ts +137 -0
- package/src/modules/forms/api/[id]/versions/[versionId]/publish/route.ts +108 -0
- package/src/modules/forms/api/[id]/versions/[versionId]/route.ts +200 -0
- package/src/modules/forms/api/[id]/versions/fork/route.ts +98 -0
- package/src/modules/forms/api/attachment-helpers.ts +160 -0
- package/src/modules/forms/api/by-key/[key]/active/route.ts +165 -0
- package/src/modules/forms/api/distributions/[distributionId]/invitations/[invitationId]/route.ts +92 -0
- package/src/modules/forms/api/distributions/[distributionId]/invitations/[invitationId]/send/route.ts +96 -0
- package/src/modules/forms/api/distributions/[distributionId]/invitations/route.ts +207 -0
- package/src/modules/forms/api/distributions/[distributionId]/route.ts +213 -0
- package/src/modules/forms/api/form-submissions/[id]/attachments/route.ts +114 -0
- package/src/modules/forms/api/form-submissions/[id]/resume-token/route.ts +140 -0
- package/src/modules/forms/api/form-submissions/[id]/route.ts +176 -0
- package/src/modules/forms/api/form-submissions/[id]/submit/route.ts +91 -0
- package/src/modules/forms/api/form-submissions/by-subject/[subject_type]/[subject_id]/route.ts +93 -0
- package/src/modules/forms/api/form-submissions/route.ts +133 -0
- package/src/modules/forms/api/helpers.ts +175 -0
- package/src/modules/forms/api/public/distributions/[slug]/embed-policy/route.ts +74 -0
- package/src/modules/forms/api/public/distributions/[slug]/route.ts +101 -0
- package/src/modules/forms/api/public/embed-loader/route.ts +136 -0
- package/src/modules/forms/api/public/invitations/[token]/route.ts +107 -0
- package/src/modules/forms/api/public/rate-limit.ts +69 -0
- package/src/modules/forms/api/public/start/route.ts +195 -0
- package/src/modules/forms/api/public/submissions/[id]/attachments/[attachmentId]/route.ts +86 -0
- package/src/modules/forms/api/public/submissions/[id]/attachments/route.ts +108 -0
- package/src/modules/forms/api/public/submissions/[id]/pdf/route.ts +96 -0
- package/src/modules/forms/api/public/submissions/[id]/route.ts +189 -0
- package/src/modules/forms/api/public/submissions/[id]/submit/route.ts +159 -0
- package/src/modules/forms/api/route.ts +240 -0
- package/src/modules/forms/api/runtime-helpers.ts +208 -0
- package/src/modules/forms/api/subjects/[subjectType]/[subjectId]/consents/route.ts +178 -0
- package/src/modules/forms/api/subjects/[subjectType]/[subjectId]/export/route.ts +135 -0
- package/src/modules/forms/api/submissions/[submissionId]/access-audit/route.ts +100 -0
- package/src/modules/forms/api/submissions/[submissionId]/actors/[actorId]/route.ts +70 -0
- package/src/modules/forms/api/submissions/[submissionId]/actors/route.ts +92 -0
- package/src/modules/forms/api/submissions/[submissionId]/anonymize/route.ts +134 -0
- package/src/modules/forms/api/submissions/[submissionId]/attachments/[attachmentId]/route.ts +90 -0
- package/src/modules/forms/api/submissions/[submissionId]/export/route.ts +111 -0
- package/src/modules/forms/api/submissions/[submissionId]/pdf/route.ts +118 -0
- package/src/modules/forms/api/submissions/[submissionId]/reopen/route.ts +69 -0
- package/src/modules/forms/api/submissions/[submissionId]/revisions/route.ts +75 -0
- package/src/modules/forms/api/submissions/[submissionId]/route.ts +90 -0
- package/src/modules/forms/backend/forms/[id]/FormStudio.tsx +3269 -0
- package/src/modules/forms/backend/forms/[id]/analytics/page.meta.ts +15 -0
- package/src/modules/forms/backend/forms/[id]/analytics/page.tsx +289 -0
- package/src/modules/forms/backend/forms/[id]/distributions/page.meta.ts +15 -0
- package/src/modules/forms/backend/forms/[id]/distributions/page.tsx +16 -0
- package/src/modules/forms/backend/forms/[id]/history/page.meta.ts +11 -0
- package/src/modules/forms/backend/forms/[id]/history/page.tsx +229 -0
- package/src/modules/forms/backend/forms/[id]/page.meta.ts +11 -0
- package/src/modules/forms/backend/forms/[id]/page.tsx +17 -0
- package/src/modules/forms/backend/forms/[id]/studio/YesNoRow.tsx +65 -0
- package/src/modules/forms/backend/forms/[id]/studio/autosave-guard.ts +25 -0
- package/src/modules/forms/backend/forms/[id]/studio/canvas/DragOverlayCard.tsx +24 -0
- package/src/modules/forms/backend/forms/[id]/studio/canvas/DropIndicator.tsx +36 -0
- package/src/modules/forms/backend/forms/[id]/studio/canvas/FieldRow.tsx +308 -0
- package/src/modules/forms/backend/forms/[id]/studio/canvas/FormCanvas.tsx +265 -0
- package/src/modules/forms/backend/forms/[id]/studio/canvas/GridSlot.tsx +176 -0
- package/src/modules/forms/backend/forms/[id]/studio/canvas/SectionContainer.tsx +473 -0
- package/src/modules/forms/backend/forms/[id]/studio/canvas/grid-collision.ts +25 -0
- package/src/modules/forms/backend/forms/[id]/studio/canvas/keyboard-coordinates.ts +128 -0
- package/src/modules/forms/backend/forms/[id]/studio/canvas/overlay-size.ts +15 -0
- package/src/modules/forms/backend/forms/[id]/studio/canvas/resize-math.ts +36 -0
- package/src/modules/forms/backend/forms/[id]/studio/canvas/row-layout.ts +110 -0
- package/src/modules/forms/backend/forms/[id]/studio/logic/ConditionBuilder.tsx +264 -0
- package/src/modules/forms/backend/forms/[id]/studio/logic/HiddenFieldsPanel.tsx +121 -0
- package/src/modules/forms/backend/forms/[id]/studio/logic/JumpsEditor.tsx +237 -0
- package/src/modules/forms/backend/forms/[id]/studio/logic/RecallTokenPicker.tsx +87 -0
- package/src/modules/forms/backend/forms/[id]/studio/logic/VariablesPanel.tsx +260 -0
- package/src/modules/forms/backend/forms/[id]/studio/logic/condition-model.ts +207 -0
- package/src/modules/forms/backend/forms/[id]/studio/lucide-icons.ts +87 -0
- package/src/modules/forms/backend/forms/[id]/studio/palette/FormAppearancePanel.tsx +561 -0
- package/src/modules/forms/backend/forms/[id]/studio/palette/FormPalettePanel.tsx +52 -0
- package/src/modules/forms/backend/forms/[id]/studio/palette/InputParametersTab.tsx +378 -0
- package/src/modules/forms/backend/forms/[id]/studio/palette/PaletteCard.tsx +40 -0
- package/src/modules/forms/backend/forms/[id]/studio/palette/RolesEditor.tsx +225 -0
- package/src/modules/forms/backend/forms/[id]/studio/palette/entries.ts +102 -0
- package/src/modules/forms/backend/forms/[id]/studio/preview/PreviewSurface.tsx +1459 -0
- package/src/modules/forms/backend/forms/[id]/studio/preview/ViewportFrame.tsx +49 -0
- package/src/modules/forms/backend/forms/[id]/studio/recall.ts +0 -0
- package/src/modules/forms/backend/forms/[id]/studio/schema-helpers.ts +2525 -0
- package/src/modules/forms/backend/forms/[id]/studio/style/BackgroundControl.tsx +137 -0
- package/src/modules/forms/backend/forms/[id]/studio/style/ColorControl.tsx +257 -0
- package/src/modules/forms/backend/forms/[id]/studio/style/contrast.ts +114 -0
- package/src/modules/forms/backend/forms/[id]/studio/style/presets.ts +104 -0
- package/src/modules/forms/backend/forms/[id]/studio/type-label.ts +13 -0
- package/src/modules/forms/backend/forms/[id]/studio/types.ts +31 -0
- package/src/modules/forms/backend/forms/[id]/studio/undo-controller.ts +52 -0
- package/src/modules/forms/backend/forms/[id]/studio/validation/FileConstraintsEditor.tsx +89 -0
- package/src/modules/forms/backend/forms/[id]/studio/validation/GroupConfigEditor.tsx +167 -0
- package/src/modules/forms/backend/forms/[id]/studio/validation/LengthRangeEditor.tsx +67 -0
- package/src/modules/forms/backend/forms/[id]/studio/validation/MatrixColumnsEditor.tsx +166 -0
- package/src/modules/forms/backend/forms/[id]/studio/validation/MatrixRowsEditor.tsx +184 -0
- package/src/modules/forms/backend/forms/[id]/studio/validation/MessageOverridesEditor.tsx +83 -0
- package/src/modules/forms/backend/forms/[id]/studio/validation/NpsAnchorsEditor.tsx +60 -0
- package/src/modules/forms/backend/forms/[id]/studio/validation/NumberRangeEditor.tsx +65 -0
- package/src/modules/forms/backend/forms/[id]/studio/validation/OpinionIconSelect.tsx +46 -0
- package/src/modules/forms/backend/forms/[id]/studio/validation/PatternEditor.tsx +122 -0
- package/src/modules/forms/backend/forms/[id]/studio/validation/RankingExhaustiveSwitch.tsx +28 -0
- package/src/modules/forms/backend/forms/[id]/studio/validation/SignatureConfigEditor.tsx +84 -0
- package/src/modules/forms/backend/forms/[id]/studio/validation/ValidationPanel.tsx +369 -0
- package/src/modules/forms/backend/forms/[id]/submissions/components/RowBadges.ts +56 -0
- package/src/modules/forms/backend/forms/[id]/submissions/components/SubmissionDrawer.tsx +605 -0
- package/src/modules/forms/backend/forms/[id]/submissions/components/formSummary.ts +19 -0
- package/src/modules/forms/backend/forms/[id]/submissions/page.meta.ts +10 -0
- package/src/modules/forms/backend/forms/[id]/submissions/page.tsx +252 -0
- package/src/modules/forms/backend/forms/create/page.meta.ts +11 -0
- package/src/modules/forms/backend/forms/create/page.tsx +113 -0
- package/src/modules/forms/backend/forms/page.meta.ts +31 -0
- package/src/modules/forms/backend/forms/page.tsx +269 -0
- package/src/modules/forms/commands/distribution.ts +506 -0
- package/src/modules/forms/commands/form-version.ts +811 -0
- package/src/modules/forms/commands/form.ts +477 -0
- package/src/modules/forms/commands/index.ts +18 -0
- package/src/modules/forms/commands/invitation.ts +428 -0
- package/src/modules/forms/commands/shared.ts +261 -0
- package/src/modules/forms/commands/submission.ts +216 -0
- package/src/modules/forms/data/entities.ts +686 -0
- package/src/modules/forms/data/validators.ts +483 -0
- package/src/modules/forms/di.ts +246 -0
- package/src/modules/forms/encryption.ts +31 -0
- package/src/modules/forms/events-payloads.ts +103 -0
- package/src/modules/forms/events.ts +50 -0
- package/src/modules/forms/extension-points.ts +41 -0
- package/src/modules/forms/frontend/[orgSlug]/portal/forms/[key]/page.meta.ts +9 -0
- package/src/modules/forms/frontend/[orgSlug]/portal/forms/[key]/page.tsx +45 -0
- package/src/modules/forms/frontend/[orgSlug]/portal/submissions/[id]/continue/page.meta.ts +9 -0
- package/src/modules/forms/frontend/[orgSlug]/portal/submissions/[id]/continue/page.tsx +56 -0
- package/src/modules/forms/frontend/embed/[slug]/page.meta.ts +42 -0
- package/src/modules/forms/frontend/embed/[slug]/page.tsx +171 -0
- package/src/modules/forms/frontend/f/[slug]/page.meta.ts +9 -0
- package/src/modules/forms/frontend/f/[slug]/page.tsx +10 -0
- package/src/modules/forms/frontend/forms/[id]/run/page.meta.ts +17 -0
- package/src/modules/forms/frontend/forms/[id]/run/page.tsx +83 -0
- package/src/modules/forms/frontend/i/[token]/page.meta.ts +9 -0
- package/src/modules/forms/frontend/i/[token]/page.tsx +10 -0
- package/src/modules/forms/i18n/de.json +821 -0
- package/src/modules/forms/i18n/en.json +821 -0
- package/src/modules/forms/i18n/es.json +821 -0
- package/src/modules/forms/i18n/ko.json +821 -0
- package/src/modules/forms/i18n/pl.json +821 -0
- package/src/modules/forms/index.ts +18 -0
- package/src/modules/forms/lib/embed-frame-policy.ts +144 -0
- package/src/modules/forms/lib/form-definition-slicing.ts +54 -0
- package/src/modules/forms/lib/log-redaction.ts +91 -0
- package/src/modules/forms/lib/navigable-url.ts +57 -0
- package/src/modules/forms/lib/retention.ts +73 -0
- package/src/modules/forms/lib/runtime-principal.ts +101 -0
- package/src/modules/forms/migrations/.snapshot-open-mercato.json +3185 -0
- package/src/modules/forms/migrations/Migration20260508135459_forms.ts +17 -0
- package/src/modules/forms/migrations/Migration20260508140932_forms.ts +26 -0
- package/src/modules/forms/migrations/Migration20260508155737_forms.ts +15 -0
- package/src/modules/forms/migrations/Migration20260520120000_forms.ts +26 -0
- package/src/modules/forms/migrations/Migration20260521090000_forms.ts +15 -0
- package/src/modules/forms/migrations/Migration20260521120000_forms.ts +21 -0
- package/src/modules/forms/runner/FormRunner.tsx +924 -0
- package/src/modules/forms/runner/MatrixField.tsx +210 -0
- package/src/modules/forms/runner/RankingField.tsx +207 -0
- package/src/modules/forms/runner/ScaleField.tsx +102 -0
- package/src/modules/forms/runner/SignatureField.tsx +158 -0
- package/src/modules/forms/runner/tamper-check.ts +131 -0
- package/src/modules/forms/schema/address-countries.ts +60 -0
- package/src/modules/forms/schema/field-type-patterns.ts +21 -0
- package/src/modules/forms/schema/field-type-registry-advanced.ts +58 -0
- package/src/modules/forms/schema/field-type-registry.ts +819 -0
- package/src/modules/forms/schema/file-field.ts +102 -0
- package/src/modules/forms/schema/group-field.ts +235 -0
- package/src/modules/forms/schema/jsonlogic-grammar.ts +95 -0
- package/src/modules/forms/schema/jsonschema-extensions.ts +1060 -0
- package/src/modules/forms/schema/layout-catalog.ts +68 -0
- package/src/modules/forms/schema/signature-field.ts +120 -0
- package/src/modules/forms/schema/style-extensions.ts +194 -0
- package/src/modules/forms/schema/style-validators.ts +252 -0
- package/src/modules/forms/services/access-audit-logger.ts +275 -0
- package/src/modules/forms/services/analytics-service.ts +498 -0
- package/src/modules/forms/services/anonymize-service.ts +177 -0
- package/src/modules/forms/services/attachment-service.ts +223 -0
- package/src/modules/forms/services/captcha-verifier.ts +156 -0
- package/src/modules/forms/services/consent-record-service.ts +162 -0
- package/src/modules/forms/services/distribution-service.ts +509 -0
- package/src/modules/forms/services/distribution-token.ts +153 -0
- package/src/modules/forms/services/encryption-service.ts +500 -0
- package/src/modules/forms/services/export-service.ts +360 -0
- package/src/modules/forms/services/field-validation-service.ts +300 -0
- package/src/modules/forms/services/form-logic-evaluator.ts +718 -0
- package/src/modules/forms/services/form-version-compiler.ts +829 -0
- package/src/modules/forms/services/form-version-differ.ts +143 -0
- package/src/modules/forms/services/jsonlogic-evaluator.ts +228 -0
- package/src/modules/forms/services/pdf-snapshot-service.ts +782 -0
- package/src/modules/forms/services/prefill-resolver.ts +125 -0
- package/src/modules/forms/services/role-policy-service.ts +90 -0
- package/src/modules/forms/services/style-compiler.ts +378 -0
- package/src/modules/forms/services/submission-service.ts +1259 -0
- package/src/modules/forms/services/upload-scanner.ts +36 -0
- package/src/modules/forms/services/upload-validation.ts +94 -0
- package/src/modules/forms/services/visibility-resolver.ts +63 -0
- package/src/modules/forms/setup.ts +16 -0
- package/src/modules/forms/subscribers/forms-consent-projector.ts +100 -0
- package/src/modules/forms/subscribers/forms-pdf-snapshot.ts +112 -0
- package/src/modules/forms/subscribers/forms-webhook-bridge-anonymized.ts +36 -0
- package/src/modules/forms/subscribers/forms-webhook-bridge.ts +56 -0
- package/src/modules/forms/subscribers/invitation-email.ts +180 -0
- package/src/modules/forms/translations.ts +14 -0
- package/src/modules/forms/ui/admin/forms/[id]/distributions/CreateDistributionDialog.tsx +401 -0
- package/src/modules/forms/ui/admin/forms/[id]/distributions/DistributionsPanel.tsx +381 -0
- package/src/modules/forms/ui/admin/forms/[id]/distributions/EmbedSettingsDialog.tsx +332 -0
- package/src/modules/forms/ui/admin/forms/[id]/distributions/RecipientsTable.tsx +460 -0
- package/src/modules/forms/ui/public/EmbeddedForm.tsx +248 -0
- package/src/modules/forms/ui/public/FormRunner.tsx +491 -0
- package/src/modules/forms/ui/public/FormTrigger.tsx +80 -0
- package/src/modules/forms/ui/public/PublicFormRunnerPage.tsx +34 -0
- package/src/modules/forms/ui/public/components/CompletionScreen.tsx +97 -0
- package/src/modules/forms/ui/public/components/LocaleSwitch.tsx +42 -0
- package/src/modules/forms/ui/public/components/ResumeGate.tsx +61 -0
- package/src/modules/forms/ui/public/components/ReviewStep.tsx +153 -0
- package/src/modules/forms/ui/public/components/SaveIndicator.tsx +69 -0
- package/src/modules/forms/ui/public/components/SectionStepper.tsx +60 -0
- package/src/modules/forms/ui/public/index.ts +48 -0
- package/src/modules/forms/ui/public/renderers/index.tsx +889 -0
- package/src/modules/forms/ui/public/state/logic-derivation.ts +91 -0
- package/src/modules/forms/ui/public/state/runtime-client.ts +495 -0
- package/src/modules/forms/ui/public/state/useAutosave.ts +97 -0
- package/src/modules/forms/ui/public/state/useFormRunner.ts +547 -0
- package/src/modules/forms/ui/public/style/LogoHeader.tsx +43 -0
- package/src/modules/forms/ui/public/style/applyStyle.ts +26 -0
- package/src/modules/forms/ui/public/types.ts +228 -0
- package/src/modules/forms/widgets/injection/access-audit-panel/widget.tsx +144 -0
- package/src/modules/forms/widgets/injection/anonymize-button/widget.tsx +177 -0
- package/src/modules/forms/widgets/injection/audit-format.ts +60 -0
- package/src/modules/forms/widgets/injection/context.ts +24 -0
- package/src/modules/forms/widgets/injection/embedded-form/widget.tsx +102 -0
- package/src/modules/forms/widgets/injection/pdf-download-button/widget.tsx +111 -0
- package/src/modules/forms/widgets/injection/self-audit-footer/widget.tsx +56 -0
- package/src/modules/forms/widgets/injection-table.ts +54 -0
- package/src/modules/forms/workers/pdf-snapshot.ts +110 -0
- package/src/modules/forms/workers/retention-purge.ts +169 -0
- package/src/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.ts +7 -1
- package/src/modules/inbox_ops/data/validators.ts +2 -1
- package/src/modules/inbox_ops/lib/llmProvider.ts +11 -0
- package/src/modules/inbox_ops/widgets/notifications/ProposalCreatedRenderer.tsx +2 -2
- package/src/modules/integrations/di.ts +5 -1
- package/src/modules/integrations/lib/credentials-service.ts +45 -36
- package/src/modules/messages/api/[id]/attachments/route.ts +12 -3
- package/src/modules/messages/api/[id]/forward-preview/route.ts +9 -3
- package/src/modules/messages/api/[id]/route.ts +83 -4
- package/src/modules/messages/api/route.ts +123 -2
- package/src/modules/messages/commands/messages.ts +81 -7
- package/src/modules/messages/components/ComposeMessagePageClient.tsx +29 -1
- package/src/modules/messages/data/validators.ts +10 -0
- package/src/modules/messages/i18n/de.json +8 -0
- package/src/modules/messages/i18n/en.json +8 -0
- package/src/modules/messages/i18n/es.json +8 -0
- package/src/modules/messages/i18n/ko.json +8 -0
- package/src/modules/messages/i18n/pl.json +8 -0
- package/src/modules/messages/lib/channelThreadAccess.ts +101 -0
- package/src/modules/messages/lib/composeSenderDelegation.ts +182 -0
- package/src/modules/messages/lib/composeSenderOptions.ts +56 -0
- package/src/modules/messages/lib/email-sender.ts +1 -17
- package/src/modules/messages/lib/forwarding.ts +17 -2
- package/src/modules/messages/lib/markdownEmailBody.ts +25 -0
- package/src/modules/messages/lib/messageSourceEntityTypes.ts +12 -0
- package/src/modules/messages/lib/routeHelpers.ts +92 -0
- package/src/modules/messages/subscribers/message-notification.ts +47 -1
- package/src/modules/notifications/AGENTS.md +1 -1
- package/src/modules/notifications/api/[id]/action/route.ts +2 -1
- package/src/modules/notifications/api/openapi.ts +1 -0
- package/src/modules/notifications/frontend/NotificationSettingsPageClient.tsx +77 -48
- package/src/modules/notifications/i18n/de.json +1 -0
- package/src/modules/notifications/i18n/en.json +1 -0
- package/src/modules/notifications/i18n/es.json +1 -0
- package/src/modules/notifications/i18n/ko.json +1 -0
- package/src/modules/notifications/i18n/pl.json +1 -0
- package/src/modules/notifications/lib/deliveryConfig.ts +31 -2
- package/src/modules/notifications/lib/notificationMapper.ts +2 -0
- package/src/modules/notifications/lib/safeHref.ts +7 -0
- package/src/modules/planner/api/availability-date-specific.ts +2 -1
- package/src/modules/planner/api/availability-weekly.ts +2 -1
- package/src/modules/progress/AGENTS.md +2 -0
- package/src/modules/progress/api/active/route.ts +14 -2
- package/src/modules/progress/api/jobs/[id]/route.ts +44 -27
- package/src/modules/progress/api/jobs/route.ts +22 -8
- package/src/modules/progress/api/requestScope.ts +43 -0
- package/src/modules/progress/lib/organizationScope.ts +17 -0
- package/src/modules/progress/lib/progressService.ts +3 -2
- package/src/modules/progress/lib/progressServiceImpl.ts +63 -14
- package/src/modules/push_notifications/api/custom-send/route.ts +4 -1
- package/src/modules/push_notifications/i18n/de.json +1 -0
- package/src/modules/push_notifications/i18n/en.json +1 -0
- package/src/modules/push_notifications/i18n/es.json +1 -0
- package/src/modules/push_notifications/i18n/ko.json +1 -0
- package/src/modules/push_notifications/i18n/pl.json +1 -0
- package/src/modules/query_index/api/status.ts +4 -9
- package/src/modules/query_index/di.ts +2 -1
- package/src/modules/query_index/lib/engine.ts +2 -0
- package/src/modules/query_index/lib/request-encryption.ts +31 -0
- package/src/modules/query_index/lib/search-tokens.ts +42 -1
- package/src/modules/resources/api/resources/tags/assign/route.ts +2 -1
- package/src/modules/resources/api/resources/tags/unassign/route.ts +2 -1
- package/src/modules/resources/commands/activities.ts +2 -2
- package/src/modules/sales/api/document-history/route.ts +5 -1
- package/src/modules/sales/api/document-numbers/route.ts +2 -1
- package/src/modules/sales/api/quotes/convert/route.ts +2 -1
- package/src/modules/sales/api/quotes/send/route.ts +2 -1
- package/src/modules/sales/api/settings/document-numbers/route.ts +7 -1
- package/src/modules/sales/api/settings/order-editing/route.ts +7 -1
- package/src/modules/sales/commands/documents.ts +451 -131
- package/src/modules/sales/commands/payments.ts +2 -1
- package/src/modules/sales/commands/settings.ts +34 -6
- package/src/modules/sales/commands/shipments.ts +2 -1
- package/src/modules/sales/components/DocumentNumberSettings.tsx +41 -28
- package/src/modules/sales/components/documents/ItemsSection.tsx +58 -13
- package/src/modules/sales/i18n/de.json +2 -0
- package/src/modules/sales/i18n/en.json +2 -0
- package/src/modules/sales/i18n/es.json +2 -0
- package/src/modules/sales/i18n/ko.json +2 -0
- package/src/modules/sales/i18n/pl.json +2 -0
- package/src/modules/sales/lib/lineSnapshots.ts +36 -0
- package/src/modules/sales/setup.ts +4 -4
- package/src/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.tsx +2 -2
- package/src/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.tsx +2 -2
- package/src/modules/staff/api/leave-requests/accept/route.ts +2 -1
- package/src/modules/staff/api/leave-requests/reject/route.ts +2 -1
- package/src/modules/staff/api/leave-requests.ts +2 -1
- package/src/modules/staff/api/team-members/self/route.ts +2 -1
- package/src/modules/staff/api/team-members/tags/assign/route.ts +2 -1
- package/src/modules/staff/api/team-members/tags/unassign/route.ts +2 -1
- package/src/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.ts +16 -16
- package/src/modules/staff/api/timesheets/my-projects/[projectId]/route.ts +2 -1
- package/src/modules/staff/api/timesheets/my-projects/route.ts +2 -1
- package/src/modules/staff/api/timesheets/my-work/route.ts +2 -1
- package/src/modules/staff/api/timesheets/projects/kpis/route.ts +2 -1
- package/src/modules/staff/api/timesheets/reports/[id]/close/route.ts +2 -1
- package/src/modules/staff/api/timesheets/reports/[id]/export/route.ts +3 -2
- package/src/modules/staff/api/timesheets/reports/[id]/sheet/route.ts +3 -2
- package/src/modules/staff/api/timesheets/reports/[id]/unlock/route.ts +3 -2
- package/src/modules/staff/api/timesheets/reports/preview/route.ts +2 -1
- package/src/modules/staff/api/timesheets/reports/shared.ts +2 -1
- package/src/modules/staff/api/timesheets/settings/reapply-rounding/route.ts +2 -1
- package/src/modules/staff/api/timesheets/tags/entry-assignments/route.ts +2 -1
- package/src/modules/staff/api/timesheets/tags/task-assignments/route.ts +2 -1
- package/src/modules/staff/api/timesheets/tasks/[id]/comments/route.ts +2 -1
- package/src/modules/staff/api/timesheets/tasks/[id]/status/route.ts +2 -1
- package/src/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.ts +3 -2
- package/src/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.ts +2 -1
- package/src/modules/staff/api/timesheets/time-entries/[id]/segments/route.ts +2 -1
- package/src/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.ts +2 -1
- package/src/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.ts +2 -1
- package/src/modules/staff/api/timesheets/time-entries/bulk/route.ts +2 -1
- package/src/modules/staff/api/timesheets/time-entries/copy-day/route.ts +3 -2
- package/src/modules/staff/api/timesheets/time-entries/overlaps/route.ts +2 -1
- package/src/modules/staff/api/timesheets/time-entries/start-timer/route.ts +3 -2
- package/src/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.ts +3 -2
- package/src/modules/staff/api/timesheets/time-projects/route.ts +2 -1
- package/src/modules/staff/commands/activities.ts +2 -2
- package/src/modules/staff/commands/timesheets-entries.ts +3 -2
- package/src/modules/staff/commands/timesheets-reports.ts +88 -15
- package/src/modules/staff/lib/timesheets-reports/buildReportSheet.ts +1 -0
- package/src/modules/staff/lib/timesheets-reports/loadReportData.ts +69 -8
- package/src/modules/staff/lib/timesheets-reports/reportPeriod.ts +18 -0
- package/src/modules/staff/lib/timesheets-ui/CalendarPicker.tsx +21 -10
- package/src/modules/sync_excel/api/import/route.ts +40 -12
- package/src/modules/sync_excel/api/upload/route.ts +34 -4
- package/src/modules/translations/api/context.ts +2 -1
- package/src/modules/warranty_claims/api/ai/assess/route.ts +2 -1
- package/src/modules/warranty_claims/api/ai/draft-reply/route.ts +2 -1
- package/src/modules/warranty_claims/api/ai/suggest/route.ts +2 -1
- package/src/modules/warranty_claims/api/assign/route.ts +2 -1
- package/src/modules/warranty_claims/api/credit-memo/route.ts +2 -1
- package/src/modules/warranty_claims/api/entitlement/route.ts +2 -1
- package/src/modules/warranty_claims/api/events/route.ts +2 -1
- package/src/modules/warranty_claims/api/external/claims/route.ts +2 -1
- package/src/modules/warranty_claims/api/receiving/route.ts +2 -1
- package/src/modules/warranty_claims/api/replacement-order/route.ts +2 -1
- package/src/modules/warranty_claims/api/return-label/route.ts +2 -1
- package/src/modules/warranty_claims/api/risk/route.ts +2 -1
- package/src/modules/warranty_claims/api/sales-return/route.ts +2 -1
- package/src/modules/warranty_claims/api/settings-general/route.ts +2 -1
- package/src/modules/warranty_claims/api/stats/route.ts +11 -11
- package/src/modules/warranty_claims/api/submit/route.ts +2 -1
- package/src/modules/warranty_claims/api/transition/route.ts +2 -1
- package/src/modules/warranty_claims/api/vendor-recovery/route.ts +2 -1
- package/src/modules/warranty_claims/api/vendor-recovery-suggestions/route.ts +2 -1
- package/src/modules/warranty_claims/i18n/de.json +1 -0
- package/src/modules/warranty_claims/i18n/en.json +1 -0
- package/src/modules/warranty_claims/i18n/es.json +1 -0
- package/src/modules/warranty_claims/i18n/ko.json +1 -0
- package/src/modules/warranty_claims/i18n/pl.json +1 -0
- package/src/modules/warranty_claims/widgets/notifications/WarrantyClaimNotificationRenderer.tsx +1 -1
- package/src/modules/wms/api/dashboard/operational/route.ts +2 -1
- package/src/modules/wms/api/inventory/cycle-count/route.ts +1 -0
- package/src/modules/wms/api/inventory/helpers.ts +2 -1
- package/src/modules/wms/api/inventory/import/helpers.ts +2 -1
- package/src/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.ts +2 -1
- package/src/modules/wms/commands/inventory-actions.ts +45 -1
- package/src/modules/wms/components/backend/CycleCountWizardDialog.tsx +14 -1
- package/src/modules/wms/di.ts +6 -0
- package/src/modules/wms/i18n/de.json +2 -0
- package/src/modules/wms/i18n/en.json +2 -0
- package/src/modules/wms/i18n/es.json +2 -0
- package/src/modules/wms/i18n/ko.json +2 -0
- package/src/modules/wms/i18n/pl.json +2 -0
- package/src/modules/wms/lib/availabilityCache.ts +137 -0
- package/src/modules/wms/lib/availabilityCalculation.ts +351 -0
- package/src/modules/wms/lib/availabilityProvider.ts +47 -0
- package/src/modules/wms/lib/loadOperationalDashboard.ts +51 -3
- package/src/modules/wms/lib/lowStockBalanceFilter.ts +23 -10
- package/src/modules/wms/lib/sqlInClause.ts +21 -0
- package/src/modules/wms/lib/tryResolve.ts +8 -0
- package/src/modules/wms/subscribers/invalidate-availability-cache-policy.ts +18 -0
- package/src/modules/wms/subscribers/invalidate-availability-cache-profile.ts +18 -0
- package/src/modules/wms/subscribers/invalidate-availability-cache.ts +30 -0
- package/src/modules/wms/widgets/notifications/WmsLowStockRenderer.tsx +2 -2
- package/src/modules/wms/widgets/notifications/WmsReservationShortfallRenderer.tsx +4 -3
- package/src/modules/workflows/AGENTS.md +7 -5
- package/src/modules/workflows/api/commands/route.ts +4 -1
- package/src/modules/workflows/api/definitions/[id]/callers/route.ts +4 -1
- package/src/modules/workflows/api/definitions/[id]/context-schema/route.ts +4 -2
- package/src/modules/workflows/api/definitions/[id]/customize/route.ts +4 -1
- package/src/modules/workflows/api/definitions/[id]/draft/route.ts +6 -1
- package/src/modules/workflows/api/definitions/[id]/publish/route.ts +10 -1
- package/src/modules/workflows/api/definitions/[id]/reset-to-code/route.ts +4 -1
- package/src/modules/workflows/api/definitions/[id]/route.ts +5 -3
- package/src/modules/workflows/api/definitions/[id]/test-step/route.ts +4 -2
- package/src/modules/workflows/api/definitions/generate/route.ts +4 -1
- package/src/modules/workflows/api/definitions/route.ts +4 -2
- package/src/modules/workflows/api/endpoints/route.ts +4 -1
- package/src/modules/workflows/api/functions/route.ts +4 -1
- package/src/modules/workflows/api/grantable-features/route.ts +2 -1
- package/src/modules/workflows/api/instances/[id]/advance/route.ts +4 -1
- package/src/modules/workflows/api/instances/[id]/cancel/route.ts +4 -1
- package/src/modules/workflows/api/instances/[id]/context/route.ts +2 -1
- package/src/modules/workflows/api/instances/[id]/rerun-step/route.ts +4 -1
- package/src/modules/workflows/api/instances/[id]/retry/route.ts +4 -1
- package/src/modules/workflows/api/instances/[id]/signal/route.ts +4 -1
- package/src/modules/workflows/api/instances/[id]/step-through/route.ts +4 -2
- package/src/modules/workflows/api/instances/route.ts +4 -2
- package/src/modules/workflows/api/instances/validate-start/route.ts +4 -1
- package/src/modules/workflows/api/rule-usage/route.ts +4 -1
- package/src/modules/workflows/api/signals/route.ts +4 -1
- package/src/modules/workflows/api/tasks/[id]/claim/route.ts +4 -1
- package/src/modules/workflows/api/tasks/[id]/complete/route.ts +4 -1
- package/src/modules/workflows/api/tasks/[id]/reassign/route.ts +2 -1
- package/src/modules/workflows/api/tasks/[id]/unclaim/route.ts +4 -1
- package/src/modules/workflows/api/templates/route.ts +4 -1
- package/src/modules/workflows/api/work-inbox/next/route.ts +4 -1
- package/src/modules/workflows/lib/activity-executor.ts +125 -28
- package/src/modules/workflows/lib/activity-types.ts +8 -4
- package/src/modules/workflows/lib/activity-worker-handler.ts +16 -12
- package/src/modules/workflows/lib/event-trigger-service.ts +18 -2
- package/src/modules/workflows/lib/step-handler.ts +13 -8
- package/src/test-utils/transactionalEntityManagerDouble.ts +51 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/customers/lib/link-channel-message-handler.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CustomerEntity, CustomerInteraction } from '../data/entities'\nimport { findPeopleByAddresses, normalizeAddresses } from './findPeopleByAddresses'\nimport { emitCustomersEvent } from '../events'\nimport { INTERACTION_STATUS_COMPLETED } from './interactionStatus'\n\n/**\n * Shared implementation for the link-channel-message subscribers.\n *\n * The auto-discovery scanner requires a single string `event` value on each\n * subscriber file. Because we must handle both `communication_channels.message.received`\n * AND `.sent`, we use TWO thin subscriber files (link-channel-message-received.ts\n * and link-channel-message-sent.ts) that both delegate here.\n */\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Payload emitted by `communication_channels.message.received` and\n * `communication_channels.message.sent`.\n *\n * The canonical field is `channelLinkId` (as emitted by the hub). The alias\n * `messageChannelLinkId` is kept for test stubs and legacy compatibility.\n */\ntype LinkChannelMessagePayload = {\n eventType?: string\n /** UUID of the MessageChannelLink row (canonical hub field name). */\n channelLinkId?: string\n /** Alias used in some older stubs / test payloads. Prefer channelLinkId. */\n messageChannelLinkId?: string\n channelId?: string | null\n tenantId?: string\n organizationId?: string | null\n providerKey?: string | null\n direction?: 'inbound' | 'outbound' | null\n /**\n * The provider's own receive/send time, carried by the hub on the event\n * (#6095). An ISO string when the event rode the queue, a Date for an\n * in-process emit. Absent on events enqueued before the field existed and on\n * adapters that supply no timestamp.\n */\n providerTimestamp?: string | Date | null\n}\n\ntype SubscriberContext = {\n resolve: <T = unknown>(name: string) => T\n}\n\n// \u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst POSTGRES_UNIQUE_VIOLATION = '23505'\n\n// \u2500\u2500 Main handler \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport default async function handler(\n payload: LinkChannelMessagePayload,\n ctx: SubscriberContext,\n): Promise<void> {\n // Resolve the link ID from either field name.\n const linkId = payload?.channelLinkId ?? payload?.messageChannelLinkId\n if (typeof linkId !== 'string' || !linkId) return\n\n // Fail-closed when tenantId is missing \u2014 unscoped queries are unsafe.\n if (typeof payload.tenantId !== 'string' || !payload.tenantId) return\n\n const tenantId = payload.tenantId\n const organizationId = payload.organizationId ?? null\n // CustomerEntity and CustomerInteraction are organization-scoped. Without an\n // organization id, fail closed instead of linking tenant-wide by email/thread.\n if (!organizationId) return\n const dscope = { tenantId, organizationId }\n\n // em.fork() gives us an isolated identity map for this event.\n const em = (ctx.resolve('em') as EntityManager).fork()\n\n // \u2500\u2500 (1) Load the MessageChannelLink row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // The customers module MUST NOT import MessageChannelLink from the\n // communication_channels module (cross-module ORM boundary rule in AGENTS.md).\n // We use the entity class name as a string so MikroORM's identity map resolves\n // it at runtime \u2014 the generated entity registry includes the hub's entities.\n // Read through findOneWithDecryption so any encrypted columns on the hub\n // entity are transparently decrypted (per the Encryption section in AGENTS.md).\n const link = (await findOneWithDecryption(\n em,\n 'MessageChannelLink' as any,\n { id: linkId, tenantId, organizationId } as any,\n undefined,\n dscope,\n )) as Record<string, unknown> | null\n\n if (!link) return\n\n const metaJson = (link.channelMetadata ?? null) as Record<string, unknown> | null\n const payloadJson = (link.channelPayload ?? null) as Record<string, unknown> | null\n\n // \u2500\u2500 (1b) Resolve when the email actually happened \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // `link.createdAt` is when the hub ingested the message, which for a history\n // import is the import minute, not the day the mail arrived (#6095). The hub\n // carries the provider's own timestamp on the event payload, so take it from\n // there: reading the communication_channels ExternalMessage row here would\n // cross the storage boundary (Cross-Module Coupling in AGENTS.md) and add a\n // peer-table query per event. Resolved once and threaded through every branch\n // below so the address-match and threading-inheritance paths agree.\n const occurredAt = resolveOccurredAt(payload, link)\n\n // \u2500\u2500 (2) Resolve the channel to get its owner userId \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // The channel.userId is needed for two purposes:\n // - authorUserId on the CustomerInteraction row\n // - default visibility ('private' for user-scoped, 'shared' for tenant-scoped)\n //\n // We look up the channel only when channelId is provided in the event payload.\n let channelUserId: string | null = null\n if (typeof payload.channelId === 'string' && payload.channelId) {\n const channel = (await findOneWithDecryption(\n em,\n 'CommunicationChannel' as any,\n { id: payload.channelId, tenantId, organizationId } as any,\n undefined,\n dscope,\n )) as { userId?: string | null } | null\n channelUserId = channel?.userId ?? null\n }\n\n // \u2500\u2500 (3) Collect recipient addresses \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // The channel metadata shape differs by provider and direction:\n // - Outbound (Gmail): subject/to/cc/bcc/from are in channelMetadata\n // (merged from GmailEmailNativeMetadata by deliver-outbound-message.ts)\n // - Inbound (Gmail): from/to/cc/bcc/subject are in channelPayload\n // (from NormalizedInboundMessage.channelPayload)\n //\n // We check channelMetadata first (works for outbound + any provider that\n // writes addresses there), then fall back to channelPayload for inbound.\n const rawAddresses: unknown[] = []\n\n // For inbound IMAP messages we ALWAYS read addresses from `channelPayload`,\n // not `channelMetadata`. The IMAP adapter stores raw provider headers in\n // `channelMetadata` (where `from` is a JSON-stringified string that's\n // useless for address matching), and the structured normalized addresses\n // in `channelPayload.from` / `.to` / `.cc` / `.bcc`. Reading metadata\n // first poisoned `rawAddresses` with stringified-JSON garbage so the\n // payload-fallback never ran.\n //\n // Priority: payloadJson (canonical normalized shape) \u2192 metaJson fallback\n // (for legacy/outbound providers that still write addresses there).\n if (payloadJson) {\n collectAddressField(rawAddresses, payloadJson.from)\n collectAddressField(rawAddresses, payloadJson.to)\n collectAddressField(rawAddresses, payloadJson.cc)\n collectAddressField(rawAddresses, payloadJson.bcc)\n }\n\n if (rawAddresses.length === 0 && metaJson) {\n collectAddressField(rawAddresses, metaJson.from)\n collectAddressField(rawAddresses, metaJson.to)\n collectAddressField(rawAddresses, metaJson.cc)\n collectAddressField(rawAddresses, metaJson.bcc)\n }\n\n const normalized = normalizeAddresses(rawAddresses as string[])\n\n // \u2500\u2500 (4) Optional explicit crmPersonId hint \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // The outbound compose route stores `crmPersonId` in channelMetadata so the\n // subscriber can link to the intended Person even if their address isn't in\n // the recipient list (e.g. typo in To: field).\n const crmPersonIdHint =\n typeof metaJson?.crmPersonId === 'string' ? (metaJson!.crmPersonId as string) : null\n\n // Defense-in-depth: the crmPersonId hint is written by the compose route\n // (which already verifies tenant ownership), but the subscriber MUST re-verify\n // the hinted Person belongs to THIS tenant before linking. Otherwise a stale or\n // forged hint could attach an interaction to a Person in another tenant.\n let crmPersonId: string | null = null\n if (crmPersonIdHint) {\n const hintedPerson = await findOneWithDecryption(\n em,\n CustomerEntity,\n { id: crmPersonIdHint, kind: 'person', tenantId, organizationId, deletedAt: null } as any,\n undefined,\n dscope,\n )\n if (hintedPerson) crmPersonId = crmPersonIdHint\n }\n\n // Early exit: no addresses AND no hint \u2192 nothing to link.\n if (normalized.length === 0 && !crmPersonId) {\n // Before giving up, try threading-inheritance (TC-CRM-EMAIL-005).\n await handleThreadingInheritance(em, link, linkId, tenantId, organizationId, channelUserId, metaJson, payloadJson, occurredAt)\n return\n }\n\n // \u2500\u2500 (5) Resolve People by address \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const matched = await findPeopleByAddresses(em, normalized, tenantId, organizationId)\n const personIdSet = new Set<string>(matched.map((m) => m.id))\n if (crmPersonId) personIdSet.add(crmPersonId)\n\n if (personIdSet.size === 0) {\n // Try threading-inheritance before giving up.\n await handleThreadingInheritance(em, link, linkId, tenantId, organizationId, channelUserId, metaJson, payloadJson, occurredAt)\n return\n }\n\n // \u2500\u2500 (6) Determine visibility \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // Priority order:\n // 1. Explicit `crmVisibility` in channelMetadata (set by compose route)\n // 2. Channel owner: 'private' if user-scoped, 'shared' if tenant-scoped\n const linkDirection =\n link.direction === 'inbound' || link.direction === 'outbound' ? link.direction : null\n const visibility: 'private' | 'shared' = resolveVisibility(metaJson, channelUserId, linkDirection)\n\n // \u2500\u2500 (7) Extract subject / body / timestamps \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const subject =\n typeof metaJson?.subject === 'string'\n ? (metaJson!.subject as string)\n : typeof payloadJson?.subject === 'string'\n ? (payloadJson!.subject as string)\n : null\n\n const bodyText =\n typeof metaJson?.bodyText === 'string'\n ? (metaJson!.bodyText as string)\n : typeof payloadJson?.text === 'string'\n ? (payloadJson!.text as string)\n : null\n\n const providerKey =\n typeof link.providerKey === 'string' ? (link.providerKey as string) : null\n\n // \u2500\u2500 (8) INSERT one CustomerInteraction per matched Person \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n await persistInteractions(\n em,\n personIdSet,\n {\n linkId,\n tenantId,\n organizationId,\n interactionType: 'email',\n title: subject,\n body: bodyText,\n authorUserId: channelUserId,\n occurredAt,\n visibility,\n channelProviderKey: providerKey,\n },\n )\n}\n\n// \u2500\u2500 Threading-inheritance fallback \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * When direct address matching finds 0 people AND crmPersonId is absent, look\n * up parent message references from channelMetadata (`inReplyTo` + `references`).\n *\n * For each reference (an RFC2822 Message-ID), find a prior MessageChannelLink\n * in this tenant whose `channelMetadata.messageId` matches. For each such\n * parent link, find any existing email CustomerInteraction rows where\n * `externalMessageId = parent.id` \u2014 and link THIS message to the same Persons.\n *\n * This enables TC-CRM-EMAIL-005: a reply from an unknown address is still\n * attached to alice's timeline because the original thread was.\n */\nasync function handleThreadingInheritance(\n em: EntityManager,\n _link: Record<string, unknown>,\n linkId: string,\n tenantId: string,\n organizationId: string | null,\n channelUserId: string | null,\n metaJson: Record<string, unknown> | null,\n payloadJson: Record<string, unknown> | null,\n occurredAt: Date,\n): Promise<void> {\n // \u2500\u2500 Primary: inherit Person(s) from the hub's authoritative thread \u2500\u2500\u2500\u2500\u2500\u2500\n //\n // The hub threads an inbound reply into the same `messages.message.thread_id`\n // as the outbound that started the conversation (via the thread token /\n // subject+participants matcher). That outbound is already linked to the CRM\n // Person (through the `crmPersonId` hint set by the compose route). So a reply\n // inherits the Person of any existing email interaction in the same thread.\n //\n // This is the dependable join where the alternatives are not:\n // - Address matching (`findPeopleByAddresses`) filters the *encrypted*\n // `primary_email` column by a plaintext value, which never matches when\n // tenant data encryption is on (ciphertext != plaintext).\n // - RFC Message-IDs are rewritten by some providers (e.g. Gmail) on send,\n // so the legacy In-Reply-To/References inheritance below also misses.\n // The hub thread id survives both, so we resolve by it first.\n const inboundMessageId = typeof _link.messageId === 'string' ? _link.messageId : null\n if (inboundMessageId && organizationId) {\n const threadPersonRows = (await em.getConnection().execute(\n `SELECT DISTINCT ci.entity_id AS entity_id\n FROM messages inbound_m\n JOIN messages thread_m ON thread_m.thread_id = inbound_m.thread_id\n JOIN message_channel_links mcl ON mcl.message_id = thread_m.id\n JOIN customer_interactions ci ON ci.external_message_id = mcl.id\n WHERE inbound_m.id = ?\n AND inbound_m.tenant_id = ?\n AND inbound_m.organization_id = ?\n AND inbound_m.deleted_at IS NULL\n AND inbound_m.thread_id IS NOT NULL\n AND thread_m.tenant_id = ?\n AND thread_m.organization_id = ?\n AND thread_m.deleted_at IS NULL\n AND mcl.tenant_id = ?\n AND mcl.organization_id = ?\n AND ci.tenant_id = ?\n AND ci.organization_id = ?\n AND ci.interaction_type = 'email'\n AND ci.deleted_at IS NULL\n AND ci.entity_id IS NOT NULL\n LIMIT 200`,\n [\n inboundMessageId,\n tenantId,\n organizationId,\n tenantId,\n organizationId,\n tenantId,\n organizationId,\n tenantId,\n organizationId,\n ],\n )) as Array<{ entity_id: string }>\n const threadPersonIds = new Set<string>(\n threadPersonRows.map((row) => row.entity_id).filter((id): id is string => !!id),\n )\n if (threadPersonIds.size > 0) {\n const subject =\n typeof metaJson?.subject === 'string'\n ? (metaJson.subject as string)\n : typeof payloadJson?.subject === 'string'\n ? (payloadJson.subject as string)\n : null\n const bodyText =\n typeof payloadJson?.text === 'string'\n ? (payloadJson.text as string)\n : typeof metaJson?.bodyText === 'string'\n ? (metaJson.bodyText as string)\n : null\n const providerKey = typeof _link.providerKey === 'string' ? (_link.providerKey as string) : null\n await persistInteractions(em, threadPersonIds, {\n linkId,\n tenantId,\n organizationId,\n interactionType: 'email',\n title: subject,\n body: bodyText,\n authorUserId: channelUserId,\n occurredAt,\n visibility: channelUserId ? 'private' : 'shared',\n channelProviderKey: providerKey,\n })\n return\n }\n }\n\n // \u2500\u2500 Fallback: legacy In-Reply-To / References Message-ID inheritance \u2500\u2500\u2500\u2500\u2500\n // Collect reference message-ids from inReplyTo + references\n const refIds: string[] = []\n const inReplyTo =\n typeof metaJson?.inReplyTo === 'string'\n ? stripBrackets(metaJson!.inReplyTo as string)\n : typeof payloadJson?.inReplyTo === 'string'\n ? stripBrackets(payloadJson!.inReplyTo as string)\n : null\n if (inReplyTo) refIds.push(inReplyTo)\n\n const refs =\n Array.isArray(metaJson?.references)\n ? (metaJson!.references as unknown[])\n : Array.isArray(payloadJson?.references)\n ? (payloadJson!.references as unknown[])\n : []\n for (const r of refs) {\n if (typeof r === 'string') {\n const stripped = stripBrackets(r)\n if (stripped && !refIds.includes(stripped)) refIds.push(stripped)\n }\n }\n\n if (refIds.length === 0) return\n\n // Find parent MessageChannelLinks whose channelMetadata.messageId is in refIds.\n // Bounded lookup: narrow to the candidate Message-IDs directly in SQL instead\n // of loading every link in the tenant and filtering in JS (which does not scale\n // on a busy mailbox \u2014 this path runs for every inbound reply that didn't match a\n // Person by address). channel_metadata is NOT an encrypted column, so a\n // parameterized raw query is safe; we match both bracketed (`<id>`) and\n // unbracketed (`id`) Message-ID storage forms, capped to a sane page.\n const dscope = { tenantId, organizationId }\n const messageIdCandidates = Array.from(\n new Set(refIds.flatMap((ref) => [ref, `<${ref}>`])),\n )\n const placeholders = messageIdCandidates.map(() => '?').join(', ')\n const parentLinkRows = (await em.getConnection().execute(\n `SELECT id FROM message_channel_links\n WHERE tenant_id = ?\n AND organization_id = ?\n AND channel_metadata->>'messageId' IN (${placeholders})\n LIMIT 200`,\n [tenantId, organizationId, ...messageIdCandidates],\n )) as Array<{ id: string }>\n\n const matchedParentIds = parentLinkRows.map((parentLink) => parentLink.id)\n\n if (matchedParentIds.length === 0) return\n\n // Find existing email CustomerInteraction rows for those parent links.\n const parentInteractions = (await findWithDecryption(\n em,\n CustomerInteraction,\n {\n externalMessageId: { $in: matchedParentIds },\n tenantId,\n organizationId,\n interactionType: 'email',\n deletedAt: null,\n } as any,\n undefined,\n dscope,\n )) as Array<{ entity: { id: string } }>\n\n const inheritedPersonIdSet = new Set<string>(\n parentInteractions.map((pi) => pi.entity?.id).filter(Boolean) as string[],\n )\n\n if (inheritedPersonIdSet.size === 0) return\n\n const visibility: 'private' | 'shared' = channelUserId ? 'private' : 'shared'\n const link = _link\n const inheritedMeta = (link.channelMetadata ?? null) as Record<string, unknown> | null\n const subject =\n typeof inheritedMeta?.subject === 'string' ? (inheritedMeta.subject as string) : null\n const providerKey =\n typeof link.providerKey === 'string' ? (link.providerKey as string) : null\n\n await persistInteractions(\n em,\n inheritedPersonIdSet,\n {\n linkId,\n tenantId,\n organizationId,\n interactionType: 'email',\n title: subject,\n body: null,\n authorUserId: channelUserId,\n occurredAt,\n visibility,\n channelProviderKey: providerKey,\n },\n )\n}\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * When the linked email happened, for `CustomerInteraction.occurredAt` (#6095).\n *\n * Preference order:\n * 1. `payload.providerTimestamp` \u2014 the provider's own receive/send time, put\n * on the hub event by ingest / delivery;\n * 2. `MessageChannelLink.createdAt` \u2014 the ingest time, the only date this\n * handler knew before #6095, and the compatibility path for events that\n * were enqueued before the field existed;\n * 3. now, for a link row with no usable `createdAt` (test stubs).\n */\nfunction resolveOccurredAt(\n payload: LinkChannelMessagePayload,\n link: Record<string, unknown>,\n): Date {\n const ingestedAt = link.createdAt instanceof Date ? link.createdAt : new Date()\n const carried = payload.providerTimestamp\n if (carried instanceof Date) {\n return Number.isNaN(carried.getTime()) ? ingestedAt : carried\n }\n if (typeof carried === 'string' && carried) {\n const parsed = new Date(carried)\n if (!Number.isNaN(parsed.getTime())) return parsed\n }\n return ingestedAt\n}\n\ninterface InteractionData {\n linkId: string\n tenantId: string\n organizationId: string | null\n interactionType: string\n title: string | null\n body: string | null\n authorUserId: string | null\n occurredAt: Date\n visibility: 'private' | 'shared'\n channelProviderKey: string | null\n}\n\nasync function persistInteractions(\n em: EntityManager,\n personIdSet: Set<string>,\n data: InteractionData,\n): Promise<void> {\n for (const personId of personIdSet) {\n // Fork per row so a unique-violation on one row doesn't poison the identity\n // map for subsequent rows. The parent em's connection pool is reused.\n const rowEm = em.fork()\n // Use em.getReference so we satisfy the ManyToOne relation without a\n // redundant SELECT \u2014 MikroORM will flush the FK column directly.\n const entityRef = rowEm.getReference(CustomerEntity, personId)\n const interaction = rowEm.create(CustomerInteraction, {\n tenantId: data.tenantId,\n organizationId: data.organizationId,\n entity: entityRef,\n interactionType: data.interactionType,\n title: data.title,\n body: data.body,\n authorUserId: data.authorUserId,\n occurredAt: data.occurredAt,\n // Emails are logged AFTER they're sent/received \u2014 they are not\n // scheduled work. Without an explicit status the entity default\n // ('planned') combined with a past `occurredAt` makes the activity\n // timeline render the email as \"overdue\", which is the wrong UX.\n // The canonical terminal-success value is `INTERACTION_STATUS_COMPLETED`\n // ('done'); see `lib/interactionStatus.ts` for the open/terminal semantics.\n status: INTERACTION_STATUS_COMPLETED,\n externalMessageId: data.linkId,\n visibility: data.visibility,\n channelProviderKey: data.channelProviderKey,\n } as any)\n try {\n await rowEm.flush()\n } catch (err) {\n // Idempotency: swallow unique-violation on (entity_id, external_message_id).\n // The partial unique index `customer_interactions_email_dedupe_uq` guarantees\n // at-most-once semantics across retries.\n const code = (err as { code?: string }).code\n if (code !== POSTGRES_UNIQUE_VIOLATION) throw err\n // Duplicate (retried delivery) \u2014 already linked, skip the refresh signal.\n continue\n }\n // Live-refresh signal for the CRM Person page (clientBroadcast \u2192 SSE). The\n // interaction is already persisted, so a failed emit must not abort linking\n // or fail this persistent (retried) subscriber.\n try {\n await emitCustomersEvent('customers.email.linked', {\n personId,\n interactionId: interaction.id,\n tenantId: data.tenantId,\n organizationId: data.organizationId,\n })\n } catch {\n /* swallow \u2014 UI refresh signal is non-critical */\n }\n }\n}\n\nfunction resolveVisibility(\n metaJson: Record<string, unknown> | null,\n channelUserId: string | null,\n direction: 'inbound' | 'outbound' | null,\n): 'private' | 'shared' {\n // The explicit `crmVisibility` override is written ONLY by the outbound compose\n // route. Inbound `channelMetadata` is provider-derived (and therefore attacker-\n // influenceable), so it MUST NOT be able to downgrade a user-owned channel's\n // inbound mail from private \u2192 shared. Honor the override on outbound only.\n if (direction === 'outbound') {\n if (metaJson?.crmVisibility === 'shared') return 'shared'\n if (metaJson?.crmVisibility === 'private') return 'private'\n }\n // Tenant-scoped channels (no userId) \u2192 shared; user-scoped \u2192 private.\n return channelUserId ? 'private' : 'shared'\n}\n\n/**\n * Collect email address strings from a field that may be:\n * - a plain string: 'alice@example.com'\n * - an array of strings: ['alice@example.com', 'bob@example.com']\n * - an object with an `address` property: { address: 'alice@example.com', name: 'Alice' }\n * - an array of such objects\n */\nfunction collectAddressField(out: unknown[], value: unknown): void {\n if (!value) return\n if (typeof value === 'string') {\n out.push(value)\n return\n }\n if (Array.isArray(value)) {\n for (const item of value) {\n if (typeof item === 'string') {\n out.push(item)\n } else if (item && typeof item === 'object' && typeof (item as Record<string, unknown>).address === 'string') {\n out.push((item as Record<string, unknown>).address as string)\n }\n }\n return\n }\n if (typeof value === 'object' && typeof (value as Record<string, unknown>).address === 'string') {\n out.push((value as Record<string, unknown>).address as string)\n }\n}\n\nfunction stripBrackets(value: string): string {\n const trimmed = value.trim()\n if (trimmed.startsWith('<') && trimmed.endsWith('>')) {\n return trimmed.slice(1, -1)\n }\n return trimmed\n}\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,uBAAuB,0BAA0B;AAC1D,SAAS,gBAAgB,2BAA2B;AACpD,SAAS,uBAAuB,0BAA0B;AAC1D,SAAS,0BAA0B;AACnC,SAAS,oCAAoC;AA8C7C,MAAM,4BAA4B;AAIlC,eAAO,QACL,SACA,KACe;AAEf,QAAM,SAAS,SAAS,iBAAiB,SAAS;AAClD,MAAI,OAAO,WAAW,YAAY,CAAC,OAAQ;AAG3C,MAAI,OAAO,QAAQ,aAAa,YAAY,CAAC,QAAQ,SAAU;AAE/D,QAAM,WAAW,QAAQ;AACzB,QAAM,iBAAiB,QAAQ,kBAAkB;AAGjD,MAAI,CAAC,eAAgB;AACrB,QAAM,SAAS,EAAE,UAAU,eAAe;AAG1C,QAAM,KAAM,IAAI,QAAQ,IAAI,EAAoB,KAAK;AAUrD,QAAM,OAAQ,MAAM;AAAA,IAClB;AAAA,IACA;AAAA,IACA,EAAE,IAAI,QAAQ,UAAU,eAAe;AAAA,IACvC;AAAA,IACA;AAAA,EACF;AAEA,MAAI,CAAC,KAAM;AAEX,QAAM,WAAY,KAAK,mBAAmB;AAC1C,QAAM,cAAe,KAAK,kBAAkB;AAW5C,QAAM,aAAa,kBAAkB,SAAS,IAAI;AASlD,MAAI,gBAA+B;
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CustomerEntity, CustomerInteraction } from '../data/entities'\nimport { findPeopleByAddresses, normalizeAddresses } from './findPeopleByAddresses'\nimport { emitCustomersEvent } from '../events'\nimport { INTERACTION_STATUS_COMPLETED } from './interactionStatus'\n\n/**\n * Shared implementation for the link-channel-message subscribers.\n *\n * The auto-discovery scanner requires a single string `event` value on each\n * subscriber file. Because we must handle both `communication_channels.message.received`\n * AND `.sent`, we use TWO thin subscriber files (link-channel-message-received.ts\n * and link-channel-message-sent.ts) that both delegate here.\n */\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Payload emitted by `communication_channels.message.received` and\n * `communication_channels.message.sent`.\n *\n * The canonical field is `channelLinkId` (as emitted by the hub). The alias\n * `messageChannelLinkId` is kept for test stubs and legacy compatibility.\n */\ntype LinkChannelMessagePayload = {\n eventType?: string\n /** UUID of the MessageChannelLink row (canonical hub field name). */\n channelLinkId?: string\n /** Alias used in some older stubs / test payloads. Prefer channelLinkId. */\n messageChannelLinkId?: string\n channelId?: string | null\n tenantId?: string\n organizationId?: string | null\n providerKey?: string | null\n direction?: 'inbound' | 'outbound' | null\n /**\n * The provider's own receive/send time, carried by the hub on the event\n * (#6095). An ISO string when the event rode the queue, a Date for an\n * in-process emit. Absent on events enqueued before the field existed and on\n * adapters that supply no timestamp.\n */\n providerTimestamp?: string | Date | null\n}\n\ntype SubscriberContext = {\n resolve: <T = unknown>(name: string) => T\n}\n\n// \u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst POSTGRES_UNIQUE_VIOLATION = '23505'\n\n// \u2500\u2500 Main handler \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport default async function handler(\n payload: LinkChannelMessagePayload,\n ctx: SubscriberContext,\n): Promise<void> {\n // Resolve the link ID from either field name.\n const linkId = payload?.channelLinkId ?? payload?.messageChannelLinkId\n if (typeof linkId !== 'string' || !linkId) return\n\n // Fail-closed when tenantId is missing \u2014 unscoped queries are unsafe.\n if (typeof payload.tenantId !== 'string' || !payload.tenantId) return\n\n const tenantId = payload.tenantId\n const organizationId = payload.organizationId ?? null\n // CustomerEntity and CustomerInteraction are organization-scoped. Without an\n // organization id, fail closed instead of linking tenant-wide by email/thread.\n if (!organizationId) return\n const dscope = { tenantId, organizationId }\n\n // em.fork() gives us an isolated identity map for this event.\n const em = (ctx.resolve('em') as EntityManager).fork()\n\n // \u2500\u2500 (1) Load the MessageChannelLink row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // The customers module MUST NOT import MessageChannelLink from the\n // communication_channels module (cross-module ORM boundary rule in AGENTS.md).\n // We use the entity class name as a string so MikroORM's identity map resolves\n // it at runtime \u2014 the generated entity registry includes the hub's entities.\n // Read through findOneWithDecryption so any encrypted columns on the hub\n // entity are transparently decrypted (per the Encryption section in AGENTS.md).\n const link = (await findOneWithDecryption(\n em,\n 'MessageChannelLink' as any,\n { id: linkId, tenantId, organizationId } as any,\n undefined,\n dscope,\n )) as Record<string, unknown> | null\n\n if (!link) return\n\n const metaJson = (link.channelMetadata ?? null) as Record<string, unknown> | null\n const payloadJson = (link.channelPayload ?? null) as Record<string, unknown> | null\n\n // \u2500\u2500 (1b) Resolve when the email actually happened \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // `link.createdAt` is when the hub ingested the message, which for a history\n // import is the import minute, not the day the mail arrived (#6095). The hub\n // carries the provider's own timestamp on the event payload, so take it from\n // there: reading the communication_channels ExternalMessage row here would\n // cross the storage boundary (Cross-Module Coupling in AGENTS.md) and add a\n // peer-table query per event. Resolved once and threaded through every branch\n // below so the address-match and threading-inheritance paths agree.\n const occurredAt = resolveOccurredAt(payload, link)\n\n // \u2500\u2500 (2) Resolve the channel to get its owner userId \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // The channel.userId is needed for two purposes:\n // - authorUserId on the CustomerInteraction row\n // - default visibility ('private' for user-scoped, 'shared' for tenant-scoped)\n //\n // We look up the channel only when channelId is provided in the event payload.\n let channelUserId: string | null = null\n // Denormalized onto each interaction so a read path can ask \"is this row's\n // channel shared?\" without a three-join hop. NULL when the event carried no\n // channelId \u2014 every predicate treats that as not shared (fail closed).\n const resolvedChannelId: string | null =\n typeof payload.channelId === 'string' && payload.channelId ? payload.channelId : null\n if (typeof payload.channelId === 'string' && payload.channelId) {\n const channel = (await findOneWithDecryption(\n em,\n 'CommunicationChannel' as any,\n { id: payload.channelId, tenantId, organizationId } as any,\n undefined,\n dscope,\n )) as { userId?: string | null } | null\n channelUserId = channel?.userId ?? null\n }\n\n // \u2500\u2500 (3) Collect recipient addresses \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // The channel metadata shape differs by provider and direction:\n // - Outbound (Gmail): subject/to/cc/bcc/from are in channelMetadata\n // (merged from GmailEmailNativeMetadata by deliver-outbound-message.ts)\n // - Inbound (Gmail): from/to/cc/bcc/subject are in channelPayload\n // (from NormalizedInboundMessage.channelPayload)\n //\n // We check channelMetadata first (works for outbound + any provider that\n // writes addresses there), then fall back to channelPayload for inbound.\n const rawAddresses: unknown[] = []\n\n // For inbound IMAP messages we ALWAYS read addresses from `channelPayload`,\n // not `channelMetadata`. The IMAP adapter stores raw provider headers in\n // `channelMetadata` (where `from` is a JSON-stringified string that's\n // useless for address matching), and the structured normalized addresses\n // in `channelPayload.from` / `.to` / `.cc` / `.bcc`. Reading metadata\n // first poisoned `rawAddresses` with stringified-JSON garbage so the\n // payload-fallback never ran.\n //\n // Priority: payloadJson (canonical normalized shape) \u2192 metaJson fallback\n // (for legacy/outbound providers that still write addresses there).\n if (payloadJson) {\n collectAddressField(rawAddresses, payloadJson.from)\n collectAddressField(rawAddresses, payloadJson.to)\n collectAddressField(rawAddresses, payloadJson.cc)\n collectAddressField(rawAddresses, payloadJson.bcc)\n }\n\n if (rawAddresses.length === 0 && metaJson) {\n collectAddressField(rawAddresses, metaJson.from)\n collectAddressField(rawAddresses, metaJson.to)\n collectAddressField(rawAddresses, metaJson.cc)\n collectAddressField(rawAddresses, metaJson.bcc)\n }\n\n const normalized = normalizeAddresses(rawAddresses as string[])\n\n // \u2500\u2500 (4) Optional explicit crmPersonId hint \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // The outbound compose route stores `crmPersonId` in channelMetadata so the\n // subscriber can link to the intended Person even if their address isn't in\n // the recipient list (e.g. typo in To: field).\n const crmPersonIdHint =\n typeof metaJson?.crmPersonId === 'string' ? (metaJson!.crmPersonId as string) : null\n\n // Defense-in-depth: the crmPersonId hint is written by the compose route\n // (which already verifies tenant ownership), but the subscriber MUST re-verify\n // the hinted Person belongs to THIS tenant before linking. Otherwise a stale or\n // forged hint could attach an interaction to a Person in another tenant.\n let crmPersonId: string | null = null\n if (crmPersonIdHint) {\n const hintedPerson = await findOneWithDecryption(\n em,\n CustomerEntity,\n { id: crmPersonIdHint, kind: 'person', tenantId, organizationId, deletedAt: null } as any,\n undefined,\n dscope,\n )\n if (hintedPerson) crmPersonId = crmPersonIdHint\n }\n\n // Early exit: no addresses AND no hint \u2192 nothing to link.\n if (normalized.length === 0 && !crmPersonId) {\n // Before giving up, try threading-inheritance (TC-CRM-EMAIL-005).\n await handleThreadingInheritance(em, link, linkId, tenantId, organizationId, channelUserId, resolvedChannelId, metaJson, payloadJson, occurredAt)\n return\n }\n\n // \u2500\u2500 (5) Resolve People by address \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const matched = await findPeopleByAddresses(em, normalized, tenantId, organizationId)\n const personIdSet = new Set<string>(matched.map((m) => m.id))\n if (crmPersonId) personIdSet.add(crmPersonId)\n\n if (personIdSet.size === 0) {\n // Try threading-inheritance before giving up.\n await handleThreadingInheritance(em, link, linkId, tenantId, organizationId, channelUserId, resolvedChannelId, metaJson, payloadJson, occurredAt)\n return\n }\n\n // \u2500\u2500 (6) Determine visibility \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // Priority order:\n // 1. Explicit `crmVisibility` in channelMetadata (set by compose route)\n // 2. Channel owner: 'private' if user-scoped, 'shared' if tenant-scoped\n const linkDirection =\n link.direction === 'inbound' || link.direction === 'outbound' ? link.direction : null\n const visibility: 'private' | 'shared' = resolveVisibility(metaJson, channelUserId, linkDirection)\n\n // \u2500\u2500 (7) Extract subject / body / timestamps \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const subject =\n typeof metaJson?.subject === 'string'\n ? (metaJson!.subject as string)\n : typeof payloadJson?.subject === 'string'\n ? (payloadJson!.subject as string)\n : null\n\n const bodyText =\n typeof metaJson?.bodyText === 'string'\n ? (metaJson!.bodyText as string)\n : typeof payloadJson?.text === 'string'\n ? (payloadJson!.text as string)\n : null\n\n const providerKey =\n typeof link.providerKey === 'string' ? (link.providerKey as string) : null\n\n // \u2500\u2500 (8) INSERT one CustomerInteraction per matched Person \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n await persistInteractions(\n em,\n personIdSet,\n {\n linkId,\n tenantId,\n organizationId,\n interactionType: 'email',\n title: subject,\n body: bodyText,\n authorUserId: channelUserId,\n occurredAt,\n visibility,\n channelProviderKey: providerKey,\n channelId: resolvedChannelId,\n },\n )\n}\n\n// \u2500\u2500 Threading-inheritance fallback \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * When direct address matching finds 0 people AND crmPersonId is absent, look\n * up parent message references from channelMetadata (`inReplyTo` + `references`).\n *\n * For each reference (an RFC2822 Message-ID), find a prior MessageChannelLink\n * in this tenant whose `channelMetadata.messageId` matches. For each such\n * parent link, find any existing email CustomerInteraction rows where\n * `externalMessageId = parent.id` \u2014 and link THIS message to the same Persons.\n *\n * This enables TC-CRM-EMAIL-005: a reply from an unknown address is still\n * attached to alice's timeline because the original thread was.\n */\nasync function handleThreadingInheritance(\n em: EntityManager,\n _link: Record<string, unknown>,\n linkId: string,\n tenantId: string,\n organizationId: string | null,\n channelUserId: string | null,\n channelId: string | null,\n metaJson: Record<string, unknown> | null,\n payloadJson: Record<string, unknown> | null,\n occurredAt: Date,\n): Promise<void> {\n // \u2500\u2500 Primary: inherit Person(s) from the hub's authoritative thread \u2500\u2500\u2500\u2500\u2500\u2500\n //\n // The hub threads an inbound reply into the same `messages.message.thread_id`\n // as the outbound that started the conversation (via the thread token /\n // subject+participants matcher). That outbound is already linked to the CRM\n // Person (through the `crmPersonId` hint set by the compose route). So a reply\n // inherits the Person of any existing email interaction in the same thread.\n //\n // This is the dependable join where the alternatives are not:\n // - Address matching (`findPeopleByAddresses`) filters the *encrypted*\n // `primary_email` column by a plaintext value, which never matches when\n // tenant data encryption is on (ciphertext != plaintext).\n // - RFC Message-IDs are rewritten by some providers (e.g. Gmail) on send,\n // so the legacy In-Reply-To/References inheritance below also misses.\n // The hub thread id survives both, so we resolve by it first.\n const inboundMessageId = typeof _link.messageId === 'string' ? _link.messageId : null\n if (inboundMessageId && organizationId) {\n const threadPersonRows = (await em.getConnection().execute(\n `SELECT DISTINCT ci.entity_id AS entity_id\n FROM messages inbound_m\n JOIN messages thread_m ON thread_m.thread_id = inbound_m.thread_id\n JOIN message_channel_links mcl ON mcl.message_id = thread_m.id\n JOIN customer_interactions ci ON ci.external_message_id = mcl.id\n WHERE inbound_m.id = ?\n AND inbound_m.tenant_id = ?\n AND inbound_m.organization_id = ?\n AND inbound_m.deleted_at IS NULL\n AND inbound_m.thread_id IS NOT NULL\n AND thread_m.tenant_id = ?\n AND thread_m.organization_id = ?\n AND thread_m.deleted_at IS NULL\n AND mcl.tenant_id = ?\n AND mcl.organization_id = ?\n AND ci.tenant_id = ?\n AND ci.organization_id = ?\n AND ci.interaction_type = 'email'\n AND ci.deleted_at IS NULL\n AND ci.entity_id IS NOT NULL\n LIMIT 200`,\n [\n inboundMessageId,\n tenantId,\n organizationId,\n tenantId,\n organizationId,\n tenantId,\n organizationId,\n tenantId,\n organizationId,\n ],\n )) as Array<{ entity_id: string }>\n const threadPersonIds = new Set<string>(\n threadPersonRows.map((row) => row.entity_id).filter((id): id is string => !!id),\n )\n if (threadPersonIds.size > 0) {\n const subject =\n typeof metaJson?.subject === 'string'\n ? (metaJson.subject as string)\n : typeof payloadJson?.subject === 'string'\n ? (payloadJson.subject as string)\n : null\n const bodyText =\n typeof payloadJson?.text === 'string'\n ? (payloadJson.text as string)\n : typeof metaJson?.bodyText === 'string'\n ? (metaJson.bodyText as string)\n : null\n const providerKey = typeof _link.providerKey === 'string' ? (_link.providerKey as string) : null\n await persistInteractions(em, threadPersonIds, {\n linkId,\n tenantId,\n organizationId,\n interactionType: 'email',\n title: subject,\n body: bodyText,\n authorUserId: channelUserId,\n occurredAt,\n // Single source of truth for the ingestion default (see resolveVisibility).\n // The threading-inheritance path deliberately passes no metadata and no\n // direction: a reply is matched by parent-thread lookup and its metadata is\n // provider-derived, so it must never be able to downgrade privacy via the\n // `crmVisibility` override.\n visibility: resolveVisibility(null, channelUserId, null),\n channelProviderKey: providerKey,\n channelId,\n })\n return\n }\n }\n\n // \u2500\u2500 Fallback: legacy In-Reply-To / References Message-ID inheritance \u2500\u2500\u2500\u2500\u2500\n // Collect reference message-ids from inReplyTo + references\n const refIds: string[] = []\n const inReplyTo =\n typeof metaJson?.inReplyTo === 'string'\n ? stripBrackets(metaJson!.inReplyTo as string)\n : typeof payloadJson?.inReplyTo === 'string'\n ? stripBrackets(payloadJson!.inReplyTo as string)\n : null\n if (inReplyTo) refIds.push(inReplyTo)\n\n const refs =\n Array.isArray(metaJson?.references)\n ? (metaJson!.references as unknown[])\n : Array.isArray(payloadJson?.references)\n ? (payloadJson!.references as unknown[])\n : []\n for (const r of refs) {\n if (typeof r === 'string') {\n const stripped = stripBrackets(r)\n if (stripped && !refIds.includes(stripped)) refIds.push(stripped)\n }\n }\n\n if (refIds.length === 0) return\n\n // Find parent MessageChannelLinks whose channelMetadata.messageId is in refIds.\n // Bounded lookup: narrow to the candidate Message-IDs directly in SQL instead\n // of loading every link in the tenant and filtering in JS (which does not scale\n // on a busy mailbox \u2014 this path runs for every inbound reply that didn't match a\n // Person by address). channel_metadata is NOT an encrypted column, so a\n // parameterized raw query is safe; we match both bracketed (`<id>`) and\n // unbracketed (`id`) Message-ID storage forms, capped to a sane page.\n const dscope = { tenantId, organizationId }\n const messageIdCandidates = Array.from(\n new Set(refIds.flatMap((ref) => [ref, `<${ref}>`])),\n )\n const placeholders = messageIdCandidates.map(() => '?').join(', ')\n const parentLinkRows = (await em.getConnection().execute(\n `SELECT id FROM message_channel_links\n WHERE tenant_id = ?\n AND organization_id = ?\n AND channel_metadata->>'messageId' IN (${placeholders})\n LIMIT 200`,\n [tenantId, organizationId, ...messageIdCandidates],\n )) as Array<{ id: string }>\n\n const matchedParentIds = parentLinkRows.map((parentLink) => parentLink.id)\n\n if (matchedParentIds.length === 0) return\n\n // Find existing email CustomerInteraction rows for those parent links.\n const parentInteractions = (await findWithDecryption(\n em,\n CustomerInteraction,\n {\n externalMessageId: { $in: matchedParentIds },\n tenantId,\n organizationId,\n interactionType: 'email',\n deletedAt: null,\n } as any,\n undefined,\n dscope,\n )) as Array<{ entity: { id: string } }>\n\n const inheritedPersonIdSet = new Set<string>(\n parentInteractions.map((pi) => pi.entity?.id).filter(Boolean) as string[],\n )\n\n if (inheritedPersonIdSet.size === 0) return\n\n // Same single source of truth as the primary ingestion path; no metadata and no\n // direction on the inheritance path (see the sibling call above).\n const visibility: 'private' | 'shared' = resolveVisibility(null, channelUserId, null)\n const link = _link\n const inheritedMeta = (link.channelMetadata ?? null) as Record<string, unknown> | null\n const subject =\n typeof inheritedMeta?.subject === 'string' ? (inheritedMeta.subject as string) : null\n const providerKey =\n typeof link.providerKey === 'string' ? (link.providerKey as string) : null\n\n await persistInteractions(\n em,\n inheritedPersonIdSet,\n {\n linkId,\n tenantId,\n organizationId,\n interactionType: 'email',\n title: subject,\n body: null,\n authorUserId: channelUserId,\n occurredAt,\n visibility,\n channelProviderKey: providerKey,\n channelId,\n },\n )\n}\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * When the linked email happened, for `CustomerInteraction.occurredAt` (#6095).\n *\n * Preference order:\n * 1. `payload.providerTimestamp` \u2014 the provider's own receive/send time, put\n * on the hub event by ingest / delivery;\n * 2. `MessageChannelLink.createdAt` \u2014 the ingest time, the only date this\n * handler knew before #6095, and the compatibility path for events that\n * were enqueued before the field existed;\n * 3. now, for a link row with no usable `createdAt` (test stubs).\n */\nfunction resolveOccurredAt(\n payload: LinkChannelMessagePayload,\n link: Record<string, unknown>,\n): Date {\n const ingestedAt = link.createdAt instanceof Date ? link.createdAt : new Date()\n const carried = payload.providerTimestamp\n if (carried instanceof Date) {\n return Number.isNaN(carried.getTime()) ? ingestedAt : carried\n }\n if (typeof carried === 'string' && carried) {\n const parsed = new Date(carried)\n if (!Number.isNaN(parsed.getTime())) return parsed\n }\n return ingestedAt\n}\n\ninterface InteractionData {\n linkId: string\n tenantId: string\n organizationId: string | null\n interactionType: string\n title: string | null\n body: string | null\n authorUserId: string | null\n occurredAt: Date\n visibility: 'private' | 'shared'\n channelProviderKey: string | null\n /**\n * Denormalized channel id, so a read path can ask \"is this row's channel\n * shared?\" without a three-join hop. NULL when the event carried no channelId\n * (the predicate then treats the row as not shared \u2014 fail closed).\n */\n channelId: string | null\n}\n\nasync function persistInteractions(\n em: EntityManager,\n personIdSet: Set<string>,\n data: InteractionData,\n): Promise<void> {\n for (const personId of personIdSet) {\n // Fork per row so a unique-violation on one row doesn't poison the identity\n // map for subsequent rows. The parent em's connection pool is reused.\n const rowEm = em.fork()\n // Use em.getReference so we satisfy the ManyToOne relation without a\n // redundant SELECT \u2014 MikroORM will flush the FK column directly.\n const entityRef = rowEm.getReference(CustomerEntity, personId)\n const interaction = rowEm.create(CustomerInteraction, {\n tenantId: data.tenantId,\n organizationId: data.organizationId,\n entity: entityRef,\n interactionType: data.interactionType,\n title: data.title,\n body: data.body,\n authorUserId: data.authorUserId,\n occurredAt: data.occurredAt,\n // Emails are logged AFTER they're sent/received \u2014 they are not\n // scheduled work. Without an explicit status the entity default\n // ('planned') combined with a past `occurredAt` makes the activity\n // timeline render the email as \"overdue\", which is the wrong UX.\n // The canonical terminal-success value is `INTERACTION_STATUS_COMPLETED`\n // ('done'); see `lib/interactionStatus.ts` for the open/terminal semantics.\n status: INTERACTION_STATUS_COMPLETED,\n externalMessageId: data.linkId,\n visibility: data.visibility,\n channelProviderKey: data.channelProviderKey,\n channelId: data.channelId,\n } as any)\n try {\n await rowEm.flush()\n } catch (err) {\n // Idempotency: swallow unique-violation on (entity_id, external_message_id).\n // The partial unique index `customer_interactions_email_dedupe_uq` guarantees\n // at-most-once semantics across retries.\n const code = (err as { code?: string }).code\n if (code !== POSTGRES_UNIQUE_VIOLATION) throw err\n // Duplicate (retried delivery) \u2014 already linked, skip the refresh signal.\n continue\n }\n // Live-refresh signal for the CRM Person page (clientBroadcast \u2192 SSE). The\n // interaction is already persisted, so a failed emit must not abort linking\n // or fail this persistent (retried) subscriber.\n try {\n await emitCustomersEvent('customers.email.linked', {\n personId,\n interactionId: interaction.id,\n tenantId: data.tenantId,\n organizationId: data.organizationId,\n })\n } catch {\n /* swallow \u2014 UI refresh signal is non-critical */\n }\n }\n}\n\nfunction resolveVisibility(\n metaJson: Record<string, unknown> | null,\n channelUserId: string | null,\n direction: 'inbound' | 'outbound' | null,\n): 'private' | 'shared' {\n // The explicit `crmVisibility` override is written ONLY by the outbound compose\n // route. Inbound `channelMetadata` is provider-derived (and therefore attacker-\n // influenceable), so it MUST NOT be able to downgrade a user-owned channel's\n // inbound mail from private \u2192 shared. Honor the override on outbound only.\n if (direction === 'outbound') {\n if (metaJson?.crmVisibility === 'shared') return 'shared'\n if (metaJson?.crmVisibility === 'private') return 'private'\n }\n // Tenant-scoped channels (no userId) \u2192 shared; user-scoped \u2192 private.\n return channelUserId ? 'private' : 'shared'\n}\n\n/**\n * Collect email address strings from a field that may be:\n * - a plain string: 'alice@example.com'\n * - an array of strings: ['alice@example.com', 'bob@example.com']\n * - an object with an `address` property: { address: 'alice@example.com', name: 'Alice' }\n * - an array of such objects\n */\nfunction collectAddressField(out: unknown[], value: unknown): void {\n if (!value) return\n if (typeof value === 'string') {\n out.push(value)\n return\n }\n if (Array.isArray(value)) {\n for (const item of value) {\n if (typeof item === 'string') {\n out.push(item)\n } else if (item && typeof item === 'object' && typeof (item as Record<string, unknown>).address === 'string') {\n out.push((item as Record<string, unknown>).address as string)\n }\n }\n return\n }\n if (typeof value === 'object' && typeof (value as Record<string, unknown>).address === 'string') {\n out.push((value as Record<string, unknown>).address as string)\n }\n}\n\nfunction stripBrackets(value: string): string {\n const trimmed = value.trim()\n if (trimmed.startsWith('<') && trimmed.endsWith('>')) {\n return trimmed.slice(1, -1)\n }\n return trimmed\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["subject", "providerKey"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { buildCollectionTags, canonicalizeResourceTag } from "@open-mercato/shared/lib/crud/cache";
|
|
2
|
+
const PERSON_DETAIL_TAG_RESOURCES = [
|
|
3
|
+
"customers.person",
|
|
4
|
+
"customers.address",
|
|
5
|
+
"customers.tagAssignment",
|
|
6
|
+
"customers.labelAssignment",
|
|
7
|
+
"customers.personCompanyLink",
|
|
8
|
+
"customers.interaction",
|
|
9
|
+
"customers.activity"
|
|
10
|
+
];
|
|
11
|
+
function buildPersonDetailCacheTags(tenantId, organizationId) {
|
|
12
|
+
const tags = [];
|
|
13
|
+
for (const resource of PERSON_DETAIL_TAG_RESOURCES) {
|
|
14
|
+
const canonical = canonicalizeResourceTag(resource) ?? resource;
|
|
15
|
+
tags.push(...buildCollectionTags(canonical, tenantId, [organizationId]));
|
|
16
|
+
}
|
|
17
|
+
return tags;
|
|
18
|
+
}
|
|
19
|
+
async function invalidatePersonDetailCache(container, tenantId, organizationId) {
|
|
20
|
+
try {
|
|
21
|
+
const cache = container.resolve("cache");
|
|
22
|
+
if (!cache?.invalidateTags) return;
|
|
23
|
+
await cache.invalidateTags(buildPersonDetailCacheTags(tenantId, organizationId));
|
|
24
|
+
} catch {
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
PERSON_DETAIL_TAG_RESOURCES,
|
|
29
|
+
buildPersonDetailCacheTags,
|
|
30
|
+
invalidatePersonDetailCache
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=personDetailCacheTags.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/customers/lib/personDetailCacheTags.ts"],
|
|
4
|
+
"sourcesContent": ["import { buildCollectionTags, canonicalizeResourceTag } from '@open-mercato/shared/lib/crud/cache'\n\n/**\n * Resources whose collection tags the cached person-detail payload depends on.\n *\n * Single source of truth, shared by the READ side (`api/people/[id]/route.ts`,\n * which stores under these tags) and every WRITE side that must invalidate them.\n * Hand-formatting the tag strings at a write site is how they silently stop\n * matching: the canonical shape is `crud:<resource>:tenant:<t>:org:<o>:collection`\n * and it is produced only by `buildCollectionTags`.\n */\nexport const PERSON_DETAIL_TAG_RESOURCES = [\n 'customers.person',\n 'customers.address',\n 'customers.tagAssignment',\n 'customers.labelAssignment',\n 'customers.personCompanyLink',\n 'customers.interaction',\n 'customers.activity',\n] as const\n\n/**\n * Collection tags the cached person-detail payload is stored under.\n *\n * The resource ids are canonicalized with `canonicalizeResourceTag` (they are\n * already canonical today, but going through the helper keeps this aligned if the\n * canonical form ever changes).\n */\nexport function buildPersonDetailCacheTags(\n tenantId: string | null,\n organizationId: string | null,\n): string[] {\n const tags: string[] = []\n for (const resource of PERSON_DETAIL_TAG_RESOURCES) {\n const canonical = canonicalizeResourceTag(resource) ?? resource\n tags.push(...buildCollectionTags(canonical, tenantId, [organizationId]))\n }\n return tags\n}\n\ntype CacheLike = { invalidateTags?: (tags: string[]) => Promise<void> }\n\n/**\n * Invalidate the person-detail collection tags after a write that widens or\n * narrows email visibility.\n *\n * Both email-sharing write paths (per-Person conversation share, whole-channel\n * flag) change which rows the read filter admits without writing any resource the\n * person-detail cache tags observe, so neither would otherwise invalidate. The\n * revoke direction is the one that matters: without this a teammate keeps reading\n * now-private email from their own warm cache entry until the TTL expires.\n *\n * Best effort \u2014 a stale cached page is a TTL-bounded annoyance, and the write is\n * already committed by the time this runs.\n */\nexport async function invalidatePersonDetailCache(\n container: { resolve: (name: string) => unknown },\n tenantId: string | null,\n organizationId: string | null,\n): Promise<void> {\n try {\n const cache = container.resolve('cache') as CacheLike | undefined\n if (!cache?.invalidateTags) return\n await cache.invalidateTags(buildPersonDetailCacheTags(tenantId, organizationId))\n } catch {\n /* best effort \u2014 never fail a committed write over cache invalidation */\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,qBAAqB,+BAA+B;AAWtD,MAAM,8BAA8B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AASO,SAAS,2BACd,UACA,gBACU;AACV,QAAM,OAAiB,CAAC;AACxB,aAAW,YAAY,6BAA6B;AAClD,UAAM,YAAY,wBAAwB,QAAQ,KAAK;AACvD,SAAK,KAAK,GAAG,oBAAoB,WAAW,UAAU,CAAC,cAAc,CAAC,CAAC;AAAA,EACzE;AACA,SAAO;AACT;AAiBA,eAAsB,4BACpB,WACA,UACA,gBACe;AACf,MAAI;AACF,UAAM,QAAQ,UAAU,QAAQ,OAAO;AACvC,QAAI,CAAC,OAAO,eAAgB;AAC5B,UAAM,MAAM,eAAe,2BAA2B,UAAU,cAAc,CAAC;AAAA,EACjF,QAAQ;AAAA,EAER;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
2
2
|
import { CustomerInteraction } from "../data/entities.js";
|
|
3
|
+
import { resolveUserNames } from "./userNames.js";
|
|
3
4
|
import { buildEmailVisibilityMikroFilter } from "./visibilityFilter.js";
|
|
4
5
|
const DEFAULT_MAX_THREADS = 50;
|
|
5
6
|
const DEFAULT_MAX_MESSAGES_PER_THREAD = 200;
|
|
@@ -54,6 +55,8 @@ async function buildPersonEmailThreads(em, opts) {
|
|
|
54
55
|
organizationId,
|
|
55
56
|
viewerUserId,
|
|
56
57
|
userFeatures,
|
|
58
|
+
sharedConversations,
|
|
59
|
+
sharedChannelIds,
|
|
57
60
|
maxThreads = DEFAULT_MAX_THREADS,
|
|
58
61
|
maxMessagesPerThread = DEFAULT_MAX_MESSAGES_PER_THREAD
|
|
59
62
|
} = opts;
|
|
@@ -64,10 +67,15 @@ async function buildPersonEmailThreads(em, opts) {
|
|
|
64
67
|
tenantId
|
|
65
68
|
};
|
|
66
69
|
if (organizationId) interactionWhere.organizationId = organizationId;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
Object.assign(
|
|
71
|
+
interactionWhere,
|
|
72
|
+
buildEmailVisibilityMikroFilter({
|
|
73
|
+
currentUserId: viewerUserId,
|
|
74
|
+
userFeatures,
|
|
75
|
+
sharedConversations,
|
|
76
|
+
sharedChannelIds
|
|
77
|
+
})
|
|
78
|
+
);
|
|
71
79
|
const dscope = { tenantId, organizationId: organizationId ?? null };
|
|
72
80
|
const interactions = await findWithDecryption(
|
|
73
81
|
em,
|
|
@@ -81,7 +89,10 @@ async function buildPersonEmailThreads(em, opts) {
|
|
|
81
89
|
for (const interaction of interactions) {
|
|
82
90
|
const linkId = interaction.externalMessageId;
|
|
83
91
|
if (!linkId || linkIdByInteraction.has(linkId)) continue;
|
|
84
|
-
linkIdByInteraction.set(linkId, {
|
|
92
|
+
linkIdByInteraction.set(linkId, {
|
|
93
|
+
occurredAt: interaction.occurredAt ?? interaction.createdAt,
|
|
94
|
+
authorUserId: interaction.authorUserId ?? null
|
|
95
|
+
});
|
|
85
96
|
linkIds.push(linkId);
|
|
86
97
|
}
|
|
87
98
|
if (linkIds.length === 0) return [];
|
|
@@ -114,11 +125,19 @@ async function buildPersonEmailThreads(em, opts) {
|
|
|
114
125
|
if (typeof message.id === "string") messageById.set(message.id, message);
|
|
115
126
|
}
|
|
116
127
|
}
|
|
128
|
+
const foreignAuthorIds = Array.from(
|
|
129
|
+
new Set(
|
|
130
|
+
Array.from(linkIdByInteraction.values()).map((entry) => entry.authorUserId).filter((id) => !!id && id !== viewerUserId)
|
|
131
|
+
)
|
|
132
|
+
);
|
|
133
|
+
const authorNames = foreignAuthorIds.length ? await resolveUserNames(em, tenantId, organizationId, foreignAuthorIds) : /* @__PURE__ */ new Map();
|
|
117
134
|
const threadsByKey = /* @__PURE__ */ new Map();
|
|
118
135
|
for (const link of links) {
|
|
119
136
|
const linkId = typeof link.id === "string" ? link.id : null;
|
|
120
137
|
if (!linkId) continue;
|
|
121
138
|
const direction = link.direction === "outbound" ? "outbound" : "inbound";
|
|
139
|
+
const authorUserId = direction === "outbound" ? linkIdByInteraction.get(linkId)?.authorUserId ?? null : null;
|
|
140
|
+
const authoredByViewer = !!viewerUserId && !!authorUserId && authorUserId === viewerUserId;
|
|
122
141
|
const providerKey = typeof link.providerKey === "string" ? link.providerKey : null;
|
|
123
142
|
const payload = link.channelPayload ?? null;
|
|
124
143
|
const meta = link.channelMetadata ?? null;
|
|
@@ -150,6 +169,8 @@ async function buildPersonEmailThreads(em, opts) {
|
|
|
150
169
|
direction,
|
|
151
170
|
fromName: fromList[0]?.name ?? null,
|
|
152
171
|
fromEmail: fromList[0]?.email ?? null,
|
|
172
|
+
authoredByViewer,
|
|
173
|
+
authorName: authoredByViewer ? null : authorUserId ? authorNames.get(authorUserId) ?? null : null,
|
|
153
174
|
to: toList.map((a) => a.email),
|
|
154
175
|
cc: ccList.map((a) => a.email),
|
|
155
176
|
subject,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/customers/lib/personEmailThreads.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CustomerInteraction } from '../data/entities'\nimport { buildEmailVisibilityMikroFilter } from './visibilityFilter'\n\n/**\n * Read model that turns a Person's email `CustomerInteraction` rows into\n * Gmail-style threads for the CRM Person page.\n *\n * The Person\u2194email anchor lives only on `CustomerInteraction`\n * (`interactionType='email'`, `externalMessageId` \u2192 `MessageChannelLink.id`).\n * The thread grouping key and the rich per-message content (From/To/Cc, body,\n * direction) live in the communication_channels hub. We read the hub entities\n * by their string class names \u2014 the same cross-module pattern used by\n * `link-channel-message-handler.ts` \u2014 so the customers module never imports the\n * hub's entity classes (root AGENTS.md: no direct ORM relationships between\n * modules).\n */\n\nexport type EmailThreadDirection = 'inbound' | 'outbound'\n\nexport type PersonEmailMessage = {\n id: string\n /** Open Mercato `messages.message` id \u2014 used as `parentMessageId` when replying so the reply joins this thread. */\n messageId: string | null\n /** RFC2822 Message-ID of this email \u2014 used as `In-Reply-To` on a reply. */\n rfcMessageId: string | null\n /** RFC2822 References chain for this email. */\n references: string[]\n direction: EmailThreadDirection\n fromName: string | null\n fromEmail: string | null\n to: string[]\n cc: string[]\n subject: string | null\n bodyText: string | null\n sentAt: string\n providerKey: string | null\n}\n\nexport type PersonEmailThread = {\n threadKey: string\n subject: string | null\n preview: string | null\n participants: string[]\n lastMessageAt: string\n messageCount: number\n providerKey: string | null\n lastDirection: EmailThreadDirection\n messages: PersonEmailMessage[]\n}\n\nexport type BuildPersonEmailThreadsOptions = {\n personId: string\n tenantId: string\n organizationId: string | null\n viewerUserId: string | null\n userFeatures: string[] | null | undefined\n maxThreads?: number\n maxMessagesPerThread?: number\n}\n\nconst DEFAULT_MAX_THREADS = 50\nconst DEFAULT_MAX_MESSAGES_PER_THREAD = 200\nconst PREVIEW_LENGTH = 140\n\ntype JsonRecord = Record<string, unknown>\n\n/** Extracts `{ email, name }[]` from the many shapes a channel address field can take. */\nfunction extractAddresses(value: unknown): Array<{ email: string; name: string | null }> {\n const out: Array<{ email: string; name: string | null }> = []\n const pushOne = (item: unknown): void => {\n if (typeof item === 'string') {\n const trimmed = item.trim()\n if (trimmed) out.push({ email: trimmed, name: null })\n return\n }\n if (item && typeof item === 'object') {\n const rec = item as JsonRecord\n const address = typeof rec.address === 'string' ? rec.address.trim() : null\n const name = typeof rec.name === 'string' && rec.name.trim() ? rec.name.trim() : null\n if (address) out.push({ email: address, name })\n }\n }\n if (Array.isArray(value)) {\n for (const item of value) pushOne(item)\n } else {\n pushOne(value)\n }\n return out\n}\n\nfunction firstString(...values: unknown[]): string | null {\n for (const value of values) {\n if (typeof value === 'string' && value.trim().length > 0) return value\n }\n return null\n}\n\nfunction toStringArray(...values: unknown[]): string[] {\n for (const value of values) {\n if (Array.isArray(value)) {\n const strings = value.filter((item): item is string => typeof item === 'string' && item.trim().length > 0)\n if (strings.length > 0) return strings\n }\n }\n return []\n}\n\nfunction truncate(value: string | null): string | null {\n if (!value) return value\n const collapsed = value.replace(/\\s+/g, ' ').trim()\n if (collapsed.length <= PREVIEW_LENGTH) return collapsed\n return `${collapsed.slice(0, PREVIEW_LENGTH - 1)}\u2026`\n}\n\n/**\n * Builds the per-Person email-thread read model. Pure data assembly \u2014 callers\n * are responsible for auth and scoping (tenantId/organizationId required).\n */\nexport async function buildPersonEmailThreads(\n em: EntityManager,\n opts: BuildPersonEmailThreadsOptions,\n): Promise<PersonEmailThread[]> {\n const {\n personId,\n tenantId,\n organizationId,\n viewerUserId,\n userFeatures,\n maxThreads = DEFAULT_MAX_THREADS,\n maxMessagesPerThread = DEFAULT_MAX_MESSAGES_PER_THREAD,\n } = opts\n\n // \u2500\u2500 (1) Load the Person's email interactions (the Person\u2194email anchor) \u2500\u2500\n const interactionWhere: JsonRecord = {\n entity: personId,\n interactionType: 'email',\n deletedAt: null,\n tenantId,\n }\n if (organizationId) interactionWhere.organizationId = organizationId\n\n // Per-email visibility (v1: strict owner-only, no admin bypass) \u2014 the CRM\n // Person page applies the SAME rule as every other interactions read path via\n // `buildEmailVisibilityMikroFilter`, so the Emails tab and the `/interactions`\n // timeline can never disagree about who sees an email:\n // - `visibility = 'shared'` is visible to every user with CRM access to this\n // Person (lets a teammate pick up a handed-off thread),\n // - `visibility = 'private'` is visible ONLY to its author (the mailbox\n // owner) \u2014 never to teammates, not even an admin/superadmin (team\n // oversight is a deliberate v2 follow-up),\n // - legacy/unset rows (`visibility IS NULL`) stay visible so pre-existing\n // CRM history is never silently hidden.\n // Fail-closed: a null viewer (API-key caller) never matches the author arm, so\n // it only ever sees shared/legacy rows \u2014 never anyone's private email.\n interactionWhere.$or = buildEmailVisibilityMikroFilter({\n currentUserId: viewerUserId,\n userFeatures,\n }).$or\n\n // `customer_interaction.title`/`body` are encrypted at rest, so reads go\n // through `findWithDecryption` even though we only consume non-encrypted\n // columns here \u2014 this keeps the encrypted-entity contract intact.\n const dscope = { tenantId, organizationId: organizationId ?? null }\n const interactions = (await findWithDecryption(\n em,\n CustomerInteraction,\n interactionWhere as never,\n { orderBy: { occurredAt: 'desc', createdAt: 'desc' }, limit: maxThreads * 20 },\n dscope,\n )) as CustomerInteraction[]\n\n const linkIdByInteraction = new Map<string, { occurredAt: Date }>()\n const linkIds: string[] = []\n for (const interaction of interactions) {\n const linkId = interaction.externalMessageId\n if (!linkId || linkIdByInteraction.has(linkId)) continue\n linkIdByInteraction.set(linkId, { occurredAt: interaction.occurredAt ?? interaction.createdAt })\n linkIds.push(linkId)\n }\n if (linkIds.length === 0) return []\n\n // \u2500\u2500 (2) Resolve MessageChannelLink rows (rich content + direction) \u2500\u2500\u2500\u2500\u2500\u2500\n const linkWhere: JsonRecord = { id: { $in: linkIds }, tenantId }\n if (organizationId) linkWhere.organizationId = organizationId\n const links = (await findWithDecryption(\n em,\n 'MessageChannelLink' as never,\n linkWhere as never,\n undefined,\n dscope,\n )) as JsonRecord[]\n\n // \u2500\u2500 (3) Resolve hub Message rows (the authoritative thread grouping) \u2500\u2500\u2500\u2500\n const messageIds = Array.from(\n new Set(\n links\n .map((link) => (typeof link.messageId === 'string' ? (link.messageId as string) : null))\n .filter((value): value is string => !!value),\n ),\n )\n const messageById = new Map<string, JsonRecord>()\n if (messageIds.length > 0) {\n const messageWhere: JsonRecord = { id: { $in: messageIds }, tenantId }\n if (organizationId) messageWhere.organizationId = organizationId\n const messages = (await findWithDecryption(\n em,\n 'Message' as never,\n messageWhere as never,\n undefined,\n dscope,\n )) as JsonRecord[]\n for (const message of messages) {\n if (typeof message.id === 'string') messageById.set(message.id, message)\n }\n }\n\n // \u2500\u2500 (4) Build per-message DTOs grouped by thread \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const threadsByKey = new Map<string, PersonEmailThread>()\n\n for (const link of links) {\n const linkId = typeof link.id === 'string' ? (link.id as string) : null\n if (!linkId) continue\n const direction: EmailThreadDirection = link.direction === 'outbound' ? 'outbound' : 'inbound'\n const providerKey = typeof link.providerKey === 'string' ? (link.providerKey as string) : null\n const payload = (link.channelPayload ?? null) as JsonRecord | null\n const meta = (link.channelMetadata ?? null) as JsonRecord | null\n const messageId = typeof link.messageId === 'string' ? (link.messageId as string) : null\n const message = messageId ? messageById.get(messageId) ?? null : null\n\n // Outbound addresses live in channelMetadata; inbound in channelPayload.\n // Prefer the direction-appropriate source, fall back to the other.\n const primary = direction === 'outbound' ? meta : payload\n const secondary = direction === 'outbound' ? payload : meta\n const fromList = extractAddresses(primary?.from ?? secondary?.from)\n const toList = extractAddresses(primary?.to ?? secondary?.to)\n const ccList = extractAddresses(primary?.cc ?? secondary?.cc)\n\n const subject = firstString(\n primary?.subject,\n secondary?.subject,\n typeof message?.subject === 'string' ? message.subject : null,\n )\n const bodyText = firstString(\n direction === 'outbound' ? meta?.bodyText : payload?.text,\n direction === 'outbound' ? payload?.text : meta?.bodyText,\n typeof message?.body === 'string' ? message.body : null,\n )\n\n const sentAtRaw =\n (typeof message?.sentAt === 'string' || message?.sentAt instanceof Date\n ? message.sentAt\n : null) ??\n (link.createdAt instanceof Date || typeof link.createdAt === 'string' ? link.createdAt : null) ??\n linkIdByInteraction.get(linkId)?.occurredAt ??\n new Date()\n const sentAt = (sentAtRaw instanceof Date ? sentAtRaw : new Date(sentAtRaw)).toISOString()\n\n const threadKey =\n (typeof message?.threadId === 'string' && message.threadId ? message.threadId : null) ??\n (messageId ? `message:${messageId}` : `link:${linkId}`)\n\n const dto: PersonEmailMessage = {\n id: linkId,\n messageId,\n rfcMessageId: firstString(primary?.messageId, secondary?.messageId),\n references: toStringArray(primary?.references, secondary?.references),\n direction,\n fromName: fromList[0]?.name ?? null,\n fromEmail: fromList[0]?.email ?? null,\n to: toList.map((a) => a.email),\n cc: ccList.map((a) => a.email),\n subject,\n bodyText,\n sentAt,\n providerKey,\n }\n\n const existing = threadsByKey.get(threadKey)\n if (existing) {\n existing.messages.push(dto)\n } else {\n threadsByKey.set(threadKey, {\n threadKey,\n subject,\n preview: null,\n participants: [],\n lastMessageAt: sentAt,\n messageCount: 0,\n providerKey,\n lastDirection: direction,\n messages: [dto],\n })\n }\n }\n\n // \u2500\u2500 (5) Finalize thread summaries \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const threads: PersonEmailThread[] = []\n for (const thread of threadsByKey.values()) {\n thread.messages.sort((a, b) => a.sentAt.localeCompare(b.sentAt))\n if (thread.messages.length > maxMessagesPerThread) {\n thread.messages = thread.messages.slice(thread.messages.length - maxMessagesPerThread)\n }\n const last = thread.messages[thread.messages.length - 1]\n const firstWithSubject = thread.messages.find((m) => m.subject)\n const participantSet = new Set<string>()\n for (const message of thread.messages) {\n // External counterpart = the \"from\" for inbound, the \"to\" for outbound.\n if (message.direction === 'inbound' && message.fromEmail) participantSet.add(message.fromEmail)\n if (message.direction === 'outbound') message.to.forEach((email) => participantSet.add(email))\n }\n thread.subject = firstWithSubject?.subject ?? thread.subject\n thread.preview = truncate(last?.bodyText ?? null)\n thread.participants = Array.from(participantSet)\n thread.lastMessageAt = last?.sentAt ?? thread.lastMessageAt\n thread.lastDirection = last?.direction ?? thread.lastDirection\n thread.providerKey = last?.providerKey ?? thread.providerKey\n thread.messageCount = thread.messages.length\n threads.push(thread)\n }\n\n threads.sort((a, b) => b.lastMessageAt.localeCompare(a.lastMessageAt))\n return threads.slice(0, maxThreads)\n}\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,0BAA0B;AACnC,SAAS,2BAA2B;AACpC,SAAS,uCAAuC;
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CustomerInteraction } from '../data/entities'\nimport { resolveUserNames } from './userNames'\nimport { buildEmailVisibilityMikroFilter } from './visibilityFilter'\nimport type { ConversationShareGrant } from './conversationShares'\n\n/**\n * Read model that turns a Person's email `CustomerInteraction` rows into\n * Gmail-style threads for the CRM Person page.\n *\n * The Person\u2194email anchor lives only on `CustomerInteraction`\n * (`interactionType='email'`, `externalMessageId` \u2192 `MessageChannelLink.id`).\n * The thread grouping key and the rich per-message content (From/To/Cc, body,\n * direction) live in the communication_channels hub. We read the hub entities\n * by their string class names \u2014 the same cross-module pattern used by\n * `link-channel-message-handler.ts` \u2014 so the customers module never imports the\n * hub's entity classes (root AGENTS.md: no direct ORM relationships between\n * modules).\n */\n\nexport type EmailThreadDirection = 'inbound' | 'outbound'\n\nexport type PersonEmailMessage = {\n id: string\n /** Open Mercato `messages.message` id \u2014 used as `parentMessageId` when replying so the reply joins this thread. */\n messageId: string | null\n /** RFC2822 Message-ID of this email \u2014 used as `In-Reply-To` on a reply. */\n rfcMessageId: string | null\n /** RFC2822 References chain for this email. */\n references: string[]\n direction: EmailThreadDirection\n fromName: string | null\n fromEmail: string | null\n /**\n * True when the viewer is the author of this message. Outbound email carries\n * no `from` header in `channelMetadata`, so the sender label cannot be derived\n * from the addresses \u2014 and since conversation/channel sharing lets a teammate\n * read someone else's outbound mail, direction alone is not the author either.\n */\n authoredByViewer: boolean\n /** Display label of the sending colleague; null for the viewer's own mail and for inbound. */\n authorName: string | null\n to: string[]\n cc: string[]\n subject: string | null\n bodyText: string | null\n sentAt: string\n providerKey: string | null\n}\n\nexport type PersonEmailThread = {\n threadKey: string\n subject: string | null\n preview: string | null\n participants: string[]\n lastMessageAt: string\n messageCount: number\n providerKey: string | null\n lastDirection: EmailThreadDirection\n messages: PersonEmailMessage[]\n}\n\nexport type BuildPersonEmailThreadsOptions = {\n personId: string\n tenantId: string\n organizationId: string | null\n viewerUserId: string | null\n userFeatures: string[] | null | undefined\n /**\n * Conversation shares that widen this viewer's access. Optional and fail-closed:\n * omitting it yields the strict owner-only view.\n */\n sharedConversations?: ConversationShareGrant[]\n /** Channels marked as shared team mailboxes; optional and fail-closed. */\n sharedChannelIds?: string[]\n maxThreads?: number\n maxMessagesPerThread?: number\n}\n\nconst DEFAULT_MAX_THREADS = 50\nconst DEFAULT_MAX_MESSAGES_PER_THREAD = 200\nconst PREVIEW_LENGTH = 140\n\ntype JsonRecord = Record<string, unknown>\n\n/** Extracts `{ email, name }[]` from the many shapes a channel address field can take. */\nfunction extractAddresses(value: unknown): Array<{ email: string; name: string | null }> {\n const out: Array<{ email: string; name: string | null }> = []\n const pushOne = (item: unknown): void => {\n if (typeof item === 'string') {\n const trimmed = item.trim()\n if (trimmed) out.push({ email: trimmed, name: null })\n return\n }\n if (item && typeof item === 'object') {\n const rec = item as JsonRecord\n const address = typeof rec.address === 'string' ? rec.address.trim() : null\n const name = typeof rec.name === 'string' && rec.name.trim() ? rec.name.trim() : null\n if (address) out.push({ email: address, name })\n }\n }\n if (Array.isArray(value)) {\n for (const item of value) pushOne(item)\n } else {\n pushOne(value)\n }\n return out\n}\n\nfunction firstString(...values: unknown[]): string | null {\n for (const value of values) {\n if (typeof value === 'string' && value.trim().length > 0) return value\n }\n return null\n}\n\nfunction toStringArray(...values: unknown[]): string[] {\n for (const value of values) {\n if (Array.isArray(value)) {\n const strings = value.filter((item): item is string => typeof item === 'string' && item.trim().length > 0)\n if (strings.length > 0) return strings\n }\n }\n return []\n}\n\nfunction truncate(value: string | null): string | null {\n if (!value) return value\n const collapsed = value.replace(/\\s+/g, ' ').trim()\n if (collapsed.length <= PREVIEW_LENGTH) return collapsed\n return `${collapsed.slice(0, PREVIEW_LENGTH - 1)}\u2026`\n}\n\n/**\n * Builds the per-Person email-thread read model. Pure data assembly \u2014 callers\n * are responsible for auth and scoping (tenantId/organizationId required).\n */\nexport async function buildPersonEmailThreads(\n em: EntityManager,\n opts: BuildPersonEmailThreadsOptions,\n): Promise<PersonEmailThread[]> {\n const {\n personId,\n tenantId,\n organizationId,\n viewerUserId,\n userFeatures,\n sharedConversations,\n sharedChannelIds,\n maxThreads = DEFAULT_MAX_THREADS,\n maxMessagesPerThread = DEFAULT_MAX_MESSAGES_PER_THREAD,\n } = opts\n\n // \u2500\u2500 (1) Load the Person's email interactions (the Person\u2194email anchor) \u2500\u2500\n const interactionWhere: JsonRecord = {\n entity: personId,\n interactionType: 'email',\n deletedAt: null,\n tenantId,\n }\n if (organizationId) interactionWhere.organizationId = organizationId\n\n // Per-email visibility (v1: strict owner-only, no admin bypass) \u2014 the CRM\n // Person page applies the SAME rule as every other interactions read path via\n // `buildEmailVisibilityMikroFilter`, so the Emails tab and the `/interactions`\n // timeline can never disagree about who sees an email:\n // - `visibility = 'shared'` is visible to every user with CRM access to this\n // Person (lets a teammate pick up a handed-off thread),\n // - `visibility = 'private'` is visible ONLY to its author (the mailbox\n // owner) \u2014 never to teammates, not even an admin/superadmin (team\n // oversight is a deliberate v2 follow-up),\n // - legacy/unset rows (`visibility IS NULL`) stay visible so pre-existing\n // CRM history is never silently hidden.\n // Fail-closed: a null viewer (API-key caller) never matches the author arm, so\n // it only ever sees shared/legacy rows \u2014 never anyone's private email.\n // Merge the WHOLE fragment. Cherry-picking `.$or` here would silently discard\n // any other arm the predicate grows, which fails OPEN at a compile-clean call\n // site \u2014 the exact hazard the fragment contract now documents.\n Object.assign(\n interactionWhere,\n buildEmailVisibilityMikroFilter({\n currentUserId: viewerUserId,\n userFeatures,\n sharedConversations,\n sharedChannelIds,\n }),\n )\n\n // `customer_interaction.title`/`body` are encrypted at rest, so reads go\n // through `findWithDecryption` even though we only consume non-encrypted\n // columns here \u2014 this keeps the encrypted-entity contract intact.\n const dscope = { tenantId, organizationId: organizationId ?? null }\n const interactions = (await findWithDecryption(\n em,\n CustomerInteraction,\n interactionWhere as never,\n { orderBy: { occurredAt: 'desc', createdAt: 'desc' }, limit: maxThreads * 20 },\n dscope,\n )) as CustomerInteraction[]\n\n const linkIdByInteraction = new Map<string, { occurredAt: Date; authorUserId: string | null }>()\n const linkIds: string[] = []\n for (const interaction of interactions) {\n const linkId = interaction.externalMessageId\n if (!linkId || linkIdByInteraction.has(linkId)) continue\n linkIdByInteraction.set(linkId, {\n occurredAt: interaction.occurredAt ?? interaction.createdAt,\n authorUserId: interaction.authorUserId ?? null,\n })\n linkIds.push(linkId)\n }\n if (linkIds.length === 0) return []\n\n // \u2500\u2500 (2) Resolve MessageChannelLink rows (rich content + direction) \u2500\u2500\u2500\u2500\u2500\u2500\n const linkWhere: JsonRecord = { id: { $in: linkIds }, tenantId }\n if (organizationId) linkWhere.organizationId = organizationId\n const links = (await findWithDecryption(\n em,\n 'MessageChannelLink' as never,\n linkWhere as never,\n undefined,\n dscope,\n )) as JsonRecord[]\n\n // \u2500\u2500 (3) Resolve hub Message rows (the authoritative thread grouping) \u2500\u2500\u2500\u2500\n const messageIds = Array.from(\n new Set(\n links\n .map((link) => (typeof link.messageId === 'string' ? (link.messageId as string) : null))\n .filter((value): value is string => !!value),\n ),\n )\n const messageById = new Map<string, JsonRecord>()\n if (messageIds.length > 0) {\n const messageWhere: JsonRecord = { id: { $in: messageIds }, tenantId }\n if (organizationId) messageWhere.organizationId = organizationId\n const messages = (await findWithDecryption(\n em,\n 'Message' as never,\n messageWhere as never,\n undefined,\n dscope,\n )) as JsonRecord[]\n for (const message of messages) {\n if (typeof message.id === 'string') messageById.set(message.id, message)\n }\n }\n\n // \u2500\u2500 (3b) Resolve sender labels for colleagues' messages \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // Only for authors other than the viewer: their own mail renders as \"You\" and\n // needs no lookup. A shared conversation is exactly the case where a message\n // the viewer did not write shows up in their thread list, so without this the\n // UI would have to fall back on direction and misattribute it to the reader.\n const foreignAuthorIds = Array.from(\n new Set(\n Array.from(linkIdByInteraction.values())\n .map((entry) => entry.authorUserId)\n .filter((id): id is string => !!id && id !== viewerUserId),\n ),\n )\n const authorNames = foreignAuthorIds.length\n ? await resolveUserNames(em, tenantId, organizationId, foreignAuthorIds)\n : new Map<string, string>()\n\n // \u2500\u2500 (4) Build per-message DTOs grouped by thread \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const threadsByKey = new Map<string, PersonEmailThread>()\n\n for (const link of links) {\n const linkId = typeof link.id === 'string' ? (link.id as string) : null\n if (!linkId) continue\n const direction: EmailThreadDirection = link.direction === 'outbound' ? 'outbound' : 'inbound'\n // `authorUserId` on the interaction is the MAILBOX OWNER, which on an\n // inbound message is the recipient, not the sender \u2014 so authorship is an\n // outbound-only notion. Inbound senders are named by the `from` header.\n const authorUserId = direction === 'outbound' ? linkIdByInteraction.get(linkId)?.authorUserId ?? null : null\n const authoredByViewer = !!viewerUserId && !!authorUserId && authorUserId === viewerUserId\n const providerKey = typeof link.providerKey === 'string' ? (link.providerKey as string) : null\n const payload = (link.channelPayload ?? null) as JsonRecord | null\n const meta = (link.channelMetadata ?? null) as JsonRecord | null\n const messageId = typeof link.messageId === 'string' ? (link.messageId as string) : null\n const message = messageId ? messageById.get(messageId) ?? null : null\n\n // Outbound addresses live in channelMetadata; inbound in channelPayload.\n // Prefer the direction-appropriate source, fall back to the other.\n const primary = direction === 'outbound' ? meta : payload\n const secondary = direction === 'outbound' ? payload : meta\n const fromList = extractAddresses(primary?.from ?? secondary?.from)\n const toList = extractAddresses(primary?.to ?? secondary?.to)\n const ccList = extractAddresses(primary?.cc ?? secondary?.cc)\n\n const subject = firstString(\n primary?.subject,\n secondary?.subject,\n typeof message?.subject === 'string' ? message.subject : null,\n )\n const bodyText = firstString(\n direction === 'outbound' ? meta?.bodyText : payload?.text,\n direction === 'outbound' ? payload?.text : meta?.bodyText,\n typeof message?.body === 'string' ? message.body : null,\n )\n\n const sentAtRaw =\n (typeof message?.sentAt === 'string' || message?.sentAt instanceof Date\n ? message.sentAt\n : null) ??\n (link.createdAt instanceof Date || typeof link.createdAt === 'string' ? link.createdAt : null) ??\n linkIdByInteraction.get(linkId)?.occurredAt ??\n new Date()\n const sentAt = (sentAtRaw instanceof Date ? sentAtRaw : new Date(sentAtRaw)).toISOString()\n\n const threadKey =\n (typeof message?.threadId === 'string' && message.threadId ? message.threadId : null) ??\n (messageId ? `message:${messageId}` : `link:${linkId}`)\n\n const dto: PersonEmailMessage = {\n id: linkId,\n messageId,\n rfcMessageId: firstString(primary?.messageId, secondary?.messageId),\n references: toStringArray(primary?.references, secondary?.references),\n direction,\n fromName: fromList[0]?.name ?? null,\n fromEmail: fromList[0]?.email ?? null,\n authoredByViewer,\n authorName: authoredByViewer ? null : authorUserId ? authorNames.get(authorUserId) ?? null : null,\n to: toList.map((a) => a.email),\n cc: ccList.map((a) => a.email),\n subject,\n bodyText,\n sentAt,\n providerKey,\n }\n\n const existing = threadsByKey.get(threadKey)\n if (existing) {\n existing.messages.push(dto)\n } else {\n threadsByKey.set(threadKey, {\n threadKey,\n subject,\n preview: null,\n participants: [],\n lastMessageAt: sentAt,\n messageCount: 0,\n providerKey,\n lastDirection: direction,\n messages: [dto],\n })\n }\n }\n\n // \u2500\u2500 (5) Finalize thread summaries \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const threads: PersonEmailThread[] = []\n for (const thread of threadsByKey.values()) {\n thread.messages.sort((a, b) => a.sentAt.localeCompare(b.sentAt))\n if (thread.messages.length > maxMessagesPerThread) {\n thread.messages = thread.messages.slice(thread.messages.length - maxMessagesPerThread)\n }\n const last = thread.messages[thread.messages.length - 1]\n const firstWithSubject = thread.messages.find((m) => m.subject)\n const participantSet = new Set<string>()\n for (const message of thread.messages) {\n // External counterpart = the \"from\" for inbound, the \"to\" for outbound.\n if (message.direction === 'inbound' && message.fromEmail) participantSet.add(message.fromEmail)\n if (message.direction === 'outbound') message.to.forEach((email) => participantSet.add(email))\n }\n thread.subject = firstWithSubject?.subject ?? thread.subject\n thread.preview = truncate(last?.bodyText ?? null)\n thread.participants = Array.from(participantSet)\n thread.lastMessageAt = last?.sentAt ?? thread.lastMessageAt\n thread.lastDirection = last?.direction ?? thread.lastDirection\n thread.providerKey = last?.providerKey ?? thread.providerKey\n thread.messageCount = thread.messages.length\n threads.push(thread)\n }\n\n threads.sort((a, b) => b.lastMessageAt.localeCompare(a.lastMessageAt))\n return threads.slice(0, maxThreads)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
2
|
+
const BULK_UPDATE_OWNER_ENDPOINT = "/api/customers/deals/bulk-update-owner";
|
|
3
|
+
async function requestBulkOwnerReassignment(params) {
|
|
4
|
+
const call = await apiCall(BULK_UPDATE_OWNER_ENDPOINT, {
|
|
5
|
+
method: "POST",
|
|
6
|
+
headers: { "content-type": "application/json" },
|
|
7
|
+
body: JSON.stringify({ ids: params.ids, ownerUserId: params.ownerUserId })
|
|
8
|
+
});
|
|
9
|
+
if (!call.ok) throw new Error(params.errorMessage);
|
|
10
|
+
return { progressJobId: call.result?.progressJobId ?? null };
|
|
11
|
+
}
|
|
12
|
+
function buildReassignOwnerSuccess(params) {
|
|
13
|
+
return {
|
|
14
|
+
ok: true,
|
|
15
|
+
progressJobId: params.progressJobId,
|
|
16
|
+
affectedCount: params.ids.length,
|
|
17
|
+
message: params.message
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
BULK_UPDATE_OWNER_ENDPOINT,
|
|
22
|
+
buildReassignOwnerSuccess,
|
|
23
|
+
requestBulkOwnerReassignment
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=reassignDealOwner.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/customers/lib/reassignDealOwner.ts"],
|
|
4
|
+
"sourcesContent": ["import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport type { BulkActionExecuteResult } from '@open-mercato/ui/backend/DataTable'\n\nexport const BULK_UPDATE_OWNER_ENDPOINT = '/api/customers/deals/bulk-update-owner'\n\ntype BulkUpdateOwnerResponse = {\n ok: boolean\n progressJobId: string | null\n message: string\n}\n\n/**\n * Posts a bulk owner reassignment and returns the queued job id.\n *\n * Split out of the deals list page so the request shape and the progress-id passthrough are\n * testable without rendering the page. `errorMessage` is supplied by the caller because the\n * page owns translation; it is thrown as-is so the guarded-mutation wrapper surfaces the same\n * text it did before this was extracted.\n */\nexport async function requestBulkOwnerReassignment(params: {\n ids: string[]\n ownerUserId: string\n errorMessage: string\n}): Promise<{ progressJobId: string | null }> {\n const call = await apiCall<BulkUpdateOwnerResponse>(BULK_UPDATE_OWNER_ENDPOINT, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ ids: params.ids, ownerUserId: params.ownerUserId }),\n })\n if (!call.ok) throw new Error(params.errorMessage)\n return { progressJobId: call.result?.progressJobId ?? null }\n}\n\n/**\n * The success shape handed back to `DataTable`. Returning `ok: true` with a `progressJobId` is\n * what makes the table clear the row selection and track the job in the top bar \u2014 that side of\n * the contract is covered by `DataTable.propBulkActions.test.tsx`; this builder is what keeps\n * our half of it honest.\n */\nexport function buildReassignOwnerSuccess(params: {\n ids: string[]\n progressJobId: string | null\n message: string\n}): BulkActionExecuteResult {\n return {\n ok: true,\n progressJobId: params.progressJobId,\n affectedCount: params.ids.length,\n message: params.message,\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,eAAe;AAGjB,MAAM,6BAA6B;AAgB1C,eAAsB,6BAA6B,QAIL;AAC5C,QAAM,OAAO,MAAM,QAAiC,4BAA4B;AAAA,IAC9E,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,EAAE,KAAK,OAAO,KAAK,aAAa,OAAO,YAAY,CAAC;AAAA,EAC3E,CAAC;AACD,MAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,OAAO,YAAY;AACjD,SAAO,EAAE,eAAe,KAAK,QAAQ,iBAAiB,KAAK;AAC7D;AAQO,SAAS,0BAA0B,QAId;AAC1B,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,eAAe,OAAO;AAAA,IACtB,eAAe,OAAO,IAAI;AAAA,IAC1B,SAAS,OAAO;AAAA,EAClB;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
2
|
+
import { User } from "@open-mercato/core/modules/auth/data/entities";
|
|
3
|
+
async function resolveUserNames(em, tenantId, organizationId, userIds) {
|
|
4
|
+
const names = /* @__PURE__ */ new Map();
|
|
5
|
+
const unique = Array.from(new Set(userIds.filter((id) => typeof id === "string" && !!id)));
|
|
6
|
+
if (unique.length === 0) return names;
|
|
7
|
+
try {
|
|
8
|
+
const users = await findWithDecryption(
|
|
9
|
+
em,
|
|
10
|
+
User,
|
|
11
|
+
{ id: { $in: unique } },
|
|
12
|
+
void 0,
|
|
13
|
+
{ tenantId, organizationId }
|
|
14
|
+
);
|
|
15
|
+
for (const user of Array.isArray(users) ? users : []) {
|
|
16
|
+
const label = user.name?.trim() || user.email?.trim() || null;
|
|
17
|
+
if (label) names.set(user.id, label);
|
|
18
|
+
}
|
|
19
|
+
} catch {
|
|
20
|
+
}
|
|
21
|
+
return names;
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
resolveUserNames
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=userNames.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/customers/lib/userNames.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\n\n/**\n * Resolves display labels for a set of user ids, tenant/organization scoped.\n *\n * Used wherever the CRM attributes something to the colleague who did it \u2014 the\n * \"Shared by {name}\" badge on the Emails tab, and the per-message sender label\n * a teammate sees on a shared conversation. Best effort by design: a caller\n * renders a generic fallback for any id that resolves to no label, so a failed\n * lookup degrades the wording rather than the read.\n */\nexport async function resolveUserNames(\n em: EntityManager,\n tenantId: string,\n organizationId: string | null,\n userIds: Array<string | null | undefined>,\n): Promise<Map<string, string>> {\n const names = new Map<string, string>()\n const unique = Array.from(new Set(userIds.filter((id): id is string => typeof id === 'string' && !!id)))\n if (unique.length === 0) return names\n try {\n const users = (await findWithDecryption(\n em,\n User,\n { id: { $in: unique } } as never,\n undefined,\n { tenantId, organizationId },\n )) as Array<{ id: string; name?: string | null; email?: string | null }>\n for (const user of Array.isArray(users) ? users : []) {\n const label = user.name?.trim() || user.email?.trim() || null\n if (label) names.set(user.id, label)\n }\n } catch {\n /* best effort \u2014 callers fall back to a generic label without a name */\n }\n return names\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,0BAA0B;AACnC,SAAS,YAAY;AAWrB,eAAsB,iBACpB,IACA,UACA,gBACA,SAC8B;AAC9B,QAAM,QAAQ,oBAAI,IAAoB;AACtC,QAAM,SAAS,MAAM,KAAK,IAAI,IAAI,QAAQ,OAAO,CAAC,OAAqB,OAAO,OAAO,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC;AACvG,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,MAAI;AACF,UAAM,QAAS,MAAM;AAAA,MACnB;AAAA,MACA;AAAA,MACA,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE;AAAA,MACtB;AAAA,MACA,EAAE,UAAU,eAAe;AAAA,IAC7B;AACA,eAAW,QAAQ,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,GAAG;AACpD,YAAM,QAAQ,KAAK,MAAM,KAAK,KAAK,KAAK,OAAO,KAAK,KAAK;AACzD,UAAI,MAAO,OAAM,IAAI,KAAK,IAAI,KAAK;AAAA,IACrC;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -13,15 +13,70 @@ function canChangeEmailVisibility(opts) {
|
|
|
13
13
|
}
|
|
14
14
|
function applyEmailVisibilityFilter(query, opts) {
|
|
15
15
|
const currentUserId = opts.currentUserId;
|
|
16
|
+
const grants = opts.sharedConversations ?? [];
|
|
17
|
+
const sharedChannelIds = opts.sharedChannelIds ?? [];
|
|
16
18
|
return query.where(
|
|
17
19
|
(eb) => eb.or([
|
|
18
20
|
eb("interaction_type", "!=", "email"),
|
|
19
21
|
eb("visibility", "is", null),
|
|
20
22
|
eb("visibility", "!=", "private"),
|
|
21
|
-
currentUserId ? eb("author_user_id", "=", currentUserId) : eb.val(false)
|
|
23
|
+
currentUserId ? eb("author_user_id", "=", currentUserId) : eb.val(false),
|
|
24
|
+
// Conversation shares: the owner handed their history with this Person to
|
|
25
|
+
// the team. One arm per grant, each an AND of the two columns the covering
|
|
26
|
+
// index already leads with.
|
|
27
|
+
...grants.map(
|
|
28
|
+
(grant) => eb.and([
|
|
29
|
+
eb("entity_id", "=", grant.personEntityId),
|
|
30
|
+
eb("author_user_id", "=", grant.ownerUserId)
|
|
31
|
+
])
|
|
32
|
+
),
|
|
33
|
+
// Shared team mailboxes: the whole channel was handed to the team. One arm
|
|
34
|
+
// for the whole set, matching the indexed `channel_id` column.
|
|
35
|
+
...sharedChannelIds.length > 0 ? [eb("channel_id", "in", sharedChannelIds)] : []
|
|
22
36
|
])
|
|
23
37
|
);
|
|
24
38
|
}
|
|
39
|
+
function isEmailHiddenFrom(opts) {
|
|
40
|
+
if (opts.interactionType !== "email") return false;
|
|
41
|
+
if (opts.visibility !== "private") return false;
|
|
42
|
+
if (opts.currentUserId && opts.authorUserId && opts.authorUserId === opts.currentUserId) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
const sharedChannelIds = opts.sharedChannelIds ?? [];
|
|
46
|
+
if (sharedChannelIds.length > 0 && opts.channelId && sharedChannelIds.includes(opts.channelId)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
const grants = opts.sharedConversations ?? [];
|
|
50
|
+
if (grants.length > 0 && opts.personEntityId && opts.authorUserId) {
|
|
51
|
+
const shared = grants.some(
|
|
52
|
+
(grant) => grant.personEntityId === opts.personEntityId && grant.ownerUserId === opts.authorUserId
|
|
53
|
+
);
|
|
54
|
+
if (shared) return false;
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
function applyEmailHiddenFilter(query, opts) {
|
|
59
|
+
const currentUserId = opts.currentUserId;
|
|
60
|
+
const grants = opts.sharedConversations ?? [];
|
|
61
|
+
const sharedChannelIds = opts.sharedChannelIds ?? [];
|
|
62
|
+
return query.where("interaction_type", "=", "email").where("visibility", "=", "private").where(
|
|
63
|
+
(eb) => currentUserId ? eb("author_user_id", "!=", currentUserId) : eb.val(true)
|
|
64
|
+
).where(
|
|
65
|
+
(eb) => sharedChannelIds.length === 0 ? eb.val(true) : eb.or([
|
|
66
|
+
eb("channel_id", "is", null),
|
|
67
|
+
eb("channel_id", "not in", sharedChannelIds)
|
|
68
|
+
])
|
|
69
|
+
).where(
|
|
70
|
+
(eb) => grants.length === 0 ? eb.val(true) : eb.and(
|
|
71
|
+
grants.map(
|
|
72
|
+
(grant) => eb.or([
|
|
73
|
+
eb("entity_id", "!=", grant.personEntityId),
|
|
74
|
+
eb("author_user_id", "!=", grant.ownerUserId)
|
|
75
|
+
])
|
|
76
|
+
)
|
|
77
|
+
)
|
|
78
|
+
);
|
|
79
|
+
}
|
|
25
80
|
async function resolveCallerEmailFeatures(container, userId, tenantId, organizationId) {
|
|
26
81
|
if (!userId) return void 0;
|
|
27
82
|
try {
|
|
@@ -33,21 +88,34 @@ async function resolveCallerEmailFeatures(container, userId, tenantId, organizat
|
|
|
33
88
|
}
|
|
34
89
|
}
|
|
35
90
|
function buildEmailVisibilityMikroFilter(opts) {
|
|
91
|
+
const grants = opts.sharedConversations ?? [];
|
|
92
|
+
const sharedChannelIds = opts.sharedChannelIds ?? [];
|
|
36
93
|
return {
|
|
37
94
|
$or: [
|
|
38
95
|
{ interactionType: { $ne: "email" } },
|
|
39
96
|
{ visibility: null },
|
|
40
97
|
{ visibility: { $ne: "private" } },
|
|
41
|
-
...opts.currentUserId ? [{ authorUserId: opts.currentUserId }] : []
|
|
98
|
+
...opts.currentUserId ? [{ authorUserId: opts.currentUserId }] : [],
|
|
99
|
+
// Mirrors the kysely share arm: one AND-pair per grant, kept flat inside
|
|
100
|
+
// this single `$or` so the fragment stays a one-key object.
|
|
101
|
+
...grants.map((grant) => ({
|
|
102
|
+
entity: grant.personEntityId,
|
|
103
|
+
authorUserId: grant.ownerUserId
|
|
104
|
+
})),
|
|
105
|
+
// Mirrors the kysely channel arm. Still flat inside this single `$or`, so
|
|
106
|
+
// the fragment stays a one-key object every caller can spread losslessly.
|
|
107
|
+
...sharedChannelIds.length > 0 ? [{ channelId: { $in: sharedChannelIds } }] : []
|
|
42
108
|
]
|
|
43
109
|
};
|
|
44
110
|
}
|
|
45
111
|
export {
|
|
46
112
|
EMAIL_VIEW_PRIVATE_FEATURE,
|
|
113
|
+
applyEmailHiddenFilter,
|
|
47
114
|
applyEmailVisibilityFilter,
|
|
48
115
|
buildEmailVisibilityMikroFilter,
|
|
49
116
|
callerHasEmailViewPrivate,
|
|
50
117
|
canChangeEmailVisibility,
|
|
118
|
+
isEmailHiddenFrom,
|
|
51
119
|
resolveCallerEmailFeatures
|
|
52
120
|
};
|
|
53
121
|
//# sourceMappingURL=visibilityFilter.js.map
|