@wildo-ai/saas-backend-lib 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/__tests__/setup.d.ts +7 -0
- package/dist/esm/__tests__/setup.d.ts.map +1 -0
- package/dist/esm/__tests__/setup.js +14 -0
- package/dist/esm/__tests__/setup.js.map +1 -0
- package/dist/esm/__tests__/test-container.d.ts +39 -0
- package/dist/esm/__tests__/test-container.d.ts.map +1 -0
- package/dist/esm/__tests__/test-container.js +94 -0
- package/dist/esm/__tests__/test-container.js.map +1 -0
- package/dist/esm/applications/models/applications.backend.schemas.d.ts +11 -0
- package/dist/esm/applications/models/applications.backend.schemas.d.ts.map +1 -0
- package/dist/esm/applications/models/applications.backend.schemas.js +15 -0
- package/dist/esm/applications/models/applications.backend.schemas.js.map +1 -0
- package/dist/esm/base-classes/models/manual-controllers.backend.definition.d.ts +12 -0
- package/dist/esm/base-classes/models/manual-controllers.backend.definition.d.ts.map +1 -0
- package/dist/esm/base-classes/models/manual-controllers.backend.definition.js +30 -0
- package/dist/esm/base-classes/models/manual-controllers.backend.definition.js.map +1 -0
- package/dist/esm/base-classes/models/repositories.backend.schemas.d.ts +98 -0
- package/dist/esm/base-classes/models/repositories.backend.schemas.d.ts.map +1 -0
- package/dist/esm/base-classes/models/repositories.backend.schemas.js +11 -0
- package/dist/esm/base-classes/models/repositories.backend.schemas.js.map +1 -0
- package/dist/esm/base-classes/services/__tests__/mock-resource-operation-helper.service.d.ts +31 -0
- package/dist/esm/base-classes/services/__tests__/mock-resource-operation-helper.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/__tests__/mock-resource-operation-helper.service.js +52 -0
- package/dist/esm/base-classes/services/__tests__/mock-resource-operation-helper.service.js.map +1 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-custom-execution.service.d.ts +56 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-custom-execution.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-custom-execution.service.js +52 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-custom-execution.service.js.map +1 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-executor.backend.service.d.ts +33 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-executor.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-executor.backend.service.js +125 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-executor.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-resource-execution.backend.service.d.ts +20 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-resource-execution.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-resource-execution.backend.service.js +45 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-resource-execution.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/controllers/abstract-controller.backend.service.d.ts +133 -0
- package/dist/esm/base-classes/services/controllers/abstract-controller.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/controllers/abstract-controller.backend.service.js +280 -0
- package/dist/esm/base-classes/services/controllers/abstract-controller.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.d.ts +147 -0
- package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.js +1320 -0
- package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.d.ts +107 -0
- package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.js +369 -0
- package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/controllers/validate-field-handler.backend.service.d.ts +194 -0
- package/dist/esm/base-classes/services/controllers/validate-field-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/controllers/validate-field-handler.backend.service.js +417 -0
- package/dist/esm/base-classes/services/controllers/validate-field-handler.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/repositories/__tests__/mock-repositories-registry-handler.service.d.ts +9 -0
- package/dist/esm/base-classes/services/repositories/__tests__/mock-repositories-registry-handler.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/repositories/__tests__/mock-repositories-registry-handler.service.js +35 -0
- package/dist/esm/base-classes/services/repositories/__tests__/mock-repositories-registry-handler.service.js.map +1 -0
- package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.d.ts +107 -0
- package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.js +800 -0
- package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.d.ts +181 -0
- package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.js +529 -0
- package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.d.ts +245 -0
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.js +1509 -0
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/resource-operations-helper.backend.service.d.ts +134 -0
- package/dist/esm/base-classes/services/resource-operations-helper.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/resource-operations-helper.backend.service.js +388 -0
- package/dist/esm/base-classes/services/resource-operations-helper.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/services/__tests__/mock-services-registry-handler.service.d.ts +9 -0
- package/dist/esm/base-classes/services/services/__tests__/mock-services-registry-handler.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/services/__tests__/mock-services-registry-handler.service.js +26 -0
- package/dist/esm/base-classes/services/services/__tests__/mock-services-registry-handler.service.js.map +1 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-base.backend.service.d.ts +144 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-base.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-base.backend.service.js +49 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-base.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.d.ts +84 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.js +156 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.d.ts +42 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.d.ts.map +1 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.js +94 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.js.map +1 -0
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.d.ts +593 -0
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js +4015 -0
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js.map +1 -0
- package/dist/esm/base-classes/utils/backend-type-utils.d.ts +43 -0
- package/dist/esm/base-classes/utils/backend-type-utils.d.ts.map +1 -0
- package/dist/esm/base-classes/utils/backend-type-utils.js +10 -0
- package/dist/esm/base-classes/utils/backend-type-utils.js.map +1 -0
- package/dist/esm/billing/services/back-office/abstract-billing.backend.service.d.ts +44 -0
- package/dist/esm/billing/services/back-office/abstract-billing.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/back-office/abstract-billing.backend.service.js +94 -0
- package/dist/esm/billing/services/back-office/abstract-billing.backend.service.js.map +1 -0
- package/dist/esm/billing/services/back-office/billing-feature-sync.backend.service.d.ts +102 -0
- package/dist/esm/billing/services/back-office/billing-feature-sync.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/back-office/billing-feature-sync.backend.service.js +405 -0
- package/dist/esm/billing/services/back-office/billing-feature-sync.backend.service.js.map +1 -0
- package/dist/esm/billing/services/back-office/billing-state.backend.service.d.ts +55 -0
- package/dist/esm/billing/services/back-office/billing-state.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/back-office/billing-state.backend.service.js +268 -0
- package/dist/esm/billing/services/back-office/billing-state.backend.service.js.map +1 -0
- package/dist/esm/billing/services/back-office/product-catalog-sync.backend.service.d.ts +83 -0
- package/dist/esm/billing/services/back-office/product-catalog-sync.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/back-office/product-catalog-sync.backend.service.js +371 -0
- package/dist/esm/billing/services/back-office/product-catalog-sync.backend.service.js.map +1 -0
- package/dist/esm/billing/services/back-office/usage-metering.backend.service.d.ts +80 -0
- package/dist/esm/billing/services/back-office/usage-metering.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/back-office/usage-metering.backend.service.js +255 -0
- package/dist/esm/billing/services/back-office/usage-metering.backend.service.js.map +1 -0
- package/dist/esm/billing/services/billing.utils.d.ts +17 -0
- package/dist/esm/billing/services/billing.utils.d.ts.map +1 -0
- package/dist/esm/billing/services/billing.utils.js +25 -0
- package/dist/esm/billing/services/billing.utils.js.map +1 -0
- package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.d.ts +50 -0
- package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.js +290 -0
- package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/billing/services/custom-impl/billing-custom-impl-utils.backend.d.ts +92 -0
- package/dist/esm/billing/services/custom-impl/billing-custom-impl-utils.backend.d.ts.map +1 -0
- package/dist/esm/billing/services/custom-impl/billing-custom-impl-utils.backend.js +193 -0
- package/dist/esm/billing/services/custom-impl/billing-custom-impl-utils.backend.js.map +1 -0
- package/dist/esm/billing/services/custom-impl/billing-custom-implementations.backend.d.ts +66 -0
- package/dist/esm/billing/services/custom-impl/billing-custom-implementations.backend.d.ts.map +1 -0
- package/dist/esm/billing/services/custom-impl/billing-custom-implementations.backend.js +180 -0
- package/dist/esm/billing/services/custom-impl/billing-custom-implementations.backend.js.map +1 -0
- package/dist/esm/billing/services/custom-impl/credit-pool.custom-ops.custom-impl.backend.service.d.ts +31 -0
- package/dist/esm/billing/services/custom-impl/credit-pool.custom-ops.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/custom-impl/credit-pool.custom-ops.custom-impl.backend.service.js +100 -0
- package/dist/esm/billing/services/custom-impl/credit-pool.custom-ops.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/billing/services/custom-impl/promotion.custom-ops.custom-impl.backend.service.d.ts +33 -0
- package/dist/esm/billing/services/custom-impl/promotion.custom-ops.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/custom-impl/promotion.custom-ops.custom-impl.backend.service.js +200 -0
- package/dist/esm/billing/services/custom-impl/promotion.custom-ops.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/billing/services/custom-impl/subscription.mutations.custom-impl.backend.service.d.ts +58 -0
- package/dist/esm/billing/services/custom-impl/subscription.mutations.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/custom-impl/subscription.mutations.custom-impl.backend.service.js +362 -0
- package/dist/esm/billing/services/custom-impl/subscription.mutations.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-adapter.backend.service.d.ts +19 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-adapter.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-adapter.backend.service.js +50 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-adapter.backend.service.js.map +1 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-capability-handler.backend.service.d.ts +21 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-capability-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-capability-handler.backend.service.js +32 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-capability-handler.backend.service.js.map +1 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-event-router.backend.service.d.ts +114 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-event-router.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-event-router.backend.service.js +569 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-event-router.backend.service.js.map +1 -0
- package/dist/esm/billing/testing/billing-test-fixtures.d.ts +109 -0
- package/dist/esm/billing/testing/billing-test-fixtures.d.ts.map +1 -0
- package/dist/esm/billing/testing/billing-test-fixtures.js +200 -0
- package/dist/esm/billing/testing/billing-test-fixtures.js.map +1 -0
- package/dist/esm/billing/testing/mock-billing-provider.d.ts +152 -0
- package/dist/esm/billing/testing/mock-billing-provider.d.ts.map +1 -0
- package/dist/esm/billing/testing/mock-billing-provider.js +394 -0
- package/dist/esm/billing/testing/mock-billing-provider.js.map +1 -0
- package/dist/esm/charts/controllers/chart.backend.controller.d.ts +46 -0
- package/dist/esm/charts/controllers/chart.backend.controller.d.ts.map +1 -0
- package/dist/esm/charts/controllers/chart.backend.controller.js +214 -0
- package/dist/esm/charts/controllers/chart.backend.controller.js.map +1 -0
- package/dist/esm/charts/services/chart-registry.backend.service.d.ts +55 -0
- package/dist/esm/charts/services/chart-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/charts/services/chart-registry.backend.service.js +102 -0
- package/dist/esm/charts/services/chart-registry.backend.service.js.map +1 -0
- package/dist/esm/compliance/audit-trails/audit-logs.custom-impl.backend.service.d.ts +9 -0
- package/dist/esm/compliance/audit-trails/audit-logs.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/compliance/audit-trails/audit-logs.custom-impl.backend.service.js +80 -0
- package/dist/esm/compliance/audit-trails/audit-logs.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/compliance/audit-trails/services/__tests__/mock-audit-logs.service.d.ts +23 -0
- package/dist/esm/compliance/audit-trails/services/__tests__/mock-audit-logs.service.d.ts.map +1 -0
- package/dist/esm/compliance/audit-trails/services/__tests__/mock-audit-logs.service.js +46 -0
- package/dist/esm/compliance/audit-trails/services/__tests__/mock-audit-logs.service.js.map +1 -0
- package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.d.ts +73 -0
- package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.d.ts.map +1 -0
- package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.js +291 -0
- package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.js.map +1 -0
- package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.d.ts +447 -0
- package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.d.ts.map +1 -0
- package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.js +898 -0
- package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.js.map +1 -0
- package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.d.ts +127 -0
- package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.d.ts.map +1 -0
- package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.js +462 -0
- package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.js.map +1 -0
- package/dist/esm/compliance/index.d.ts +2 -0
- package/dist/esm/compliance/index.d.ts.map +1 -0
- package/dist/esm/compliance/index.js +1 -0
- package/dist/esm/compliance/index.js.map +1 -0
- package/dist/esm/config/custom/application-config-controller.backend.service.d.ts +31 -0
- package/dist/esm/config/custom/application-config-controller.backend.service.d.ts.map +1 -0
- package/dist/esm/config/custom/application-config-controller.backend.service.js +112 -0
- package/dist/esm/config/custom/application-config-controller.backend.service.js.map +1 -0
- package/dist/esm/config/models/app-config-overrides.backend.definitions.d.ts +29 -0
- package/dist/esm/config/models/app-config-overrides.backend.definitions.d.ts.map +1 -0
- package/dist/esm/config/models/app-config-overrides.backend.definitions.js +143 -0
- package/dist/esm/config/models/app-config-overrides.backend.definitions.js.map +1 -0
- package/dist/esm/config/models/app-config-secrets.backend.schemas.d.ts +56 -0
- package/dist/esm/config/models/app-config-secrets.backend.schemas.d.ts.map +1 -0
- package/dist/esm/config/models/app-config-secrets.backend.schemas.js +121 -0
- package/dist/esm/config/models/app-config-secrets.backend.schemas.js.map +1 -0
- package/dist/esm/config/models/app-config.backend-authored.definitions.d.ts +35 -0
- package/dist/esm/config/models/app-config.backend-authored.definitions.d.ts.map +1 -0
- package/dist/esm/config/models/app-config.backend-authored.definitions.js +89 -0
- package/dist/esm/config/models/app-config.backend-authored.definitions.js.map +1 -0
- package/dist/esm/config/models/app-config.backend.schemas.d.ts +1651 -0
- package/dist/esm/config/models/app-config.backend.schemas.d.ts.map +1 -0
- package/dist/esm/config/models/app-config.backend.schemas.js +478 -0
- package/dist/esm/config/models/app-config.backend.schemas.js.map +1 -0
- package/dist/esm/config/models/app-env-config.backend.schemas.d.ts +74 -0
- package/dist/esm/config/models/app-env-config.backend.schemas.d.ts.map +1 -0
- package/dist/esm/config/models/app-env-config.backend.schemas.js +115 -0
- package/dist/esm/config/models/app-env-config.backend.schemas.js.map +1 -0
- package/dist/esm/config/models/config-mutation-boundary.utils.d.ts +11 -0
- package/dist/esm/config/models/config-mutation-boundary.utils.d.ts.map +1 -0
- package/dist/esm/config/models/config-mutation-boundary.utils.js +50 -0
- package/dist/esm/config/models/config-mutation-boundary.utils.js.map +1 -0
- package/dist/esm/config/models/postgresql-env-config.backend.schemas.d.ts +48 -0
- package/dist/esm/config/models/postgresql-env-config.backend.schemas.d.ts.map +1 -0
- package/dist/esm/config/models/postgresql-env-config.backend.schemas.js +106 -0
- package/dist/esm/config/models/postgresql-env-config.backend.schemas.js.map +1 -0
- package/dist/esm/config/models/runtime-topology.backend.contracts.d.ts +12 -0
- package/dist/esm/config/models/runtime-topology.backend.contracts.d.ts.map +1 -0
- package/dist/esm/config/models/runtime-topology.backend.contracts.js +23 -0
- package/dist/esm/config/models/runtime-topology.backend.contracts.js.map +1 -0
- package/dist/esm/config/services/__tests__/mock-app-configuration.service.d.ts +39 -0
- package/dist/esm/config/services/__tests__/mock-app-configuration.service.d.ts.map +1 -0
- package/dist/esm/config/services/__tests__/mock-app-configuration.service.js +124 -0
- package/dist/esm/config/services/__tests__/mock-app-configuration.service.js.map +1 -0
- package/dist/esm/config/services/app-configuration-loader.backend.service.d.ts +76 -0
- package/dist/esm/config/services/app-configuration-loader.backend.service.d.ts.map +1 -0
- package/dist/esm/config/services/app-configuration-loader.backend.service.js +375 -0
- package/dist/esm/config/services/app-configuration-loader.backend.service.js.map +1 -0
- package/dist/esm/config/services/app-configuration.backend.service.d.ts +148 -0
- package/dist/esm/config/services/app-configuration.backend.service.d.ts.map +1 -0
- package/dist/esm/config/services/app-configuration.backend.service.js +494 -0
- package/dist/esm/config/services/app-configuration.backend.service.js.map +1 -0
- package/dist/esm/config/services/app-configuration.backend.utils.d.ts +17 -0
- package/dist/esm/config/services/app-configuration.backend.utils.d.ts.map +1 -0
- package/dist/esm/config/services/app-configuration.backend.utils.js +61 -0
- package/dist/esm/config/services/app-configuration.backend.utils.js.map +1 -0
- package/dist/esm/config/services/application-startup-config-validator.backend.service.d.ts +70 -0
- package/dist/esm/config/services/application-startup-config-validator.backend.service.d.ts.map +1 -0
- package/dist/esm/config/services/application-startup-config-validator.backend.service.js +470 -0
- package/dist/esm/config/services/application-startup-config-validator.backend.service.js.map +1 -0
- package/dist/esm/databases/models/aggregation.backend.schemas.d.ts +136 -0
- package/dist/esm/databases/models/aggregation.backend.schemas.d.ts.map +1 -0
- package/dist/esm/databases/models/aggregation.backend.schemas.js +9 -0
- package/dist/esm/databases/models/aggregation.backend.schemas.js.map +1 -0
- package/dist/esm/databases/models/databases.backend.schemas.d.ts +32 -0
- package/dist/esm/databases/models/databases.backend.schemas.d.ts.map +1 -0
- package/dist/esm/databases/models/databases.backend.schemas.js +60 -0
- package/dist/esm/databases/models/databases.backend.schemas.js.map +1 -0
- package/dist/esm/databases/models/filter.backend.schemas.d.ts +83 -0
- package/dist/esm/databases/models/filter.backend.schemas.d.ts.map +1 -0
- package/dist/esm/databases/models/filter.backend.schemas.js +27 -0
- package/dist/esm/databases/models/filter.backend.schemas.js.map +1 -0
- package/dist/esm/databases/models/sql.backend.schemas.d.ts +75 -0
- package/dist/esm/databases/models/sql.backend.schemas.d.ts.map +1 -0
- package/dist/esm/databases/models/sql.backend.schemas.js +31 -0
- package/dist/esm/databases/models/sql.backend.schemas.js.map +1 -0
- package/dist/esm/databases/models/transaction.shared.schemas.d.ts +120 -0
- package/dist/esm/databases/models/transaction.shared.schemas.d.ts.map +1 -0
- package/dist/esm/databases/models/transaction.shared.schemas.js +30 -0
- package/dist/esm/databases/models/transaction.shared.schemas.js.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-mongo-transaction-registry.service.d.ts +15 -0
- package/dist/esm/databases/services/__tests__/mock-mongo-transaction-registry.service.d.ts.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-mongo-transaction-registry.service.js +60 -0
- package/dist/esm/databases/services/__tests__/mock-mongo-transaction-registry.service.js.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-mongodb.service.d.ts +19 -0
- package/dist/esm/databases/services/__tests__/mock-mongodb.service.d.ts.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-mongodb.service.js +69 -0
- package/dist/esm/databases/services/__tests__/mock-mongodb.service.js.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-mongoose-model.service.d.ts +11 -0
- package/dist/esm/databases/services/__tests__/mock-mongoose-model.service.d.ts.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-mongoose-model.service.js +315 -0
- package/dist/esm/databases/services/__tests__/mock-mongoose-model.service.js.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-redis.service.d.ts +29 -0
- package/dist/esm/databases/services/__tests__/mock-redis.service.d.ts.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-redis.service.js +65 -0
- package/dist/esm/databases/services/__tests__/mock-redis.service.js.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-zod-mongoose-schema-convertor.service.d.ts +19 -0
- package/dist/esm/databases/services/__tests__/mock-zod-mongoose-schema-convertor.service.d.ts.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-zod-mongoose-schema-convertor.service.js +44 -0
- package/dist/esm/databases/services/__tests__/mock-zod-mongoose-schema-convertor.service.js.map +1 -0
- package/dist/esm/databases/services/aggregation/aggregation-authorization.backend.service.d.ts +74 -0
- package/dist/esm/databases/services/aggregation/aggregation-authorization.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/aggregation/aggregation-authorization.backend.service.js +369 -0
- package/dist/esm/databases/services/aggregation/aggregation-authorization.backend.service.js.map +1 -0
- package/dist/esm/databases/services/aggregation/aggregation-query.backend.service.d.ts +110 -0
- package/dist/esm/databases/services/aggregation/aggregation-query.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/aggregation/aggregation-query.backend.service.js +444 -0
- package/dist/esm/databases/services/aggregation/aggregation-query.backend.service.js.map +1 -0
- package/dist/esm/databases/services/aggregation/computed-measure-evaluator.backend.service.d.ts +38 -0
- package/dist/esm/databases/services/aggregation/computed-measure-evaluator.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/aggregation/computed-measure-evaluator.backend.service.js +180 -0
- package/dist/esm/databases/services/aggregation/computed-measure-evaluator.backend.service.js.map +1 -0
- package/dist/esm/databases/services/aggregation/field-access-validator.backend.service.d.ts +42 -0
- package/dist/esm/databases/services/aggregation/field-access-validator.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/aggregation/field-access-validator.backend.service.js +183 -0
- package/dist/esm/databases/services/aggregation/field-access-validator.backend.service.js.map +1 -0
- package/dist/esm/databases/services/aggregation/time-series-densifier.backend.service.d.ts +48 -0
- package/dist/esm/databases/services/aggregation/time-series-densifier.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/aggregation/time-series-densifier.backend.service.js +320 -0
- package/dist/esm/databases/services/aggregation/time-series-densifier.backend.service.js.map +1 -0
- package/dist/esm/databases/services/aggregation/topn-processor.backend.service.d.ts +47 -0
- package/dist/esm/databases/services/aggregation/topn-processor.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/aggregation/topn-processor.backend.service.js +187 -0
- package/dist/esm/databases/services/aggregation/topn-processor.backend.service.js.map +1 -0
- package/dist/esm/databases/services/aggregation/window-function-processor.backend.service.d.ts +47 -0
- package/dist/esm/databases/services/aggregation/window-function-processor.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/aggregation/window-function-processor.backend.service.js +250 -0
- package/dist/esm/databases/services/aggregation/window-function-processor.backend.service.js.map +1 -0
- package/dist/esm/databases/services/db-utils.d.ts +56 -0
- package/dist/esm/databases/services/db-utils.d.ts.map +1 -0
- package/dist/esm/databases/services/db-utils.js +66 -0
- package/dist/esm/databases/services/db-utils.js.map +1 -0
- package/dist/esm/databases/services/mongo-aggregation.backend.service.d.ts +91 -0
- package/dist/esm/databases/services/mongo-aggregation.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/mongo-aggregation.backend.service.js +652 -0
- package/dist/esm/databases/services/mongo-aggregation.backend.service.js.map +1 -0
- package/dist/esm/databases/services/mongodb.service.d.ts +132 -0
- package/dist/esm/databases/services/mongodb.service.d.ts.map +1 -0
- package/dist/esm/databases/services/mongodb.service.js +630 -0
- package/dist/esm/databases/services/mongodb.service.js.map +1 -0
- package/dist/esm/databases/services/postgresql-aggregation.backend.service.d.ts +113 -0
- package/dist/esm/databases/services/postgresql-aggregation.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/postgresql-aggregation.backend.service.js +635 -0
- package/dist/esm/databases/services/postgresql-aggregation.backend.service.js.map +1 -0
- package/dist/esm/databases/services/postgresql-database.backend.service.d.ts +75 -0
- package/dist/esm/databases/services/postgresql-database.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/postgresql-database.backend.service.js +255 -0
- package/dist/esm/databases/services/postgresql-database.backend.service.js.map +1 -0
- package/dist/esm/databases/services/postgresql-filter.backend.service.d.ts +116 -0
- package/dist/esm/databases/services/postgresql-filter.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/postgresql-filter.backend.service.js +624 -0
- package/dist/esm/databases/services/postgresql-filter.backend.service.js.map +1 -0
- package/dist/esm/databases/services/redis.service.d.ts +143 -0
- package/dist/esm/databases/services/redis.service.d.ts.map +1 -0
- package/dist/esm/databases/services/redis.service.js +429 -0
- package/dist/esm/databases/services/redis.service.js.map +1 -0
- package/dist/esm/databases/services/zod-to-mongoose-schema-convertor.backend.service.d.ts +302 -0
- package/dist/esm/databases/services/zod-to-mongoose-schema-convertor.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/zod-to-mongoose-schema-convertor.backend.service.js +1787 -0
- package/dist/esm/databases/services/zod-to-mongoose-schema-convertor.backend.service.js.map +1 -0
- package/dist/esm/databases/services/zod-to-sql-hybrid-schema.planner.d.ts +65 -0
- package/dist/esm/databases/services/zod-to-sql-hybrid-schema.planner.d.ts.map +1 -0
- package/dist/esm/databases/services/zod-to-sql-hybrid-schema.planner.js +237 -0
- package/dist/esm/databases/services/zod-to-sql-hybrid-schema.planner.js.map +1 -0
- package/dist/esm/errors/services/__tests__/mock-error-builder.service.d.ts +339 -0
- package/dist/esm/errors/services/__tests__/mock-error-builder.service.d.ts.map +1 -0
- package/dist/esm/errors/services/__tests__/mock-error-builder.service.js +209 -0
- package/dist/esm/errors/services/__tests__/mock-error-builder.service.js.map +1 -0
- package/dist/esm/errors/services/error-builder.backend.service.d.ts +95 -0
- package/dist/esm/errors/services/error-builder.backend.service.d.ts.map +1 -0
- package/dist/esm/errors/services/error-builder.backend.service.js +334 -0
- package/dist/esm/errors/services/error-builder.backend.service.js.map +1 -0
- package/dist/esm/errors/services/error-handler.backend.service.d.ts +43 -0
- package/dist/esm/errors/services/error-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/errors/services/error-handler.backend.service.js +219 -0
- package/dist/esm/errors/services/error-handler.backend.service.js.map +1 -0
- package/dist/esm/errors/services/rate-limit.backend.service.d.ts +23 -0
- package/dist/esm/errors/services/rate-limit.backend.service.d.ts.map +1 -0
- package/dist/esm/errors/services/rate-limit.backend.service.js +59 -0
- package/dist/esm/errors/services/rate-limit.backend.service.js.map +1 -0
- package/dist/esm/external-providers/models/external-providers.backend.schemas.d.ts +135 -0
- package/dist/esm/external-providers/models/external-providers.backend.schemas.d.ts.map +1 -0
- package/dist/esm/external-providers/models/external-providers.backend.schemas.js +129 -0
- package/dist/esm/external-providers/models/external-providers.backend.schemas.js.map +1 -0
- package/dist/esm/external-providers/services/__tests__/mock-external-providers-registry.service.d.ts +18 -0
- package/dist/esm/external-providers/services/__tests__/mock-external-providers-registry.service.d.ts.map +1 -0
- package/dist/esm/external-providers/services/__tests__/mock-external-providers-registry.service.js +38 -0
- package/dist/esm/external-providers/services/__tests__/mock-external-providers-registry.service.js.map +1 -0
- package/dist/esm/external-providers/services/__tests__/mock-lazy-provider-registry.service.d.ts +20 -0
- package/dist/esm/external-providers/services/__tests__/mock-lazy-provider-registry.service.d.ts.map +1 -0
- package/dist/esm/external-providers/services/__tests__/mock-lazy-provider-registry.service.js +44 -0
- package/dist/esm/external-providers/services/__tests__/mock-lazy-provider-registry.service.js.map +1 -0
- package/dist/esm/external-providers/services/external-api-handler.backend.service.d.ts +9 -0
- package/dist/esm/external-providers/services/external-api-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/external-providers/services/external-api-handler.backend.service.js +36 -0
- package/dist/esm/external-providers/services/external-api-handler.backend.service.js.map +1 -0
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts +83 -0
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.js +422 -0
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.js.map +1 -0
- package/dist/esm/external-providers/services/feature-bindings.backend.service.d.ts +102 -0
- package/dist/esm/external-providers/services/feature-bindings.backend.service.d.ts.map +1 -0
- package/dist/esm/external-providers/services/feature-bindings.backend.service.js +352 -0
- package/dist/esm/external-providers/services/feature-bindings.backend.service.js.map +1 -0
- package/dist/esm/external-providers/services/lazy-provider-registry.backend.service.d.ts +141 -0
- package/dist/esm/external-providers/services/lazy-provider-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/external-providers/services/lazy-provider-registry.backend.service.js +391 -0
- package/dist/esm/external-providers/services/lazy-provider-registry.backend.service.js.map +1 -0
- package/dist/esm/features/controllers/features.backend.controller.d.ts +35 -0
- package/dist/esm/features/controllers/features.backend.controller.d.ts.map +1 -0
- package/dist/esm/features/controllers/features.backend.controller.js +179 -0
- package/dist/esm/features/controllers/features.backend.controller.js.map +1 -0
- package/dist/esm/features/services/__tests__/mock-capability-bindings.service.d.ts +8 -0
- package/dist/esm/features/services/__tests__/mock-capability-bindings.service.d.ts.map +1 -0
- package/dist/esm/features/services/__tests__/mock-capability-bindings.service.js +31 -0
- package/dist/esm/features/services/__tests__/mock-capability-bindings.service.js.map +1 -0
- package/dist/esm/features/services/__tests__/mock-feature-definition-registry.service.d.ts +22 -0
- package/dist/esm/features/services/__tests__/mock-feature-definition-registry.service.d.ts.map +1 -0
- package/dist/esm/features/services/__tests__/mock-feature-definition-registry.service.js +52 -0
- package/dist/esm/features/services/__tests__/mock-feature-definition-registry.service.js.map +1 -0
- package/dist/esm/features/services/__tests__/mock-feature-resolution.service.d.ts +13 -0
- package/dist/esm/features/services/__tests__/mock-feature-resolution.service.d.ts.map +1 -0
- package/dist/esm/features/services/__tests__/mock-feature-resolution.service.js +36 -0
- package/dist/esm/features/services/__tests__/mock-feature-resolution.service.js.map +1 -0
- package/dist/esm/features/services/feature-definition-registry.backend.service.d.ts +111 -0
- package/dist/esm/features/services/feature-definition-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/features/services/feature-definition-registry.backend.service.js +437 -0
- package/dist/esm/features/services/feature-definition-registry.backend.service.js.map +1 -0
- package/dist/esm/features/services/feature-gate.backend.service.d.ts +110 -0
- package/dist/esm/features/services/feature-gate.backend.service.d.ts.map +1 -0
- package/dist/esm/features/services/feature-gate.backend.service.js +414 -0
- package/dist/esm/features/services/feature-gate.backend.service.js.map +1 -0
- package/dist/esm/features/services/feature-resolution.backend.service.d.ts +163 -0
- package/dist/esm/features/services/feature-resolution.backend.service.d.ts.map +1 -0
- package/dist/esm/features/services/feature-resolution.backend.service.js +550 -0
- package/dist/esm/features/services/feature-resolution.backend.service.js.map +1 -0
- package/dist/esm/features/testing/feature-test-utils.d.ts +85 -0
- package/dist/esm/features/testing/feature-test-utils.d.ts.map +1 -0
- package/dist/esm/features/testing/feature-test-utils.js +127 -0
- package/dist/esm/features/testing/feature-test-utils.js.map +1 -0
- package/dist/esm/files/batches/files-cleanup.batch.backend.service.d.ts +34 -0
- package/dist/esm/files/batches/files-cleanup.batch.backend.service.d.ts.map +1 -0
- package/dist/esm/files/batches/files-cleanup.batch.backend.service.js +226 -0
- package/dist/esm/files/batches/files-cleanup.batch.backend.service.js.map +1 -0
- package/dist/esm/files/constraints/file-analyzers.types.d.ts +76 -0
- package/dist/esm/files/constraints/file-analyzers.types.d.ts.map +1 -0
- package/dist/esm/files/constraints/file-analyzers.types.js +16 -0
- package/dist/esm/files/constraints/file-analyzers.types.js.map +1 -0
- package/dist/esm/files/constraints/file-constraint-resolver-chain.backend.service.d.ts +38 -0
- package/dist/esm/files/constraints/file-constraint-resolver-chain.backend.service.d.ts.map +1 -0
- package/dist/esm/files/constraints/file-constraint-resolver-chain.backend.service.js +99 -0
- package/dist/esm/files/constraints/file-constraint-resolver-chain.backend.service.js.map +1 -0
- package/dist/esm/files/constraints/file-constraint.types.d.ts +77 -0
- package/dist/esm/files/constraints/file-constraint.types.d.ts.map +1 -0
- package/dist/esm/files/constraints/file-constraint.types.js +16 -0
- package/dist/esm/files/constraints/file-constraint.types.js.map +1 -0
- package/dist/esm/files/constraints/file-validation.backend.service.d.ts +63 -0
- package/dist/esm/files/constraints/file-validation.backend.service.d.ts.map +1 -0
- package/dist/esm/files/constraints/file-validation.backend.service.js +317 -0
- package/dist/esm/files/constraints/file-validation.backend.service.js.map +1 -0
- package/dist/esm/files/constraints/resource-field-constraint-resolver.backend.service.d.ts +33 -0
- package/dist/esm/files/constraints/resource-field-constraint-resolver.backend.service.d.ts.map +1 -0
- package/dist/esm/files/constraints/resource-field-constraint-resolver.backend.service.js +126 -0
- package/dist/esm/files/constraints/resource-field-constraint-resolver.backend.service.js.map +1 -0
- package/dist/esm/files/controllers/file.controller.d.ts +145 -0
- package/dist/esm/files/controllers/file.controller.d.ts.map +1 -0
- package/dist/esm/files/controllers/file.controller.js +806 -0
- package/dist/esm/files/controllers/file.controller.js.map +1 -0
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.d.ts +85 -0
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.js +512 -0
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.js.map +1 -0
- package/dist/esm/files/rag/weaviate-vector-store.backend.service.d.ts +84 -0
- package/dist/esm/files/rag/weaviate-vector-store.backend.service.d.ts.map +1 -0
- package/dist/esm/files/rag/weaviate-vector-store.backend.service.js +224 -0
- package/dist/esm/files/rag/weaviate-vector-store.backend.service.js.map +1 -0
- package/dist/esm/files/scanning/clamav-scanner.backend.service.d.ts +55 -0
- package/dist/esm/files/scanning/clamav-scanner.backend.service.d.ts.map +1 -0
- package/dist/esm/files/scanning/clamav-scanner.backend.service.js +202 -0
- package/dist/esm/files/scanning/clamav-scanner.backend.service.js.map +1 -0
- package/dist/esm/files/scanning/file-scan.types.d.ts +17 -0
- package/dist/esm/files/scanning/file-scan.types.d.ts.map +1 -0
- package/dist/esm/files/scanning/file-scan.types.js +7 -0
- package/dist/esm/files/scanning/file-scan.types.js.map +1 -0
- package/dist/esm/files/scanning/yara-scanner.backend.service.d.ts +73 -0
- package/dist/esm/files/scanning/yara-scanner.backend.service.d.ts.map +1 -0
- package/dist/esm/files/scanning/yara-scanner.backend.service.js +184 -0
- package/dist/esm/files/scanning/yara-scanner.backend.service.js.map +1 -0
- package/dist/esm/files/services/__tests__/mock-file-field-detection.service.d.ts +12 -0
- package/dist/esm/files/services/__tests__/mock-file-field-detection.service.d.ts.map +1 -0
- package/dist/esm/files/services/__tests__/mock-file-field-detection.service.js +41 -0
- package/dist/esm/files/services/__tests__/mock-file-field-detection.service.js.map +1 -0
- package/dist/esm/files/services/__tests__/mock-file-operation-handler.service.d.ts +33 -0
- package/dist/esm/files/services/__tests__/mock-file-operation-handler.service.d.ts.map +1 -0
- package/dist/esm/files/services/__tests__/mock-file-operation-handler.service.js +71 -0
- package/dist/esm/files/services/__tests__/mock-file-operation-handler.service.js.map +1 -0
- package/dist/esm/files/services/__tests__/mock-file-repository.service.d.ts +16 -0
- package/dist/esm/files/services/__tests__/mock-file-repository.service.d.ts.map +1 -0
- package/dist/esm/files/services/__tests__/mock-file-repository.service.js +95 -0
- package/dist/esm/files/services/__tests__/mock-file-repository.service.js.map +1 -0
- package/dist/esm/files/services/file-field-detection.backend.service.d.ts +57 -0
- package/dist/esm/files/services/file-field-detection.backend.service.d.ts.map +1 -0
- package/dist/esm/files/services/file-field-detection.backend.service.js +145 -0
- package/dist/esm/files/services/file-field-detection.backend.service.js.map +1 -0
- package/dist/esm/files/services/file-operation-handler.backend.service.d.ts +103 -0
- package/dist/esm/files/services/file-operation-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/files/services/file-operation-handler.backend.service.js +604 -0
- package/dist/esm/files/services/file-operation-handler.backend.service.js.map +1 -0
- package/dist/esm/files/services/file-population.backend.service.d.ts +73 -0
- package/dist/esm/files/services/file-population.backend.service.d.ts.map +1 -0
- package/dist/esm/files/services/file-population.backend.service.js +367 -0
- package/dist/esm/files/services/file-population.backend.service.js.map +1 -0
- package/dist/esm/files/services/file-rag-indexing.backend.service.d.ts +64 -0
- package/dist/esm/files/services/file-rag-indexing.backend.service.d.ts.map +1 -0
- package/dist/esm/files/services/file-rag-indexing.backend.service.js +188 -0
- package/dist/esm/files/services/file-rag-indexing.backend.service.js.map +1 -0
- package/dist/esm/files/services/file-scanning.backend.service.d.ts +97 -0
- package/dist/esm/files/services/file-scanning.backend.service.d.ts.map +1 -0
- package/dist/esm/files/services/file-scanning.backend.service.js +323 -0
- package/dist/esm/files/services/file-scanning.backend.service.js.map +1 -0
- package/dist/esm/files/services/file-text-extraction.backend.service.d.ts +52 -0
- package/dist/esm/files/services/file-text-extraction.backend.service.d.ts.map +1 -0
- package/dist/esm/files/services/file-text-extraction.backend.service.js +168 -0
- package/dist/esm/files/services/file-text-extraction.backend.service.js.map +1 -0
- package/dist/esm/files/services/files.backend.service.d.ts +235 -0
- package/dist/esm/files/services/files.backend.service.d.ts.map +1 -0
- package/dist/esm/files/services/files.backend.service.js +987 -0
- package/dist/esm/files/services/files.backend.service.js.map +1 -0
- package/dist/esm/files/storage/file-storage-path-resolver.backend.service.d.ts +50 -0
- package/dist/esm/files/storage/file-storage-path-resolver.backend.service.d.ts.map +1 -0
- package/dist/esm/files/storage/file-storage-path-resolver.backend.service.js +253 -0
- package/dist/esm/files/storage/file-storage-path-resolver.backend.service.js.map +1 -0
- package/dist/esm/files/storage/file-storage-provider.types.d.ts +156 -0
- package/dist/esm/files/storage/file-storage-provider.types.d.ts.map +1 -0
- package/dist/esm/files/storage/file-storage-provider.types.js +10 -0
- package/dist/esm/files/storage/file-storage-provider.types.js.map +1 -0
- package/dist/esm/files/storage/file-storage-router.backend.service.d.ts +68 -0
- package/dist/esm/files/storage/file-storage-router.backend.service.d.ts.map +1 -0
- package/dist/esm/files/storage/file-storage-router.backend.service.js +168 -0
- package/dist/esm/files/storage/file-storage-router.backend.service.js.map +1 -0
- package/dist/esm/files/storage/local-directory-storage-provider.backend.service.d.ts +57 -0
- package/dist/esm/files/storage/local-directory-storage-provider.backend.service.d.ts.map +1 -0
- package/dist/esm/files/storage/local-directory-storage-provider.backend.service.js +307 -0
- package/dist/esm/files/storage/local-directory-storage-provider.backend.service.js.map +1 -0
- package/dist/esm/files/storage/wildo-managed-storage-provider.backend.service.d.ts +41 -0
- package/dist/esm/files/storage/wildo-managed-storage-provider.backend.service.d.ts.map +1 -0
- package/dist/esm/files/storage/wildo-managed-storage-provider.backend.service.js +397 -0
- package/dist/esm/files/storage/wildo-managed-storage-provider.backend.service.js.map +1 -0
- package/dist/esm/files/utils/file-field-schema-path.backend.utils.d.ts +30 -0
- package/dist/esm/files/utils/file-field-schema-path.backend.utils.d.ts.map +1 -0
- package/dist/esm/files/utils/file-field-schema-path.backend.utils.js +251 -0
- package/dist/esm/files/utils/file-field-schema-path.backend.utils.js.map +1 -0
- package/dist/esm/files/utils/file-upload.utils.d.ts +74 -0
- package/dist/esm/files/utils/file-upload.utils.d.ts.map +1 -0
- package/dist/esm/files/utils/file-upload.utils.js +116 -0
- package/dist/esm/files/utils/file-upload.utils.js.map +1 -0
- package/dist/esm/files/utils/file-uploader.utils.d.ts +15 -0
- package/dist/esm/files/utils/file-uploader.utils.d.ts.map +1 -0
- package/dist/esm/files/utils/file-uploader.utils.js +47 -0
- package/dist/esm/files/utils/file-uploader.utils.js.map +1 -0
- package/dist/esm/files/utils/file-validation.utils.d.ts +111 -0
- package/dist/esm/files/utils/file-validation.utils.d.ts.map +1 -0
- package/dist/esm/files/utils/file-validation.utils.js +516 -0
- package/dist/esm/files/utils/file-validation.utils.js.map +1 -0
- package/dist/esm/flows-actors/agent-catalogs.backend.d.ts +222 -0
- package/dist/esm/flows-actors/agent-catalogs.backend.d.ts.map +1 -0
- package/dist/esm/flows-actors/agent-catalogs.backend.js +320 -0
- package/dist/esm/flows-actors/agent-catalogs.backend.js.map +1 -0
- package/dist/esm/flows-actors/controllers/flows-actors.controller.d.ts +33 -0
- package/dist/esm/flows-actors/controllers/flows-actors.controller.d.ts.map +1 -0
- package/dist/esm/flows-actors/controllers/flows-actors.controller.js +96 -0
- package/dist/esm/flows-actors/controllers/flows-actors.controller.js.map +1 -0
- package/dist/esm/flows-actors/models/agent-catalogs.backend.definitions.d.ts +225 -0
- package/dist/esm/flows-actors/models/agent-catalogs.backend.definitions.d.ts.map +1 -0
- package/dist/esm/flows-actors/models/agent-catalogs.backend.definitions.js +323 -0
- package/dist/esm/flows-actors/models/agent-catalogs.backend.definitions.js.map +1 -0
- package/dist/esm/flows-actors/models/agent-facets.backend.definitions.d.ts +77 -0
- package/dist/esm/flows-actors/models/agent-facets.backend.definitions.d.ts.map +1 -0
- package/dist/esm/flows-actors/models/agent-facets.backend.definitions.js +28 -0
- package/dist/esm/flows-actors/models/agent-facets.backend.definitions.js.map +1 -0
- package/dist/esm/flows-actors/models/agents.backend.definitions.d.ts +1 -0
- package/dist/esm/flows-actors/models/agents.backend.definitions.d.ts.map +1 -0
- package/dist/esm/flows-actors/models/agents.backend.definitions.js +1 -0
- package/dist/esm/flows-actors/models/agents.backend.definitions.js.map +1 -0
- package/dist/esm/flows-actors/models/core-facets.backend.definitions.d.ts +52 -0
- package/dist/esm/flows-actors/models/core-facets.backend.definitions.d.ts.map +1 -0
- package/dist/esm/flows-actors/models/core-facets.backend.definitions.js +307 -0
- package/dist/esm/flows-actors/models/core-facets.backend.definitions.js.map +1 -0
- package/dist/esm/flows-actors/models/flows-actors.backend.definitions.d.ts +7 -0
- package/dist/esm/flows-actors/models/flows-actors.backend.definitions.d.ts.map +1 -0
- package/dist/esm/flows-actors/models/flows-actors.backend.definitions.js +8 -0
- package/dist/esm/flows-actors/models/flows-actors.backend.definitions.js.map +1 -0
- package/dist/esm/flows-actors/models/flows-actors.backend.schemas.d.ts +30 -0
- package/dist/esm/flows-actors/models/flows-actors.backend.schemas.d.ts.map +1 -0
- package/dist/esm/flows-actors/models/flows-actors.backend.schemas.js +7 -0
- package/dist/esm/flows-actors/models/flows-actors.backend.schemas.js.map +1 -0
- package/dist/esm/flows-actors/services/actors-system.backend.service.d.ts +72 -0
- package/dist/esm/flows-actors/services/actors-system.backend.service.d.ts.map +1 -0
- package/dist/esm/flows-actors/services/actors-system.backend.service.js +229 -0
- package/dist/esm/flows-actors/services/actors-system.backend.service.js.map +1 -0
- package/dist/esm/flows-actors/services/agent-facets.backend.service.d.ts +95 -0
- package/dist/esm/flows-actors/services/agent-facets.backend.service.d.ts.map +1 -0
- package/dist/esm/flows-actors/services/agent-facets.backend.service.js +276 -0
- package/dist/esm/flows-actors/services/agent-facets.backend.service.js.map +1 -0
- package/dist/esm/flows-actors/services/agents.backend.service.d.ts +183 -0
- package/dist/esm/flows-actors/services/agents.backend.service.d.ts.map +1 -0
- package/dist/esm/flows-actors/services/agents.backend.service.js +2095 -0
- package/dist/esm/flows-actors/services/agents.backend.service.js.map +1 -0
- package/dist/esm/flows-actors/services/context-curation.backend.service.d.ts +64 -0
- package/dist/esm/flows-actors/services/context-curation.backend.service.d.ts.map +1 -0
- package/dist/esm/flows-actors/services/context-curation.backend.service.js +180 -0
- package/dist/esm/flows-actors/services/context-curation.backend.service.js.map +1 -0
- package/dist/esm/flows-actors/services/flows-actors-registry.service.d.ts +101 -0
- package/dist/esm/flows-actors/services/flows-actors-registry.service.d.ts.map +1 -0
- package/dist/esm/flows-actors/services/flows-actors-registry.service.js +313 -0
- package/dist/esm/flows-actors/services/flows-actors-registry.service.js.map +1 -0
- package/dist/esm/flows-actors/services/flows.backend.services.d.ts +64 -0
- package/dist/esm/flows-actors/services/flows.backend.services.d.ts.map +1 -0
- package/dist/esm/flows-actors/services/flows.backend.services.js +203 -0
- package/dist/esm/flows-actors/services/flows.backend.services.js.map +1 -0
- package/dist/esm/flows-actors/services/prompt-compiler.backend.service.d.ts +91 -0
- package/dist/esm/flows-actors/services/prompt-compiler.backend.service.d.ts.map +1 -0
- package/dist/esm/flows-actors/services/prompt-compiler.backend.service.js +629 -0
- package/dist/esm/flows-actors/services/prompt-compiler.backend.service.js.map +1 -0
- package/dist/esm/flows-actors/utils/cli-runtime-operation-support.backend.utils.d.ts +15 -0
- package/dist/esm/flows-actors/utils/cli-runtime-operation-support.backend.utils.d.ts.map +1 -0
- package/dist/esm/flows-actors/utils/cli-runtime-operation-support.backend.utils.js +55 -0
- package/dist/esm/flows-actors/utils/cli-runtime-operation-support.backend.utils.js.map +1 -0
- package/dist/esm/flows-actors/utils/cli-runtime-runner.backend.utils.d.ts +22 -0
- package/dist/esm/flows-actors/utils/cli-runtime-runner.backend.utils.d.ts.map +1 -0
- package/dist/esm/flows-actors/utils/cli-runtime-runner.backend.utils.js +131 -0
- package/dist/esm/flows-actors/utils/cli-runtime-runner.backend.utils.js.map +1 -0
- package/dist/esm/flows-actors/utils/flows-actors-frontend-extractor.utils.d.ts +15 -0
- package/dist/esm/flows-actors/utils/flows-actors-frontend-extractor.utils.d.ts.map +1 -0
- package/dist/esm/flows-actors/utils/flows-actors-frontend-extractor.utils.js +43 -0
- package/dist/esm/flows-actors/utils/flows-actors-frontend-extractor.utils.js.map +1 -0
- package/dist/esm/flows-actors/utils/prompt-ir-adapters.backend.utils.d.ts +66 -0
- package/dist/esm/flows-actors/utils/prompt-ir-adapters.backend.utils.d.ts.map +1 -0
- package/dist/esm/flows-actors/utils/prompt-ir-adapters.backend.utils.js +219 -0
- package/dist/esm/flows-actors/utils/prompt-ir-adapters.backend.utils.js.map +1 -0
- package/dist/esm/guidance/batches/dormancy-detection.batch.backend.service.d.ts +17 -0
- package/dist/esm/guidance/batches/dormancy-detection.batch.backend.service.d.ts.map +1 -0
- package/dist/esm/guidance/batches/dormancy-detection.batch.backend.service.js +110 -0
- package/dist/esm/guidance/batches/dormancy-detection.batch.backend.service.js.map +1 -0
- package/dist/esm/guidance/services/guidance-trigger-evaluator.backend.service.d.ts +41 -0
- package/dist/esm/guidance/services/guidance-trigger-evaluator.backend.service.d.ts.map +1 -0
- package/dist/esm/guidance/services/guidance-trigger-evaluator.backend.service.js +135 -0
- package/dist/esm/guidance/services/guidance-trigger-evaluator.backend.service.js.map +1 -0
- package/dist/esm/guidance/services/lifecycle-custom-implementations.backend.d.ts +33 -0
- package/dist/esm/guidance/services/lifecycle-custom-implementations.backend.d.ts.map +1 -0
- package/dist/esm/guidance/services/lifecycle-custom-implementations.backend.js +105 -0
- package/dist/esm/guidance/services/lifecycle-custom-implementations.backend.js.map +1 -0
- package/dist/esm/guidance/services/lifecycle-evaluator.backend.service.d.ts +103 -0
- package/dist/esm/guidance/services/lifecycle-evaluator.backend.service.d.ts.map +1 -0
- package/dist/esm/guidance/services/lifecycle-evaluator.backend.service.js +685 -0
- package/dist/esm/guidance/services/lifecycle-evaluator.backend.service.js.map +1 -0
- package/dist/esm/guidance/services/milestone-condition-registry.backend.service.d.ts +23 -0
- package/dist/esm/guidance/services/milestone-condition-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/guidance/services/milestone-condition-registry.backend.service.js +57 -0
- package/dist/esm/guidance/services/milestone-condition-registry.backend.service.js.map +1 -0
- package/dist/esm/guidance/services/milestone-definition-registry.backend.service.d.ts +49 -0
- package/dist/esm/guidance/services/milestone-definition-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/guidance/services/milestone-definition-registry.backend.service.js +248 -0
- package/dist/esm/guidance/services/milestone-definition-registry.backend.service.js.map +1 -0
- package/dist/esm/guidance/services/milestone-evaluator.backend.service.d.ts +64 -0
- package/dist/esm/guidance/services/milestone-evaluator.backend.service.d.ts.map +1 -0
- package/dist/esm/guidance/services/milestone-evaluator.backend.service.js +487 -0
- package/dist/esm/guidance/services/milestone-evaluator.backend.service.js.map +1 -0
- package/dist/esm/i18n/controllers/i18n-controller.backend.service.d.ts +55 -0
- package/dist/esm/i18n/controllers/i18n-controller.backend.service.d.ts.map +1 -0
- package/dist/esm/i18n/controllers/i18n-controller.backend.service.js +208 -0
- package/dist/esm/i18n/controllers/i18n-controller.backend.service.js.map +1 -0
- package/dist/esm/i18n/services/i18n.backend.service.d.ts +43 -0
- package/dist/esm/i18n/services/i18n.backend.service.d.ts.map +1 -0
- package/dist/esm/i18n/services/i18n.backend.service.js +83 -0
- package/dist/esm/i18n/services/i18n.backend.service.js.map +1 -0
- package/dist/esm/index.d.ts +203 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +239 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/inject/models/container.d.ts +44 -0
- package/dist/esm/inject/models/container.d.ts.map +1 -0
- package/dist/esm/inject/models/container.js +489 -0
- package/dist/esm/inject/models/container.js.map +1 -0
- package/dist/esm/inject/models/service-types.d.ts +198 -0
- package/dist/esm/inject/models/service-types.d.ts.map +1 -0
- package/dist/esm/inject/models/service-types.js +226 -0
- package/dist/esm/inject/models/service-types.js.map +1 -0
- package/dist/esm/monitoring/analytics/controllers/analytics.backend.controller.d.ts +34 -0
- package/dist/esm/monitoring/analytics/controllers/analytics.backend.controller.d.ts.map +1 -0
- package/dist/esm/monitoring/analytics/controllers/analytics.backend.controller.js +122 -0
- package/dist/esm/monitoring/analytics/controllers/analytics.backend.controller.js.map +1 -0
- package/dist/esm/monitoring/analytics/services/value-moment-engine.backend.service.d.ts +41 -0
- package/dist/esm/monitoring/analytics/services/value-moment-engine.backend.service.d.ts.map +1 -0
- package/dist/esm/monitoring/analytics/services/value-moment-engine.backend.service.js +62 -0
- package/dist/esm/monitoring/analytics/services/value-moment-engine.backend.service.js.map +1 -0
- package/dist/esm/monitoring/analytics/services/value-moment-handler-registry.backend.service.d.ts +18 -0
- package/dist/esm/monitoring/analytics/services/value-moment-handler-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/monitoring/analytics/services/value-moment-handler-registry.backend.service.js +43 -0
- package/dist/esm/monitoring/analytics/services/value-moment-handler-registry.backend.service.js.map +1 -0
- package/dist/esm/monitoring/logger/middleware/logging.middleware.d.ts +12 -0
- package/dist/esm/monitoring/logger/middleware/logging.middleware.d.ts.map +1 -0
- package/dist/esm/monitoring/logger/middleware/logging.middleware.js +25 -0
- package/dist/esm/monitoring/logger/middleware/logging.middleware.js.map +1 -0
- package/dist/esm/monitoring/logger/models/logger.backend.schemas.d.ts +41 -0
- package/dist/esm/monitoring/logger/models/logger.backend.schemas.d.ts.map +1 -0
- package/dist/esm/monitoring/logger/models/logger.backend.schemas.js +29 -0
- package/dist/esm/monitoring/logger/models/logger.backend.schemas.js.map +1 -0
- package/dist/esm/monitoring/logger/services/__tests__/mock-logger.service.d.ts +22 -0
- package/dist/esm/monitoring/logger/services/__tests__/mock-logger.service.d.ts.map +1 -0
- package/dist/esm/monitoring/logger/services/__tests__/mock-logger.service.js +53 -0
- package/dist/esm/monitoring/logger/services/__tests__/mock-logger.service.js.map +1 -0
- package/dist/esm/monitoring/logger/services/logger.service.d.ts +37 -0
- package/dist/esm/monitoring/logger/services/logger.service.d.ts.map +1 -0
- package/dist/esm/monitoring/logger/services/logger.service.js +189 -0
- package/dist/esm/monitoring/logger/services/logger.service.js.map +1 -0
- package/dist/esm/monitoring/observability/middleware/metrics.middleware.d.ts +38 -0
- package/dist/esm/monitoring/observability/middleware/metrics.middleware.d.ts.map +1 -0
- package/dist/esm/monitoring/observability/middleware/metrics.middleware.js +147 -0
- package/dist/esm/monitoring/observability/middleware/metrics.middleware.js.map +1 -0
- package/dist/esm/monitoring/observability/middleware/telemetry.middleware.d.ts +26 -0
- package/dist/esm/monitoring/observability/middleware/telemetry.middleware.d.ts.map +1 -0
- package/dist/esm/monitoring/observability/middleware/telemetry.middleware.js +117 -0
- package/dist/esm/monitoring/observability/middleware/telemetry.middleware.js.map +1 -0
- package/dist/esm/monitoring/observability/middleware/tracing.middleware.d.ts +28 -0
- package/dist/esm/monitoring/observability/middleware/tracing.middleware.d.ts.map +1 -0
- package/dist/esm/monitoring/observability/middleware/tracing.middleware.js +182 -0
- package/dist/esm/monitoring/observability/middleware/tracing.middleware.js.map +1 -0
- package/dist/esm/monitoring/observability/models/observability.backend.schemas.d.ts +86 -0
- package/dist/esm/monitoring/observability/models/observability.backend.schemas.d.ts.map +1 -0
- package/dist/esm/monitoring/observability/models/observability.backend.schemas.js +1 -0
- package/dist/esm/monitoring/observability/models/observability.backend.schemas.js.map +1 -0
- package/dist/esm/monitoring/observability/services/instrumentations/custom.instrumentations.d.ts +57 -0
- package/dist/esm/monitoring/observability/services/instrumentations/custom.instrumentations.d.ts.map +1 -0
- package/dist/esm/monitoring/observability/services/instrumentations/custom.instrumentations.js +77 -0
- package/dist/esm/monitoring/observability/services/instrumentations/custom.instrumentations.js.map +1 -0
- package/dist/esm/monitoring/observability/services/metrics.service.d.ts +27 -0
- package/dist/esm/monitoring/observability/services/metrics.service.d.ts.map +1 -0
- package/dist/esm/monitoring/observability/services/metrics.service.js +236 -0
- package/dist/esm/monitoring/observability/services/metrics.service.js.map +1 -0
- package/dist/esm/monitoring/observability/services/telemetry.service.d.ts +28 -0
- package/dist/esm/monitoring/observability/services/telemetry.service.d.ts.map +1 -0
- package/dist/esm/monitoring/observability/services/telemetry.service.js +144 -0
- package/dist/esm/monitoring/observability/services/telemetry.service.js.map +1 -0
- package/dist/esm/monitoring/observability/services/tracer.service.d.ts +24 -0
- package/dist/esm/monitoring/observability/services/tracer.service.d.ts.map +1 -0
- package/dist/esm/monitoring/observability/services/tracer.service.js +287 -0
- package/dist/esm/monitoring/observability/services/tracer.service.js.map +1 -0
- package/dist/esm/notifications/email/components/email-components.d.ts +90 -0
- package/dist/esm/notifications/email/components/email-components.d.ts.map +1 -0
- package/dist/esm/notifications/email/components/email-components.js +171 -0
- package/dist/esm/notifications/email/components/email-components.js.map +1 -0
- package/dist/esm/notifications/email/models/email-context-provider.interface.d.ts +80 -0
- package/dist/esm/notifications/email/models/email-context-provider.interface.d.ts.map +1 -0
- package/dist/esm/notifications/email/models/email-context-provider.interface.js +25 -0
- package/dist/esm/notifications/email/models/email-context-provider.interface.js.map +1 -0
- package/dist/esm/notifications/email/models/email-template-definition.d.ts +68 -0
- package/dist/esm/notifications/email/models/email-template-definition.d.ts.map +1 -0
- package/dist/esm/notifications/email/models/email-template-definition.js +12 -0
- package/dist/esm/notifications/email/models/email-template-definition.js.map +1 -0
- package/dist/esm/notifications/email/models/email-template.actors-system.backend.definitions.d.ts +19 -0
- package/dist/esm/notifications/email/models/email-template.actors-system.backend.definitions.d.ts.map +1 -0
- package/dist/esm/notifications/email/models/email-template.actors-system.backend.definitions.js +66 -0
- package/dist/esm/notifications/email/models/email-template.actors-system.backend.definitions.js.map +1 -0
- package/dist/esm/notifications/email/models/email.backend.scheamas.d.ts +1 -0
- package/dist/esm/notifications/email/models/email.backend.scheamas.d.ts.map +1 -0
- package/dist/esm/notifications/email/models/email.backend.scheamas.js +1 -0
- package/dist/esm/notifications/email/models/email.backend.scheamas.js.map +1 -0
- package/dist/esm/notifications/email/services/email-batch-send.batch.backend.service.d.ts +74 -0
- package/dist/esm/notifications/email/services/email-batch-send.batch.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email-batch-send.batch.backend.service.js +196 -0
- package/dist/esm/notifications/email/services/email-batch-send.batch.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/services/email-context-provider-registry.backend.service.d.ts +49 -0
- package/dist/esm/notifications/email/services/email-context-provider-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email-context-provider-registry.backend.service.js +141 -0
- package/dist/esm/notifications/email/services/email-context-provider-registry.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/services/email-renderer.backend.service.d.ts +74 -0
- package/dist/esm/notifications/email/services/email-renderer.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email-renderer.backend.service.js +215 -0
- package/dist/esm/notifications/email/services/email-renderer.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/services/email-template-compiler.backend.service.d.ts +37 -0
- package/dist/esm/notifications/email/services/email-template-compiler.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email-template-compiler.backend.service.js +121 -0
- package/dist/esm/notifications/email/services/email-template-compiler.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/services/email-template-generation.backend.service.d.ts +115 -0
- package/dist/esm/notifications/email/services/email-template-generation.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email-template-generation.backend.service.js +634 -0
- package/dist/esm/notifications/email/services/email-template-generation.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/services/email-template-registry.backend.service.d.ts +48 -0
- package/dist/esm/notifications/email/services/email-template-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email-template-registry.backend.service.js +146 -0
- package/dist/esm/notifications/email/services/email-template-registry.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/services/email-template-sandbox.backend.service.d.ts +58 -0
- package/dist/esm/notifications/email/services/email-template-sandbox.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email-template-sandbox.backend.service.js +223 -0
- package/dist/esm/notifications/email/services/email-template-sandbox.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/services/email-template-validator.backend.service.d.ts +49 -0
- package/dist/esm/notifications/email/services/email-template-validator.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email-template-validator.backend.service.js +204 -0
- package/dist/esm/notifications/email/services/email-template-validator.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/services/email.backend.service.d.ts +76 -0
- package/dist/esm/notifications/email/services/email.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email.backend.service.js +294 -0
- package/dist/esm/notifications/email/services/email.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/utils/color-conversion.utils.d.ts +56 -0
- package/dist/esm/notifications/email/utils/color-conversion.utils.d.ts.map +1 -0
- package/dist/esm/notifications/email/utils/color-conversion.utils.js +108 -0
- package/dist/esm/notifications/email/utils/color-conversion.utils.js.map +1 -0
- package/dist/esm/notifications/email/utils/interpolate-email-label.utils.d.ts +8 -0
- package/dist/esm/notifications/email/utils/interpolate-email-label.utils.d.ts.map +1 -0
- package/dist/esm/notifications/email/utils/interpolate-email-label.utils.js +15 -0
- package/dist/esm/notifications/email/utils/interpolate-email-label.utils.js.map +1 -0
- package/dist/esm/notifications/email/utils/zod-to-typescript.utils.d.ts +50 -0
- package/dist/esm/notifications/email/utils/zod-to-typescript.utils.d.ts.map +1 -0
- package/dist/esm/notifications/email/utils/zod-to-typescript.utils.js +281 -0
- package/dist/esm/notifications/email/utils/zod-to-typescript.utils.js.map +1 -0
- package/dist/esm/notifications/services/notification-badge.backend.service.d.ts +94 -0
- package/dist/esm/notifications/services/notification-badge.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/services/notification-badge.backend.service.js +292 -0
- package/dist/esm/notifications/services/notification-badge.backend.service.js.map +1 -0
- package/dist/esm/notifications/services/notifications-dispatcher.backend.service.d.ts +202 -0
- package/dist/esm/notifications/services/notifications-dispatcher.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/services/notifications-dispatcher.backend.service.js +1290 -0
- package/dist/esm/notifications/services/notifications-dispatcher.backend.service.js.map +1 -0
- package/dist/esm/notifications/sms/services/sms.backend.service.d.ts +50 -0
- package/dist/esm/notifications/sms/services/sms.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/sms/services/sms.backend.service.js +209 -0
- package/dist/esm/notifications/sms/services/sms.backend.service.js.map +1 -0
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.d.ts +58 -0
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.js +184 -0
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.js.map +1 -0
- package/dist/esm/notifications/webhooks/services/polymorphic-lookup.backend.service.d.ts +56 -0
- package/dist/esm/notifications/webhooks/services/polymorphic-lookup.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/webhooks/services/polymorphic-lookup.backend.service.js +109 -0
- package/dist/esm/notifications/webhooks/services/polymorphic-lookup.backend.service.js.map +1 -0
- package/dist/esm/notifications/webhooks/services/webhook-handler.backend.service.d.ts +96 -0
- package/dist/esm/notifications/webhooks/services/webhook-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/webhooks/services/webhook-handler.backend.service.js +396 -0
- package/dist/esm/notifications/webhooks/services/webhook-handler.backend.service.js.map +1 -0
- package/dist/esm/organizations/services/org-creation-on-registration.backend.utils.d.ts +39 -0
- package/dist/esm/organizations/services/org-creation-on-registration.backend.utils.d.ts.map +1 -0
- package/dist/esm/organizations/services/org-creation-on-registration.backend.utils.js +73 -0
- package/dist/esm/organizations/services/org-creation-on-registration.backend.utils.js.map +1 -0
- package/dist/esm/organizations/services/org-member-roles-validation.backend.utils.d.ts +22 -0
- package/dist/esm/organizations/services/org-member-roles-validation.backend.utils.d.ts.map +1 -0
- package/dist/esm/organizations/services/org-member-roles-validation.backend.utils.js +35 -0
- package/dist/esm/organizations/services/org-member-roles-validation.backend.utils.js.map +1 -0
- package/dist/esm/organizations/services/organization-custom-implementation.backend.service.d.ts +10 -0
- package/dist/esm/organizations/services/organization-custom-implementation.backend.service.d.ts.map +1 -0
- package/dist/esm/organizations/services/organization-custom-implementation.backend.service.js +77 -0
- package/dist/esm/organizations/services/organization-custom-implementation.backend.service.js.map +1 -0
- package/dist/esm/organizations/services/organization-member-custom-implementation.backend.service.d.ts +10 -0
- package/dist/esm/organizations/services/organization-member-custom-implementation.backend.service.d.ts.map +1 -0
- package/dist/esm/organizations/services/organization-member-custom-implementation.backend.service.js +131 -0
- package/dist/esm/organizations/services/organization-member-custom-implementation.backend.service.js.map +1 -0
- package/dist/esm/organizations/services/scim-provisioning-gate.backend.utils.d.ts +22 -0
- package/dist/esm/organizations/services/scim-provisioning-gate.backend.utils.d.ts.map +1 -0
- package/dist/esm/organizations/services/scim-provisioning-gate.backend.utils.js +21 -0
- package/dist/esm/organizations/services/scim-provisioning-gate.backend.utils.js.map +1 -0
- package/dist/esm/organizations/services/user-org-type-grant.backend.utils.d.ts +25 -0
- package/dist/esm/organizations/services/user-org-type-grant.backend.utils.d.ts.map +1 -0
- package/dist/esm/organizations/services/user-org-type-grant.backend.utils.js +34 -0
- package/dist/esm/organizations/services/user-org-type-grant.backend.utils.js.map +1 -0
- package/dist/esm/organizations/services/user-type-revocation-on-org-leave.backend.utils.d.ts +32 -0
- package/dist/esm/organizations/services/user-type-revocation-on-org-leave.backend.utils.d.ts.map +1 -0
- package/dist/esm/organizations/services/user-type-revocation-on-org-leave.backend.utils.js +66 -0
- package/dist/esm/organizations/services/user-type-revocation-on-org-leave.backend.utils.js.map +1 -0
- package/dist/esm/queue/adapters/rabbitmq-adapter.backend.service.d.ts +126 -0
- package/dist/esm/queue/adapters/rabbitmq-adapter.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/adapters/rabbitmq-adapter.backend.service.js +370 -0
- package/dist/esm/queue/adapters/rabbitmq-adapter.backend.service.js.map +1 -0
- package/dist/esm/queue/apps-crontabs-manager.backend.service.d.ts +86 -0
- package/dist/esm/queue/apps-crontabs-manager.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/apps-crontabs-manager.backend.service.js +176 -0
- package/dist/esm/queue/apps-crontabs-manager.backend.service.js.map +1 -0
- package/dist/esm/queue/cron-job-sync.backend.service.d.ts +42 -0
- package/dist/esm/queue/cron-job-sync.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/cron-job-sync.backend.service.js +181 -0
- package/dist/esm/queue/cron-job-sync.backend.service.js.map +1 -0
- package/dist/esm/queue/domain-queue-consumer.backend.service.d.ts +84 -0
- package/dist/esm/queue/domain-queue-consumer.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/domain-queue-consumer.backend.service.js +275 -0
- package/dist/esm/queue/domain-queue-consumer.backend.service.js.map +1 -0
- package/dist/esm/queue/job-completion-registry.backend.service.d.ts +111 -0
- package/dist/esm/queue/job-completion-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/job-completion-registry.backend.service.js +237 -0
- package/dist/esm/queue/job-completion-registry.backend.service.js.map +1 -0
- package/dist/esm/queue/job-consumer.backend.service.d.ts +109 -0
- package/dist/esm/queue/job-consumer.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/job-consumer.backend.service.js +515 -0
- package/dist/esm/queue/job-consumer.backend.service.js.map +1 -0
- package/dist/esm/queue/job-executor.backend.service.d.ts +53 -0
- package/dist/esm/queue/job-executor.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/job-executor.backend.service.js +278 -0
- package/dist/esm/queue/job-executor.backend.service.js.map +1 -0
- package/dist/esm/queue/job-payload-storage.backend.service.d.ts +86 -0
- package/dist/esm/queue/job-payload-storage.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/job-payload-storage.backend.service.js +250 -0
- package/dist/esm/queue/job-payload-storage.backend.service.js.map +1 -0
- package/dist/esm/queue/job-status-tracking.backend.service.d.ts +97 -0
- package/dist/esm/queue/job-status-tracking.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/job-status-tracking.backend.service.js +281 -0
- package/dist/esm/queue/job-status-tracking.backend.service.js.map +1 -0
- package/dist/esm/queue/queue-monitoring.backend.service.d.ts +71 -0
- package/dist/esm/queue/queue-monitoring.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/queue-monitoring.backend.service.js +297 -0
- package/dist/esm/queue/queue-monitoring.backend.service.js.map +1 -0
- package/dist/esm/queue/queue-worker-initializer.backend.service.d.ts +63 -0
- package/dist/esm/queue/queue-worker-initializer.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/queue-worker-initializer.backend.service.js +171 -0
- package/dist/esm/queue/queue-worker-initializer.backend.service.js.map +1 -0
- package/dist/esm/queue/queue.backend.service.d.ts +108 -0
- package/dist/esm/queue/queue.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/queue.backend.service.js +419 -0
- package/dist/esm/queue/queue.backend.service.js.map +1 -0
- package/dist/esm/queue/scheduled-message-verifier.backend.service.d.ts +74 -0
- package/dist/esm/queue/scheduled-message-verifier.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/scheduled-message-verifier.backend.service.js +189 -0
- package/dist/esm/queue/scheduled-message-verifier.backend.service.js.map +1 -0
- package/dist/esm/queue/worker-shutdown-manager.backend.service.d.ts +124 -0
- package/dist/esm/queue/worker-shutdown-manager.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/worker-shutdown-manager.backend.service.js +250 -0
- package/dist/esm/queue/worker-shutdown-manager.backend.service.js.map +1 -0
- package/dist/esm/requests/models/api-routes.backend.defintions.d.ts +34 -0
- package/dist/esm/requests/models/api-routes.backend.defintions.d.ts.map +1 -0
- package/dist/esm/requests/models/api-routes.backend.defintions.js +42 -0
- package/dist/esm/requests/models/api-routes.backend.defintions.js.map +1 -0
- package/dist/esm/requests/models/requests.backend.schemas.d.ts +48 -0
- package/dist/esm/requests/models/requests.backend.schemas.d.ts.map +1 -0
- package/dist/esm/requests/models/requests.backend.schemas.js +7 -0
- package/dist/esm/requests/models/requests.backend.schemas.js.map +1 -0
- package/dist/esm/requests/service/__tests__/mock-apps-shared-resources-gateway.service.d.ts +6 -0
- package/dist/esm/requests/service/__tests__/mock-apps-shared-resources-gateway.service.d.ts.map +1 -0
- package/dist/esm/requests/service/__tests__/mock-apps-shared-resources-gateway.service.js +20 -0
- package/dist/esm/requests/service/__tests__/mock-apps-shared-resources-gateway.service.js.map +1 -0
- package/dist/esm/requests/service/apps-shared-resources-gateway.backend.service.d.ts +84 -0
- package/dist/esm/requests/service/apps-shared-resources-gateway.backend.service.d.ts.map +1 -0
- package/dist/esm/requests/service/apps-shared-resources-gateway.backend.service.js +462 -0
- package/dist/esm/requests/service/apps-shared-resources-gateway.backend.service.js.map +1 -0
- package/dist/esm/requests/service/platform-mutualized-handler.backend.service.d.ts +9 -0
- package/dist/esm/requests/service/platform-mutualized-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/requests/service/platform-mutualized-handler.backend.service.js +36 -0
- package/dist/esm/requests/service/platform-mutualized-handler.backend.service.js.map +1 -0
- package/dist/esm/requests/service/platform-requests.backend.utils.d.ts +6 -0
- package/dist/esm/requests/service/platform-requests.backend.utils.d.ts.map +1 -0
- package/dist/esm/requests/service/platform-requests.backend.utils.js +47 -0
- package/dist/esm/requests/service/platform-requests.backend.utils.js.map +1 -0
- package/dist/esm/requests/service/remote-client-base.backend.service.d.ts +111 -0
- package/dist/esm/requests/service/remote-client-base.backend.service.d.ts.map +1 -0
- package/dist/esm/requests/service/remote-client-base.backend.service.js +354 -0
- package/dist/esm/requests/service/remote-client-base.backend.service.js.map +1 -0
- package/dist/esm/requests/service/serverless-services-handler.backend.service.d.ts +9 -0
- package/dist/esm/requests/service/serverless-services-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/requests/service/serverless-services-handler.backend.service.js +36 -0
- package/dist/esm/requests/service/serverless-services-handler.backend.service.js.map +1 -0
- package/dist/esm/requests/service/websocket.service.d.ts +507 -0
- package/dist/esm/requests/service/websocket.service.d.ts.map +1 -0
- package/dist/esm/requests/service/websocket.service.js +2222 -0
- package/dist/esm/requests/service/websocket.service.js.map +1 -0
- package/dist/esm/resources/models/custom-service-implementations.backend.definition.d.ts +3 -0
- package/dist/esm/resources/models/custom-service-implementations.backend.definition.d.ts.map +1 -0
- package/dist/esm/resources/models/custom-service-implementations.backend.definition.js +17 -0
- package/dist/esm/resources/models/custom-service-implementations.backend.definition.js.map +1 -0
- package/dist/esm/resources/models/index.d.ts +7 -0
- package/dist/esm/resources/models/index.d.ts.map +1 -0
- package/dist/esm/resources/models/index.js +7 -0
- package/dist/esm/resources/models/index.js.map +1 -0
- package/dist/esm/resources/models/resources-operations.backend.definitions.d.ts +4 -0
- package/dist/esm/resources/models/resources-operations.backend.definitions.d.ts.map +1 -0
- package/dist/esm/resources/models/resources-operations.backend.definitions.js +7 -0
- package/dist/esm/resources/models/resources-operations.backend.definitions.js.map +1 -0
- package/dist/esm/resources/models/resources-relationships.backend.definitions.d.ts +3 -0
- package/dist/esm/resources/models/resources-relationships.backend.definitions.d.ts.map +1 -0
- package/dist/esm/resources/models/resources-relationships.backend.definitions.js +19 -0
- package/dist/esm/resources/models/resources-relationships.backend.definitions.js.map +1 -0
- package/dist/esm/resources/models/resources-types.backend.schemas.d.ts +13 -0
- package/dist/esm/resources/models/resources-types.backend.schemas.d.ts.map +1 -0
- package/dist/esm/resources/models/resources-types.backend.schemas.js +14 -0
- package/dist/esm/resources/models/resources-types.backend.schemas.js.map +1 -0
- package/dist/esm/resources/models/resources.backend.schemas.d.ts +7 -0
- package/dist/esm/resources/models/resources.backend.schemas.d.ts.map +1 -0
- package/dist/esm/resources/models/resources.backend.schemas.js +8 -0
- package/dist/esm/resources/models/resources.backend.schemas.js.map +1 -0
- package/dist/esm/resources/models/virtual-fields.backend.types.d.ts +121 -0
- package/dist/esm/resources/models/virtual-fields.backend.types.d.ts.map +1 -0
- package/dist/esm/resources/models/virtual-fields.backend.types.js +10 -0
- package/dist/esm/resources/models/virtual-fields.backend.types.js.map +1 -0
- package/dist/esm/resources/services/__tests__/mock-resources-registry.service.d.ts +25 -0
- package/dist/esm/resources/services/__tests__/mock-resources-registry.service.d.ts.map +1 -0
- package/dist/esm/resources/services/__tests__/mock-resources-registry.service.js +59 -0
- package/dist/esm/resources/services/__tests__/mock-resources-registry.service.js.map +1 -0
- package/dist/esm/resources/services/resource-context.backend.service.d.ts +321 -0
- package/dist/esm/resources/services/resource-context.backend.service.d.ts.map +1 -0
- package/dist/esm/resources/services/resource-context.backend.service.js +723 -0
- package/dist/esm/resources/services/resource-context.backend.service.js.map +1 -0
- package/dist/esm/resources/services/resource-id.backend.service.d.ts +110 -0
- package/dist/esm/resources/services/resource-id.backend.service.d.ts.map +1 -0
- package/dist/esm/resources/services/resource-id.backend.service.js +267 -0
- package/dist/esm/resources/services/resource-id.backend.service.js.map +1 -0
- package/dist/esm/resources/services/resource-population.backend.service.d.ts +149 -0
- package/dist/esm/resources/services/resource-population.backend.service.d.ts.map +1 -0
- package/dist/esm/resources/services/resource-population.backend.service.js +543 -0
- package/dist/esm/resources/services/resource-population.backend.service.js.map +1 -0
- package/dist/esm/resources/services/resources-registry.backend.service.d.ts +151 -0
- package/dist/esm/resources/services/resources-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/resources/services/resources-registry.backend.service.js +867 -0
- package/dist/esm/resources/services/resources-registry.backend.service.js.map +1 -0
- package/dist/esm/resources/services/virtual-fields.backend.service.d.ts +72 -0
- package/dist/esm/resources/services/virtual-fields.backend.service.d.ts.map +1 -0
- package/dist/esm/resources/services/virtual-fields.backend.service.js +254 -0
- package/dist/esm/resources/services/virtual-fields.backend.service.js.map +1 -0
- package/dist/esm/runtime/controllers/health-controller.backend.service.d.ts +73 -0
- package/dist/esm/runtime/controllers/health-controller.backend.service.d.ts.map +1 -0
- package/dist/esm/runtime/controllers/health-controller.backend.service.js +275 -0
- package/dist/esm/runtime/controllers/health-controller.backend.service.js.map +1 -0
- package/dist/esm/runtime/domain-module.backend.definitions.d.ts +43 -0
- package/dist/esm/runtime/domain-module.backend.definitions.d.ts.map +1 -0
- package/dist/esm/runtime/domain-module.backend.definitions.js +70 -0
- package/dist/esm/runtime/domain-module.backend.definitions.js.map +1 -0
- package/dist/esm/runtime/models/execution-context.backend.schemas.d.ts +253 -0
- package/dist/esm/runtime/models/execution-context.backend.schemas.d.ts.map +1 -0
- package/dist/esm/runtime/models/execution-context.backend.schemas.js +329 -0
- package/dist/esm/runtime/models/execution-context.backend.schemas.js.map +1 -0
- package/dist/esm/runtime/models/runtime.backend.schemas.d.ts +45 -0
- package/dist/esm/runtime/models/runtime.backend.schemas.d.ts.map +1 -0
- package/dist/esm/runtime/models/runtime.backend.schemas.js +73 -0
- package/dist/esm/runtime/models/runtime.backend.schemas.js.map +1 -0
- package/dist/esm/runtime/services/execution-context-creator.backend.service.d.ts +315 -0
- package/dist/esm/runtime/services/execution-context-creator.backend.service.d.ts.map +1 -0
- package/dist/esm/runtime/services/execution-context-creator.backend.service.js +1525 -0
- package/dist/esm/runtime/services/execution-context-creator.backend.service.js.map +1 -0
- package/dist/esm/runtime/services/execution-context-handler.backend.service.d.ts +60 -0
- package/dist/esm/runtime/services/execution-context-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/runtime/services/execution-context-handler.backend.service.js +150 -0
- package/dist/esm/runtime/services/execution-context-handler.backend.service.js.map +1 -0
- package/dist/esm/runtime/services/health-readiness-contributor.backend.interface.d.ts +11 -0
- package/dist/esm/runtime/services/health-readiness-contributor.backend.interface.d.ts.map +1 -0
- package/dist/esm/runtime/services/health-readiness-contributor.backend.interface.js +1 -0
- package/dist/esm/runtime/services/health-readiness-contributor.backend.interface.js.map +1 -0
- package/dist/esm/runtime/services/http-server.backend.service.d.ts +188 -0
- package/dist/esm/runtime/services/http-server.backend.service.d.ts.map +1 -0
- package/dist/esm/runtime/services/http-server.backend.service.js +755 -0
- package/dist/esm/runtime/services/http-server.backend.service.js.map +1 -0
- package/dist/esm/runtime/services/start-application.backend.service.d.ts +240 -0
- package/dist/esm/runtime/services/start-application.backend.service.d.ts.map +1 -0
- package/dist/esm/runtime/services/start-application.backend.service.js +977 -0
- package/dist/esm/runtime/services/start-application.backend.service.js.map +1 -0
- package/dist/esm/runtime/testing/execution-context-test-fixtures.d.ts +10 -0
- package/dist/esm/runtime/testing/execution-context-test-fixtures.d.ts.map +1 -0
- package/dist/esm/runtime/testing/execution-context-test-fixtures.js +13 -0
- package/dist/esm/runtime/testing/execution-context-test-fixtures.js.map +1 -0
- package/dist/esm/runtime/testing/mock-execution-context-creator.service.d.ts +15 -0
- package/dist/esm/runtime/testing/mock-execution-context-creator.service.d.ts.map +1 -0
- package/dist/esm/runtime/testing/mock-execution-context-creator.service.js +42 -0
- package/dist/esm/runtime/testing/mock-execution-context-creator.service.js.map +1 -0
- package/dist/esm/runtime/utils/scan-default-exports.backend.utils.d.ts +85 -0
- package/dist/esm/runtime/utils/scan-default-exports.backend.utils.d.ts.map +1 -0
- package/dist/esm/runtime/utils/scan-default-exports.backend.utils.js +171 -0
- package/dist/esm/runtime/utils/scan-default-exports.backend.utils.js.map +1 -0
- package/dist/esm/security/authentications/batches/anonymous-session-cleanup.batch.backend.service.d.ts +19 -0
- package/dist/esm/security/authentications/batches/anonymous-session-cleanup.batch.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/batches/anonymous-session-cleanup.batch.backend.service.js +59 -0
- package/dist/esm/security/authentications/batches/anonymous-session-cleanup.batch.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/controllers/auth-method-management-controller.backend.service.d.ts +31 -0
- package/dist/esm/security/authentications/controllers/auth-method-management-controller.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/controllers/auth-method-management-controller.backend.service.js +215 -0
- package/dist/esm/security/authentications/controllers/auth-method-management-controller.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/controllers/authentication-controller.backend.service.d.ts +493 -0
- package/dist/esm/security/authentications/controllers/authentication-controller.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/controllers/authentication-controller.backend.service.js +2371 -0
- package/dist/esm/security/authentications/controllers/authentication-controller.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/models/auth-constants.backend.d.ts +83 -0
- package/dist/esm/security/authentications/models/auth-constants.backend.d.ts.map +1 -0
- package/dist/esm/security/authentications/models/auth-constants.backend.js +113 -0
- package/dist/esm/security/authentications/models/auth-constants.backend.js.map +1 -0
- package/dist/esm/security/authentications/models/authentications.backend.schemas.d.ts +98 -0
- package/dist/esm/security/authentications/models/authentications.backend.schemas.d.ts.map +1 -0
- package/dist/esm/security/authentications/models/authentications.backend.schemas.js +59 -0
- package/dist/esm/security/authentications/models/authentications.backend.schemas.js.map +1 -0
- package/dist/esm/security/authentications/models/jwt.backend.schemas.d.ts +42 -0
- package/dist/esm/security/authentications/models/jwt.backend.schemas.d.ts.map +1 -0
- package/dist/esm/security/authentications/models/jwt.backend.schemas.js +98 -0
- package/dist/esm/security/authentications/models/jwt.backend.schemas.js.map +1 -0
- package/dist/esm/security/authentications/models/oauth2-connection.backend.schemas.d.ts +163 -0
- package/dist/esm/security/authentications/models/oauth2-connection.backend.schemas.d.ts.map +1 -0
- package/dist/esm/security/authentications/models/oauth2-connection.backend.schemas.js +12 -0
- package/dist/esm/security/authentications/models/oauth2-connection.backend.schemas.js.map +1 -0
- package/dist/esm/security/authentications/models/saml-authentication.backend.schemas.d.ts +102 -0
- package/dist/esm/security/authentications/models/saml-authentication.backend.schemas.d.ts.map +1 -0
- package/dist/esm/security/authentications/models/saml-authentication.backend.schemas.js +7 -0
- package/dist/esm/security/authentications/models/saml-authentication.backend.schemas.js.map +1 -0
- package/dist/esm/security/authentications/models/sso-connection.backend.schemas.d.ts +88 -0
- package/dist/esm/security/authentications/models/sso-connection.backend.schemas.d.ts.map +1 -0
- package/dist/esm/security/authentications/models/sso-connection.backend.schemas.js +17 -0
- package/dist/esm/security/authentications/models/sso-connection.backend.schemas.js.map +1 -0
- package/dist/esm/security/authentications/services/__tests__/mock-auth-execution-context-factory.service.d.ts +27 -0
- package/dist/esm/security/authentications/services/__tests__/mock-auth-execution-context-factory.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/__tests__/mock-auth-execution-context-factory.service.js +66 -0
- package/dist/esm/security/authentications/services/__tests__/mock-auth-execution-context-factory.service.js.map +1 -0
- package/dist/esm/security/authentications/services/__tests__/mock-auth-token-issuer.service.d.ts +30 -0
- package/dist/esm/security/authentications/services/__tests__/mock-auth-token-issuer.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/__tests__/mock-auth-token-issuer.service.js +44 -0
- package/dist/esm/security/authentications/services/__tests__/mock-auth-token-issuer.service.js.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-domain-to-org-lookup.service.d.ts +19 -0
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-domain-to-org-lookup.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-domain-to-org-lookup.service.js +43 -0
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-domain-to-org-lookup.service.js.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-enterprise-user-provisioning.service.d.ts +37 -0
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-enterprise-user-provisioning.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-enterprise-user-provisioning.service.js +58 -0
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-enterprise-user-provisioning.service.js.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/auth-organization-configuration.service.d.ts +85 -0
- package/dist/esm/security/authentications/services/admin-config/auth-organization-configuration.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/auth-organization-configuration.service.js +379 -0
- package/dist/esm/security/authentications/services/admin-config/auth-organization-configuration.service.js.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/domain-to-org-lookup.backend.service.d.ts +79 -0
- package/dist/esm/security/authentications/services/admin-config/domain-to-org-lookup.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/domain-to-org-lookup.backend.service.js +205 -0
- package/dist/esm/security/authentications/services/admin-config/domain-to-org-lookup.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/domain-verification.backend.service.d.ts +59 -0
- package/dist/esm/security/authentications/services/admin-config/domain-verification.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/domain-verification.backend.service.js +179 -0
- package/dist/esm/security/authentications/services/admin-config/domain-verification.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/enterprise-user-provisioning.backend.service.d.ts +116 -0
- package/dist/esm/security/authentications/services/admin-config/enterprise-user-provisioning.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/enterprise-user-provisioning.backend.service.js +436 -0
- package/dist/esm/security/authentications/services/admin-config/enterprise-user-provisioning.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/oidc-discovery.backend.service.d.ts +67 -0
- package/dist/esm/security/authentications/services/admin-config/oidc-discovery.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/oidc-discovery.backend.service.js +222 -0
- package/dist/esm/security/authentications/services/admin-config/oidc-discovery.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/anonymous-session.backend.service.d.ts +80 -0
- package/dist/esm/security/authentications/services/anonymous-session.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/anonymous-session.backend.service.js +368 -0
- package/dist/esm/security/authentications/services/anonymous-session.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-credential-verifier.backend.service.d.ts +75 -0
- package/dist/esm/security/authentications/services/auth-credential-verifier.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-credential-verifier.backend.service.js +139 -0
- package/dist/esm/security/authentications/services/auth-credential-verifier.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-execution-context-factory.backend.service.d.ts +72 -0
- package/dist/esm/security/authentications/services/auth-execution-context-factory.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-execution-context-factory.backend.service.js +127 -0
- package/dist/esm/security/authentications/services/auth-execution-context-factory.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.d.ts +57 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.js +459 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-mfa.backend.service.d.ts +44 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-mfa.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-mfa.backend.service.js +131 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-mfa.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.d.ts +58 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.js +209 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-phone-verification.backend.service.d.ts +46 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-phone-verification.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-phone-verification.backend.service.js +124 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-phone-verification.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-registration.backend.service.d.ts +165 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-registration.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-registration.backend.service.js +816 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-registration.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-authentication.backend.service.d.ts +218 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-authentication.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-authentication.backend.service.js +1026 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-authentication.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service.d.ts +150 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service.js +737 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-assertion-validator.backend.service.d.ts +224 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-assertion-validator.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-assertion-validator.backend.service.js +593 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-assertion-validator.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-authentication.backend.service.d.ts +267 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-authentication.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-authentication.backend.service.js +1376 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-authentication.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-metadata.backend.service.d.ts +93 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-metadata.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-metadata.backend.service.js +396 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-metadata.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-replay-guard.backend.service.d.ts +40 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-replay-guard.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-replay-guard.backend.service.js +92 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-replay-guard.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/webauthn.backend.service.d.ts +82 -0
- package/dist/esm/security/authentications/services/auth-methods/webauthn.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/webauthn.backend.service.js +325 -0
- package/dist/esm/security/authentications/services/auth-methods/webauthn.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-session-store.backend.service.d.ts +66 -0
- package/dist/esm/security/authentications/services/auth-session-store.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-session-store.backend.service.js +198 -0
- package/dist/esm/security/authentications/services/auth-session-store.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.d.ts +108 -0
- package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.js +406 -0
- package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/authentication-orchestrator.backend.service.d.ts +366 -0
- package/dist/esm/security/authentications/services/authentication-orchestrator.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/authentication-orchestrator.backend.service.js +2631 -0
- package/dist/esm/security/authentications/services/authentication-orchestrator.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/auth-custom-implementations.backend.d.ts +13 -0
- package/dist/esm/security/authentications/services/custom-impls/auth-custom-implementations.backend.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/auth-custom-implementations.backend.js +53 -0
- package/dist/esm/security/authentications/services/custom-impls/auth-custom-implementations.backend.js.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/auth-policy.custom-impl.backend.service.d.ts +12 -0
- package/dist/esm/security/authentications/services/custom-impls/auth-policy.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/auth-policy.custom-impl.backend.service.js +41 -0
- package/dist/esm/security/authentications/services/custom-impls/auth-policy.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/scim-provisioning-config.custom-impl.backend.service.d.ts +18 -0
- package/dist/esm/security/authentications/services/custom-impls/scim-provisioning-config.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/scim-provisioning-config.custom-impl.backend.service.js +140 -0
- package/dist/esm/security/authentications/services/custom-impls/scim-provisioning-config.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/scim-tokens.custom-impl.backend.service.d.ts +16 -0
- package/dist/esm/security/authentications/services/custom-impls/scim-tokens.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/scim-tokens.custom-impl.backend.service.js +112 -0
- package/dist/esm/security/authentications/services/custom-impls/scim-tokens.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.d.ts +16 -0
- package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.js +101 -0
- package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/siem-export-config.custom-impl.backend.service.d.ts +18 -0
- package/dist/esm/security/authentications/services/custom-impls/siem-export-config.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/siem-export-config.custom-impl.backend.service.js +136 -0
- package/dist/esm/security/authentications/services/custom-impls/siem-export-config.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/sso-config.custom-impl.backend.service.d.ts +19 -0
- package/dist/esm/security/authentications/services/custom-impls/sso-config.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/sso-config.custom-impl.backend.service.js +154 -0
- package/dist/esm/security/authentications/services/custom-impls/sso-config.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/sso-connection.custom-impl.backend.service.d.ts +26 -0
- package/dist/esm/security/authentications/services/custom-impls/sso-connection.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/sso-connection.custom-impl.backend.service.js +657 -0
- package/dist/esm/security/authentications/services/custom-impls/sso-connection.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/utils/__tests__/mock-auth-user-lookup.service.d.ts +27 -0
- package/dist/esm/security/authentications/services/utils/__tests__/mock-auth-user-lookup.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/utils/__tests__/mock-auth-user-lookup.service.js +60 -0
- package/dist/esm/security/authentications/services/utils/__tests__/mock-auth-user-lookup.service.js.map +1 -0
- package/dist/esm/security/authentications/services/utils/auth-controller.utils.d.ts +23 -0
- package/dist/esm/security/authentications/services/utils/auth-controller.utils.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/utils/auth-controller.utils.js +44 -0
- package/dist/esm/security/authentications/services/utils/auth-controller.utils.js.map +1 -0
- package/dist/esm/security/authentications/services/utils/auth-credential-ops.backend.service.d.ts +89 -0
- package/dist/esm/security/authentications/services/utils/auth-credential-ops.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/utils/auth-credential-ops.backend.service.js +192 -0
- package/dist/esm/security/authentications/services/utils/auth-credential-ops.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/utils/auth-response-helper.backend.service.d.ts +20 -0
- package/dist/esm/security/authentications/services/utils/auth-response-helper.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/utils/auth-response-helper.backend.service.js +55 -0
- package/dist/esm/security/authentications/services/utils/auth-response-helper.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/utils/auth-user-lookup.backend.service.d.ts +50 -0
- package/dist/esm/security/authentications/services/utils/auth-user-lookup.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/utils/auth-user-lookup.backend.service.js +135 -0
- package/dist/esm/security/authentications/services/utils/auth-user-lookup.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/utils/saml-java-availability.d.ts +26 -0
- package/dist/esm/security/authentications/services/utils/saml-java-availability.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/utils/saml-java-availability.js +59 -0
- package/dist/esm/security/authentications/services/utils/saml-java-availability.js.map +1 -0
- package/dist/esm/security/authorizations/services/authorizations.backend.service.d.ts +137 -0
- package/dist/esm/security/authorizations/services/authorizations.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authorizations/services/authorizations.backend.service.js +723 -0
- package/dist/esm/security/authorizations/services/authorizations.backend.service.js.map +1 -0
- package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.d.ts +28 -0
- package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.d.ts.map +1 -0
- package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.js +156 -0
- package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.js.map +1 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.d.ts +4 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.d.ts.map +1 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.js +72 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.js.map +1 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.shared.schemas.d.ts +125 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.shared.schemas.d.ts.map +1 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.shared.schemas.js +69 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.shared.schemas.js.map +1 -0
- package/dist/esm/security/consumable-tokens/models/index.d.ts +3 -0
- package/dist/esm/security/consumable-tokens/models/index.d.ts.map +1 -0
- package/dist/esm/security/consumable-tokens/models/index.js +3 -0
- package/dist/esm/security/consumable-tokens/models/index.js.map +1 -0
- package/dist/esm/security/consumable-tokens/services/__tests__/mock-consumable-token.service.d.ts +26 -0
- package/dist/esm/security/consumable-tokens/services/__tests__/mock-consumable-token.service.d.ts.map +1 -0
- package/dist/esm/security/consumable-tokens/services/__tests__/mock-consumable-token.service.js +55 -0
- package/dist/esm/security/consumable-tokens/services/__tests__/mock-consumable-token.service.js.map +1 -0
- package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.d.ts +142 -0
- package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.d.ts.map +1 -0
- package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.js +446 -0
- package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.js.map +1 -0
- package/dist/esm/security/jwt/services/auth-jwt-guard.backend.service.d.ts +46 -0
- package/dist/esm/security/jwt/services/auth-jwt-guard.backend.service.d.ts.map +1 -0
- package/dist/esm/security/jwt/services/auth-jwt-guard.backend.service.js +147 -0
- package/dist/esm/security/jwt/services/auth-jwt-guard.backend.service.js.map +1 -0
- package/dist/esm/security/jwt/services/jwt.backend.service.d.ts +75 -0
- package/dist/esm/security/jwt/services/jwt.backend.service.d.ts.map +1 -0
- package/dist/esm/security/jwt/services/jwt.backend.service.js +368 -0
- package/dist/esm/security/jwt/services/jwt.backend.service.js.map +1 -0
- package/dist/esm/security/scim/controllers/scim.backend.controller.d.ts +71 -0
- package/dist/esm/security/scim/controllers/scim.backend.controller.d.ts.map +1 -0
- package/dist/esm/security/scim/controllers/scim.backend.controller.js +863 -0
- package/dist/esm/security/scim/controllers/scim.backend.controller.js.map +1 -0
- package/dist/esm/security/scim/models/scim-protocol.backend.schemas.d.ts +275 -0
- package/dist/esm/security/scim/models/scim-protocol.backend.schemas.d.ts.map +1 -0
- package/dist/esm/security/scim/models/scim-protocol.backend.schemas.js +139 -0
- package/dist/esm/security/scim/models/scim-protocol.backend.schemas.js.map +1 -0
- package/dist/esm/security/scim/utils/scim-filter-parser.d.ts +35 -0
- package/dist/esm/security/scim/utils/scim-filter-parser.d.ts.map +1 -0
- package/dist/esm/security/scim/utils/scim-filter-parser.js +232 -0
- package/dist/esm/security/scim/utils/scim-filter-parser.js.map +1 -0
- package/dist/esm/security/scim/utils/scim-response-formatter.d.ts +42 -0
- package/dist/esm/security/scim/utils/scim-response-formatter.d.ts.map +1 -0
- package/dist/esm/security/scim/utils/scim-response-formatter.js +89 -0
- package/dist/esm/security/scim/utils/scim-response-formatter.js.map +1 -0
- package/dist/esm/testing.d.ts +31 -0
- package/dist/esm/testing.d.ts.map +1 -0
- package/dist/esm/testing.js +31 -0
- package/dist/esm/testing.js.map +1 -0
- package/dist/esm/users/services/user-self-custom-implementations.backend.d.ts +9 -0
- package/dist/esm/users/services/user-self-custom-implementations.backend.d.ts.map +1 -0
- package/dist/esm/users/services/user-self-custom-implementations.backend.js +48 -0
- package/dist/esm/users/services/user-self-custom-implementations.backend.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +163 -0
- package/src/__tests__/integration/bulk-repository-write-contract.integration.test.ts +373 -0
- package/src/__tests__/integration/custom-batch-job-execution.integration.test.ts +147 -0
- package/src/__tests__/integration/delete-file-rollback-persistence.integration.test.ts +551 -0
- package/src/__tests__/integration/file-management-nested-persistence.integration.test.ts +487 -0
- package/src/__tests__/integration/file-management-postgresql-persistence.integration.test.ts +466 -0
- package/src/__tests__/integration/files-cleanup-persistence.integration.test.ts +335 -0
- package/src/__tests__/integration/generated-bulk-relationship-runtime.integration.test.ts +545 -0
- package/src/__tests__/integration/lifecycle-delete-rollback-persistence.integration.test.ts +537 -0
- package/src/__tests__/integration/postgresql-contextual-filter-enforcement.integration.test.ts +170 -0
- package/src/__tests__/integration/postgresql-delete-best-effort-boundary.integration.test.ts +604 -0
- package/src/__tests__/integration/prompt-compiler.integration.test.ts +723 -0
- package/src/__tests__/integration/relationship-service-semantics.integration.test.ts +2086 -0
- package/src/__tests__/integration/repositories-registry.integration.test.ts +296 -0
- package/src/__tests__/integration/resource-factory-pipeline.integration.test.ts +556 -0
- package/src/__tests__/integration/resource-services.integration.test.ts +265 -0
- package/src/__tests__/integration/resources-registry.integration.test.ts +327 -0
- package/src/__tests__/integration/services-registry.integration.test.ts +231 -0
- package/src/__tests__/integration/update-many-runtime-guards.integration.test.ts +290 -0
- package/src/__tests__/setup.ts +15 -0
- package/src/__tests__/test-container.ts +120 -0
- package/src/applications/models/applications.backend.schemas.ts +18 -0
- package/src/base-classes/__tests__/batches-cronjobs-executor.test.ts +63 -0
- package/src/base-classes/__tests__/bulk-delete-child-file-guard.test.ts +152 -0
- package/src/base-classes/__tests__/bulk-nested-file-update-coordination.test.ts +171 -0
- package/src/base-classes/__tests__/delete-file-coordination.test.ts +185 -0
- package/src/base-classes/__tests__/postgresql-file-transaction-coordination.test.ts +424 -0
- package/src/base-classes/__tests__/postgresql-repository-contextual-filter-enforcement.test.ts +88 -0
- package/src/base-classes/__tests__/repository-contextual-filter-enforcement.test.ts +87 -0
- package/src/base-classes/__tests__/resource-operation-helper-context-enforcement.test.ts +74 -0
- package/src/base-classes/__tests__/transaction-boundaries.test.ts +153 -0
- package/src/base-classes/models/manual-controllers.backend.definition.ts +56 -0
- package/src/base-classes/models/repositories.backend.schemas.ts +105 -0
- package/src/base-classes/services/__tests__/mock-resource-operation-helper.service.ts +61 -0
- package/src/base-classes/services/batches/batches-cronjobs-custom-execution.service.ts +148 -0
- package/src/base-classes/services/batches/batches-cronjobs-executor.backend.service.ts +115 -0
- package/src/base-classes/services/batches/batches-cronjobs-resource-execution.backend.service.ts +58 -0
- package/src/base-classes/services/controllers/__tests__/controller-request-validation.utils.test.ts +292 -0
- package/src/base-classes/services/controllers/__tests__/controller-resource-file-upload-routes.test.ts +1335 -0
- package/src/base-classes/services/controllers/__tests__/controller-resource.version-conflict.test.ts +372 -0
- package/src/base-classes/services/controllers/abstract-controller.backend.service.ts +302 -0
- package/src/base-classes/services/controllers/controller-resource.backend.service.ts +1833 -0
- package/src/base-classes/services/controllers/controllers-registry-handler.backend.service.ts +494 -0
- package/src/base-classes/services/controllers/validate-field-handler.backend.service.ts +613 -0
- package/src/base-classes/services/repositories/__tests__/mock-repositories-registry-handler.service.ts +31 -0
- package/src/base-classes/services/repositories/__tests__/repository-resource.singleton-read.test.ts +50 -0
- package/src/base-classes/services/repositories/postgresql-resource-repository.backend.service.ts +1207 -0
- package/src/base-classes/services/repositories/repositories-registry-handler.backend.service.ts +804 -0
- package/src/base-classes/services/repositories/repository-resource.backend.service.ts +2186 -0
- package/src/base-classes/services/resource-operations-helper.backend.service.ts +468 -0
- package/src/base-classes/services/services/__tests__/mock-services-registry-handler.service.ts +21 -0
- package/src/base-classes/services/services/__tests__/services-registry-handler.notifications.test.ts +65 -0
- package/src/base-classes/services/services/resource-operation-custom-implementation-base.backend.service.ts +305 -0
- package/src/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.ts +224 -0
- package/src/base-classes/services/services/resource-operation-custom-implementation.factory.backend.ts +331 -0
- package/src/base-classes/services/services/services-registry-handler.backend.service.ts +6288 -0
- package/src/base-classes/utils/backend-type-utils.ts +64 -0
- package/src/billing/services/back-office/__tests__/billing-feature-sync.backend.service.test.ts +132 -0
- package/src/billing/services/back-office/__tests__/billing-state.backend.service.test.ts +245 -0
- package/src/billing/services/back-office/__tests__/product-catalog-sync.backend.service.test.ts +238 -0
- package/src/billing/services/back-office/abstract-billing.backend.service.ts +89 -0
- package/src/billing/services/back-office/billing-feature-sync.backend.service.ts +473 -0
- package/src/billing/services/back-office/billing-state.backend.service.ts +348 -0
- package/src/billing/services/back-office/product-catalog-sync.backend.service.ts +415 -0
- package/src/billing/services/back-office/usage-metering.backend.service.ts +326 -0
- package/src/billing/services/billing.utils.ts +26 -0
- package/src/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.ts +342 -0
- package/src/billing/services/custom-impl/billing-custom-impl-utils.backend.ts +274 -0
- package/src/billing/services/custom-impl/billing-custom-implementations.backend.ts +236 -0
- package/src/billing/services/custom-impl/credit-pool.custom-ops.custom-impl.backend.service.ts +133 -0
- package/src/billing/services/custom-impl/promotion.custom-ops.custom-impl.backend.service.ts +242 -0
- package/src/billing/services/custom-impl/subscription.mutations.custom-impl.backend.service.ts +434 -0
- package/src/billing/services/webhooks/billing-webhook-adapter.backend.service.ts +70 -0
- package/src/billing/services/webhooks/billing-webhook-capability-handler.backend.service.ts +46 -0
- package/src/billing/services/webhooks/billing-webhook-event-router.backend.service.ts +727 -0
- package/src/billing/testing/billing-test-fixtures.ts +296 -0
- package/src/billing/testing/mock-billing-provider.ts +548 -0
- package/src/charts/controllers/__tests__/chart.backend.controller.test.ts +403 -0
- package/src/charts/controllers/chart.backend.controller.ts +238 -0
- package/src/charts/services/__tests__/chart-registry.backend.service.test.ts +120 -0
- package/src/charts/services/chart-registry.backend.service.ts +109 -0
- package/src/compliance/audit-trails/audit-logs.custom-impl.backend.service.ts +104 -0
- package/src/compliance/audit-trails/services/__tests__/mock-audit-logs.service.ts +48 -0
- package/src/compliance/audit-trails/services/audit-event-dispatcher.backend.service.ts +325 -0
- package/src/compliance/audit-trails/services/audit-logs.backend.service.ts +1313 -0
- package/src/compliance/audit-trails/services/siem-webhook-delivery.backend.service.ts +542 -0
- package/src/compliance/index.ts +1 -0
- package/src/config/custom/application-config-controller.backend.service.ts +119 -0
- package/src/config/models/__tests__/app-config-secrets.boundaries.test.ts +56 -0
- package/src/config/models/__tests__/app-config.backend-authored.definitions.test.ts +286 -0
- package/src/config/models/app-config-secrets.backend.schemas.ts +154 -0
- package/src/config/models/app-config.backend-authored.definitions.ts +165 -0
- package/src/config/models/app-config.backend.schemas.ts +614 -0
- package/src/config/models/app-env-config.backend.schemas.ts +135 -0
- package/src/config/models/config-mutation-boundary.utils.ts +76 -0
- package/src/config/models/postgresql-env-config.backend.schemas.ts +126 -0
- package/src/config/models/runtime-topology.backend.contracts.ts +42 -0
- package/src/config/services/__tests__/app-configuration-loader.backend.service.test.ts +118 -0
- package/src/config/services/__tests__/app-configuration.backend.service.test.ts +40 -0
- package/src/config/services/__tests__/app-configuration.backend.utils.test.ts +72 -0
- package/src/config/services/__tests__/application-startup-config-validator.backend.service.test.ts +404 -0
- package/src/config/services/__tests__/mock-app-configuration.service.ts +131 -0
- package/src/config/services/app-configuration-loader.backend.service.ts +443 -0
- package/src/config/services/app-configuration.backend.service.ts +570 -0
- package/src/config/services/app-configuration.backend.utils.ts +94 -0
- package/src/config/services/application-startup-config-validator.backend.service.ts +611 -0
- package/src/databases/models/aggregation.backend.schemas.ts +174 -0
- package/src/databases/models/databases.backend.schemas.ts +70 -0
- package/src/databases/models/filter.backend.schemas.ts +101 -0
- package/src/databases/models/sql.backend.schemas.ts +111 -0
- package/src/databases/models/transaction.shared.schemas.ts +172 -0
- package/src/databases/services/__tests__/mock-mongo-transaction-registry.service.ts +90 -0
- package/src/databases/services/__tests__/mock-mongodb.service.ts +86 -0
- package/src/databases/services/__tests__/mock-mongoose-model.service.ts +411 -0
- package/src/databases/services/__tests__/mock-redis.service.ts +72 -0
- package/src/databases/services/__tests__/mock-zod-mongoose-schema-convertor.service.ts +41 -0
- package/src/databases/services/__tests__/mongo-aggregation-compiler.test.ts +918 -0
- package/src/databases/services/__tests__/postgresql-filter.backend.service.test.ts +180 -0
- package/src/databases/services/__tests__/sql-hybrid-transform.test.ts +73 -0
- package/src/databases/services/aggregation/__tests__/aggregation-authorization.backend.service.test.ts +444 -0
- package/src/databases/services/aggregation/__tests__/aggregation-query.backend.service.test.ts +150 -0
- package/src/databases/services/aggregation/__tests__/computed-measure-evaluator.test.ts +525 -0
- package/src/databases/services/aggregation/__tests__/field-access-validator.test.ts +458 -0
- package/src/databases/services/aggregation/__tests__/time-series-densifier.test.ts +631 -0
- package/src/databases/services/aggregation/__tests__/window-function-processor.test.ts +598 -0
- package/src/databases/services/aggregation/aggregation-authorization.backend.service.ts +516 -0
- package/src/databases/services/aggregation/aggregation-query.backend.service.ts +514 -0
- package/src/databases/services/aggregation/computed-measure-evaluator.backend.service.ts +196 -0
- package/src/databases/services/aggregation/field-access-validator.backend.service.ts +225 -0
- package/src/databases/services/aggregation/time-series-densifier.backend.service.ts +389 -0
- package/src/databases/services/aggregation/topn-processor.backend.service.ts +221 -0
- package/src/databases/services/aggregation/window-function-processor.backend.service.ts +301 -0
- package/src/databases/services/db-utils.ts +96 -0
- package/src/databases/services/mongo-aggregation.backend.service.ts +762 -0
- package/src/databases/services/mongodb.service.ts +736 -0
- package/src/databases/services/postgresql-aggregation.backend.service.ts +794 -0
- package/src/databases/services/postgresql-database.backend.service.ts +288 -0
- package/src/databases/services/postgresql-filter.backend.service.ts +673 -0
- package/src/databases/services/redis.service.ts +531 -0
- package/src/databases/services/zod-to-mongoose-schema-convertor.backend.service.ts +2486 -0
- package/src/databases/services/zod-to-sql-hybrid-schema.planner.ts +312 -0
- package/src/errors/services/__tests__/error-builder.backend.service.test.ts +31 -0
- package/src/errors/services/__tests__/error-handler.backend.service.test.ts +82 -0
- package/src/errors/services/__tests__/mock-error-builder.service.ts +288 -0
- package/src/errors/services/error-builder.backend.service.ts +403 -0
- package/src/errors/services/error-handler.backend.service.ts +236 -0
- package/src/errors/services/rate-limit.backend.service.ts +45 -0
- package/src/external-providers/models/external-providers.backend.schemas.ts +243 -0
- package/src/external-providers/services/__tests__/external-providers-registry.backend.service.test.ts +136 -0
- package/src/external-providers/services/__tests__/feature-bindings.backend.service.test.ts +40 -0
- package/src/external-providers/services/__tests__/mock-external-providers-registry.service.ts +33 -0
- package/src/external-providers/services/__tests__/mock-lazy-provider-registry.service.ts +45 -0
- package/src/external-providers/services/external-api-handler.backend.service.ts +19 -0
- package/src/external-providers/services/external-providers-registry.backend.service.ts +534 -0
- package/src/external-providers/services/feature-bindings.backend.service.ts +422 -0
- package/src/external-providers/services/lazy-provider-registry.backend.service.ts +486 -0
- package/src/features/__tests__/feature-builders.test.ts +152 -0
- package/src/features/controllers/__tests__/features.backend.controller.test.ts +173 -0
- package/src/features/controllers/features.backend.controller.ts +200 -0
- package/src/features/services/__tests__/feature-definition-registry.backend.service.test.ts +152 -0
- package/src/features/services/__tests__/feature-gate.test.ts +484 -0
- package/src/features/services/__tests__/feature-resolution.backend.service.test.ts +203 -0
- package/src/features/services/__tests__/mock-capability-bindings.service.ts +26 -0
- package/src/features/services/__tests__/mock-feature-definition-registry.service.ts +56 -0
- package/src/features/services/__tests__/mock-feature-resolution.service.ts +36 -0
- package/src/features/services/feature-definition-registry.backend.service.ts +537 -0
- package/src/features/services/feature-gate.backend.service.ts +522 -0
- package/src/features/services/feature-resolution.backend.service.ts +652 -0
- package/src/features/testing/feature-test-utils.ts +200 -0
- package/src/files/batches/__tests__/files-cleanup.batch.backend.service.test.ts +186 -0
- package/src/files/batches/files-cleanup.batch.backend.service.ts +259 -0
- package/src/files/constraints/file-analyzers.types.ts +85 -0
- package/src/files/constraints/file-constraint-resolver-chain.backend.service.ts +99 -0
- package/src/files/constraints/file-constraint.types.ts +104 -0
- package/src/files/constraints/file-validation.backend.service.ts +359 -0
- package/src/files/constraints/resource-field-constraint-resolver.backend.service.ts +138 -0
- package/src/files/controllers/__tests__/file.controller.behavior.test.ts +655 -0
- package/src/files/controllers/file.controller.ts +1030 -0
- package/src/files/handlers/__tests__/resource-file-upload-handler.backend.service.test.ts +392 -0
- package/src/files/handlers/resource-file-upload-handler.backend.service.ts +605 -0
- package/src/files/rag/weaviate-vector-store.backend.service.ts +271 -0
- package/src/files/scanning/clamav-scanner.backend.service.ts +214 -0
- package/src/files/scanning/file-scan.types.ts +17 -0
- package/src/files/scanning/yara-scanner.backend.service.ts +212 -0
- package/src/files/services/__tests__/file-field-detection.backend.service.test.ts +91 -0
- package/src/files/services/__tests__/file-operation-handler.backend.service.test.ts +272 -0
- package/src/files/services/__tests__/file-population.backend.service.test.ts +120 -0
- package/src/files/services/__tests__/file-scanning.backend.service.test.ts +163 -0
- package/src/files/services/__tests__/files.backend.service.test.ts +885 -0
- package/src/files/services/__tests__/mock-file-field-detection.service.ts +43 -0
- package/src/files/services/__tests__/mock-file-operation-handler.service.ts +113 -0
- package/src/files/services/__tests__/mock-file-repository.service.ts +104 -0
- package/src/files/services/file-field-detection.backend.service.ts +156 -0
- package/src/files/services/file-operation-handler.backend.service.ts +861 -0
- package/src/files/services/file-population.backend.service.ts +485 -0
- package/src/files/services/file-rag-indexing.backend.service.ts +229 -0
- package/src/files/services/file-scanning.backend.service.ts +373 -0
- package/src/files/services/file-text-extraction.backend.service.ts +193 -0
- package/src/files/services/files.backend.service.ts +1356 -0
- package/src/files/storage/file-storage-path-resolver.backend.service.ts +289 -0
- package/src/files/storage/file-storage-provider.types.ts +188 -0
- package/src/files/storage/file-storage-router.backend.service.ts +172 -0
- package/src/files/storage/local-directory-storage-provider.backend.service.ts +417 -0
- package/src/files/storage/wildo-managed-storage-provider.backend.service.ts +530 -0
- package/src/files/utils/__tests__/file-field-schema-path.backend.utils.test.ts +44 -0
- package/src/files/utils/__tests__/file-uploader.utils.test.ts +57 -0
- package/src/files/utils/__tests__/file-validation.utils.test.ts +559 -0
- package/src/files/utils/file-field-schema-path.backend.utils.ts +385 -0
- package/src/files/utils/file-upload.utils.ts +146 -0
- package/src/files/utils/file-uploader.utils.ts +65 -0
- package/src/files/utils/file-validation.utils.ts +753 -0
- package/src/flows-actors/agent-catalogs.backend.ts +427 -0
- package/src/flows-actors/controllers/flows-actors.controller.ts +91 -0
- package/src/flows-actors/models/agent-catalogs.backend.definitions.ts +430 -0
- package/src/flows-actors/models/agent-facets.backend.definitions.ts +120 -0
- package/src/flows-actors/models/agents.backend.definitions.ts +4 -0
- package/src/flows-actors/models/core-facets.backend.definitions.ts +348 -0
- package/src/flows-actors/models/flows-actors.backend.definitions.ts +13 -0
- package/src/flows-actors/models/flows-actors.backend.schemas.ts +44 -0
- package/src/flows-actors/services/__tests__/agent-facets-catalogs.test.ts +544 -0
- package/src/flows-actors/services/__tests__/agents.backend.service.cli-runtime.test.ts +234 -0
- package/src/flows-actors/services/actors-system.backend.service.ts +270 -0
- package/src/flows-actors/services/agent-facets.backend.service.ts +350 -0
- package/src/flows-actors/services/agents.backend.service.ts +2730 -0
- package/src/flows-actors/services/context-curation.backend.service.ts +203 -0
- package/src/flows-actors/services/flows-actors-registry.service.ts +374 -0
- package/src/flows-actors/services/flows.backend.services.ts +237 -0
- package/src/flows-actors/services/prompt-compiler.backend.service.ts +734 -0
- package/src/flows-actors/utils/__tests__/cli-runtime-operation-support.backend.utils.test.ts +95 -0
- package/src/flows-actors/utils/cli-runtime-operation-support.backend.utils.ts +87 -0
- package/src/flows-actors/utils/cli-runtime-runner.backend.utils.ts +171 -0
- package/src/flows-actors/utils/flows-actors-frontend-extractor.utils.ts +63 -0
- package/src/flows-actors/utils/prompt-ir-adapters.backend.utils.ts +257 -0
- package/src/guidance/batches/dormancy-detection.batch.backend.service.ts +126 -0
- package/src/guidance/services/__tests__/guidance-trigger-evaluator.backend.service.test.ts +49 -0
- package/src/guidance/services/__tests__/lifecycle-evaluator.backend.service.test.ts +85 -0
- package/src/guidance/services/__tests__/milestone-definition-registry.backend.service.test.ts +211 -0
- package/src/guidance/services/__tests__/milestone-evaluator.backend.service.test.ts +561 -0
- package/src/guidance/services/guidance-trigger-evaluator.backend.service.ts +151 -0
- package/src/guidance/services/lifecycle-custom-implementations.backend.ts +139 -0
- package/src/guidance/services/lifecycle-evaluator.backend.service.ts +908 -0
- package/src/guidance/services/milestone-condition-registry.backend.service.ts +57 -0
- package/src/guidance/services/milestone-definition-registry.backend.service.ts +265 -0
- package/src/guidance/services/milestone-evaluator.backend.service.ts +611 -0
- package/src/i18n/controllers/i18n-controller.backend.service.ts +227 -0
- package/src/i18n/services/i18n.backend.service.ts +88 -0
- package/src/index.ts +286 -0
- package/src/inject/models/container.ts +586 -0
- package/src/inject/models/service-types.ts +488 -0
- package/src/monitoring/analytics/controllers/analytics.backend.controller.ts +114 -0
- package/src/monitoring/analytics/services/value-moment-engine.backend.service.ts +53 -0
- package/src/monitoring/analytics/services/value-moment-handler-registry.backend.service.ts +38 -0
- package/src/monitoring/logger/middleware/logging.middleware.ts +40 -0
- package/src/monitoring/logger/models/logger.backend.schemas.ts +56 -0
- package/src/monitoring/logger/services/__tests__/mock-logger.service.ts +49 -0
- package/src/monitoring/logger/services/logger.service.ts +214 -0
- package/src/monitoring/observability/middleware/metrics.middleware.ts +205 -0
- package/src/monitoring/observability/middleware/telemetry.middleware.ts +188 -0
- package/src/monitoring/observability/middleware/tracing.middleware.ts +265 -0
- package/src/monitoring/observability/models/observability.backend.schemas.ts +96 -0
- package/src/monitoring/observability/services/instrumentations/custom.instrumentations.ts +132 -0
- package/src/monitoring/observability/services/metrics.service.ts +266 -0
- package/src/monitoring/observability/services/telemetry.service.ts +157 -0
- package/src/monitoring/observability/services/tracer.service.ts +334 -0
- package/src/notifications/email/components/email-components.ts +341 -0
- package/src/notifications/email/models/email-context-provider.interface.ts +107 -0
- package/src/notifications/email/models/email-template-definition.ts +74 -0
- package/src/notifications/email/models/email-template.actors-system.backend.definitions.ts +80 -0
- package/src/notifications/email/models/email.backend.scheamas.ts +0 -0
- package/src/notifications/email/services/email-batch-send.batch.backend.service.ts +236 -0
- package/src/notifications/email/services/email-context-provider-registry.backend.service.ts +157 -0
- package/src/notifications/email/services/email-renderer.backend.service.ts +274 -0
- package/src/notifications/email/services/email-template-compiler.backend.service.ts +136 -0
- package/src/notifications/email/services/email-template-generation.backend.service.ts +811 -0
- package/src/notifications/email/services/email-template-registry.backend.service.ts +166 -0
- package/src/notifications/email/services/email-template-sandbox.backend.service.ts +255 -0
- package/src/notifications/email/services/email-template-validator.backend.service.ts +229 -0
- package/src/notifications/email/services/email.backend.service.ts +429 -0
- package/src/notifications/email/utils/color-conversion.utils.ts +142 -0
- package/src/notifications/email/utils/interpolate-email-label.utils.ts +16 -0
- package/src/notifications/email/utils/zod-to-typescript.utils.ts +352 -0
- package/src/notifications/services/__tests__/notifications-dispatcher.operation-semantics.test.ts +773 -0
- package/src/notifications/services/__tests__/notifications-dispatcher.websocket-integration.test.ts +173 -0
- package/src/notifications/services/notification-badge.backend.service.ts +412 -0
- package/src/notifications/services/notifications-dispatcher.backend.service.ts +1696 -0
- package/src/notifications/sms/services/sms.backend.service.ts +283 -0
- package/src/notifications/webhooks/controllers/webhook-auto-controller.backend.service.ts +220 -0
- package/src/notifications/webhooks/services/polymorphic-lookup.backend.service.ts +131 -0
- package/src/notifications/webhooks/services/webhook-handler.backend.service.ts +481 -0
- package/src/organizations/services/__tests__/org-creation-on-registration.backend.utils.test.ts +193 -0
- package/src/organizations/services/__tests__/org-member-roles-validation.backend.utils.test.ts +101 -0
- package/src/organizations/services/__tests__/organization-custom-implementation.backend.service.test.ts +113 -0
- package/src/organizations/services/__tests__/scim-provisioning-gate.backend.utils.test.ts +94 -0
- package/src/organizations/services/__tests__/user-org-type-grant.backend.utils.test.ts +164 -0
- package/src/organizations/services/__tests__/user-type-revocation-on-org-leave.backend.utils.test.ts +161 -0
- package/src/organizations/services/org-creation-on-registration.backend.utils.ts +119 -0
- package/src/organizations/services/org-member-roles-validation.backend.utils.ts +51 -0
- package/src/organizations/services/organization-custom-implementation.backend.service.ts +106 -0
- package/src/organizations/services/organization-member-custom-implementation.backend.service.ts +150 -0
- package/src/organizations/services/scim-provisioning-gate.backend.utils.ts +34 -0
- package/src/organizations/services/user-org-type-grant.backend.utils.ts +49 -0
- package/src/organizations/services/user-type-revocation-on-org-leave.backend.utils.ts +102 -0
- package/src/queue/adapters/rabbitmq-adapter.backend.service.ts +494 -0
- package/src/queue/apps-crontabs-manager.backend.service.ts +258 -0
- package/src/queue/cron-job-sync.backend.service.ts +184 -0
- package/src/queue/domain-queue-consumer.backend.service.ts +333 -0
- package/src/queue/job-completion-registry.backend.service.ts +342 -0
- package/src/queue/job-consumer.backend.service.ts +646 -0
- package/src/queue/job-executor.backend.service.ts +315 -0
- package/src/queue/job-payload-storage.backend.service.ts +297 -0
- package/src/queue/job-status-tracking.backend.service.ts +376 -0
- package/src/queue/queue-monitoring.backend.service.ts +333 -0
- package/src/queue/queue-worker-initializer.backend.service.ts +179 -0
- package/src/queue/queue.backend.service.ts +530 -0
- package/src/queue/scheduled-message-verifier.backend.service.ts +228 -0
- package/src/queue/worker-shutdown-manager.backend.service.ts +298 -0
- package/src/requests/models/api-routes.backend.defintions.ts +45 -0
- package/src/requests/models/requests.backend.schemas.ts +73 -0
- package/src/requests/service/__tests__/websocket.service.auth-refresh.test.ts +361 -0
- package/src/requests/service/__tests__/websocket.service.resource-room-validation.test.ts +234 -0
- package/src/requests/service/__tests__/websocket.service.variant-authorization.test.ts +94 -0
- package/src/requests/service/platform-mutualized-handler.backend.service.ts +19 -0
- package/src/requests/service/platform-requests.backend.utils.ts +54 -0
- package/src/requests/service/remote-client-base.backend.service.ts +485 -0
- package/src/requests/service/serverless-services-handler.backend.service.ts +19 -0
- package/src/requests/service/websocket.service.ts +2844 -0
- package/src/resources/models/custom-service-implementations.backend.definition.ts +22 -0
- package/src/resources/models/index.ts +7 -0
- package/src/resources/models/resources-operations.backend.definitions.ts +9 -0
- package/src/resources/models/resources-relationships.backend.definitions.ts +30 -0
- package/src/resources/models/resources-types.backend.schemas.ts +14 -0
- package/src/resources/models/resources.backend.schemas.ts +6 -0
- package/src/resources/models/virtual-fields.backend.types.ts +132 -0
- package/src/resources/services/__tests__/mock-resources-registry.service.ts +69 -0
- package/src/resources/services/__tests__/resource-id.backend.service.test.ts +69 -0
- package/src/resources/services/resource-context.backend.service.ts +1107 -0
- package/src/resources/services/resource-id.backend.service.ts +280 -0
- package/src/resources/services/resource-population.backend.service.ts +761 -0
- package/src/resources/services/resources-registry.backend.service.ts +1126 -0
- package/src/resources/services/virtual-fields.backend.service.ts +303 -0
- package/src/runtime/__tests__/execution-context-creator.backend.service.test.ts +469 -0
- package/src/runtime/controllers/health-controller.backend.service.ts +297 -0
- package/src/runtime/domain-module.backend.definitions.test.ts +83 -0
- package/src/runtime/domain-module.backend.definitions.ts +161 -0
- package/src/runtime/models/execution-context.backend.schemas.ts +456 -0
- package/src/runtime/models/runtime.backend.schemas.ts +82 -0
- package/src/runtime/services/execution-context-creator.backend.service.ts +2102 -0
- package/src/runtime/services/execution-context-handler.backend.service.ts +224 -0
- package/src/runtime/services/health-readiness-contributor.backend.interface.ts +11 -0
- package/src/runtime/services/http-server.backend.service.ts +870 -0
- package/src/runtime/services/start-application.backend.service.ts +1109 -0
- package/src/runtime/testing/execution-context-test-fixtures.ts +14 -0
- package/src/runtime/testing/mock-execution-context-creator.service.ts +46 -0
- package/src/runtime/utils/scan-default-exports.backend.utils.ts +247 -0
- package/src/security/authentications/__tests__/auth-registration.test.ts +338 -0
- package/src/security/authentications/__tests__/authentication-controller.test.ts +31 -0
- package/src/security/authentications/__tests__/authentication-orchestrator.test.ts +27 -0
- package/src/security/authentications/__tests__/saml-assertion-validator.test.ts +631 -0
- package/src/security/authentications/__tests__/saml-authentication.test.ts +126 -0
- package/src/security/authentications/__tests__/saml-integration-test-helpers.test.ts +234 -0
- package/src/security/authentications/__tests__/saml-metadata.test.ts +185 -0
- package/src/security/authentications/__tests__/saml-replay-guard.test.ts +99 -0
- package/src/security/authentications/__tests__/saml-sso-flow.integration.test.ts +355 -0
- package/src/security/authentications/__tests__/saml-test-fixtures.test.ts +433 -0
- package/src/security/authentications/__tests__/saml-test-parser.test.ts +117 -0
- package/src/security/authentications/__tests__/sso-connection-custom-ops.integration.test.ts +236 -0
- package/src/security/authentications/batches/anonymous-session-cleanup.batch.backend.service.ts +71 -0
- package/src/security/authentications/controllers/auth-method-management-controller.backend.service.ts +205 -0
- package/src/security/authentications/controllers/authentication-controller.backend.service.ts +2712 -0
- package/src/security/authentications/models/auth-constants.backend.ts +141 -0
- package/src/security/authentications/models/authentications.backend.schemas.ts +106 -0
- package/src/security/authentications/models/jwt.backend.schemas.ts +107 -0
- package/src/security/authentications/models/oauth2-connection.backend.schemas.ts +196 -0
- package/src/security/authentications/models/saml-authentication.backend.schemas.ts +124 -0
- package/src/security/authentications/models/sso-connection.backend.schemas.ts +104 -0
- package/src/security/authentications/services/__tests__/mock-auth-execution-context-factory.service.ts +73 -0
- package/src/security/authentications/services/__tests__/mock-auth-token-issuer.service.ts +46 -0
- package/src/security/authentications/services/admin-config/__tests__/mock-domain-to-org-lookup.service.ts +40 -0
- package/src/security/authentications/services/admin-config/__tests__/mock-enterprise-user-provisioning.service.ts +67 -0
- package/src/security/authentications/services/admin-config/auth-organization-configuration.service.ts +424 -0
- package/src/security/authentications/services/admin-config/domain-to-org-lookup.backend.service.ts +244 -0
- package/src/security/authentications/services/admin-config/domain-verification.backend.service.ts +215 -0
- package/src/security/authentications/services/admin-config/enterprise-user-provisioning.backend.service.ts +509 -0
- package/src/security/authentications/services/admin-config/oidc-discovery.backend.service.ts +250 -0
- package/src/security/authentications/services/anonymous-session.backend.service.ts +442 -0
- package/src/security/authentications/services/auth-credential-verifier.backend.service.ts +147 -0
- package/src/security/authentications/services/auth-execution-context-factory.backend.service.ts +132 -0
- package/src/security/authentications/services/auth-methods/auth-method-management.backend.service.ts +532 -0
- package/src/security/authentications/services/auth-methods/auth-mfa.backend.service.ts +141 -0
- package/src/security/authentications/services/auth-methods/auth-password-reset.backend.service.ts +215 -0
- package/src/security/authentications/services/auth-methods/auth-phone-verification.backend.service.ts +136 -0
- package/src/security/authentications/services/auth-methods/auth-registration.backend.service.ts +994 -0
- package/src/security/authentications/services/auth-methods/oauth2-authentication.backend.service.ts +1210 -0
- package/src/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service.ts +903 -0
- package/src/security/authentications/services/auth-methods/saml-assertion-validator.backend.service.ts +791 -0
- package/src/security/authentications/services/auth-methods/saml-authentication.backend.service.ts +1727 -0
- package/src/security/authentications/services/auth-methods/saml-metadata.backend.service.ts +432 -0
- package/src/security/authentications/services/auth-methods/saml-replay-guard.backend.service.ts +90 -0
- package/src/security/authentications/services/auth-methods/webauthn.backend.service.ts +393 -0
- package/src/security/authentications/services/auth-session-store.backend.service.ts +211 -0
- package/src/security/authentications/services/auth-token-issuer.backend.service.ts +496 -0
- package/src/security/authentications/services/authentication-orchestrator.backend.service.ts +3156 -0
- package/src/security/authentications/services/custom-impls/auth-custom-implementations.backend.ts +88 -0
- package/src/security/authentications/services/custom-impls/auth-policy.custom-impl.backend.service.ts +54 -0
- package/src/security/authentications/services/custom-impls/scim-provisioning-config.custom-impl.backend.service.ts +167 -0
- package/src/security/authentications/services/custom-impls/scim-tokens.custom-impl.backend.service.ts +136 -0
- package/src/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.ts +123 -0
- package/src/security/authentications/services/custom-impls/siem-export-config.custom-impl.backend.service.ts +161 -0
- package/src/security/authentications/services/custom-impls/sso-config.custom-impl.backend.service.ts +185 -0
- package/src/security/authentications/services/custom-impls/sso-connection.custom-impl.backend.service.ts +792 -0
- package/src/security/authentications/services/utils/__tests__/mock-auth-user-lookup.service.ts +62 -0
- package/src/security/authentications/services/utils/auth-controller.utils.ts +51 -0
- package/src/security/authentications/services/utils/auth-credential-ops.backend.service.ts +202 -0
- package/src/security/authentications/services/utils/auth-response-helper.backend.service.ts +38 -0
- package/src/security/authentications/services/utils/auth-user-lookup.backend.service.ts +128 -0
- package/src/security/authentications/services/utils/saml-java-availability.ts +64 -0
- package/src/security/authorizations/__tests__/authorizations.backend.service.test.ts +82 -0
- package/src/security/authorizations/services/authorizations.backend.service.ts +934 -0
- package/src/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.ts +168 -0
- package/src/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.ts +92 -0
- package/src/security/consumable-tokens/models/consumable-tokens.shared.schemas.ts +86 -0
- package/src/security/consumable-tokens/models/index.ts +3 -0
- package/src/security/consumable-tokens/services/__tests__/mock-consumable-token.service.ts +63 -0
- package/src/security/consumable-tokens/services/consumable-token.backend.service.ts +568 -0
- package/src/security/jwt/services/auth-jwt-guard.backend.service.ts +137 -0
- package/src/security/jwt/services/jwt.backend.service.ts +397 -0
- package/src/security/scim/__tests__/scim-filter-parser.test.ts +121 -0
- package/src/security/scim/controllers/scim.backend.controller.ts +1066 -0
- package/src/security/scim/models/scim-protocol.backend.schemas.ts +258 -0
- package/src/security/scim/utils/scim-filter-parser.ts +289 -0
- package/src/security/scim/utils/scim-response-formatter.ts +122 -0
- package/src/testing.ts +30 -0
- package/src/types/xmldom.d.ts +9 -0
- package/src/users/services/user-self-custom-implementations.backend.ts +62 -0
|
@@ -0,0 +1,4015 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import 'reflect-metadata';
|
|
14
|
+
import { injectable, inject, optional } from 'inversify';
|
|
15
|
+
import { CoreResourceOperation, CoreResourceType, DEFAULT_PERSISTENCE_ADAPTER, ResourcesConfig_OperationPathUtils, ErrorType, ErrorCustomMessageReference, ResourceOperationVariantType, ResourceOperationsUtils, DataMode, OPERATION_VARIANT_KEY, ChildLifecycleMode, ResourceOperation_ServiceRuntimeMode, ExecutionContext_ExecutionType, CoreConsumableTokenTypes, isWildoBackendError, Resources_SharedUtils, ResourceRelationshipBulkAction, ResourceRelationshipBulkActionRequestSchema, ResourceRelationshipBulkClearOperationRequestSchema, ResourceRelationshipBulkCreateOperationRequestSchema, ResourceRelationshipBulkLinkOperationRequestSchema, ResourceRelationshipBulkReplaceOperationRequestSchema, ResourceRelationshipBulkSetOperationRequestSchema, ResourceRelationshipBulkUnlinkOperationRequestSchema, } from '@wildo-ai/saas-models';
|
|
16
|
+
import { SAAS_SERVICE_TYPES } from '../../../inject/models/service-types.js';
|
|
17
|
+
import { RepositoriesRegistryHandlerBackendService } from '../../../base-classes/services/repositories/repositories-registry-handler.backend.service.js';
|
|
18
|
+
import { ResourceOperationHelperBackendService } from '../../../base-classes/services/resource-operations-helper.backend.service.js';
|
|
19
|
+
import { extractFunctionContextNeeds, dataModeToVariantKey, } from '@wildo-ai/saas-models';
|
|
20
|
+
import { LoggerService } from '../../../monitoring/logger/services/logger.service.js';
|
|
21
|
+
import { ErrorBuilderBackendService } from '../../../errors/services/error-builder.backend.service.js';
|
|
22
|
+
import { z } from 'zod';
|
|
23
|
+
import { PlatformMutualizedHandlerBackendService } from '../../../requests/service/platform-mutualized-handler.backend.service.js';
|
|
24
|
+
import { ResourcesRegistryBackendService } from '../../../resources/services/resources-registry.backend.service.js';
|
|
25
|
+
import { ExternalApiHandlerBackendService } from '../../../external-providers/services/external-api-handler.backend.service.js';
|
|
26
|
+
import { ResourceOperationCustomImplementationRegistryBackendService } from './resource-operation-custom-implementation-registry.backend.service.js';
|
|
27
|
+
import { ServerlessServicesHandlerBackendService } from '../../../requests/service/serverless-services-handler.backend.service.js';
|
|
28
|
+
import { ResourceOperation_CustomServiceImplementationMode } from '@wildo-ai/saas-models';
|
|
29
|
+
import { NotificationDispatcherService } from '../../../notifications/services/notifications-dispatcher.backend.service.js';
|
|
30
|
+
import { ResourcePopulationBackendService } from '../../../resources/services/resource-population.backend.service.js';
|
|
31
|
+
import { VirtualFieldsBackendService } from '../../../resources/services/virtual-fields.backend.service.js';
|
|
32
|
+
import { MongoDBService } from '../../../databases/services/mongodb.service.js';
|
|
33
|
+
import { PostgreSQLDatabaseBackendService } from '../../../databases/services/postgresql-database.backend.service.js';
|
|
34
|
+
import { ResourceParentResourceRequirement, isOneToOneCardinality, getChildDirectionRelationships } from '@wildo-ai/saas-models';
|
|
35
|
+
import { FileOperationHandlerBackendService } from '../../../files/services/file-operation-handler.backend.service.js';
|
|
36
|
+
import { FileFieldDetectionBackendService } from '../../../files/services/file-field-detection.backend.service.js';
|
|
37
|
+
import { hasExplicitCanonicalFieldMutation } from '../../../files/utils/file-field-schema-path.backend.utils.js';
|
|
38
|
+
import { ExecutionContextCreatorBackendService } from '../../../runtime/services/execution-context-creator.backend.service.js';
|
|
39
|
+
import { QueueBackendService } from '../../../queue/queue.backend.service.js';
|
|
40
|
+
import { FeatureGateBackendService } from '../../../features/services/feature-gate.backend.service.js';
|
|
41
|
+
import { ConsumableTokenBackendService } from '../../../security/consumable-tokens/services/consumable-token.backend.service.js';
|
|
42
|
+
import { AppConfigurationService } from '../../../config/services/app-configuration.backend.service.js';
|
|
43
|
+
import { GuidanceTriggerEvaluatorBackendService } from '../../../guidance/services/guidance-trigger-evaluator.backend.service.js';
|
|
44
|
+
import { MilestoneEvaluatorBackendService } from '../../../guidance/services/milestone-evaluator.backend.service.js';
|
|
45
|
+
import { LifecycleEvaluatorBackendService } from '../../../guidance/services/lifecycle-evaluator.backend.service.js';
|
|
46
|
+
export async function dispatchPostOperationNotificationsBestEffort(deps, executionContext, inputData, currentResult, tokenGenerationResult) {
|
|
47
|
+
const resourceRoomParameters = {
|
|
48
|
+
inputDto: inputData,
|
|
49
|
+
currentObject: currentResult,
|
|
50
|
+
initiatorIds: executionContext.initiatorIds,
|
|
51
|
+
};
|
|
52
|
+
try {
|
|
53
|
+
// Resource-room notifications run first and on thinner inputs on purpose:
|
|
54
|
+
// websocket coherence only needs authoritative object truth + initiator ids,
|
|
55
|
+
// not the richer population/user context required by authored notifications.
|
|
56
|
+
await deps.notificationDispatcher.dispatchResourceRoomNotifications(executionContext, resourceRoomParameters);
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
deps.logger.error('Failed to dispatch resource-room notifications', {
|
|
60
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
61
|
+
operationIdentifier: executionContext.operation.operationIdentifier,
|
|
62
|
+
resourceIdentifier: executionContext.operation.resourceIdentifier,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
// Configured notifications are the richer second phase. They may depend on
|
|
67
|
+
// populated object context, user context, and additional authored delivery
|
|
68
|
+
// channels, so they intentionally run after the lightweight websocket pass.
|
|
69
|
+
const resourceType = executionContext.operation.resourceIdentifier;
|
|
70
|
+
const needs = deps.populationService.analyzeContextNeeds(resourceType);
|
|
71
|
+
const computationContext = await deps.populationService.fetchComputationContext(resourceType, currentResult, needs, executionContext);
|
|
72
|
+
const functionParameters = {
|
|
73
|
+
inputDto: inputData,
|
|
74
|
+
currentObject: currentResult,
|
|
75
|
+
objectContext: computationContext.objectContext,
|
|
76
|
+
initiatorUserContext: computationContext.userContext,
|
|
77
|
+
initiatorIds: executionContext.initiatorIds,
|
|
78
|
+
};
|
|
79
|
+
if (tokenGenerationResult) {
|
|
80
|
+
functionParameters.additionalContext = {
|
|
81
|
+
...(functionParameters.additionalContext || {}),
|
|
82
|
+
tokenValue: tokenGenerationResult.tokenValue,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
await deps.notificationDispatcher.dispatchConfiguredNotifications(executionContext, functionParameters);
|
|
86
|
+
deps.logDebug('Configured notifications dispatched successfully');
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
deps.logger.error('Failed to dispatch configured notifications', {
|
|
90
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
91
|
+
operationIdentifier: executionContext.operation.operationIdentifier,
|
|
92
|
+
resourceIdentifier: executionContext.operation.resourceIdentifier,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
let ServicesRegistryHandlerBackendService = class ServicesRegistryHandlerBackendService {
|
|
97
|
+
repositoriesRegistry;
|
|
98
|
+
logger;
|
|
99
|
+
errorBuilder;
|
|
100
|
+
resourcesRegistry;
|
|
101
|
+
repositoryHelper;
|
|
102
|
+
customImplRegistry;
|
|
103
|
+
externalApiHandler;
|
|
104
|
+
platformMutualizedHandler;
|
|
105
|
+
serverlessServicesHandler;
|
|
106
|
+
notificationDispatcher;
|
|
107
|
+
populationService;
|
|
108
|
+
virtualFieldsService;
|
|
109
|
+
mongoDBService;
|
|
110
|
+
fileOperationHandler;
|
|
111
|
+
fileFieldDetection;
|
|
112
|
+
executionContextCreator;
|
|
113
|
+
queueService;
|
|
114
|
+
featureGate;
|
|
115
|
+
consumableTokenService;
|
|
116
|
+
appConfigService;
|
|
117
|
+
guidanceTriggerEvaluator;
|
|
118
|
+
milestoneEvaluator;
|
|
119
|
+
lifecycleEvaluator;
|
|
120
|
+
postgreSQLDatabaseService;
|
|
121
|
+
samlMetadataService;
|
|
122
|
+
services;
|
|
123
|
+
serviceOperationsMap;
|
|
124
|
+
isInitialized = false;
|
|
125
|
+
logDebug;
|
|
126
|
+
/**
|
|
127
|
+
* Post-operation hooks: fire after a successful mutation on a resource type.
|
|
128
|
+
* Key = resource type identifier, Value = array of hook callbacks.
|
|
129
|
+
*/
|
|
130
|
+
postOperationHooks = new Map();
|
|
131
|
+
constructor(repositoriesRegistry, logger, errorBuilder, resourcesRegistry, repositoryHelper, customImplRegistry, externalApiHandler, platformMutualizedHandler, serverlessServicesHandler, notificationDispatcher, populationService, virtualFieldsService, mongoDBService, fileOperationHandler, fileFieldDetection, executionContextCreator, queueService, featureGate, consumableTokenService, appConfigService, guidanceTriggerEvaluator, milestoneEvaluator, lifecycleEvaluator, postgreSQLDatabaseService, samlMetadataService) {
|
|
132
|
+
this.repositoriesRegistry = repositoriesRegistry;
|
|
133
|
+
this.logger = logger;
|
|
134
|
+
this.errorBuilder = errorBuilder;
|
|
135
|
+
this.resourcesRegistry = resourcesRegistry;
|
|
136
|
+
this.repositoryHelper = repositoryHelper;
|
|
137
|
+
this.customImplRegistry = customImplRegistry;
|
|
138
|
+
this.externalApiHandler = externalApiHandler;
|
|
139
|
+
this.platformMutualizedHandler = platformMutualizedHandler;
|
|
140
|
+
this.serverlessServicesHandler = serverlessServicesHandler;
|
|
141
|
+
this.notificationDispatcher = notificationDispatcher;
|
|
142
|
+
this.populationService = populationService;
|
|
143
|
+
this.virtualFieldsService = virtualFieldsService;
|
|
144
|
+
this.mongoDBService = mongoDBService;
|
|
145
|
+
this.fileOperationHandler = fileOperationHandler;
|
|
146
|
+
this.fileFieldDetection = fileFieldDetection;
|
|
147
|
+
this.executionContextCreator = executionContextCreator;
|
|
148
|
+
this.queueService = queueService;
|
|
149
|
+
this.featureGate = featureGate;
|
|
150
|
+
this.consumableTokenService = consumableTokenService;
|
|
151
|
+
this.appConfigService = appConfigService;
|
|
152
|
+
this.guidanceTriggerEvaluator = guidanceTriggerEvaluator;
|
|
153
|
+
this.milestoneEvaluator = milestoneEvaluator;
|
|
154
|
+
this.lifecycleEvaluator = lifecycleEvaluator;
|
|
155
|
+
this.postgreSQLDatabaseService = postgreSQLDatabaseService;
|
|
156
|
+
this.samlMetadataService = samlMetadataService;
|
|
157
|
+
this.logger = logger;
|
|
158
|
+
this.errorBuilder = errorBuilder;
|
|
159
|
+
this.services = new Map();
|
|
160
|
+
this.serviceOperationsMap = new Map();
|
|
161
|
+
this.logDebug = this.logger.debugByType('ServicesRegistryHandler');
|
|
162
|
+
this.logger.setDebugTypeLogging('ServicesRegistryHandler', false);
|
|
163
|
+
this.logDebug('Services registry service created');
|
|
164
|
+
}
|
|
165
|
+
/** Exposes SAML metadata service for custom impl utils (DISCOVER_ENDPOINTS). */
|
|
166
|
+
getSamlMetadataService() {
|
|
167
|
+
return this.samlMetadataService;
|
|
168
|
+
}
|
|
169
|
+
// ================================
|
|
170
|
+
// Initialization Methods
|
|
171
|
+
// ================================
|
|
172
|
+
async initializeServices() {
|
|
173
|
+
if (this.isInitialized) {
|
|
174
|
+
this.logDebug('Registry already initialized, skipping...');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const resourceTypes = this.resourcesRegistry.getResourceTypes();
|
|
178
|
+
this.logDebug('Initializing services', { resourceCount: resourceTypes.length, resourceTypes: resourceTypes });
|
|
179
|
+
// First pass: Create all services
|
|
180
|
+
for (const resourceType of resourceTypes) {
|
|
181
|
+
try {
|
|
182
|
+
await this.createService(resourceType);
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
throw this.errorBuilder.buildError(ErrorType.INTERNAL, undefined, { customMessageReference: ErrorCustomMessageReference.SERVICE_CREATION_FAILED, context: { resourceType, error: error instanceof Error ? error.message : 'Unknown error' } });
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
this.buildOperationPathsMap();
|
|
189
|
+
this.isInitialized = true;
|
|
190
|
+
this.logDebug('Services registry initialization completed', {
|
|
191
|
+
serviceCount: this.services.size,
|
|
192
|
+
operationPathsCount: this.serviceOperationsMap.size
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
async createService(resourceType) {
|
|
196
|
+
this.logDebug('Creating service', { resourceType });
|
|
197
|
+
const service = ServiceResourceBackendService.createInstance(resourceType, this.logger, this.errorBuilder, this.repositoriesRegistry, this, this.resourcesRegistry, this.repositoryHelper, this.customImplRegistry, this.externalApiHandler, this.platformMutualizedHandler, this.serverlessServicesHandler, this.notificationDispatcher, this.populationService, this.virtualFieldsService, this.mongoDBService, this.fileOperationHandler, this.fileFieldDetection, this.executionContextCreator, this.queueService, this.featureGate, this.consumableTokenService, this.appConfigService, this.guidanceTriggerEvaluator, this.milestoneEvaluator, this.lifecycleEvaluator, this.postgreSQLDatabaseService);
|
|
198
|
+
this.services.set(resourceType, service);
|
|
199
|
+
this.logDebug('Service created successfully', { resourceType });
|
|
200
|
+
}
|
|
201
|
+
buildOperationPathsMap() {
|
|
202
|
+
this.logDebug('Building operation paths map');
|
|
203
|
+
let totalOperationPaths = 0;
|
|
204
|
+
this.services.forEach((service, resourceType) => {
|
|
205
|
+
const resourceConfiguration = this.resourcesRegistry.getResourceConfiguration(resourceType);
|
|
206
|
+
if (!resourceConfiguration.operations) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
resourceConfiguration.operations.forEach(operation => {
|
|
210
|
+
const operationPath = ResourcesConfig_OperationPathUtils.extractOperationPath(operation);
|
|
211
|
+
const operationKey = ResourcesConfig_OperationPathUtils.createOperationPathKey(operationPath);
|
|
212
|
+
this.serviceOperationsMap.set(operationKey, { service, operationPath });
|
|
213
|
+
totalOperationPaths++;
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
this.logDebug('Operation paths map built', { totalOperationPaths, operationKeys: Array.from(this.serviceOperationsMap.keys()).slice(0, 5) });
|
|
217
|
+
}
|
|
218
|
+
// ================================
|
|
219
|
+
// Service Access Methods
|
|
220
|
+
// ================================
|
|
221
|
+
getService(resourceType) {
|
|
222
|
+
const service = this.services.get(resourceType);
|
|
223
|
+
if (!service) {
|
|
224
|
+
this.logDebug('Service not found', { resourceType });
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
227
|
+
return service;
|
|
228
|
+
}
|
|
229
|
+
getServiceOrThrow(resourceType) {
|
|
230
|
+
const service = this.getService(resourceType);
|
|
231
|
+
if (!service) {
|
|
232
|
+
throw this.errorBuilder.buildError(ErrorType.NOT_FOUND, undefined, { customMessageReference: ErrorCustomMessageReference.SERVICE_NOT_FOUND, context: { resourceType } });
|
|
233
|
+
}
|
|
234
|
+
return service;
|
|
235
|
+
}
|
|
236
|
+
// ================================
|
|
237
|
+
// Execution Methods
|
|
238
|
+
// ================================
|
|
239
|
+
async doByOperationPath(operationPath, executionContext, id_or_ids_or_filter, data, options) {
|
|
240
|
+
const operationKey = ResourcesConfig_OperationPathUtils.createOperationPathKey(operationPath);
|
|
241
|
+
const operationInfo = this.serviceOperationsMap.get(operationKey);
|
|
242
|
+
if (!operationInfo) {
|
|
243
|
+
throw this.errorBuilder.buildError(ErrorType.NOT_FOUND, executionContext, { customMessageReference: ErrorCustomMessageReference.SERVICE_NOT_FOUND, context: { operationKey, operationPath } });
|
|
244
|
+
}
|
|
245
|
+
this.logDebug('Executing operation by path', { operationPath, operationKey, id_or_ids_or_filter });
|
|
246
|
+
return operationInfo.service.doByOperationPath(operationPath, executionContext, id_or_ids_or_filter, data, options);
|
|
247
|
+
}
|
|
248
|
+
async doByExecutionContext(executionContext, data, options) {
|
|
249
|
+
const operation = executionContext.operation;
|
|
250
|
+
const resourceType = operation.resourceIdentifier;
|
|
251
|
+
const service = this.getServiceOrThrow(resourceType);
|
|
252
|
+
this.logDebug('Executing operation by execution context', { resourceType, operationIdentifier: operation.operationIdentifier });
|
|
253
|
+
return service.doByExecutionContext(executionContext, data, options);
|
|
254
|
+
}
|
|
255
|
+
// ════════════════════════════════════════════════════════════════════
|
|
256
|
+
// Convenience methods for programmatic resource operations.
|
|
257
|
+
//
|
|
258
|
+
// These pass the caller's executionContext through to doByOperationPath,
|
|
259
|
+
// which resolves the target operation from the registry. If the caller's
|
|
260
|
+
// executionContext.operation differs from the target operation (e.g., a
|
|
261
|
+
// webhook handler calling create(SUBSCRIPTION, webhookCtx)), doOperation's
|
|
262
|
+
// Correction Point 1 corrects the context before any pipeline logic runs.
|
|
263
|
+
//
|
|
264
|
+
// For proper sub-call depth tracking and cycle detection, callers should
|
|
265
|
+
// use executionContextCreator.createForSubCall() before calling these
|
|
266
|
+
// methods. Without it, operations are functionally correct but skip
|
|
267
|
+
// depth/cycle safety checks.
|
|
268
|
+
// ════════════════════════════════════════════════════════════════════
|
|
269
|
+
async create(resourceType, executionContext, data, options) {
|
|
270
|
+
const service = this.getServiceOrThrow(resourceType);
|
|
271
|
+
const operationPath = this.resourcesRegistry.getOperationPathDefault(resourceType, CoreResourceOperation.CREATE);
|
|
272
|
+
return service.doByOperationPath(operationPath, executionContext, undefined, data, options);
|
|
273
|
+
}
|
|
274
|
+
async createMany(resourceType, executionContext, data, options) {
|
|
275
|
+
const service = this.getServiceOrThrow(resourceType);
|
|
276
|
+
const operationPath = this.resourcesRegistry.getOperationPathDefault(resourceType, CoreResourceOperation.CREATE_MANY);
|
|
277
|
+
return service.doByOperationPath(operationPath, executionContext, undefined, data, options);
|
|
278
|
+
}
|
|
279
|
+
async read(resourceType, executionContext, id_or_ids_or_filter, options) {
|
|
280
|
+
const service = this.getServiceOrThrow(resourceType);
|
|
281
|
+
// If variantKey is specified, get that variant's operationPath
|
|
282
|
+
const operationPath = options?.variantKey
|
|
283
|
+
? this.resourcesRegistry.getOperationPath(resourceType, CoreResourceOperation.READ, options.variantKey)
|
|
284
|
+
: this.resourcesRegistry.getOperationPathDefault(resourceType, CoreResourceOperation.READ);
|
|
285
|
+
return service.doByOperationPath(operationPath, executionContext, id_or_ids_or_filter, undefined, options);
|
|
286
|
+
}
|
|
287
|
+
async update(resourceType, executionContext, id_or_ids_or_filter, data, options) {
|
|
288
|
+
const service = this.getServiceOrThrow(resourceType);
|
|
289
|
+
const operationPath = this.resourcesRegistry.getOperationPathDefault(resourceType, CoreResourceOperation.UPDATE);
|
|
290
|
+
return service.doByOperationPath(operationPath, executionContext, id_or_ids_or_filter, data, options);
|
|
291
|
+
}
|
|
292
|
+
async updateMany(resourceType, executionContext, id_or_ids_or_filter, data, options) {
|
|
293
|
+
const service = this.getServiceOrThrow(resourceType);
|
|
294
|
+
const operationPath = this.resourcesRegistry.getOperationPathDefault(resourceType, CoreResourceOperation.UPDATE_MANY);
|
|
295
|
+
return service.doByOperationPath(operationPath, executionContext, id_or_ids_or_filter, data, options);
|
|
296
|
+
}
|
|
297
|
+
async delete(resourceType, executionContext, resourceId, options) {
|
|
298
|
+
if (typeof resourceId !== 'string' || resourceId.length === 0) {
|
|
299
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
300
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
301
|
+
context: {
|
|
302
|
+
operation: CoreResourceOperation.DELETE,
|
|
303
|
+
reason: 'ServicesRegistryHandlerBackendService.delete() only accepts a single resource id. Use deleteMany() for ids or filters.',
|
|
304
|
+
resourceType,
|
|
305
|
+
},
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
const service = this.getServiceOrThrow(resourceType);
|
|
309
|
+
const operationPath = this.resourcesRegistry.getOperationPathDefault(resourceType, CoreResourceOperation.DELETE);
|
|
310
|
+
return service.doByOperationPath(operationPath, executionContext, resourceId, undefined, options);
|
|
311
|
+
}
|
|
312
|
+
async deleteMany(resourceType, executionContext, id_or_ids_or_filter, options) {
|
|
313
|
+
const service = this.getServiceOrThrow(resourceType);
|
|
314
|
+
const operationPath = this.resourcesRegistry.getOperationPathDefault(resourceType, CoreResourceOperation.DELETE_MANY);
|
|
315
|
+
return service.doByOperationPath(operationPath, executionContext, id_or_ids_or_filter, undefined, options);
|
|
316
|
+
}
|
|
317
|
+
// ════════════════════════════════════════════════════════════════════
|
|
318
|
+
// Custom operations
|
|
319
|
+
// ════════════════════════════════════════════════════════════════════
|
|
320
|
+
/**
|
|
321
|
+
* Execute a custom operation on a resource through the full pipeline.
|
|
322
|
+
* Routes through the same operation pipeline as HTTP-triggered custom operations
|
|
323
|
+
* (Zod validation, RBAC, custom impl dispatch, post-operation hooks).
|
|
324
|
+
*
|
|
325
|
+
* @param resourceType - The resource type to execute the operation on
|
|
326
|
+
* @param customOperationIdentifier - The custom operation name (e.g., 'top_up', 'consume')
|
|
327
|
+
* @param executionContext - The execution context for RBAC and scoping
|
|
328
|
+
* @param id_or_ids_or_filter - The resource ID to target (most custom ops require this)
|
|
329
|
+
* @param data - The request payload for the custom operation
|
|
330
|
+
* @param options - Optional service options
|
|
331
|
+
*/
|
|
332
|
+
async executeCustomOperation(resourceType, customOperationIdentifier, executionContext, id_or_ids_or_filter, data, options) {
|
|
333
|
+
const service = this.getServiceOrThrow(resourceType);
|
|
334
|
+
const operationPath = this.resourcesRegistry.getOperationPathDefault(resourceType, customOperationIdentifier);
|
|
335
|
+
return service.doByOperationPath(operationPath, executionContext, id_or_ids_or_filter, data, options);
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Execute an explicit multi-target relationship action.
|
|
339
|
+
*
|
|
340
|
+
* This is the service-level implementation seam behind the planned operation
|
|
341
|
+
* split:
|
|
342
|
+
* - `UPDATE_MANY` stays a bulk patch of the main resource
|
|
343
|
+
* - explicit relationship actions (`set`, `clear`, `create`, `link`,
|
|
344
|
+
* `unlink`) are applied to a named relationship from the current resource's
|
|
345
|
+
* perspective
|
|
346
|
+
*/
|
|
347
|
+
async applyRelationshipActionMany(resourceType, executionContext, id_or_ids_or_filter, request, options) {
|
|
348
|
+
const service = this.getServiceOrThrow(resourceType);
|
|
349
|
+
const parsedRequest = ResourceRelationshipBulkActionRequestSchema.parse(request);
|
|
350
|
+
return service.applyRelationshipActionMany(executionContext, id_or_ids_or_filter, parsedRequest, options);
|
|
351
|
+
}
|
|
352
|
+
// ════════════════════════════════════════════════════════════════════
|
|
353
|
+
// Post-operation hooks
|
|
354
|
+
// ════════════════════════════════════════════════════════════════════
|
|
355
|
+
/**
|
|
356
|
+
* Register a callback that fires after any successful mutation on a resource type.
|
|
357
|
+
* Hooks are fire-and-forget — errors are logged but do not fail the operation.
|
|
358
|
+
*
|
|
359
|
+
* @param resourceType - The resource type to observe
|
|
360
|
+
* @param callback - Invoked after CREATE, UPDATE, DELETE, or custom mutation succeeds
|
|
361
|
+
*/
|
|
362
|
+
registerPostOperationHook(resourceType, callback) {
|
|
363
|
+
const hooks = this.postOperationHooks.get(resourceType) ?? [];
|
|
364
|
+
hooks.push(callback);
|
|
365
|
+
this.postOperationHooks.set(resourceType, hooks);
|
|
366
|
+
this.logDebug('Post-operation hook registered', { resourceType });
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Dispatch post-operation hooks for a resource type.
|
|
370
|
+
* Called by ServiceResourceBackendService after successful operations.
|
|
371
|
+
* @internal
|
|
372
|
+
*/
|
|
373
|
+
async dispatchPostOperationHooks(resourceType, operationIdentifier, result, executionContext) {
|
|
374
|
+
const hooks = this.postOperationHooks.get(resourceType);
|
|
375
|
+
if (!hooks || hooks.length === 0)
|
|
376
|
+
return;
|
|
377
|
+
for (const hook of hooks) {
|
|
378
|
+
try {
|
|
379
|
+
await hook(resourceType, operationIdentifier, result, executionContext);
|
|
380
|
+
}
|
|
381
|
+
catch (error) {
|
|
382
|
+
this.logger.warn('Post-operation hook failed', {
|
|
383
|
+
resourceType,
|
|
384
|
+
operationIdentifier,
|
|
385
|
+
error: error.message,
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
// ════════════════════════════════════════════════════════════════════
|
|
391
|
+
// Read / List / Search / Count
|
|
392
|
+
// ════════════════════════════════════════════════════════════════════
|
|
393
|
+
/**
|
|
394
|
+
* List resources with optional pagination.
|
|
395
|
+
* @param options.paginated - When true, returns { data: T[], pagination: {...} }. Default: false (returns T[])
|
|
396
|
+
* @param options.variantKey - Optional variant key (e.g., 'summary', 'context')
|
|
397
|
+
* @param options.dataMode - Optional data mode for population behavior
|
|
398
|
+
*/
|
|
399
|
+
async list(resourceType, executionContext, filter, pagination, options) {
|
|
400
|
+
const service = this.getServiceOrThrow(resourceType);
|
|
401
|
+
// If variantKey is specified, get that variant's operationPath
|
|
402
|
+
const operationPath = options?.variantKey
|
|
403
|
+
? this.resourcesRegistry.getOperationPath(resourceType, CoreResourceOperation.LIST, options.variantKey)
|
|
404
|
+
: this.resourcesRegistry.getOperationPathDefault(resourceType, CoreResourceOperation.LIST);
|
|
405
|
+
const listData = { filter, page: pagination?.page, limit: pagination?.limit };
|
|
406
|
+
return service.doByOperationPath(operationPath, executionContext, undefined, listData, options);
|
|
407
|
+
}
|
|
408
|
+
async search(resourceType, executionContext, searchQuery, filter, options) {
|
|
409
|
+
const service = this.getServiceOrThrow(resourceType);
|
|
410
|
+
const operationPath = this.resourcesRegistry.getOperationPathDefault(resourceType, CoreResourceOperation.SEARCH);
|
|
411
|
+
return service.doByOperationPath(operationPath, executionContext, undefined, { searchQuery, filter }, options);
|
|
412
|
+
}
|
|
413
|
+
async count(resourceType, executionContext, filter, options) {
|
|
414
|
+
const service = this.getServiceOrThrow(resourceType);
|
|
415
|
+
const operationPath = this.resourcesRegistry.getOperationPathDefault(resourceType, CoreResourceOperation.COUNT);
|
|
416
|
+
const countData = filter ? { filter } : undefined;
|
|
417
|
+
return service.doByOperationPath(operationPath, executionContext, undefined, countData, options);
|
|
418
|
+
}
|
|
419
|
+
// ================================
|
|
420
|
+
// Utility Methods
|
|
421
|
+
// ================================
|
|
422
|
+
getAvailableOperationPaths() {
|
|
423
|
+
return Array.from(this.serviceOperationsMap.values()).map(info => info.operationPath);
|
|
424
|
+
}
|
|
425
|
+
hasService(resourceType) {
|
|
426
|
+
return this.services.has(resourceType);
|
|
427
|
+
}
|
|
428
|
+
getRegisteredResourceTypes() {
|
|
429
|
+
return Array.from(this.services.keys());
|
|
430
|
+
}
|
|
431
|
+
getServiceCount() {
|
|
432
|
+
return this.services.size;
|
|
433
|
+
}
|
|
434
|
+
getDebugInfo() {
|
|
435
|
+
return {
|
|
436
|
+
serviceCount: this.services.size,
|
|
437
|
+
operationPathsCount: this.serviceOperationsMap.size,
|
|
438
|
+
resourceTypes: Array.from(this.services.keys()),
|
|
439
|
+
isInitialized: this.isInitialized
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
ServicesRegistryHandlerBackendService = __decorate([
|
|
444
|
+
injectable(),
|
|
445
|
+
__param(0, inject(SAAS_SERVICE_TYPES.RepositoriesRegistryHandlerService)),
|
|
446
|
+
__param(1, inject(SAAS_SERVICE_TYPES.Logger)),
|
|
447
|
+
__param(2, inject(SAAS_SERVICE_TYPES.ErrorBuilderService)),
|
|
448
|
+
__param(3, inject(SAAS_SERVICE_TYPES.ResourceRegistryService)),
|
|
449
|
+
__param(4, inject(SAAS_SERVICE_TYPES.ResourceOperationHelperService)),
|
|
450
|
+
__param(5, inject(SAAS_SERVICE_TYPES.ResourceOperationCustomImplementationRegistryService)),
|
|
451
|
+
__param(6, inject(SAAS_SERVICE_TYPES.ExternalApiHandlerService)),
|
|
452
|
+
__param(7, inject(SAAS_SERVICE_TYPES.PlatformMutualizedHandlerService)),
|
|
453
|
+
__param(8, inject(SAAS_SERVICE_TYPES.ServerlessServicesHandlerService)),
|
|
454
|
+
__param(9, inject(SAAS_SERVICE_TYPES.NotificationDispatcherService)),
|
|
455
|
+
__param(10, inject(SAAS_SERVICE_TYPES.ResourcePopulationService)),
|
|
456
|
+
__param(11, inject(SAAS_SERVICE_TYPES.VirtualFieldsService)),
|
|
457
|
+
__param(12, inject(SAAS_SERVICE_TYPES.MongoDBService)),
|
|
458
|
+
__param(13, inject(SAAS_SERVICE_TYPES.FileOperationHandlerService)),
|
|
459
|
+
__param(14, inject(SAAS_SERVICE_TYPES.FileFieldDetectionService)),
|
|
460
|
+
__param(15, inject(SAAS_SERVICE_TYPES.ExecutionContextCreatorBackendService)),
|
|
461
|
+
__param(16, inject(SAAS_SERVICE_TYPES.QueueBackendService)),
|
|
462
|
+
__param(17, inject(SAAS_SERVICE_TYPES.FeatureGateService)),
|
|
463
|
+
__param(18, inject(SAAS_SERVICE_TYPES.ConsumableTokenService)),
|
|
464
|
+
__param(19, inject(SAAS_SERVICE_TYPES.AppConfigService)),
|
|
465
|
+
__param(20, inject(SAAS_SERVICE_TYPES.GuidanceTriggerEvaluator)),
|
|
466
|
+
__param(20, optional()),
|
|
467
|
+
__param(21, inject(SAAS_SERVICE_TYPES.MilestoneEvaluator)),
|
|
468
|
+
__param(21, optional()),
|
|
469
|
+
__param(22, inject(SAAS_SERVICE_TYPES.LifecycleEvaluator)),
|
|
470
|
+
__param(22, optional()),
|
|
471
|
+
__param(23, inject(SAAS_SERVICE_TYPES.PostgreSQLDatabaseService)),
|
|
472
|
+
__param(23, optional()),
|
|
473
|
+
__param(24, inject(SAAS_SERVICE_TYPES.SAMLMetadataService)),
|
|
474
|
+
__param(24, optional()),
|
|
475
|
+
__metadata("design:paramtypes", [RepositoriesRegistryHandlerBackendService,
|
|
476
|
+
LoggerService,
|
|
477
|
+
ErrorBuilderBackendService,
|
|
478
|
+
ResourcesRegistryBackendService,
|
|
479
|
+
ResourceOperationHelperBackendService,
|
|
480
|
+
ResourceOperationCustomImplementationRegistryBackendService,
|
|
481
|
+
ExternalApiHandlerBackendService,
|
|
482
|
+
PlatformMutualizedHandlerBackendService,
|
|
483
|
+
ServerlessServicesHandlerBackendService,
|
|
484
|
+
NotificationDispatcherService,
|
|
485
|
+
ResourcePopulationBackendService,
|
|
486
|
+
VirtualFieldsBackendService,
|
|
487
|
+
MongoDBService,
|
|
488
|
+
FileOperationHandlerBackendService,
|
|
489
|
+
FileFieldDetectionBackendService,
|
|
490
|
+
ExecutionContextCreatorBackendService,
|
|
491
|
+
QueueBackendService,
|
|
492
|
+
FeatureGateBackendService,
|
|
493
|
+
ConsumableTokenBackendService,
|
|
494
|
+
AppConfigurationService,
|
|
495
|
+
GuidanceTriggerEvaluatorBackendService,
|
|
496
|
+
MilestoneEvaluatorBackendService,
|
|
497
|
+
LifecycleEvaluatorBackendService,
|
|
498
|
+
PostgreSQLDatabaseBackendService, Function])
|
|
499
|
+
], ServicesRegistryHandlerBackendService);
|
|
500
|
+
export { ServicesRegistryHandlerBackendService };
|
|
501
|
+
//============================================================================================================================
|
|
502
|
+
//
|
|
503
|
+
// Service Resource Backend Service
|
|
504
|
+
//
|
|
505
|
+
//============================================================================================================================
|
|
506
|
+
export class ServiceResourceBackendService {
|
|
507
|
+
resourcesRegistry;
|
|
508
|
+
logger;
|
|
509
|
+
errorBuilder;
|
|
510
|
+
repositoryHelper;
|
|
511
|
+
customImplRegistry;
|
|
512
|
+
repositoriesRegistry;
|
|
513
|
+
servicesRegistry;
|
|
514
|
+
externalApiHandler;
|
|
515
|
+
platformMutualizedHandler;
|
|
516
|
+
serverlessServicesHandler;
|
|
517
|
+
notificationDispatcher;
|
|
518
|
+
populationService;
|
|
519
|
+
virtualFieldsService;
|
|
520
|
+
mongoDBService;
|
|
521
|
+
fileOperationHandler;
|
|
522
|
+
fileFieldDetection;
|
|
523
|
+
executionContextCreator;
|
|
524
|
+
queueService;
|
|
525
|
+
featureGate;
|
|
526
|
+
consumableTokenService;
|
|
527
|
+
appConfigService;
|
|
528
|
+
guidanceTriggerEvaluator;
|
|
529
|
+
milestoneEvaluator;
|
|
530
|
+
lifecycleEvaluator;
|
|
531
|
+
postgreSQLDatabaseService;
|
|
532
|
+
resourceConfiguration;
|
|
533
|
+
operationsMap;
|
|
534
|
+
logDebug;
|
|
535
|
+
constructor(resourceType, resourcesRegistry, logger, errorBuilder, repositoryHelper, customImplRegistry, repositoriesRegistry, servicesRegistry, externalApiHandler, platformMutualizedHandler, serverlessServicesHandler, notificationDispatcher, populationService, virtualFieldsService, mongoDBService, fileOperationHandler, fileFieldDetection, executionContextCreator, queueService, featureGate, consumableTokenService, appConfigService, guidanceTriggerEvaluator, milestoneEvaluator, lifecycleEvaluator, postgreSQLDatabaseService) {
|
|
536
|
+
this.resourcesRegistry = resourcesRegistry;
|
|
537
|
+
this.logger = logger;
|
|
538
|
+
this.errorBuilder = errorBuilder;
|
|
539
|
+
this.repositoryHelper = repositoryHelper;
|
|
540
|
+
this.customImplRegistry = customImplRegistry;
|
|
541
|
+
this.repositoriesRegistry = repositoriesRegistry;
|
|
542
|
+
this.servicesRegistry = servicesRegistry;
|
|
543
|
+
this.externalApiHandler = externalApiHandler;
|
|
544
|
+
this.platformMutualizedHandler = platformMutualizedHandler;
|
|
545
|
+
this.serverlessServicesHandler = serverlessServicesHandler;
|
|
546
|
+
this.notificationDispatcher = notificationDispatcher;
|
|
547
|
+
this.populationService = populationService;
|
|
548
|
+
this.virtualFieldsService = virtualFieldsService;
|
|
549
|
+
this.mongoDBService = mongoDBService;
|
|
550
|
+
this.fileOperationHandler = fileOperationHandler;
|
|
551
|
+
this.fileFieldDetection = fileFieldDetection;
|
|
552
|
+
this.executionContextCreator = executionContextCreator;
|
|
553
|
+
this.queueService = queueService;
|
|
554
|
+
this.featureGate = featureGate;
|
|
555
|
+
this.consumableTokenService = consumableTokenService;
|
|
556
|
+
this.appConfigService = appConfigService;
|
|
557
|
+
this.guidanceTriggerEvaluator = guidanceTriggerEvaluator;
|
|
558
|
+
this.milestoneEvaluator = milestoneEvaluator;
|
|
559
|
+
this.lifecycleEvaluator = lifecycleEvaluator;
|
|
560
|
+
this.postgreSQLDatabaseService = postgreSQLDatabaseService;
|
|
561
|
+
this.operationsMap = new Map();
|
|
562
|
+
this.resourceConfiguration = this.resourcesRegistry.getResourceConfiguration(resourceType);
|
|
563
|
+
this.logDebug = this.logger.debugByType(`ServiceResource_${resourceType}`);
|
|
564
|
+
this.logger.setDebugTypeLogging(`ServiceResource_${resourceType}`, false);
|
|
565
|
+
this.initializeOperationsMap();
|
|
566
|
+
this.logDebug('Service resource created', {
|
|
567
|
+
resourceType: this.resourceConfiguration.resourceIdentifier,
|
|
568
|
+
operationsCount: this.operationsMap.size
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
static createInstance(resourceType, logger, errorBuilder, repositoriesRegistry, servicesRegistry, resourcesRegistry, repositoryHelper, customImplRegistry, externalApiHandler, platformMutualizedHandler, serverlessServicesHandler, notificationDispatcher, populationService, virtualFieldsService, mongoDBService, fileOperationHandler, fileFieldDetection, executionContextCreator, queueService, featureGate, consumableTokenService, appConfigService, guidanceTriggerEvaluator, milestoneEvaluator, lifecycleEvaluator, postgreSQLDatabaseService) {
|
|
572
|
+
return new ServiceResourceBackendService(resourceType, resourcesRegistry, logger, errorBuilder, repositoryHelper, customImplRegistry, repositoriesRegistry, servicesRegistry, externalApiHandler, platformMutualizedHandler, serverlessServicesHandler, notificationDispatcher, populationService, virtualFieldsService, mongoDBService, fileOperationHandler, fileFieldDetection, executionContextCreator, queueService, featureGate, consumableTokenService, appConfigService, guidanceTriggerEvaluator, milestoneEvaluator, lifecycleEvaluator, postgreSQLDatabaseService);
|
|
573
|
+
}
|
|
574
|
+
async applyRelationshipActionMany(executionContext, id_or_ids_or_filter, request, options) {
|
|
575
|
+
const resourceType = this.resourceConfiguration.resourceIdentifier;
|
|
576
|
+
const parsedRequest = ResourceRelationshipBulkActionRequestSchema.parse(request);
|
|
577
|
+
let relationship;
|
|
578
|
+
try {
|
|
579
|
+
relationship = this.getRelationshipForBulkAction(parsedRequest.relationshipField);
|
|
580
|
+
}
|
|
581
|
+
catch (error) {
|
|
582
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
583
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
584
|
+
context: {
|
|
585
|
+
relationshipField: parsedRequest.relationshipField,
|
|
586
|
+
resourceType,
|
|
587
|
+
reason: error instanceof Error ? error.message : 'Invalid relationship field for bulk action',
|
|
588
|
+
},
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
const allowedActions = Resources_SharedUtils.resolveAllowedBulkRelationshipActionsForResource(relationship, resourceType);
|
|
592
|
+
if (!allowedActions.includes(parsedRequest.action)) {
|
|
593
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
594
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
595
|
+
context: {
|
|
596
|
+
relationshipField: parsedRequest.relationshipField,
|
|
597
|
+
action: parsedRequest.action,
|
|
598
|
+
resourceType,
|
|
599
|
+
allowedActions,
|
|
600
|
+
reason: 'Requested bulk relationship action is not allowed for this relationship from the current resource perspective',
|
|
601
|
+
},
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
switch (parsedRequest.action) {
|
|
605
|
+
case ResourceRelationshipBulkAction.SET:
|
|
606
|
+
return this.applyReferenceSetActionMany(executionContext, id_or_ids_or_filter, relationship, parsedRequest.relationshipField, parsedRequest.targetId, options);
|
|
607
|
+
case ResourceRelationshipBulkAction.CLEAR:
|
|
608
|
+
return this.applyReferenceClearActionMany(executionContext, id_or_ids_or_filter, relationship, parsedRequest.relationshipField, options);
|
|
609
|
+
case ResourceRelationshipBulkAction.CREATE:
|
|
610
|
+
return this.applyCompositionCreateActionMany(executionContext, id_or_ids_or_filter, relationship, parsedRequest.relationshipField, parsedRequest.data, options);
|
|
611
|
+
case ResourceRelationshipBulkAction.LINK:
|
|
612
|
+
return this.applyAssociationLinkActionMany(executionContext, id_or_ids_or_filter, relationship, parsedRequest.relationshipField, parsedRequest.peerIds, options);
|
|
613
|
+
case ResourceRelationshipBulkAction.UNLINK:
|
|
614
|
+
return this.applyAssociationUnlinkActionMany(executionContext, id_or_ids_or_filter, relationship, parsedRequest.relationshipField, parsedRequest.peerIds, options);
|
|
615
|
+
case ResourceRelationshipBulkAction.REPLACE:
|
|
616
|
+
return this.applyAssociationReplaceActionMany(executionContext, id_or_ids_or_filter, relationship, parsedRequest.relationshipField, parsedRequest.peerIds, options);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
async executeGeneratedRelationshipBulkOperation(resolvedOperation, operation, executionContext, data, options) {
|
|
620
|
+
switch (operation.action) {
|
|
621
|
+
case ResourceRelationshipBulkAction.SET: {
|
|
622
|
+
const request = this.parseGeneratedRelationshipBulkOperationRequest(ResourceRelationshipBulkSetOperationRequestSchema, operation, data, executionContext);
|
|
623
|
+
await this.assertGeneratedRelationshipBulkOperationEnabled(resolvedOperation, request, executionContext);
|
|
624
|
+
return this.applyRelationshipActionMany(executionContext, this.resolveGeneratedRelationshipBulkSelector(request), {
|
|
625
|
+
relationshipField: operation.relationshipField,
|
|
626
|
+
action: ResourceRelationshipBulkAction.SET,
|
|
627
|
+
targetId: request.targetId,
|
|
628
|
+
}, options);
|
|
629
|
+
}
|
|
630
|
+
case ResourceRelationshipBulkAction.CLEAR: {
|
|
631
|
+
const request = this.parseGeneratedRelationshipBulkOperationRequest(ResourceRelationshipBulkClearOperationRequestSchema, operation, data, executionContext);
|
|
632
|
+
await this.assertGeneratedRelationshipBulkOperationEnabled(resolvedOperation, request, executionContext);
|
|
633
|
+
return this.applyRelationshipActionMany(executionContext, this.resolveGeneratedRelationshipBulkSelector(request), {
|
|
634
|
+
relationshipField: operation.relationshipField,
|
|
635
|
+
action: ResourceRelationshipBulkAction.CLEAR,
|
|
636
|
+
}, options);
|
|
637
|
+
}
|
|
638
|
+
case ResourceRelationshipBulkAction.CREATE: {
|
|
639
|
+
const request = this.parseGeneratedRelationshipBulkOperationRequest(ResourceRelationshipBulkCreateOperationRequestSchema, operation, data, executionContext);
|
|
640
|
+
await this.assertGeneratedRelationshipBulkOperationEnabled(resolvedOperation, request, executionContext);
|
|
641
|
+
return this.applyRelationshipActionMany(executionContext, this.resolveGeneratedRelationshipBulkSelector(request), {
|
|
642
|
+
relationshipField: operation.relationshipField,
|
|
643
|
+
action: ResourceRelationshipBulkAction.CREATE,
|
|
644
|
+
data: request.data,
|
|
645
|
+
}, options);
|
|
646
|
+
}
|
|
647
|
+
case ResourceRelationshipBulkAction.LINK: {
|
|
648
|
+
const request = this.parseGeneratedRelationshipBulkOperationRequest(ResourceRelationshipBulkLinkOperationRequestSchema, operation, data, executionContext);
|
|
649
|
+
await this.assertGeneratedRelationshipBulkOperationEnabled(resolvedOperation, request, executionContext);
|
|
650
|
+
return this.applyRelationshipActionMany(executionContext, this.resolveGeneratedRelationshipBulkSelector(request), {
|
|
651
|
+
relationshipField: operation.relationshipField,
|
|
652
|
+
action: ResourceRelationshipBulkAction.LINK,
|
|
653
|
+
peerIds: request.peerIds,
|
|
654
|
+
}, options);
|
|
655
|
+
}
|
|
656
|
+
case ResourceRelationshipBulkAction.UNLINK: {
|
|
657
|
+
const request = this.parseGeneratedRelationshipBulkOperationRequest(ResourceRelationshipBulkUnlinkOperationRequestSchema, operation, data, executionContext);
|
|
658
|
+
await this.assertGeneratedRelationshipBulkOperationEnabled(resolvedOperation, request, executionContext);
|
|
659
|
+
return this.applyRelationshipActionMany(executionContext, this.resolveGeneratedRelationshipBulkSelector(request), {
|
|
660
|
+
relationshipField: operation.relationshipField,
|
|
661
|
+
action: ResourceRelationshipBulkAction.UNLINK,
|
|
662
|
+
peerIds: request.peerIds,
|
|
663
|
+
}, options);
|
|
664
|
+
}
|
|
665
|
+
case ResourceRelationshipBulkAction.REPLACE: {
|
|
666
|
+
const request = this.parseGeneratedRelationshipBulkOperationRequest(ResourceRelationshipBulkReplaceOperationRequestSchema, operation, data, executionContext);
|
|
667
|
+
await this.assertGeneratedRelationshipBulkOperationEnabled(resolvedOperation, request, executionContext);
|
|
668
|
+
return this.applyRelationshipActionMany(executionContext, this.resolveGeneratedRelationshipBulkSelector(request), {
|
|
669
|
+
relationshipField: operation.relationshipField,
|
|
670
|
+
action: ResourceRelationshipBulkAction.REPLACE,
|
|
671
|
+
peerIds: request.peerIds,
|
|
672
|
+
}, options);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
parseGeneratedRelationshipBulkOperationRequest(schema, operation, data, executionContext) {
|
|
677
|
+
try {
|
|
678
|
+
return schema.parse(data);
|
|
679
|
+
}
|
|
680
|
+
catch (error) {
|
|
681
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
682
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
683
|
+
context: {
|
|
684
|
+
action: operation.action,
|
|
685
|
+
relationshipField: operation.relationshipField,
|
|
686
|
+
reason: error instanceof Error ? error.message : 'Invalid bulk relationship operation payload',
|
|
687
|
+
},
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
resolveGeneratedRelationshipBulkSelector(request) {
|
|
692
|
+
if ('_ids' in request && Array.isArray(request._ids)) {
|
|
693
|
+
return request._ids.length === 1 ? request._ids[0] : request._ids;
|
|
694
|
+
}
|
|
695
|
+
if ('filter' in request && request.filter) {
|
|
696
|
+
return request.filter;
|
|
697
|
+
}
|
|
698
|
+
throw new Error('Bulk relationship operation selector must provide either _ids or filter');
|
|
699
|
+
}
|
|
700
|
+
async assertGeneratedRelationshipBulkOperationEnabled(operation, request, executionContext) {
|
|
701
|
+
if (!('enabledCondition' in operation) || !operation.enabledCondition) {
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
const selector = this.resolveGeneratedRelationshipBulkSelector(request);
|
|
705
|
+
const resourceType = this.resourceConfiguration.resourceIdentifier;
|
|
706
|
+
const singleSelectedId = Array.isArray(request._ids) && request._ids.length === 1
|
|
707
|
+
? request._ids[0]
|
|
708
|
+
: undefined;
|
|
709
|
+
const needs = extractFunctionContextNeeds(operation.enabledCondition);
|
|
710
|
+
if (!singleSelectedId && needs.needsObjectContext) {
|
|
711
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {
|
|
712
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_DISABLED,
|
|
713
|
+
context: {
|
|
714
|
+
reason: 'Generated bulk relationship operations with multi-target selectors cannot satisfy enabledCondition object-context requirements',
|
|
715
|
+
operationIdentifier: String(operation.operationIdentifier),
|
|
716
|
+
},
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
const currentObject = singleSelectedId
|
|
720
|
+
? await this.fetchCurrentObjectForOperation(CoreResourceOperation.UPDATE_MANY, resourceType, singleSelectedId, executionContext)
|
|
721
|
+
: undefined;
|
|
722
|
+
if (singleSelectedId && needs.needsObjectContext && !currentObject) {
|
|
723
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {
|
|
724
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_DISABLED,
|
|
725
|
+
context: {
|
|
726
|
+
reason: 'Generated bulk relationship operations requiring object context cannot run when the selected current object cannot be loaded',
|
|
727
|
+
operationIdentifier: String(operation.operationIdentifier),
|
|
728
|
+
},
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
const { objectContext, initiatorUserContext } = await this.fetchContextsForOperationFunction(operation.enabledCondition, resourceType, currentObject, executionContext);
|
|
732
|
+
// Generated bulk operations only have a persisted current object when the
|
|
733
|
+
// selector is exactly one `_id`. Multi-target selectors deliberately fail
|
|
734
|
+
// closed before this point if `needsObjectContext` is declared.
|
|
735
|
+
const isEnabled = operation.enabledCondition({
|
|
736
|
+
inputDto: request,
|
|
737
|
+
currentObject: currentObject,
|
|
738
|
+
objectContext,
|
|
739
|
+
initiatorUserContext,
|
|
740
|
+
initiatorIds: executionContext.initiatorIds,
|
|
741
|
+
});
|
|
742
|
+
if (!isEnabled) {
|
|
743
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, { customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_DISABLED });
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
resolveSingleSelectedId(id_or_ids_or_filter) {
|
|
747
|
+
if (typeof id_or_ids_or_filter === 'string') {
|
|
748
|
+
return id_or_ids_or_filter;
|
|
749
|
+
}
|
|
750
|
+
if (Array.isArray(id_or_ids_or_filter)
|
|
751
|
+
&& id_or_ids_or_filter.length === 1
|
|
752
|
+
&& typeof id_or_ids_or_filter[0] === 'string') {
|
|
753
|
+
return id_or_ids_or_filter[0];
|
|
754
|
+
}
|
|
755
|
+
if (id_or_ids_or_filter
|
|
756
|
+
&& typeof id_or_ids_or_filter === 'object'
|
|
757
|
+
&& !Array.isArray(id_or_ids_or_filter)) {
|
|
758
|
+
if ('id_or_ids' in id_or_ids_or_filter
|
|
759
|
+
&& Array.isArray(id_or_ids_or_filter.id_or_ids)
|
|
760
|
+
&& id_or_ids_or_filter.id_or_ids.length === 1
|
|
761
|
+
&& typeof id_or_ids_or_filter.id_or_ids[0] === 'string') {
|
|
762
|
+
return id_or_ids_or_filter.id_or_ids[0];
|
|
763
|
+
}
|
|
764
|
+
if ('ids' in id_or_ids_or_filter
|
|
765
|
+
&& Array.isArray(id_or_ids_or_filter.ids)
|
|
766
|
+
&& id_or_ids_or_filter.ids.length === 1
|
|
767
|
+
&& typeof id_or_ids_or_filter.ids[0] === 'string') {
|
|
768
|
+
return id_or_ids_or_filter.ids[0];
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
return undefined;
|
|
772
|
+
}
|
|
773
|
+
resolveHookCurrentObject(coreOperation, currentObject, data) {
|
|
774
|
+
return coreOperation === CoreResourceOperation.CREATE
|
|
775
|
+
|| coreOperation === CoreResourceOperation.CREATE_MANY
|
|
776
|
+
? data
|
|
777
|
+
: currentObject;
|
|
778
|
+
}
|
|
779
|
+
assertBulkHookObjectContextAvailability(coreOperation, isBulkOperation, fn, currentObject, executionContext, operationIdentifier, hookName) {
|
|
780
|
+
const isBulkUpdateOperation = coreOperation === CoreResourceOperation.UPDATE_MANY
|
|
781
|
+
|| (coreOperation === CoreResourceOperation.UPDATE && isBulkOperation === true);
|
|
782
|
+
if (!isBulkUpdateOperation) {
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
const needs = extractFunctionContextNeeds(fn);
|
|
786
|
+
if (!needs.needsObjectContext || currentObject) {
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {
|
|
790
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_DISABLED,
|
|
791
|
+
context: {
|
|
792
|
+
reason: `${hookName} requires object context, but this bulk update cannot provide a single persisted current object`,
|
|
793
|
+
operationIdentifier,
|
|
794
|
+
},
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
initializeOperationsMap() {
|
|
798
|
+
if (!this.resourceConfiguration.operations) {
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
801
|
+
// Include operations that should be handled by services
|
|
802
|
+
const serviceOperations = this.resourceConfiguration.operations.filter((op) => op.variantType === ResourceOperationVariantType.INTERNAL_CALL ||
|
|
803
|
+
op.variantType === ResourceOperationVariantType.API_CALL ||
|
|
804
|
+
op.variantType === ResourceOperationVariantType.CRON_JOB ||
|
|
805
|
+
op.variantType === ResourceOperationVariantType.BATCH_JOB);
|
|
806
|
+
serviceOperations.forEach(operation => {
|
|
807
|
+
const operationKey = ResourcesConfig_OperationPathUtils.createOperationPathKeyFromOperation(operation);
|
|
808
|
+
this.operationsMap.set(operationKey, operation);
|
|
809
|
+
});
|
|
810
|
+
this.logDebug('Service operations map initialized', {
|
|
811
|
+
totalOperations: this.resourceConfiguration.operations.length,
|
|
812
|
+
serviceOperations: serviceOperations.length
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Entry point from registry convenience methods (`create`, `update`, `delete`, etc.)
|
|
817
|
+
* and controller-level `doByOperationPath`.
|
|
818
|
+
*
|
|
819
|
+
* Resolves `operation` from this handler's `operationsMap`. The caller's
|
|
820
|
+
* `executionContext.operation` may point to a DIFFERENT operation (e.g., a parent's
|
|
821
|
+
* operation or a generic webhook operation). `doOperation()` corrects this mismatch
|
|
822
|
+
* via Correction Point 1 before any pipeline logic executes.
|
|
823
|
+
*/
|
|
824
|
+
async doByOperationPath(operationPath, executionContext, id_or_ids_or_filter, data, options) {
|
|
825
|
+
const operationKey = ResourcesConfig_OperationPathUtils.createOperationPathKey(operationPath);
|
|
826
|
+
const operation = this.operationsMap.get(operationKey);
|
|
827
|
+
if (!operation) {
|
|
828
|
+
const error = this.errorBuilder.buildError(ErrorType.NOT_FOUND, executionContext, { customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED });
|
|
829
|
+
throw error;
|
|
830
|
+
}
|
|
831
|
+
this.logDebug('Executing operation by path', {
|
|
832
|
+
operationPath,
|
|
833
|
+
operationKey,
|
|
834
|
+
resourceType: this.resourceConfiguration.resourceIdentifier,
|
|
835
|
+
id_or_ids_or_filter
|
|
836
|
+
});
|
|
837
|
+
return this.doOperation(operation, executionContext, id_or_ids_or_filter, data, options);
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* Entry point from controller-level `doByExecutionContext`.
|
|
841
|
+
*
|
|
842
|
+
* Reads `operation` directly from `executionContext.operation` — guaranteed to match
|
|
843
|
+
* (same object reference). `doOperation()` correction points are no-ops in this path.
|
|
844
|
+
*/
|
|
845
|
+
async doByExecutionContext(executionContext, data, options) {
|
|
846
|
+
const operation = executionContext.operation;
|
|
847
|
+
// Extract IDs based on resourceFieldIdentifier from execution context
|
|
848
|
+
const id_or_ids_or_filter = this.repositoryHelper.extractIdsFromExecutionContext(executionContext, this.resourceConfiguration.resourceFieldIdentifier);
|
|
849
|
+
this.logDebug('Executing operation by execution context', {
|
|
850
|
+
resourceType: this.resourceConfiguration.resourceIdentifier,
|
|
851
|
+
operationIdentifier: operation.operationIdentifier,
|
|
852
|
+
extractedIds: id_or_ids_or_filter,
|
|
853
|
+
resourceFieldIdentifier: this.resourceConfiguration.resourceFieldIdentifier
|
|
854
|
+
});
|
|
855
|
+
return this.doOperation(operation, executionContext, id_or_ids_or_filter, data, options);
|
|
856
|
+
}
|
|
857
|
+
resolveOperationForDataMode(operation, dataMode) {
|
|
858
|
+
if (!dataMode || dataMode === DataMode.RAW) {
|
|
859
|
+
return operation;
|
|
860
|
+
}
|
|
861
|
+
return this.resolveOperationVariant(operation, dataMode);
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* Helper method to fetch contexts for operation functions (enabledCondition, basicPrefixOperation).
|
|
865
|
+
* Fetches objectContext and userContext only when needed based on function flags.
|
|
866
|
+
*
|
|
867
|
+
* @param fn - Function with optional context needs flags
|
|
868
|
+
* @param resourceType - Resource type for context fetching
|
|
869
|
+
* @param currentObject - Current object (fetched if needed for UPDATE/DELETE)
|
|
870
|
+
* @param executionContext - Execution context
|
|
871
|
+
* @returns Object with objectContext, userContext, and resolved currentObject
|
|
872
|
+
*/
|
|
873
|
+
async fetchContextsForOperationFunction(fn, resourceType, currentObject, executionContext) {
|
|
874
|
+
const needs = extractFunctionContextNeeds(fn);
|
|
875
|
+
let objectContext = undefined;
|
|
876
|
+
let initiatorUserContext = undefined;
|
|
877
|
+
if (needs.needsObjectContext) {
|
|
878
|
+
const resourceNeeds = this.populationService.analyzeContextNeeds(resourceType);
|
|
879
|
+
const computationContext = await this.populationService.fetchComputationContext(resourceType, currentObject || {}, resourceNeeds, executionContext);
|
|
880
|
+
objectContext = computationContext.objectContext;
|
|
881
|
+
}
|
|
882
|
+
if (needs.needsUserContext) {
|
|
883
|
+
initiatorUserContext = executionContext.user; // Initiator user context from execution context
|
|
884
|
+
}
|
|
885
|
+
return { objectContext, initiatorUserContext, currentObject };
|
|
886
|
+
}
|
|
887
|
+
/**
|
|
888
|
+
* Fetch current object for UPDATE/DELETE operations.
|
|
889
|
+
* For CREATE operations, returns undefined (object doesn't exist yet).
|
|
890
|
+
*
|
|
891
|
+
* @param coreOperation - The core operation type
|
|
892
|
+
* @param resourceType - Resource type
|
|
893
|
+
* @param id_or_ids_or_filter - ID or filter
|
|
894
|
+
* @param executionContext - Execution context
|
|
895
|
+
* @returns Current object or undefined for CREATE
|
|
896
|
+
*/
|
|
897
|
+
async fetchCurrentObjectForOperation(coreOperation, resourceType, id_or_ids_or_filter, executionContext) {
|
|
898
|
+
const isCreateOperation = coreOperation === CoreResourceOperation.CREATE ||
|
|
899
|
+
coreOperation === CoreResourceOperation.CREATE_MANY;
|
|
900
|
+
// For CREATE operations, currentObject is undefined (object doesn't exist yet)
|
|
901
|
+
if (isCreateOperation) {
|
|
902
|
+
return undefined;
|
|
903
|
+
}
|
|
904
|
+
const singleSelectedId = this.resolveSingleSelectedId(id_or_ids_or_filter);
|
|
905
|
+
// For UPDATE/DELETE/READ operations, fetch current object if we have exactly one ID
|
|
906
|
+
if (singleSelectedId) {
|
|
907
|
+
try {
|
|
908
|
+
const repo = this.repositoriesRegistry.getRepository(resourceType);
|
|
909
|
+
if (repo && 'read' in repo) {
|
|
910
|
+
const readResult = await repo.read(executionContext, singleSelectedId);
|
|
911
|
+
return Array.isArray(readResult) ? readResult[0] : readResult;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
catch (error) {
|
|
915
|
+
// If object doesn't exist, return undefined (enabledCondition will handle it)
|
|
916
|
+
this.logDebug('Failed to fetch current object for enabledCondition', {
|
|
917
|
+
resourceType,
|
|
918
|
+
id: singleSelectedId,
|
|
919
|
+
error: error instanceof Error ? error.message : 'Unknown'
|
|
920
|
+
});
|
|
921
|
+
return undefined;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
// Fallback: return undefined if we can't determine the object
|
|
925
|
+
return undefined;
|
|
926
|
+
}
|
|
927
|
+
static STEP_UP_EXEMPT_OPERATIONS = new Set([
|
|
928
|
+
CoreResourceOperation.READ,
|
|
929
|
+
CoreResourceOperation.LIST,
|
|
930
|
+
CoreResourceOperation.SEARCH,
|
|
931
|
+
CoreResourceOperation.COUNT,
|
|
932
|
+
]);
|
|
933
|
+
/**
|
|
934
|
+
* W7.1: Enforces step-up re-authentication for sensitive (mutating) operations.
|
|
935
|
+
*
|
|
936
|
+
* Skip conditions (all must be false for enforcement to apply):
|
|
937
|
+
* 1. Non-user requests (INTERNAL_CALL, API_KEY, etc.) — exempt
|
|
938
|
+
* 2. Worker executions — already authorized at queue time
|
|
939
|
+
* 3. Sub-calls (subCallDepth > 0) — parent already passed step-up
|
|
940
|
+
* 4. Read-only operations (READ, LIST, SEARCH, COUNT) — exempt
|
|
941
|
+
* 5. stepUpAuth not enabled for this user type — no-op
|
|
942
|
+
*
|
|
943
|
+
* When enforced and auth is stale (beyond maxAgeSeconds), accepts either:
|
|
944
|
+
* - A valid REAUTH consumable token via X-Reauth-Token header
|
|
945
|
+
* - Otherwise throws STEP_UP_REQUIRED (HTTP 403)
|
|
946
|
+
*/
|
|
947
|
+
async enforceStepUpAuth(coreOperation, executionContext, options) {
|
|
948
|
+
if (executionContext.executionType !== ExecutionContext_ExecutionType.USER_REQUEST)
|
|
949
|
+
return;
|
|
950
|
+
if (options?.isWorkerExecution)
|
|
951
|
+
return;
|
|
952
|
+
if (executionContext.subCallDepth > 0)
|
|
953
|
+
return;
|
|
954
|
+
if (coreOperation && ServiceResourceBackendService.STEP_UP_EXEMPT_OPERATIONS.has(coreOperation))
|
|
955
|
+
return;
|
|
956
|
+
const activeUserType = executionContext.activeUserType;
|
|
957
|
+
if (!activeUserType)
|
|
958
|
+
return;
|
|
959
|
+
const authPolicy = this.appConfigService.getUserTypeAuthPolicy(activeUserType);
|
|
960
|
+
const stepUpConfig = authPolicy?.stepUpAuth;
|
|
961
|
+
if (!stepUpConfig?.enabled)
|
|
962
|
+
return;
|
|
963
|
+
const lastAuthAt = executionContext.lastAuthenticatedAt ?? 0;
|
|
964
|
+
const nowSeconds = Math.floor(Date.now() / 1000);
|
|
965
|
+
if (nowSeconds - lastAuthAt <= stepUpConfig.maxAgeSeconds)
|
|
966
|
+
return;
|
|
967
|
+
const reAuthTokenValue = executionContext.reAuthTokenValue;
|
|
968
|
+
if (reAuthTokenValue) {
|
|
969
|
+
try {
|
|
970
|
+
const consumed = await this.consumableTokenService.consumeToken(reAuthTokenValue);
|
|
971
|
+
if (consumed.tokenType === CoreConsumableTokenTypes.REAUTH
|
|
972
|
+
&& consumed.userId === executionContext.initiatorIds.userId) {
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
catch (err) {
|
|
977
|
+
if (isWildoBackendError(err)) {
|
|
978
|
+
this.logDebug('Re-auth token consumption failed', { error: err.customMessageReference });
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {
|
|
983
|
+
customMessageReference: ErrorCustomMessageReference.STEP_UP_REQUIRED,
|
|
984
|
+
context: { maxAgeSeconds: stepUpConfig.maxAgeSeconds },
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
/**
|
|
988
|
+
* Central orchestration method — ALL resource operations flow through here.
|
|
989
|
+
*
|
|
990
|
+
* Two entry points:
|
|
991
|
+
* - `doByOperationPath()` — resolves `operation` from the operations map. The caller's
|
|
992
|
+
* `executionContext.operation` may differ (e.g., webhook context with a generic operation).
|
|
993
|
+
* - `doByExecutionContext()` — reads `operation` from `executionContext.operation`.
|
|
994
|
+
* Guaranteed to match (same reference).
|
|
995
|
+
*
|
|
996
|
+
* Two correction points enforce the invariant that `executionContext.operation` always
|
|
997
|
+
* matches the operation being executed:
|
|
998
|
+
* - Correction Point 1 (pre-queue): corrects to the base `operation` parameter.
|
|
999
|
+
* - Correction Point 2 (post-variant): refines to `resolvedOperation` when `dataMode !== RAW`.
|
|
1000
|
+
*
|
|
1001
|
+
* After correction, ALL downstream reads of `executionContext.operation` — notifications,
|
|
1002
|
+
* guidance, milestones, queue serialization, repositories — use the correct operation.
|
|
1003
|
+
*/
|
|
1004
|
+
async doOperation(operation, executionContext, id_or_ids_or_filter, data, options) {
|
|
1005
|
+
let currentState;
|
|
1006
|
+
if (operation.variantType === ResourceOperationVariantType.REPOSITORY_ONLY) {
|
|
1007
|
+
throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, { customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED });
|
|
1008
|
+
}
|
|
1009
|
+
// ── INVARIANT: executionContext.operation must match the operation being executed ──
|
|
1010
|
+
// Correction Point 1 (pre-queue): ensures queue serialization and all non-INLINE
|
|
1011
|
+
// dispatch paths use the correct operation. Without this, QueueBackendService.buildJobPayload
|
|
1012
|
+
// would serialize the caller's stale operation path.
|
|
1013
|
+
if (executionContext.operation !== operation) {
|
|
1014
|
+
this.logDebug('Correcting executionContext.operation mismatch', {
|
|
1015
|
+
contextOp: `${executionContext.operation.resourceIdentifier}.${executionContext.operation.operationIdentifier}`,
|
|
1016
|
+
actualOp: `${operation.resourceIdentifier}.${operation.operationIdentifier}`,
|
|
1017
|
+
});
|
|
1018
|
+
executionContext = executionContext.withOperation(operation);
|
|
1019
|
+
}
|
|
1020
|
+
// ============================================
|
|
1021
|
+
// STEP 1: Check serviceRuntimeMode FIRST
|
|
1022
|
+
// Skip this check if executing from worker (prevents infinite loop)
|
|
1023
|
+
// ============================================
|
|
1024
|
+
const runtimeMode = operation.serviceRuntimeMode ?? ResourceOperation_ServiceRuntimeMode.INLINE;
|
|
1025
|
+
if (!options?.isWorkerExecution && runtimeMode !== ResourceOperation_ServiceRuntimeMode.INLINE) {
|
|
1026
|
+
switch (runtimeMode) {
|
|
1027
|
+
case ResourceOperation_ServiceRuntimeMode.NONE:
|
|
1028
|
+
throw this.errorBuilder.buildError(ErrorType.CONFIGURATION, executionContext, {
|
|
1029
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED,
|
|
1030
|
+
context: { message: 'Operation has serviceRuntimeMode: NONE (disabled)' },
|
|
1031
|
+
});
|
|
1032
|
+
case ResourceOperation_ServiceRuntimeMode.QUEUED:
|
|
1033
|
+
// Queue and wait for result via RPC pattern
|
|
1034
|
+
return this.executeQueued(executionContext, id_or_ids_or_filter, data, true);
|
|
1035
|
+
case ResourceOperation_ServiceRuntimeMode.QUEUED_NOT_AWAITABLE:
|
|
1036
|
+
// Queue and return immediately
|
|
1037
|
+
return this.executeQueued(executionContext, id_or_ids_or_filter, data, false);
|
|
1038
|
+
case ResourceOperation_ServiceRuntimeMode.BACKGROUND_JOB:
|
|
1039
|
+
// Queue with callback pattern (async notification)
|
|
1040
|
+
return this.executeBackgroundJob(executionContext, id_or_ids_or_filter, data);
|
|
1041
|
+
case ResourceOperation_ServiceRuntimeMode.INLINE_NOT_AWAITABLE:
|
|
1042
|
+
// Fire and forget - execute async but don't wait
|
|
1043
|
+
this.executeInlineAsync(operation, executionContext, id_or_ids_or_filter, data, options);
|
|
1044
|
+
return { acknowledged: true };
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
// ============================================
|
|
1048
|
+
// STEP 2: Continue with inline execution (existing logic)
|
|
1049
|
+
// ============================================
|
|
1050
|
+
const operationIdentifier = String(operation.operationIdentifier);
|
|
1051
|
+
// CRITICAL FIX: Resolve operation variant BEFORE custom impl lookup
|
|
1052
|
+
// If dataMode is specified in options, resolve the variant first so custom impl
|
|
1053
|
+
// lookup can match the correct variant operation (e.g., 'context' variant)
|
|
1054
|
+
const dataMode = options?.dataMode ?? DataMode.RAW;
|
|
1055
|
+
const resolvedOperation = dataMode !== DataMode.RAW
|
|
1056
|
+
? this.resolveOperationVariant(operation, dataMode)
|
|
1057
|
+
: operation;
|
|
1058
|
+
// Correction Point 2 (post-variant): when dataMode !== RAW, the resolvedOperation
|
|
1059
|
+
// may differ from the base operation. Update the context to the variant so all
|
|
1060
|
+
// downstream reads (notifications, guidance, milestones, repos) use variant configs.
|
|
1061
|
+
if (executionContext.operation !== resolvedOperation) {
|
|
1062
|
+
executionContext = executionContext.withOperation(resolvedOperation);
|
|
1063
|
+
}
|
|
1064
|
+
this.logDebug('Operation variant resolution for doOperation', {
|
|
1065
|
+
operationIdentifier,
|
|
1066
|
+
originalVariantKey: operation.variantKey,
|
|
1067
|
+
dataMode,
|
|
1068
|
+
resolvedVariantKey: resolvedOperation.variantKey,
|
|
1069
|
+
variantResolved: resolvedOperation !== operation
|
|
1070
|
+
});
|
|
1071
|
+
const operationPath = ResourcesConfig_OperationPathUtils.extractOperationPath(resolvedOperation);
|
|
1072
|
+
const coreOperation = ResourceOperationsUtils.getCoreResourceOperationFromOperation(resolvedOperation);
|
|
1073
|
+
const generatedBulkRelationshipOperation = Resources_SharedUtils.parseRelationshipBulkOperationIdentifier(operationIdentifier);
|
|
1074
|
+
if (generatedBulkRelationshipOperation) {
|
|
1075
|
+
await this.featureGate.checkOperationFeatures(resolvedOperation, executionContext, data);
|
|
1076
|
+
await this.enforceStepUpAuth(coreOperation, executionContext, options);
|
|
1077
|
+
return this.executeGeneratedRelationshipBulkOperation(resolvedOperation, generatedBulkRelationshipOperation, executionContext, data, options);
|
|
1078
|
+
}
|
|
1079
|
+
// Lookup custom impl registrations with RESOLVED operation (includes variantKey if dataMode specified)
|
|
1080
|
+
const customImplRegistrations = this.customImplRegistry.getRegistrationsForOperation(resolvedOperation);
|
|
1081
|
+
const customImplPlaceholders = new Set(customImplRegistrations.flatMap(r => r.implementation.getPlaceholders()));
|
|
1082
|
+
this.logDebug('Custom implementation check', {
|
|
1083
|
+
operationIdentifier,
|
|
1084
|
+
resourceIdentifier: this.resourceConfiguration.resourceIdentifier,
|
|
1085
|
+
registrationCount: customImplRegistrations.length,
|
|
1086
|
+
placeholders: [...customImplPlaceholders],
|
|
1087
|
+
registrations: customImplRegistrations.map(r => r.debugLabel),
|
|
1088
|
+
operationPathKey: ResourcesConfig_OperationPathUtils.createOperationPathKeyFromOperation(resolvedOperation),
|
|
1089
|
+
usedResolvedOperation: resolvedOperation !== operation
|
|
1090
|
+
});
|
|
1091
|
+
// Fetch current object for UPDATE/DELETE operations (needed for enabledCondition and basicPrefixOperation)
|
|
1092
|
+
const resourceType = this.resourceConfiguration.resourceIdentifier;
|
|
1093
|
+
const currentObject = await this.fetchCurrentObjectForOperation(coreOperation, resourceType, id_or_ids_or_filter, executionContext);
|
|
1094
|
+
const hookCurrentObject = this.resolveHookCurrentObject(coreOperation, currentObject, data);
|
|
1095
|
+
// Fetch computation context for custom implementations
|
|
1096
|
+
const needs = this.populationService.analyzeContextNeeds(resourceType);
|
|
1097
|
+
const computationContext = await this.populationService.fetchComputationContext(resourceType, hookCurrentObject || {}, needs, executionContext);
|
|
1098
|
+
const customImplUtils = {
|
|
1099
|
+
logger: this.logger,
|
|
1100
|
+
errorBuilder: this.errorBuilder,
|
|
1101
|
+
resourcesRegistry: this.resourcesRegistry,
|
|
1102
|
+
servicesRegistry: this.servicesRegistry,
|
|
1103
|
+
repositoriesRegistry: this.repositoriesRegistry,
|
|
1104
|
+
externalApiHandler: this.externalApiHandler,
|
|
1105
|
+
platformMutualizedHandler: this.platformMutualizedHandler,
|
|
1106
|
+
serverlessServicesHandler: this.serverlessServicesHandler,
|
|
1107
|
+
executionContextCreator: this.executionContextCreator,
|
|
1108
|
+
samlMetadataService: this.servicesRegistry.getSamlMetadataService?.(),
|
|
1109
|
+
objectContext: {
|
|
1110
|
+
parents: computationContext.objectContext?.parents || {},
|
|
1111
|
+
children: computationContext.objectContext?.children || {}
|
|
1112
|
+
},
|
|
1113
|
+
initiatorUserContext: computationContext.userContext,
|
|
1114
|
+
currentObject: hookCurrentObject
|
|
1115
|
+
};
|
|
1116
|
+
// Check feature gate — is this capability available for this scope?
|
|
1117
|
+
// Runs before enabledCondition because feature availability is independent of RBAC/object state.
|
|
1118
|
+
// The gate handles its own bypass logic (INTERNAL_CALL, REPOSITORY_ONLY, system resources).
|
|
1119
|
+
await this.featureGate.checkOperationFeatures(resolvedOperation, executionContext, data);
|
|
1120
|
+
// W7.1: Step-up authentication enforcement
|
|
1121
|
+
await this.enforceStepUpAuth(coreOperation, executionContext, options);
|
|
1122
|
+
// Check enabledCondition if it exists (available in both frontend and backend)
|
|
1123
|
+
// Only API_CALL and API_CALL_WITH_CALLBACK variants have enabledCondition
|
|
1124
|
+
if ('enabledCondition' in operation && operation.enabledCondition) {
|
|
1125
|
+
this.assertBulkHookObjectContextAvailability(coreOperation, operation.isBulkOperation, operation.enabledCondition, currentObject, executionContext, operationIdentifier, 'enabledCondition');
|
|
1126
|
+
// Fetch contexts only if needed
|
|
1127
|
+
const { objectContext, initiatorUserContext } = await this.fetchContextsForOperationFunction(operation.enabledCondition, resourceType, currentObject, executionContext);
|
|
1128
|
+
// Check if operation is enabled
|
|
1129
|
+
const isEnabled = operation.enabledCondition({
|
|
1130
|
+
inputDto: data,
|
|
1131
|
+
currentObject: hookCurrentObject,
|
|
1132
|
+
objectContext,
|
|
1133
|
+
initiatorUserContext,
|
|
1134
|
+
initiatorIds: executionContext.initiatorIds,
|
|
1135
|
+
});
|
|
1136
|
+
if (!isEnabled) {
|
|
1137
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, { customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_DISABLED });
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
if (customImplPlaceholders.has(ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL)) {
|
|
1141
|
+
const winner = this.customImplRegistry.resolveSingleOwner(customImplRegistrations, ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL, this.logger);
|
|
1142
|
+
if (winner) {
|
|
1143
|
+
return winner.implementation.overrideAll(id_or_ids_or_filter, data, executionContext, customImplUtils);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
// Check for custom implementation - basicPrefixOperation
|
|
1147
|
+
// Use resolvedOperation to get correct variant-specific configuration
|
|
1148
|
+
if ('basicPrefixOperation' in resolvedOperation && resolvedOperation.basicPrefixOperation) {
|
|
1149
|
+
this.assertBulkHookObjectContextAvailability(coreOperation, 'isBulkOperation' in resolvedOperation ? resolvedOperation.isBulkOperation : false, resolvedOperation.basicPrefixOperation, currentObject, executionContext, operationIdentifier, 'basicPrefixOperation');
|
|
1150
|
+
// Fetch contexts only if needed
|
|
1151
|
+
const { objectContext, initiatorUserContext } = await this.fetchContextsForOperationFunction(resolvedOperation.basicPrefixOperation, resourceType, currentObject, executionContext);
|
|
1152
|
+
const inputAdding = resolvedOperation.basicPrefixOperation({
|
|
1153
|
+
inputDto: data,
|
|
1154
|
+
currentObject: hookCurrentObject,
|
|
1155
|
+
objectContext,
|
|
1156
|
+
initiatorUserContext,
|
|
1157
|
+
initiatorIds: executionContext.initiatorIds,
|
|
1158
|
+
});
|
|
1159
|
+
// Ensure inputAdding is an object before spreading
|
|
1160
|
+
if (inputAdding && typeof inputAdding === 'object' && !Array.isArray(inputAdding)) {
|
|
1161
|
+
data = { ...data, ...inputAdding };
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
if (customImplPlaceholders.has(ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS)) {
|
|
1165
|
+
const prefixRegs = this.customImplRegistry.resolveRegistrationsForMode(customImplRegistrations, ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS, this.logger);
|
|
1166
|
+
for (const reg of prefixRegs) {
|
|
1167
|
+
const prefixResult = await reg.implementation.prefixCoreOperations(id_or_ids_or_filter, data, executionContext, customImplUtils);
|
|
1168
|
+
if (Array.isArray(data)) {
|
|
1169
|
+
// Array inputs (CREATE_MANY): handler must return the full transformed array
|
|
1170
|
+
if (Array.isArray(prefixResult)) {
|
|
1171
|
+
data = prefixResult;
|
|
1172
|
+
}
|
|
1173
|
+
else {
|
|
1174
|
+
this.logDebug(`[CustomImpl] PREFIX handler [${reg.debugLabel}] returned non-array for array input, result ignored`);
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
else if (prefixResult && typeof prefixResult === 'object' && !Array.isArray(prefixResult)) {
|
|
1178
|
+
data = { ...data, ...prefixResult };
|
|
1179
|
+
}
|
|
1180
|
+
else if (prefixResult !== undefined && prefixResult !== null) {
|
|
1181
|
+
this.logDebug(`[CustomImpl] PREFIX handler [${reg.debugLabel}] returned non-object (${typeof prefixResult}), result ignored`);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
// PREFIX augments `data` for the core write — do NOT set `currentState`.
|
|
1185
|
+
// Leaving it undefined ensures revocationTarget falls back to `currentObject`
|
|
1186
|
+
// (the pre-fetched DB record), which has the identity fields needed for revocation.
|
|
1187
|
+
}
|
|
1188
|
+
// ── TOKEN REVOCATION (pre-operation) ────────────────────────────────
|
|
1189
|
+
// Revoke existing tokens BEFORE the core operation (e.g., on DELETE).
|
|
1190
|
+
// Uses currentObject (the pre-existing DB record fetched at line ~781) to resolve the relatedId.
|
|
1191
|
+
// Use 'in' narrowing because ResourceConfiguration_Operation is a union — CronJob variant lacks tokenRevocation.
|
|
1192
|
+
const revocationTarget = currentObject;
|
|
1193
|
+
if ('tokenRevocation' in resolvedOperation && resolvedOperation.tokenRevocation && revocationTarget) {
|
|
1194
|
+
await this.consumableTokenService.processTokenRevocation(resolvedOperation.tokenRevocation, revocationTarget, { organizationId: executionContext.initiatorIds?.organizationId });
|
|
1195
|
+
}
|
|
1196
|
+
// Handle core operations - use resolvedOperation for variant-aware execution
|
|
1197
|
+
switch (coreOperation) {
|
|
1198
|
+
case CoreResourceOperation.CREATE:
|
|
1199
|
+
currentState = await this.create(resolvedOperation, executionContext, data, options);
|
|
1200
|
+
break;
|
|
1201
|
+
case CoreResourceOperation.CREATE_MANY:
|
|
1202
|
+
currentState = await this.createMany(resolvedOperation, executionContext, data, options);
|
|
1203
|
+
break;
|
|
1204
|
+
case CoreResourceOperation.READ:
|
|
1205
|
+
currentState = await this.read(resolvedOperation, executionContext, id_or_ids_or_filter, options);
|
|
1206
|
+
break;
|
|
1207
|
+
case CoreResourceOperation.UPDATE:
|
|
1208
|
+
currentState = await this.update(resolvedOperation, executionContext, id_or_ids_or_filter, data, options);
|
|
1209
|
+
break;
|
|
1210
|
+
case CoreResourceOperation.UPDATE_MANY:
|
|
1211
|
+
currentState = await this.updateMany(resolvedOperation, executionContext, id_or_ids_or_filter, data, options);
|
|
1212
|
+
break;
|
|
1213
|
+
case CoreResourceOperation.DELETE:
|
|
1214
|
+
currentState = await this.delete(resolvedOperation, executionContext, id_or_ids_or_filter, options);
|
|
1215
|
+
break;
|
|
1216
|
+
case CoreResourceOperation.DELETE_MANY:
|
|
1217
|
+
currentState = await this.deleteMany(resolvedOperation, executionContext, id_or_ids_or_filter, options);
|
|
1218
|
+
break;
|
|
1219
|
+
case CoreResourceOperation.LIST:
|
|
1220
|
+
currentState = await this.list(resolvedOperation, executionContext, data?.filter, { page: data?.page, limit: data?.limit }, options);
|
|
1221
|
+
break;
|
|
1222
|
+
case CoreResourceOperation.COUNT:
|
|
1223
|
+
currentState = await this.count(resolvedOperation, executionContext, data?.filter, options);
|
|
1224
|
+
break;
|
|
1225
|
+
case CoreResourceOperation.SEARCH:
|
|
1226
|
+
currentState = await this.search(resolvedOperation, executionContext, data?.searchQuery ?? '', data?.filter, {
|
|
1227
|
+
...(options ?? {}),
|
|
1228
|
+
searchOptions: {
|
|
1229
|
+
page: data?.page,
|
|
1230
|
+
limit: data?.limit,
|
|
1231
|
+
sort: data?.sort,
|
|
1232
|
+
},
|
|
1233
|
+
});
|
|
1234
|
+
break;
|
|
1235
|
+
default:
|
|
1236
|
+
throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, { customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED, context: { operationIdentifier, operationPath } });
|
|
1237
|
+
}
|
|
1238
|
+
if (customImplPlaceholders.has(ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS)) {
|
|
1239
|
+
const replaceWinner = this.customImplRegistry.resolveSingleOwner(customImplRegistrations, ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS, this.logger);
|
|
1240
|
+
if (replaceWinner) {
|
|
1241
|
+
currentState = await replaceWinner.implementation.replaceCoreOperations(id_or_ids_or_filter, data, executionContext, customImplUtils);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
if (customImplPlaceholders.has(ResourceOperation_CustomServiceImplementationMode.POSTFIX_CORE_OPERARTIONS)) {
|
|
1245
|
+
const postfixRegs = this.customImplRegistry.resolveRegistrationsForMode(customImplRegistrations, ResourceOperation_CustomServiceImplementationMode.POSTFIX_CORE_OPERARTIONS, this.logger);
|
|
1246
|
+
for (const reg of postfixRegs) {
|
|
1247
|
+
this.logDebug(`Executing postfixCoreOperations [${reg.debugLabel}]`, {
|
|
1248
|
+
operationIdentifier,
|
|
1249
|
+
currentStateKeys: currentState && typeof currentState === 'object' ? Object.keys(currentState) : typeof currentState,
|
|
1250
|
+
});
|
|
1251
|
+
currentState = await reg.implementation.postfixCoreOperations(id_or_ids_or_filter, currentState, executionContext, customImplUtils);
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
// ── TOKEN GENERATION (post-operation) ─────────────────────────────
|
|
1255
|
+
// Generate a new token as a side-effect of a successful operation.
|
|
1256
|
+
// The tokenValue is injected into notification additionalContext for email templates.
|
|
1257
|
+
let tokenGenerationResult = null;
|
|
1258
|
+
// Use 'in' narrowing because ResourceConfiguration_Operation is a union — CronJob variant lacks tokenGeneration.
|
|
1259
|
+
if ('tokenGeneration' in resolvedOperation && resolvedOperation.tokenGeneration && currentState) {
|
|
1260
|
+
tokenGenerationResult = await this.consumableTokenService.processTokenGeneration(resolvedOperation.tokenGeneration, currentState, {
|
|
1261
|
+
organizationId: executionContext.initiatorIds?.organizationId,
|
|
1262
|
+
userId: executionContext.initiatorIds?.userId,
|
|
1263
|
+
resourceType: operation.resourceIdentifier,
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
// ── TOKEN CONSUMPTION (post-operation, MF2) ─────────────────────
|
|
1267
|
+
// Consume the token ONLY after the core operation succeeded (Trap 4).
|
|
1268
|
+
// Checks consumableTokenValue presence (not executionType) so it works for BOTH:
|
|
1269
|
+
// - ALTERNATIVE tokens (executionType = CONSUMABLE_TOKEN)
|
|
1270
|
+
// - ADDITIVE tokens (executionType = USER_REQUEST, token validated alongside JWT)
|
|
1271
|
+
// consumptionMode logic (SINGLE_USE vs BOUNDED_REUSE) lives inside consumeToken().
|
|
1272
|
+
if (executionContext.consumableTokenValue) {
|
|
1273
|
+
await this.consumableTokenService.consumeToken(executionContext.consumableTokenValue);
|
|
1274
|
+
executionContext.markConsumableTokenConsumed();
|
|
1275
|
+
}
|
|
1276
|
+
// Dispatch notifications after the main operation/postfix work and token
|
|
1277
|
+
// consumption. This path is intentionally unconditional: resource-room
|
|
1278
|
+
// coherence is part of the standard post-write contract even when authored
|
|
1279
|
+
// notification arrays are empty, and NotificationDispatcherService already
|
|
1280
|
+
// no-ops internally for empty/non-write lanes.
|
|
1281
|
+
await this.dispatchNotifications(executionContext, data, currentState, tokenGenerationResult);
|
|
1282
|
+
// GUIDANCE / MILESTONE / LIFECYCLE EVALUATIONS (fire-and-forget)
|
|
1283
|
+
// NOTE: In-flight evaluations are lost on server restart.
|
|
1284
|
+
// Self-healing: next user operation re-triggers evaluation.
|
|
1285
|
+
// Acceptable trade-off for v1 — eliminates request latency impact.
|
|
1286
|
+
// GUIDANCE TRIGGER EVALUATION: Fire-and-forget evaluation of guidance flows
|
|
1287
|
+
// triggered by EVENT-type triggers matching this resource operation.
|
|
1288
|
+
// Wrapped in setImmediate to avoid occupying the current event loop tick.
|
|
1289
|
+
if (this.guidanceTriggerEvaluator) {
|
|
1290
|
+
setImmediate(() => {
|
|
1291
|
+
this.guidanceTriggerEvaluator.evaluateForOperation({
|
|
1292
|
+
resourceType: executionContext.operation.resourceIdentifier,
|
|
1293
|
+
operationIdentifier: executionContext.operation.operationIdentifier,
|
|
1294
|
+
userId: executionContext.initiatorIds?.userId ?? '',
|
|
1295
|
+
organizationId: executionContext.initiatorIds?.organizationId,
|
|
1296
|
+
}).catch((err) => {
|
|
1297
|
+
this.logDebug('Guidance trigger evaluation failed (non-blocking)', {
|
|
1298
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1299
|
+
});
|
|
1300
|
+
});
|
|
1301
|
+
});
|
|
1302
|
+
}
|
|
1303
|
+
// MILESTONE EVALUATION: Fire-and-forget evaluation of milestone conditions
|
|
1304
|
+
// triggered by the current resource operation. Runs after guidance evaluation.
|
|
1305
|
+
if (this.milestoneEvaluator) {
|
|
1306
|
+
setImmediate(() => {
|
|
1307
|
+
this.milestoneEvaluator.evaluateForOperation({
|
|
1308
|
+
resourceType: executionContext.operation.resourceIdentifier,
|
|
1309
|
+
operationIdentifier: executionContext.operation.operationIdentifier,
|
|
1310
|
+
userId: executionContext.initiatorIds?.userId ?? '',
|
|
1311
|
+
organizationId: executionContext.initiatorIds?.organizationId,
|
|
1312
|
+
}).catch((err) => {
|
|
1313
|
+
this.logDebug('Milestone evaluation failed (non-blocking)', {
|
|
1314
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1315
|
+
});
|
|
1316
|
+
});
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
// LIFECYCLE ACTIVITY CHECK: Fire-and-forget tri-scope activity tracking + reactivation
|
|
1320
|
+
if (this.lifecycleEvaluator) {
|
|
1321
|
+
setImmediate(() => {
|
|
1322
|
+
this.lifecycleEvaluator.onOperation({
|
|
1323
|
+
userId: executionContext.initiatorIds?.userId ?? '',
|
|
1324
|
+
organizationId: executionContext.initiatorIds?.organizationId,
|
|
1325
|
+
operationIdentifier: String(operationPath.operationIdentifier),
|
|
1326
|
+
resourceIdentifier: operationPath.resourceIdentifier,
|
|
1327
|
+
executionContext,
|
|
1328
|
+
}).catch((err) => {
|
|
1329
|
+
this.logDebug('Lifecycle activity check failed (non-blocking)', {
|
|
1330
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1331
|
+
});
|
|
1332
|
+
});
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
if (customImplPlaceholders.has(ResourceOperation_CustomServiceImplementationMode.AFTER_USER_NOTIFICATIONS)) {
|
|
1336
|
+
const afterNotifRegs = this.customImplRegistry.resolveRegistrationsForMode(customImplRegistrations, ResourceOperation_CustomServiceImplementationMode.AFTER_USER_NOTIFICATIONS, this.logger);
|
|
1337
|
+
for (const reg of afterNotifRegs) {
|
|
1338
|
+
currentState = await reg.implementation.afterUserNotifications(id_or_ids_or_filter, currentState, executionContext, customImplUtils);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
if (customImplPlaceholders.has(ResourceOperation_CustomServiceImplementationMode.AT_THE_END)) {
|
|
1342
|
+
const atEndRegs = this.customImplRegistry.resolveRegistrationsForMode(customImplRegistrations, ResourceOperation_CustomServiceImplementationMode.AT_THE_END, this.logger);
|
|
1343
|
+
for (const reg of atEndRegs) {
|
|
1344
|
+
currentState = await reg.implementation.atTheEnd(id_or_ids_or_filter, currentState, executionContext, customImplUtils);
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
// READ/UPDATE/DELETE can legitimately return null (document not found).
|
|
1348
|
+
// Skip Zod output validation for null — callers already handle it.
|
|
1349
|
+
if (currentState == null) {
|
|
1350
|
+
return null;
|
|
1351
|
+
}
|
|
1352
|
+
// Transform output using resolved operation's internalDto
|
|
1353
|
+
// Use the already-resolved operation to avoid double resolution
|
|
1354
|
+
const finalResult = await this.transformOutput(executionContext, currentState, dataMode, resolvedOperation);
|
|
1355
|
+
return finalResult;
|
|
1356
|
+
}
|
|
1357
|
+
// ================================
|
|
1358
|
+
// Queue Runtime Mode Methods
|
|
1359
|
+
// ================================
|
|
1360
|
+
/**
|
|
1361
|
+
* Execute operation via queue with RPC pattern (QUEUED / QUEUED_NOT_AWAITABLE).
|
|
1362
|
+
*
|
|
1363
|
+
* @param executionContext - The execution context with operation
|
|
1364
|
+
* @param id_or_ids_or_filter - Resource ID(s) or filter for the operation
|
|
1365
|
+
* @param data - Input data for the operation
|
|
1366
|
+
* @param awaitable - If true, wait for result (QUEUED); if false, return immediately (QUEUED_NOT_AWAITABLE)
|
|
1367
|
+
* @returns For awaitable: the operation result; otherwise: { jobId, status: 'queued' }
|
|
1368
|
+
*/
|
|
1369
|
+
async executeQueued(executionContext, id_or_ids_or_filter, data, awaitable) {
|
|
1370
|
+
// Extract inputId for READ/UPDATE/DELETE operations
|
|
1371
|
+
const inputId = typeof id_or_ids_or_filter === 'string' ? id_or_ids_or_filter : undefined;
|
|
1372
|
+
if (awaitable) {
|
|
1373
|
+
// QUEUED: Wait for result via RPC
|
|
1374
|
+
return this.queueService.enqueueAndWait(executionContext, data, inputId);
|
|
1375
|
+
}
|
|
1376
|
+
else {
|
|
1377
|
+
// QUEUED_NOT_AWAITABLE: Fire and forget to queue
|
|
1378
|
+
const result = await this.queueService.enqueueOperation(executionContext, data, inputId);
|
|
1379
|
+
return { jobId: result.jobId, status: 'queued' };
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
/**
|
|
1383
|
+
* Execute operation via queue with callback pattern (BACKGROUND_JOB).
|
|
1384
|
+
* Returns immediately with job tracking info.
|
|
1385
|
+
*
|
|
1386
|
+
* @param executionContext - The execution context with operation
|
|
1387
|
+
* @param id_or_ids_or_filter - Resource ID(s) or filter for the operation
|
|
1388
|
+
* @param data - Input data for the operation
|
|
1389
|
+
* @returns Job tracking info: { jobId, status: 'processing', message }
|
|
1390
|
+
*/
|
|
1391
|
+
async executeBackgroundJob(executionContext, id_or_ids_or_filter, data) {
|
|
1392
|
+
const inputId = typeof id_or_ids_or_filter === 'string' ? id_or_ids_or_filter : undefined;
|
|
1393
|
+
// Enqueue with callback (async result notification)
|
|
1394
|
+
const result = await this.queueService.enqueueWithCallback(executionContext, data, inputId);
|
|
1395
|
+
// Return immediately with job tracking info
|
|
1396
|
+
return {
|
|
1397
|
+
jobId: result.jobId,
|
|
1398
|
+
status: 'processing',
|
|
1399
|
+
message: 'Job has been queued for background processing',
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1402
|
+
/**
|
|
1403
|
+
* Execute operation inline but don't wait for result (INLINE_NOT_AWAITABLE).
|
|
1404
|
+
* Fire and forget pattern - executes in the next tick.
|
|
1405
|
+
*
|
|
1406
|
+
* @param operation - The operation to execute
|
|
1407
|
+
* @param executionContext - The execution context
|
|
1408
|
+
* @param id_or_ids_or_filter - Resource ID(s) or filter
|
|
1409
|
+
* @param data - Input data
|
|
1410
|
+
* @param options - Repository options
|
|
1411
|
+
*/
|
|
1412
|
+
executeInlineAsync(operation, executionContext, id_or_ids_or_filter, data, options) {
|
|
1413
|
+
// Execute in next tick, don't await - use setImmediate for true async
|
|
1414
|
+
setImmediate(async () => {
|
|
1415
|
+
try {
|
|
1416
|
+
// Call doOperation with isWorkerExecution to prevent infinite loop
|
|
1417
|
+
await this.doOperation(operation, executionContext, id_or_ids_or_filter, data, {
|
|
1418
|
+
...options,
|
|
1419
|
+
isWorkerExecution: true, // Prevents runtime mode check
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1422
|
+
catch (error) {
|
|
1423
|
+
this.logger.error('Inline async operation failed', {
|
|
1424
|
+
operationPathKey: ResourcesConfig_OperationPathUtils.createOperationPathKeyFromOperation(operation),
|
|
1425
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1428
|
+
});
|
|
1429
|
+
}
|
|
1430
|
+
async callRepository(operation, executionContext, id_or_ids_or_filter, data, options) {
|
|
1431
|
+
const resourceType = this.resourceConfiguration.resourceIdentifier;
|
|
1432
|
+
const repository = this.repositoriesRegistry.getRepositoryOrThrow(resourceType);
|
|
1433
|
+
const operationRepositoryPath = ResourcesConfig_OperationPathUtils.extractOperationRepositoryPath(operation);
|
|
1434
|
+
return repository.doByPath(operationRepositoryPath, executionContext, id_or_ids_or_filter, data, options);
|
|
1435
|
+
}
|
|
1436
|
+
// ================================
|
|
1437
|
+
// Business Logic Methods
|
|
1438
|
+
// ================================
|
|
1439
|
+
async create(operation, executionContext, data, options) {
|
|
1440
|
+
this.logDebug('Executing create business operation');
|
|
1441
|
+
// 0. Clean input data (remove mandatory discard fields)
|
|
1442
|
+
const cleanedData = this.repositoryHelper.cleanInputData(data, CoreResourceOperation.CREATE);
|
|
1443
|
+
this.logDebug('Data cleaned for create operation', {
|
|
1444
|
+
originalKeys: typeof data === 'object' ? Object.keys(data) : 'not-object',
|
|
1445
|
+
cleanedKeys: typeof cleanedData === 'object' ? Object.keys(cleanedData) : 'not-object'
|
|
1446
|
+
});
|
|
1447
|
+
// 1. Validate input against operation's requestDto
|
|
1448
|
+
const validatedData = await this.validateAndTransformInput(executionContext, cleanedData);
|
|
1449
|
+
// 2. Extract nested data if nested operations are configured
|
|
1450
|
+
const resourceRelationships = this.resourceConfiguration.resourceRelationships;
|
|
1451
|
+
const childRelationships = getChildDirectionRelationships(resourceRelationships);
|
|
1452
|
+
const relationshipsWithNested = childRelationships.filter(rel => this.getResolvedNestedMutationConfig(rel, CoreResourceOperation.CREATE));
|
|
1453
|
+
const { parentData, nestedData } = relationshipsWithNested.length > 0
|
|
1454
|
+
? this.extractNestedData(validatedData, relationshipsWithNested, CoreResourceOperation.CREATE)
|
|
1455
|
+
: { parentData: validatedData, nestedData: {} };
|
|
1456
|
+
// 3. Apply business validation
|
|
1457
|
+
const businessValidatedData = await this.applyBusinessValidation(CoreResourceOperation.CREATE, parentData, executionContext);
|
|
1458
|
+
// 3.5. Validate file fields (fail fast before resource creation)
|
|
1459
|
+
// ============================================================================
|
|
1460
|
+
// FILE FIELD VALIDATION (Pre-CREATE)
|
|
1461
|
+
// ============================================================================
|
|
1462
|
+
// This validation runs BEFORE resource creation to fail fast if file references
|
|
1463
|
+
// are invalid. However, note the following limitations:
|
|
1464
|
+
//
|
|
1465
|
+
// 1. Files are validated by fileId lookup but scope validation (ensuring the file
|
|
1466
|
+
// belongs to the same organization/user scope) relies on organizationId in
|
|
1467
|
+
// ExecutionContext. Scope-based file segregation is not fully implemented.
|
|
1468
|
+
//
|
|
1469
|
+
// 2. The validation doesn't check if the user has permission to link the specific
|
|
1470
|
+
// file - only that the file exists and is in UPLOADED status.
|
|
1471
|
+
//
|
|
1472
|
+
// 3. For PostgreSQL resources, file metadata lookup still uses MongoDB,
|
|
1473
|
+
// which could have latency implications.
|
|
1474
|
+
//
|
|
1475
|
+
// See: .cursor/plans for file/storage context
|
|
1476
|
+
// ============================================================================
|
|
1477
|
+
const resourceType = this.resourceConfiguration.resourceIdentifier;
|
|
1478
|
+
if (this.fileFieldDetection.hasFileFields(resourceType)) {
|
|
1479
|
+
try {
|
|
1480
|
+
await this.fileOperationHandler.validateFileFieldsForCreate(businessValidatedData, resourceType, executionContext, this.buildFileRepositoryOptions(options));
|
|
1481
|
+
}
|
|
1482
|
+
catch (error) {
|
|
1483
|
+
// File validation errors should fail the operation
|
|
1484
|
+
throw error;
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
// 4. Execute pre-creation business logic
|
|
1488
|
+
const enrichedData = await this.executePreOperationLogic(CoreResourceOperation.CREATE, businessValidatedData, executionContext);
|
|
1489
|
+
// 5. Execute repository operation (create parent) and process nested operations
|
|
1490
|
+
// ALWAYS use transaction for file operations, even without nested operations
|
|
1491
|
+
// Extract organizationId early (needed for file operations and transactions)
|
|
1492
|
+
const hasFileFields = this.fileFieldDetection.hasFileFields(resourceType);
|
|
1493
|
+
const hasNestedOperations = relationshipsWithNested.length > 0 && Object.keys(nestedData).length > 0;
|
|
1494
|
+
const persistenceAdapter = this.getResolvedPersistenceAdapter();
|
|
1495
|
+
let result;
|
|
1496
|
+
if (hasNestedOperations || hasFileFields) {
|
|
1497
|
+
result = await this.executeResourceTransaction(executionContext, async (optionsWithTransaction) => {
|
|
1498
|
+
// 1. Create resource within transaction
|
|
1499
|
+
const parentResult = await this.callRepository(operation, executionContext, undefined, enrichedData, optionsWithTransaction);
|
|
1500
|
+
const activeRelationships = hasNestedOperations
|
|
1501
|
+
? this.filterRelationshipsByParent(relationshipsWithNested, parentResult)
|
|
1502
|
+
: [];
|
|
1503
|
+
if (activeRelationships.length > 0) {
|
|
1504
|
+
this.assertNestedMutationAdaptersMatchCurrentResource(activeRelationships, executionContext);
|
|
1505
|
+
}
|
|
1506
|
+
if (persistenceAdapter === 'postgresql') {
|
|
1507
|
+
if (activeRelationships.length > 0) {
|
|
1508
|
+
await this.processNestedOperations(CoreResourceOperation.CREATE, parentResult, nestedData, {}, activeRelationships, executionContext, optionsWithTransaction);
|
|
1509
|
+
}
|
|
1510
|
+
if (hasFileFields) {
|
|
1511
|
+
const resourceId = parentResult?._id?.toString() || parentResult?.id;
|
|
1512
|
+
if (resourceId) {
|
|
1513
|
+
await this.executeFileMetadataWork(executionContext, options, async (fileOptions) => this.fileOperationHandler.processFileFieldsForCreate(enrichedData, resourceType, resourceId, executionContext, fileOptions));
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
else {
|
|
1518
|
+
// Mongo-backed resources still keep parent + file metadata mutations in
|
|
1519
|
+
// the same transaction context.
|
|
1520
|
+
if (hasFileFields) {
|
|
1521
|
+
const resourceId = parentResult?._id?.toString() || parentResult?.id;
|
|
1522
|
+
if (resourceId) {
|
|
1523
|
+
await this.fileOperationHandler.processFileFieldsForCreate(enrichedData, resourceType, resourceId, executionContext, optionsWithTransaction);
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
if (activeRelationships.length > 0) {
|
|
1527
|
+
await this.processNestedOperations(CoreResourceOperation.CREATE, parentResult, nestedData, {}, activeRelationships, executionContext, optionsWithTransaction);
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
return parentResult;
|
|
1531
|
+
}, options);
|
|
1532
|
+
}
|
|
1533
|
+
else {
|
|
1534
|
+
// No file fields, no nested operations - no transaction needed
|
|
1535
|
+
result = await this.callRepository(operation, executionContext, undefined, enrichedData, options);
|
|
1536
|
+
}
|
|
1537
|
+
// 8. Execute post-creation business logic (including engine cascading)
|
|
1538
|
+
const processedResult = await this.executePostOperationLogic(CoreResourceOperation.CREATE, result, executionContext);
|
|
1539
|
+
this.logDebug('Create business operation completed');
|
|
1540
|
+
return processedResult;
|
|
1541
|
+
}
|
|
1542
|
+
async createMany(operation, executionContext, data, options) {
|
|
1543
|
+
this.logDebug('Executing createMany business operation');
|
|
1544
|
+
const normalizedCreateManyPayload = this.normalizeCreateManyRequestPayload(data, executionContext);
|
|
1545
|
+
// 0. Clean input data array (remove mandatory discard fields)
|
|
1546
|
+
const cleanedDataArray = this.repositoryHelper.cleanInputDataArray(normalizedCreateManyPayload.data, CoreResourceOperation.CREATE_MANY);
|
|
1547
|
+
const cleanedRequestPayload = {
|
|
1548
|
+
...normalizedCreateManyPayload,
|
|
1549
|
+
data: cleanedDataArray,
|
|
1550
|
+
};
|
|
1551
|
+
this.logDebug('Data array cleaned for createMany operation', {
|
|
1552
|
+
originalCount: normalizedCreateManyPayload.data.length,
|
|
1553
|
+
cleanedCount: cleanedDataArray?.length
|
|
1554
|
+
});
|
|
1555
|
+
// 1. Validate input against operation's requestDto
|
|
1556
|
+
const validatedData = await this.validateAndTransformInput(executionContext, cleanedRequestPayload);
|
|
1557
|
+
// 2. Extract nested data per item if nested operations are configured
|
|
1558
|
+
const resourceRelationships = this.resourceConfiguration.resourceRelationships;
|
|
1559
|
+
const childRelationships = getChildDirectionRelationships(resourceRelationships);
|
|
1560
|
+
const relationshipsWithNested = childRelationships.filter(rel => this.getResolvedNestedMutationConfig(rel, CoreResourceOperation.CREATE_MANY));
|
|
1561
|
+
const validatedDataArray = this.normalizeCreateManyInput(validatedData, executionContext);
|
|
1562
|
+
const { parentDataArray, nestedDataArray } = relationshipsWithNested.length > 0
|
|
1563
|
+
? this.extractNestedDataArray(validatedDataArray, relationshipsWithNested, CoreResourceOperation.CREATE_MANY, executionContext)
|
|
1564
|
+
: { parentDataArray: validatedDataArray, nestedDataArray: [] };
|
|
1565
|
+
// 3. Apply business validation
|
|
1566
|
+
const businessValidatedData = await this.applyBusinessValidation(CoreResourceOperation.CREATE_MANY, parentDataArray, executionContext);
|
|
1567
|
+
const resourceType = this.resourceConfiguration.resourceIdentifier;
|
|
1568
|
+
const hasFileFields = this.fileFieldDetection.hasFileFields(resourceType);
|
|
1569
|
+
if (hasFileFields) {
|
|
1570
|
+
for (const item of businessValidatedData) {
|
|
1571
|
+
await this.fileOperationHandler.validateFileFieldsForCreate(item, resourceType, executionContext, options);
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
// 4. Execute pre-creation business logic
|
|
1575
|
+
const enrichedData = await this.executePreOperationLogic(CoreResourceOperation.CREATE_MANY, businessValidatedData, executionContext);
|
|
1576
|
+
const hasNestedOperations = relationshipsWithNested.length > 0 &&
|
|
1577
|
+
nestedDataArray.some(item => Object.keys(item).length > 0);
|
|
1578
|
+
const requiresTransactionalBulkCreate = hasNestedOperations || hasFileFields;
|
|
1579
|
+
let result;
|
|
1580
|
+
if (requiresTransactionalBulkCreate) {
|
|
1581
|
+
// Bulk create currently needs a Mongo-compatible transaction whenever it must
|
|
1582
|
+
// coordinate parent writes with nested child replay or file-link side effects.
|
|
1583
|
+
this.assertMongoBulkTransactionSupport(executionContext, hasNestedOperations
|
|
1584
|
+
? 'Bulk nested create transactions currently require MongoDB-backed resources'
|
|
1585
|
+
: 'Bulk create file-field transactions currently require MongoDB-backed resources');
|
|
1586
|
+
result = await this.mongoDBService.executeTransaction(async (ctx) => {
|
|
1587
|
+
const optionsWithTransaction = { ...options, transaction: ctx };
|
|
1588
|
+
const parentResults = await this.callRepository(operation, executionContext, undefined, enrichedData, optionsWithTransaction);
|
|
1589
|
+
if (hasFileFields) {
|
|
1590
|
+
await this.processBulkCreateFileFields(parentResults, enrichedData, resourceType, executionContext, optionsWithTransaction);
|
|
1591
|
+
}
|
|
1592
|
+
await this.processBulkNestedOperations(CoreResourceOperation.CREATE_MANY, parentResults, nestedDataArray, [], relationshipsWithNested, executionContext, optionsWithTransaction);
|
|
1593
|
+
return parentResults;
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1596
|
+
else {
|
|
1597
|
+
// 5. Execute repository operation
|
|
1598
|
+
result = await this.callRepository(operation, executionContext, undefined, enrichedData, options);
|
|
1599
|
+
}
|
|
1600
|
+
// 6. Execute post-creation business logic (including engine cascading)
|
|
1601
|
+
const processedResult = await this.executePostOperationLogic(CoreResourceOperation.CREATE_MANY, result, executionContext);
|
|
1602
|
+
this.logDebug('CreateMany business operation completed', { resultCount: processedResult?.length });
|
|
1603
|
+
return processedResult;
|
|
1604
|
+
}
|
|
1605
|
+
/**
|
|
1606
|
+
* Resolve operation variant based on dataMode.
|
|
1607
|
+
* Maps dataMode to appropriate variantKey:
|
|
1608
|
+
* - RAW -> default variant (no variantKey)
|
|
1609
|
+
* - SUMMARY -> 'summary' variant (throws if not found)
|
|
1610
|
+
* - CONTEXT -> 'context' variant (throws if not found)
|
|
1611
|
+
*
|
|
1612
|
+
* Throws error if requested variant doesn't exist (fail-fast).
|
|
1613
|
+
*/
|
|
1614
|
+
resolveOperationVariant(operation, dataMode) {
|
|
1615
|
+
// RAW mode uses default variant (provided operation)
|
|
1616
|
+
if (dataMode === DataMode.RAW) {
|
|
1617
|
+
return operation;
|
|
1618
|
+
}
|
|
1619
|
+
// Determine variantKey based on dataMode using enum-based helper
|
|
1620
|
+
const variantKey = dataModeToVariantKey(dataMode);
|
|
1621
|
+
// If no variant key (RAW mode), return the provided operation
|
|
1622
|
+
if (!variantKey) {
|
|
1623
|
+
return operation;
|
|
1624
|
+
}
|
|
1625
|
+
// Find variant with matching variantKey (throws if not found)
|
|
1626
|
+
const resourceType = operation.resourceIdentifier;
|
|
1627
|
+
const operationIdentifier = operation.operationIdentifier;
|
|
1628
|
+
// Create operation path object directly
|
|
1629
|
+
const variantPath = {
|
|
1630
|
+
resourceIdentifier: resourceType,
|
|
1631
|
+
operationIdentifier,
|
|
1632
|
+
variantType: operation.variantType,
|
|
1633
|
+
isOperationDefault: false,
|
|
1634
|
+
variantKey,
|
|
1635
|
+
isBulkOperation: false,
|
|
1636
|
+
};
|
|
1637
|
+
// This will throw ErrorCustomMessageReference.RESOURCES_REGISTRY_OPERATION_PATH_NOT_FOUND if variant doesn't exist
|
|
1638
|
+
const variantOperation = this.resourcesRegistry.getOperationFromPath(variantPath);
|
|
1639
|
+
this.logDebug(`Resolved variant for ${operationIdentifier}`, { dataMode, variantKey, found: true });
|
|
1640
|
+
return variantOperation;
|
|
1641
|
+
}
|
|
1642
|
+
async read(operation, executionContext, id_or_ids_or_filter, options) {
|
|
1643
|
+
// Extract dataMode from ServiceOptions, or infer from operation's variantKey
|
|
1644
|
+
// This allows direct URL calls to /resource/{id}/context to use CONTEXT mode
|
|
1645
|
+
let dataMode = options?.dataMode ?? DataMode.RAW;
|
|
1646
|
+
// If operation already has a variantKey (direct URL call), infer dataMode from it
|
|
1647
|
+
if (operation.variantKey === OPERATION_VARIANT_KEY.CONTEXT) {
|
|
1648
|
+
dataMode = DataMode.CONTEXT;
|
|
1649
|
+
}
|
|
1650
|
+
else if (operation.variantKey === OPERATION_VARIANT_KEY.SUMMARY) {
|
|
1651
|
+
dataMode = DataMode.SUMMARY;
|
|
1652
|
+
}
|
|
1653
|
+
// Resolve operation variant based on dataMode
|
|
1654
|
+
const resolvedOperation = this.resolveOperationVariant(operation, dataMode);
|
|
1655
|
+
this.logDebug('Executing read business operation', { id_or_ids_or_filter, dataMode, variantKey: resolvedOperation.variantKey });
|
|
1656
|
+
// 1. Execute repository operation with resolved variant (uses correct repositoryDto)
|
|
1657
|
+
const result = await this.callRepository(resolvedOperation, executionContext, id_or_ids_or_filter, undefined, options);
|
|
1658
|
+
if (!result) {
|
|
1659
|
+
return null;
|
|
1660
|
+
}
|
|
1661
|
+
// 2. Process nested read operations if configured
|
|
1662
|
+
const resourceRelationships = this.resourceConfiguration.resourceRelationships;
|
|
1663
|
+
const childRelationships = getChildDirectionRelationships(resourceRelationships);
|
|
1664
|
+
const relationshipsWithNestedRead = childRelationships.filter(rel => this.getResolvedNestedReadConfig(rel));
|
|
1665
|
+
// Application point #2: Nested READ — filter by discriminator/condition using
|
|
1666
|
+
// the read result (parent data) so we only fetch nested children for relationships
|
|
1667
|
+
// that are active for this particular parent resource variant.
|
|
1668
|
+
if (relationshipsWithNestedRead.length > 0) {
|
|
1669
|
+
const activeReadRelationships = this.filterRelationshipsByParent(relationshipsWithNestedRead, result);
|
|
1670
|
+
if (activeReadRelationships.length > 0) {
|
|
1671
|
+
await this.processNestedRead(result, activeReadRelationships, executionContext, options);
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
// 3. Process based on DataMode
|
|
1675
|
+
let processedResult = result;
|
|
1676
|
+
const resourceType = this.resourceConfiguration.resourceIdentifier;
|
|
1677
|
+
if (dataMode !== DataMode.RAW) {
|
|
1678
|
+
// Analyze context needs for virtual fields
|
|
1679
|
+
const needs = this.populationService.analyzeContextNeeds(resourceType);
|
|
1680
|
+
// Fetch computation context if needed (for virtual field computation only)
|
|
1681
|
+
let computationContext = {};
|
|
1682
|
+
if (needs.needsObjectContext || needs.needsUserContext) {
|
|
1683
|
+
computationContext = await this.populationService.fetchComputationContext(resourceType, result, needs, executionContext);
|
|
1684
|
+
}
|
|
1685
|
+
// Compute virtual fields with fault tolerance
|
|
1686
|
+
processedResult = await this.virtualFieldsService.computeVirtualFields(resourceType, processedResult, executionContext, {
|
|
1687
|
+
faultTolerant: true,
|
|
1688
|
+
includeContextDependent: needs.needsObjectContext || needs.needsUserContext,
|
|
1689
|
+
objectContext: computationContext.objectContext,
|
|
1690
|
+
userContext: computationContext.userContext,
|
|
1691
|
+
forSummary: dataMode === DataMode.SUMMARY,
|
|
1692
|
+
});
|
|
1693
|
+
// Apply population based on DataMode
|
|
1694
|
+
// Extract populateFiles option from ServiceOptions (default: true)
|
|
1695
|
+
const populateFiles = options?.populateFiles !== false;
|
|
1696
|
+
const populationOptions = { populateFiles };
|
|
1697
|
+
if (dataMode === DataMode.SUMMARY) {
|
|
1698
|
+
processedResult = await this.populationService.populateForSummary(resourceType, processedResult, executionContext, populationOptions, options);
|
|
1699
|
+
}
|
|
1700
|
+
else if (dataMode === DataMode.CONTEXT) {
|
|
1701
|
+
processedResult = await this.populationService.populateForContext(resourceType, processedResult, executionContext, populationOptions, options);
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
// 3. Apply business context enrichment
|
|
1705
|
+
const enrichedResult = await this.enrichBusinessContext(CoreResourceOperation.READ, processedResult, executionContext);
|
|
1706
|
+
this.logDebug('Read business operation completed', { dataMode });
|
|
1707
|
+
return enrichedResult;
|
|
1708
|
+
}
|
|
1709
|
+
async update(operation, executionContext, id_or_ids_or_filter, data, options) {
|
|
1710
|
+
this.logDebug('Executing update business operation', { id_or_ids_or_filter });
|
|
1711
|
+
if (!id_or_ids_or_filter) {
|
|
1712
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
1713
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
1714
|
+
context: { operation: 'UPDATE', missingParameter: 'id_or_ids_or_filter' },
|
|
1715
|
+
});
|
|
1716
|
+
}
|
|
1717
|
+
if (!data) {
|
|
1718
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
1719
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
1720
|
+
context: { operation: 'UPDATE', missingParameter: 'data' },
|
|
1721
|
+
});
|
|
1722
|
+
}
|
|
1723
|
+
// 0. Clean input data (remove mandatory discard fields)
|
|
1724
|
+
const cleanedData = this.repositoryHelper.cleanInputData(data, CoreResourceOperation.UPDATE);
|
|
1725
|
+
this.logDebug('Data cleaned for update operation', {
|
|
1726
|
+
originalKeys: typeof data === 'object' ? Object.keys(data) : 'not-object',
|
|
1727
|
+
cleanedKeys: typeof cleanedData === 'object' ? Object.keys(cleanedData) : 'not-object'
|
|
1728
|
+
});
|
|
1729
|
+
// 1. Validate input against operation's requestDto
|
|
1730
|
+
const validatedData = await this.validateAndTransformInput(executionContext, cleanedData);
|
|
1731
|
+
// 1.5. Extract nested data if nested operations are configured
|
|
1732
|
+
const resourceRelationships = this.resourceConfiguration.resourceRelationships;
|
|
1733
|
+
const childRelationships = getChildDirectionRelationships(resourceRelationships);
|
|
1734
|
+
const relationshipsWithNested = childRelationships.filter(rel => this.getResolvedNestedMutationConfig(rel, CoreResourceOperation.UPDATE));
|
|
1735
|
+
const { parentData, nestedData, deleteData } = relationshipsWithNested.length > 0
|
|
1736
|
+
? this.extractNestedDataForUpdate(validatedData, relationshipsWithNested)
|
|
1737
|
+
: { parentData: validatedData, nestedData: {}, deleteData: {} };
|
|
1738
|
+
// 2. Get current state - for single updates only (bulk update skips current state fetching)
|
|
1739
|
+
let currentState = null;
|
|
1740
|
+
if (typeof id_or_ids_or_filter === 'string') {
|
|
1741
|
+
currentState = await this.fetchCurrentObjectForOperation(CoreResourceOperation.UPDATE, this.resourceConfiguration.resourceIdentifier, id_or_ids_or_filter, executionContext);
|
|
1742
|
+
if (!currentState) {
|
|
1743
|
+
throw this.errorBuilder.buildError(ErrorType.NOT_FOUND, executionContext, {
|
|
1744
|
+
customMessageReference: ErrorCustomMessageReference.CONTROLLER_RESOURCE_NOT_FOUND,
|
|
1745
|
+
context: { operation: 'UPDATE', id_or_ids_or_filter },
|
|
1746
|
+
});
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
// 3. Apply business validation for changes
|
|
1750
|
+
const businessValidatedData = await this.applyBusinessValidation(CoreResourceOperation.UPDATE, parentData, executionContext, currentState);
|
|
1751
|
+
// 3.5. Validate file fields (fail fast before resource update)
|
|
1752
|
+
// Note: we only reuse validateFileFieldsForCreate() when this UPDATE path does
|
|
1753
|
+
// not have a persisted current state to diff against. When currentState exists,
|
|
1754
|
+
// processFileFieldsForUpdate() owns validation of newly introduced file ids
|
|
1755
|
+
// inside the same transaction as the parent update.
|
|
1756
|
+
// ============================================================================
|
|
1757
|
+
// FILE FIELD VALIDATION (Pre-UPDATE)
|
|
1758
|
+
// ============================================================================
|
|
1759
|
+
// Same limitations as CREATE validation apply here. Additionally:
|
|
1760
|
+
//
|
|
1761
|
+
// 1. Only NEW file references are validated. The old-to-new file transition
|
|
1762
|
+
// (unlinking old files, linking new ones) happens in processFileFieldsForUpdate
|
|
1763
|
+
// which runs AFTER the resource update, not during validation.
|
|
1764
|
+
//
|
|
1765
|
+
// 2. If a file being replaced is still referenced by other resources, this
|
|
1766
|
+
// validation doesn't check for that. File reference counting is not implemented.
|
|
1767
|
+
//
|
|
1768
|
+
// 3. Bulk UPDATE_MANY now has its own dedicated path: it validates explicit
|
|
1769
|
+
// file-field mutations and reloads per-parent snapshots before processing
|
|
1770
|
+
// file diffs inside the transactional bulk branch.
|
|
1771
|
+
//
|
|
1772
|
+
// See: .cursor/plans for file/storage context
|
|
1773
|
+
// ============================================================================
|
|
1774
|
+
const resourceType = this.resourceConfiguration.resourceIdentifier;
|
|
1775
|
+
if (this.fileFieldDetection.hasFileFields(resourceType) && !currentState) {
|
|
1776
|
+
try {
|
|
1777
|
+
await this.fileOperationHandler.validateFileFieldsForCreate(businessValidatedData, resourceType, executionContext, this.buildFileRepositoryOptions(options));
|
|
1778
|
+
}
|
|
1779
|
+
catch (error) {
|
|
1780
|
+
// File validation errors should fail the operation
|
|
1781
|
+
throw error;
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
// 4. Execute pre-update business logic
|
|
1785
|
+
const enrichedData = await this.executePreOperationLogic(CoreResourceOperation.UPDATE, businessValidatedData, executionContext, currentState);
|
|
1786
|
+
// 5. Execute repository operation (update parent) and process nested operations
|
|
1787
|
+
// ALWAYS use transaction for file operations, even without nested operations
|
|
1788
|
+
// Extract organizationId early (needed for file operations and transactions)
|
|
1789
|
+
const hasFileFields = this.fileFieldDetection.hasFileFields(resourceType);
|
|
1790
|
+
const hasNestedOperations = relationshipsWithNested.length > 0 && (Object.keys(nestedData).length > 0 || Object.keys(deleteData).length > 0);
|
|
1791
|
+
// Note: File operations only for single updates (currentState is only fetched for single updates)
|
|
1792
|
+
const canProcessFileFields = hasFileFields && currentState && typeof id_or_ids_or_filter === 'string';
|
|
1793
|
+
const persistenceAdapter = this.getResolvedPersistenceAdapter();
|
|
1794
|
+
let result;
|
|
1795
|
+
if (hasNestedOperations || canProcessFileFields) {
|
|
1796
|
+
result = await this.executeResourceTransaction(executionContext, async (optionsWithTransaction) => {
|
|
1797
|
+
// 1. Update resource within transaction
|
|
1798
|
+
const parentResult = await this.callRepository(operation, executionContext, id_or_ids_or_filter, enrichedData, optionsWithTransaction);
|
|
1799
|
+
const activeRelationships = hasNestedOperations
|
|
1800
|
+
? this.filterRelationshipsByParent(relationshipsWithNested, parentResult)
|
|
1801
|
+
: [];
|
|
1802
|
+
if (activeRelationships.length > 0) {
|
|
1803
|
+
this.assertNestedMutationAdaptersMatchCurrentResource(activeRelationships, executionContext);
|
|
1804
|
+
}
|
|
1805
|
+
if (persistenceAdapter === 'postgresql') {
|
|
1806
|
+
if (activeRelationships.length > 0) {
|
|
1807
|
+
await this.processNestedOperations(CoreResourceOperation.UPDATE, parentResult, nestedData, deleteData, activeRelationships, executionContext, optionsWithTransaction);
|
|
1808
|
+
}
|
|
1809
|
+
if (canProcessFileFields) {
|
|
1810
|
+
const resourceId = typeof id_or_ids_or_filter === 'string'
|
|
1811
|
+
? id_or_ids_or_filter
|
|
1812
|
+
: parentResult?._id?.toString() || parentResult?.id;
|
|
1813
|
+
if (resourceId) {
|
|
1814
|
+
await this.executeFileMetadataWork(executionContext, options, async (fileOptions) => this.fileOperationHandler.processFileFieldsForUpdate(enrichedData, currentState, resourceType, resourceId, executionContext, fileOptions));
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
else {
|
|
1819
|
+
// Mongo-backed resources still keep parent + file metadata mutations in
|
|
1820
|
+
// the same transaction context.
|
|
1821
|
+
if (canProcessFileFields) {
|
|
1822
|
+
const resourceId = typeof id_or_ids_or_filter === 'string'
|
|
1823
|
+
? id_or_ids_or_filter
|
|
1824
|
+
: parentResult?._id?.toString() || parentResult?.id;
|
|
1825
|
+
if (resourceId) {
|
|
1826
|
+
await this.fileOperationHandler.processFileFieldsForUpdate(enrichedData, currentState, resourceType, resourceId, executionContext, optionsWithTransaction);
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
if (activeRelationships.length > 0) {
|
|
1830
|
+
await this.processNestedOperations(CoreResourceOperation.UPDATE, parentResult, nestedData, deleteData, activeRelationships, executionContext, optionsWithTransaction);
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
return parentResult;
|
|
1834
|
+
}, options);
|
|
1835
|
+
}
|
|
1836
|
+
else {
|
|
1837
|
+
// No file fields, no nested operations - no transaction needed
|
|
1838
|
+
result = await this.callRepository(operation, executionContext, id_or_ids_or_filter, enrichedData, options);
|
|
1839
|
+
}
|
|
1840
|
+
// 7. Execute post-update business logic (including engine cascading)
|
|
1841
|
+
const processedResult = await this.executePostOperationLogic(CoreResourceOperation.UPDATE, result, executionContext, currentState);
|
|
1842
|
+
this.logDebug('Update business operation completed');
|
|
1843
|
+
return processedResult;
|
|
1844
|
+
}
|
|
1845
|
+
async updateMany(operation, executionContext, id_or_ids_or_filter, data, options) {
|
|
1846
|
+
this.logDebug('Executing updateMany business operation', { id_or_ids_or_filter });
|
|
1847
|
+
if (!id_or_ids_or_filter) {
|
|
1848
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
1849
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
1850
|
+
context: { operation: 'UPDATE_MANY', missingParameter: 'id_or_ids_or_filter' },
|
|
1851
|
+
});
|
|
1852
|
+
}
|
|
1853
|
+
if (!data) {
|
|
1854
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
1855
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
1856
|
+
context: { operation: 'UPDATE_MANY', missingParameter: 'data' },
|
|
1857
|
+
});
|
|
1858
|
+
}
|
|
1859
|
+
// 0. Clean input data (remove mandatory discard fields - preserve _id for updateMany)
|
|
1860
|
+
const cleanedData = this.repositoryHelper.cleanInputData(data, CoreResourceOperation.UPDATE_MANY);
|
|
1861
|
+
this.logDebug('Data cleaned for updateMany operation', {
|
|
1862
|
+
originalKeys: typeof data === 'object' ? Object.keys(data) : 'not-object',
|
|
1863
|
+
cleanedKeys: typeof cleanedData === 'object' ? Object.keys(cleanedData) : 'not-object'
|
|
1864
|
+
});
|
|
1865
|
+
// 1. Validate input against operation's requestDto
|
|
1866
|
+
const validatedData = await this.validateAndTransformInput(executionContext, cleanedData);
|
|
1867
|
+
// 1.5. Extract nested data if nested operations are configured
|
|
1868
|
+
const resourceRelationships = this.resourceConfiguration.resourceRelationships;
|
|
1869
|
+
const childRelationships = getChildDirectionRelationships(resourceRelationships);
|
|
1870
|
+
const relationshipsWithNested = childRelationships.filter(rel => this.getResolvedNestedMutationConfig(rel, CoreResourceOperation.UPDATE_MANY));
|
|
1871
|
+
const { parentData, nestedData, deleteData } = relationshipsWithNested.length > 0
|
|
1872
|
+
? this.extractNestedDataForUpdate(validatedData, relationshipsWithNested)
|
|
1873
|
+
: { parentData: validatedData, nestedData: {}, deleteData: {} };
|
|
1874
|
+
// 2. Apply business validation for bulk changes (no current state fetching for bulk operations)
|
|
1875
|
+
const businessValidatedData = await this.applyBusinessValidation(CoreResourceOperation.UPDATE_MANY, parentData, executionContext);
|
|
1876
|
+
const resourceType = this.resourceConfiguration.resourceIdentifier;
|
|
1877
|
+
const hasFileFields = this.fileFieldDetection.hasFileFields(resourceType);
|
|
1878
|
+
const hasBulkFileMutations = hasFileFields && this.hasExplicitFileFieldMutations(resourceType, businessValidatedData);
|
|
1879
|
+
if (hasBulkFileMutations) {
|
|
1880
|
+
await this.fileOperationHandler.validateFileFieldsForCreate(businessValidatedData, resourceType, executionContext, options);
|
|
1881
|
+
}
|
|
1882
|
+
// 3. Execute pre-update business logic
|
|
1883
|
+
const enrichedData = await this.executePreOperationLogic(CoreResourceOperation.UPDATE_MANY, businessValidatedData, executionContext);
|
|
1884
|
+
const hasNestedOperations = relationshipsWithNested.length > 0 &&
|
|
1885
|
+
(Object.keys(nestedData).length > 0 || Object.keys(deleteData).length > 0);
|
|
1886
|
+
const requiresTransactionalBulkUpdate = hasNestedOperations || hasBulkFileMutations;
|
|
1887
|
+
let result;
|
|
1888
|
+
if (requiresTransactionalBulkUpdate) {
|
|
1889
|
+
// UPDATE_MANY shares the same limitation as CREATE_MANY: once nested payloads
|
|
1890
|
+
// or file-field mutations are present, the service currently relies on
|
|
1891
|
+
// MongoDBService to own the outer transaction while parent updates and
|
|
1892
|
+
// follow-up side effects are replayed.
|
|
1893
|
+
this.assertMongoBulkTransactionSupport(executionContext, hasNestedOperations
|
|
1894
|
+
? 'Bulk nested update transactions currently require MongoDB-backed resources'
|
|
1895
|
+
: 'Bulk update file-field transactions currently require MongoDB-backed resources');
|
|
1896
|
+
result = await this.mongoDBService.executeTransaction(async (ctx) => {
|
|
1897
|
+
const optionsWithTransaction = { ...options, transaction: ctx };
|
|
1898
|
+
const currentStatesById = hasBulkFileMutations
|
|
1899
|
+
? await this.loadBulkParentStateMap(executionContext, id_or_ids_or_filter, optionsWithTransaction)
|
|
1900
|
+
: new Map();
|
|
1901
|
+
const parentResults = await this.callRepository(operation, executionContext, id_or_ids_or_filter, enrichedData, optionsWithTransaction);
|
|
1902
|
+
if (Object.keys(deleteData).length > 0 && Array.isArray(parentResults) && parentResults.length > 1) {
|
|
1903
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
1904
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
1905
|
+
context: {
|
|
1906
|
+
operation: CoreResourceOperation.UPDATE_MANY,
|
|
1907
|
+
parentResultsCount: parentResults.length,
|
|
1908
|
+
reason: 'nested delete payloads in UPDATE_MANY are only supported when the mutation targets exactly one parent resource',
|
|
1909
|
+
},
|
|
1910
|
+
});
|
|
1911
|
+
}
|
|
1912
|
+
if (hasBulkFileMutations) {
|
|
1913
|
+
await this.processBulkUpdateFileFields(parentResults, currentStatesById, enrichedData, resourceType, executionContext, optionsWithTransaction);
|
|
1914
|
+
}
|
|
1915
|
+
// Contract: UPDATE_MANY uses broadcast semantics for nested create/update payloads.
|
|
1916
|
+
// The validated nestedData object is treated as one shared envelope and replayed
|
|
1917
|
+
// once per matched parent result. This is intentional: bulk parent mutation +
|
|
1918
|
+
// nested mutation means "apply this same nested update plan to every parent that
|
|
1919
|
+
// matched the bulk selector". Nested deletes remain stricter because replaying the
|
|
1920
|
+
// same child-id delete list across multiple parents is ambiguous and unsafe.
|
|
1921
|
+
await this.processBulkNestedOperations(CoreResourceOperation.UPDATE_MANY, parentResults, Array.isArray(parentResults) ? parentResults.map(() => nestedData) : [], Array.isArray(parentResults) ? parentResults.map(() => deleteData) : [], relationshipsWithNested, executionContext, optionsWithTransaction);
|
|
1922
|
+
return parentResults;
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
else {
|
|
1926
|
+
// 4. Execute repository operation
|
|
1927
|
+
result = await this.callRepository(operation, executionContext, id_or_ids_or_filter, enrichedData, options);
|
|
1928
|
+
}
|
|
1929
|
+
// 5. Execute post-update business logic (including engine cascading)
|
|
1930
|
+
const processedResult = await this.executePostOperationLogic(CoreResourceOperation.UPDATE_MANY, result, executionContext);
|
|
1931
|
+
this.logDebug('UpdateMany business operation completed', { resultCount: processedResult?.length });
|
|
1932
|
+
return processedResult;
|
|
1933
|
+
}
|
|
1934
|
+
async delete(operation, executionContext, id_or_ids_or_filter, options) {
|
|
1935
|
+
this.logDebug('Executing delete business operation', { id_or_ids_or_filter });
|
|
1936
|
+
if (!id_or_ids_or_filter) {
|
|
1937
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
1938
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
1939
|
+
context: { operation: 'DELETE', missingParameter: 'id_or_ids_or_filter' },
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
1942
|
+
// 1. Get current state - for single deletes only (bulk delete skips current state fetching)
|
|
1943
|
+
let currentState = null;
|
|
1944
|
+
const resourceType = this.resourceConfiguration.resourceIdentifier;
|
|
1945
|
+
const hasFileFields = this.fileFieldDetection.hasFileFields(resourceType);
|
|
1946
|
+
// ============================================================================
|
|
1947
|
+
// FILE MANAGEMENT DELETE NOTES
|
|
1948
|
+
// ============================================================================
|
|
1949
|
+
//
|
|
1950
|
+
// Current contract:
|
|
1951
|
+
// 1. Parent deletes fail closed if pre-delete file cleanup throws.
|
|
1952
|
+
// 2. Mongo-backed parents still keep parent + file metadata work in one Mongo
|
|
1953
|
+
// transaction context.
|
|
1954
|
+
// 3. PostgreSQL-backed parents use a best-effort split boundary: file metadata
|
|
1955
|
+
// cleanup runs through the Mongo-backed FILES seam first, then parent delete
|
|
1956
|
+
// runs inside the PostgreSQL transaction.
|
|
1957
|
+
//
|
|
1958
|
+
// Remaining limitations:
|
|
1959
|
+
// 1. Cross-database delete is still best-effort, not one ACID transaction.
|
|
1960
|
+
// 2. File storage cleanup stays outside the parent DB rollback boundary and is
|
|
1961
|
+
// intentionally owned later by the cleanup batch.
|
|
1962
|
+
// 3. Lifecycle-delete coverage for child resources that own file fields is
|
|
1963
|
+
// still narrower than the direct parent delete path.
|
|
1964
|
+
//
|
|
1965
|
+
// NOTE: organizationId validation is intentionally NOT done here. Tenant isolation
|
|
1966
|
+
// is enforced at the FilesBackendService level, not duplicated in the service handler.
|
|
1967
|
+
// See: .cursor/plans for file/storage context
|
|
1968
|
+
//
|
|
1969
|
+
// ============================================================================
|
|
1970
|
+
if (typeof id_or_ids_or_filter === 'string') {
|
|
1971
|
+
currentState = await this.fetchCurrentObjectForOperation(CoreResourceOperation.DELETE, resourceType, id_or_ids_or_filter, executionContext);
|
|
1972
|
+
if (!currentState) {
|
|
1973
|
+
return '';
|
|
1974
|
+
}
|
|
1975
|
+
// 2. Check business constraints for deletion
|
|
1976
|
+
await this.validateDeletionConstraints(currentState, executionContext);
|
|
1977
|
+
// 3. Execute pre-deletion business logic
|
|
1978
|
+
await this.executePreOperationLogic(CoreResourceOperation.DELETE, currentState, executionContext);
|
|
1979
|
+
// 4. Execute repository operation plus lifecycle cascading inside the
|
|
1980
|
+
// resource transaction so child-delete failures can still roll back the
|
|
1981
|
+
// parent row on same-adapter paths.
|
|
1982
|
+
const result = await this.executeResourceTransaction(executionContext, async (optionsWithTransaction) => {
|
|
1983
|
+
if (hasFileFields) {
|
|
1984
|
+
const persistenceAdapter = this.getResolvedPersistenceAdapter();
|
|
1985
|
+
if (persistenceAdapter === 'postgresql') {
|
|
1986
|
+
await this.executeFileMetadataWork(executionContext, options, async (fileOptions) => this.fileOperationHandler.processFileFieldsForDelete(resourceType, id_or_ids_or_filter, executionContext, fileOptions));
|
|
1987
|
+
}
|
|
1988
|
+
else {
|
|
1989
|
+
await this.fileOperationHandler.processFileFieldsForDelete(resourceType, id_or_ids_or_filter, executionContext, optionsWithTransaction);
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
const deleteResult = await this.callRepository(operation, executionContext, id_or_ids_or_filter, undefined, optionsWithTransaction);
|
|
1993
|
+
await this.executeLifecycleOperations(CoreResourceOperation.DELETE, deleteResult, executionContext, currentState, optionsWithTransaction);
|
|
1994
|
+
return deleteResult;
|
|
1995
|
+
}, options);
|
|
1996
|
+
// 5. Execute non-cascading post-deletion logic after the delete transaction commits.
|
|
1997
|
+
await this.executeAdditionalPostOperationLogic(CoreResourceOperation.DELETE, result, executionContext, currentState);
|
|
1998
|
+
this.logDebug('Delete business operation completed');
|
|
1999
|
+
return result;
|
|
2000
|
+
}
|
|
2001
|
+
const deleteManyOperationPath = this.resourcesRegistry.getOperationPathDefault(resourceType, CoreResourceOperation.DELETE_MANY);
|
|
2002
|
+
const deleteManyOperation = this.resourcesRegistry.getOperationFromPath(deleteManyOperationPath);
|
|
2003
|
+
return this.deleteMany(deleteManyOperation, executionContext, id_or_ids_or_filter, options);
|
|
2004
|
+
}
|
|
2005
|
+
async deleteMany(operation, executionContext, id_or_ids_or_filter, options) {
|
|
2006
|
+
this.logDebug('Executing deleteMany business operation', { id_or_ids_or_filter });
|
|
2007
|
+
if (!id_or_ids_or_filter) {
|
|
2008
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
2009
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
2010
|
+
context: { operation: 'DELETE_MANY', missingParameter: 'id_or_ids_or_filter' },
|
|
2011
|
+
});
|
|
2012
|
+
}
|
|
2013
|
+
// 1. Fetch resources BEFORE deletion so post-delete lifecycle logic can still
|
|
2014
|
+
// evaluate relationship activation against real parent snapshots. The same
|
|
2015
|
+
// snapshot set is also reused for pre-delete file handling.
|
|
2016
|
+
const resourceType = this.resourceConfiguration.resourceIdentifier;
|
|
2017
|
+
const hasFileFields = this.fileFieldDetection.hasFileFields(resourceType);
|
|
2018
|
+
const childRelationships = getChildDirectionRelationships(this.resourceConfiguration.resourceRelationships);
|
|
2019
|
+
const hasLifecycleDeleteRelationships = childRelationships
|
|
2020
|
+
.some((relationship) => this.getResolvedLifecycleOnParentDelete(relationship)?.enabled === true);
|
|
2021
|
+
const hasFileOwningChildRelationships = childRelationships
|
|
2022
|
+
.some((relationship) => this.fileFieldDetection.hasFileFields(relationship.resourceType2));
|
|
2023
|
+
const currentStates = await this.loadBulkTargetResources(executionContext, id_or_ids_or_filter, options);
|
|
2024
|
+
// ============================================================================
|
|
2025
|
+
// FILE MANAGEMENT DELETE_MANY NOTES
|
|
2026
|
+
// ============================================================================
|
|
2027
|
+
//
|
|
2028
|
+
// Current contract:
|
|
2029
|
+
// 1. Bulk deletes now keep lifecycle cascades inside the parent resource
|
|
2030
|
+
// transaction whenever a shared same-adapter transaction is available.
|
|
2031
|
+
// 2. MongoDB-backed bulk deletes with file fields reuse that same
|
|
2032
|
+
// transaction for file metadata cleanup plus parent-row deletion.
|
|
2033
|
+
// 3. Non-Mongo bulk deletes without lifecycle still fail closed before the
|
|
2034
|
+
// repository delete if any resource-level file cleanup throws.
|
|
2035
|
+
// 4. File cleanup no longer inherits a foreign PostgreSQL transaction when the
|
|
2036
|
+
// parent bulk delete is called inside an outer SQL transaction.
|
|
2037
|
+
//
|
|
2038
|
+
// Remaining limitations:
|
|
2039
|
+
// 1. PostgreSQL-backed bulk deletes still have no shared parent+file rollback
|
|
2040
|
+
// boundary because FILES remains Mongo-backed by design.
|
|
2041
|
+
// 2. Fetching all resources before deletion can be expensive for large
|
|
2042
|
+
// datasets. Consider streaming/pagination for very large deletes.
|
|
2043
|
+
// 3. Scope-based cleanup still relies on FilesBackendService boundaries rather
|
|
2044
|
+
// than service-layer duplication.
|
|
2045
|
+
//
|
|
2046
|
+
// NOTE: organizationId validation is intentionally NOT done here. Tenant isolation
|
|
2047
|
+
// is enforced at the FilesBackendService level, not duplicated in the service handler.
|
|
2048
|
+
//
|
|
2049
|
+
// ============================================================================
|
|
2050
|
+
if (this.getResolvedPersistenceAdapter() === 'postgresql'
|
|
2051
|
+
&& hasFileOwningChildRelationships
|
|
2052
|
+
&& !hasLifecycleDeleteRelationships) {
|
|
2053
|
+
throw this.errorBuilder.buildError(ErrorType.CONFIGURATION, executionContext, {
|
|
2054
|
+
customMessageReference: ErrorCustomMessageReference.CONFIGURATION,
|
|
2055
|
+
context: {
|
|
2056
|
+
message: 'PostgreSQL bulk delete is not supported for resources with file-owning child relationships unless service-managed lifecycle delete is enabled',
|
|
2057
|
+
resourceType,
|
|
2058
|
+
},
|
|
2059
|
+
});
|
|
2060
|
+
}
|
|
2061
|
+
const processBulkDeleteFileCleanup = async (fileRepositoryOptions) => {
|
|
2062
|
+
const batchSize = 100;
|
|
2063
|
+
for (let i = 0; i < currentStates.length; i += batchSize) {
|
|
2064
|
+
const batch = currentStates.slice(i, i + batchSize);
|
|
2065
|
+
for (const resource of batch) {
|
|
2066
|
+
const resourceId = resource._id?.toString() || resource.id;
|
|
2067
|
+
if (!resourceId) {
|
|
2068
|
+
this.logger.warn('Resource missing ID in bulk delete, skipping file processing', {
|
|
2069
|
+
resource,
|
|
2070
|
+
});
|
|
2071
|
+
continue;
|
|
2072
|
+
}
|
|
2073
|
+
await this.fileOperationHandler.processFileFieldsForDelete(resourceType, resourceId, executionContext, fileRepositoryOptions);
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
};
|
|
2077
|
+
const requiresTransactionalBulkDelete = hasLifecycleDeleteRelationships
|
|
2078
|
+
|| (hasFileFields && this.getResolvedPersistenceAdapter() === 'mongodb');
|
|
2079
|
+
const processBulkDeleteWithinTransaction = async (optionsWithTransaction) => {
|
|
2080
|
+
if (hasFileFields) {
|
|
2081
|
+
if (optionsWithTransaction.transaction?.databaseType === 'postgresql') {
|
|
2082
|
+
await this.executeFileMetadataWork(executionContext, optionsWithTransaction, async (fileOptions) => processBulkDeleteFileCleanup(fileOptions));
|
|
2083
|
+
}
|
|
2084
|
+
else {
|
|
2085
|
+
await processBulkDeleteFileCleanup(optionsWithTransaction);
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
const deleteResult = await this.callRepository(operation, executionContext, id_or_ids_or_filter, undefined, optionsWithTransaction);
|
|
2089
|
+
if (hasLifecycleDeleteRelationships) {
|
|
2090
|
+
await this.executeLifecycleOperations(CoreResourceOperation.DELETE_MANY, deleteResult, executionContext, currentStates, optionsWithTransaction);
|
|
2091
|
+
}
|
|
2092
|
+
return deleteResult;
|
|
2093
|
+
};
|
|
2094
|
+
let result;
|
|
2095
|
+
if (requiresTransactionalBulkDelete) {
|
|
2096
|
+
if (hasFileFields && this.getResolvedPersistenceAdapter() === 'mongodb') {
|
|
2097
|
+
this.assertMongoBulkTransactionSupport(executionContext, 'Bulk delete file-field transactions currently require MongoDB-backed resources');
|
|
2098
|
+
}
|
|
2099
|
+
result = await this.executeResourceTransaction(executionContext, async (optionsWithTransaction) => processBulkDeleteWithinTransaction(optionsWithTransaction), options);
|
|
2100
|
+
await this.executeAdditionalPostOperationLogic(CoreResourceOperation.DELETE_MANY, result, executionContext, currentStates);
|
|
2101
|
+
}
|
|
2102
|
+
else {
|
|
2103
|
+
if (hasFileFields) {
|
|
2104
|
+
const fileRepositoryOptions = this.buildFileRepositoryOptions(options);
|
|
2105
|
+
if (!this.mongoDBService) {
|
|
2106
|
+
this.logger.warn('Transaction support unavailable for file operations during DELETE_MANY, processing sequentially', {
|
|
2107
|
+
resourceType,
|
|
2108
|
+
reason: 'MongoDBService not available'
|
|
2109
|
+
});
|
|
2110
|
+
}
|
|
2111
|
+
// Process file fields for each resource BEFORE deletion so non-Mongo bulk
|
|
2112
|
+
// paths still fail closed before the repository mutation lands.
|
|
2113
|
+
await processBulkDeleteFileCleanup(fileRepositoryOptions);
|
|
2114
|
+
}
|
|
2115
|
+
// 2. Execute repository operation (delete resources)
|
|
2116
|
+
result = await this.callRepository(operation, executionContext, id_or_ids_or_filter, undefined, options);
|
|
2117
|
+
// 3. Execute post-deletion business logic (including engine cascading)
|
|
2118
|
+
await this.executePostOperationLogic(CoreResourceOperation.DELETE_MANY, result, executionContext, currentStates);
|
|
2119
|
+
}
|
|
2120
|
+
this.logDebug('DeleteMany business operation completed', { deletedCount: result?.length });
|
|
2121
|
+
return result;
|
|
2122
|
+
}
|
|
2123
|
+
async list(operation, executionContext, filter, pagination, options) {
|
|
2124
|
+
const paginated = options?.paginated ?? false;
|
|
2125
|
+
// Extract dataMode from ServiceOptions, or infer from operation's variantKey
|
|
2126
|
+
// This allows direct URL calls to /resource/context to use CONTEXT mode
|
|
2127
|
+
let dataMode = options?.dataMode ?? DataMode.RAW;
|
|
2128
|
+
// If operation already has a variantKey (direct URL call), infer dataMode from it
|
|
2129
|
+
if (operation.variantKey === OPERATION_VARIANT_KEY.CONTEXT) {
|
|
2130
|
+
dataMode = DataMode.CONTEXT;
|
|
2131
|
+
}
|
|
2132
|
+
else if (operation.variantKey === OPERATION_VARIANT_KEY.SUMMARY) {
|
|
2133
|
+
dataMode = DataMode.SUMMARY;
|
|
2134
|
+
}
|
|
2135
|
+
// Resolve operation variant based on dataMode
|
|
2136
|
+
const resolvedOperation = this.resolveOperationVariant(operation, dataMode);
|
|
2137
|
+
this.logDebug('Executing list business operation', { hasFilter: !!filter, pagination, paginated, dataMode, variantKey: resolvedOperation.variantKey, hasOptions: !!options });
|
|
2138
|
+
// 1. Apply business filtering to the provided filter
|
|
2139
|
+
const businessFilter = await this.applyBusinessFilter(filter || {}, executionContext);
|
|
2140
|
+
// 2. Execute repository operation with resolved variant (uses correct repositoryDto) - pass filter and pagination
|
|
2141
|
+
const listOptions = pagination ? { ...options, listOptions: pagination } : options;
|
|
2142
|
+
const result = await this.callRepository(resolvedOperation, executionContext, businessFilter, undefined, listOptions);
|
|
2143
|
+
// 3. Process based on DataMode
|
|
2144
|
+
const resourceType = this.resourceConfiguration.resourceIdentifier;
|
|
2145
|
+
const processItems = async (items) => {
|
|
2146
|
+
if (dataMode === DataMode.RAW) {
|
|
2147
|
+
// No population or virtual fields processing
|
|
2148
|
+
return items;
|
|
2149
|
+
}
|
|
2150
|
+
// Analyze context needs for virtual fields
|
|
2151
|
+
const needs = this.populationService.analyzeContextNeeds(resourceType);
|
|
2152
|
+
const includeContextDependent = needs.needsObjectContext || needs.needsUserContext;
|
|
2153
|
+
// Process each item with virtual fields
|
|
2154
|
+
let processedItems = items;
|
|
2155
|
+
if (includeContextDependent) {
|
|
2156
|
+
// Process items with computation context (slower path)
|
|
2157
|
+
processedItems = await Promise.all(items.map(async (item) => {
|
|
2158
|
+
const computationContext = await this.populationService.fetchComputationContext(resourceType, item, needs, executionContext);
|
|
2159
|
+
return this.virtualFieldsService.computeVirtualFields(resourceType, item, executionContext, {
|
|
2160
|
+
faultTolerant: true,
|
|
2161
|
+
includeContextDependent: true,
|
|
2162
|
+
objectContext: computationContext.objectContext,
|
|
2163
|
+
userContext: computationContext.userContext,
|
|
2164
|
+
forSummary: dataMode === DataMode.SUMMARY,
|
|
2165
|
+
});
|
|
2166
|
+
}));
|
|
2167
|
+
}
|
|
2168
|
+
else {
|
|
2169
|
+
// Process items without context fetching (fast path)
|
|
2170
|
+
processedItems = await Promise.all(items.map((item) => this.virtualFieldsService.computeVirtualFields(resourceType, item, executionContext, {
|
|
2171
|
+
faultTolerant: true,
|
|
2172
|
+
forSummary: dataMode === DataMode.SUMMARY,
|
|
2173
|
+
})));
|
|
2174
|
+
}
|
|
2175
|
+
// Apply population based on DataMode
|
|
2176
|
+
// Extract populateFiles option from ServiceOptions (default: true)
|
|
2177
|
+
const populateFiles = options?.populateFiles !== false;
|
|
2178
|
+
const populationOptions = { populateFiles };
|
|
2179
|
+
if (dataMode === DataMode.SUMMARY) {
|
|
2180
|
+
return this.populationService.populateListForSummary(resourceType, processedItems, executionContext, populationOptions, options);
|
|
2181
|
+
}
|
|
2182
|
+
else if (dataMode === DataMode.CONTEXT) {
|
|
2183
|
+
return this.populationService.populateListForContext(resourceType, processedItems, executionContext, populationOptions, options);
|
|
2184
|
+
}
|
|
2185
|
+
return processedItems;
|
|
2186
|
+
};
|
|
2187
|
+
// 4. Handle both raw array and paginated response from repository
|
|
2188
|
+
if (paginated && result.data !== undefined) {
|
|
2189
|
+
// Repository returned { data: [...], pagination: {...} }
|
|
2190
|
+
const processedData = await processItems(result.data);
|
|
2191
|
+
const enrichedData = await Promise.all(processedData.map((item) => this.enrichBusinessContext(CoreResourceOperation.LIST, item, executionContext)));
|
|
2192
|
+
this.logDebug('List business operation completed (paginated)', { count: enrichedData.length, pagination: result.pagination, dataMode });
|
|
2193
|
+
return { data: enrichedData, pagination: result.pagination };
|
|
2194
|
+
}
|
|
2195
|
+
else {
|
|
2196
|
+
// Repository returned raw array
|
|
2197
|
+
const items = Array.isArray(result) ? result : result.data || [];
|
|
2198
|
+
const processedData = await processItems(items);
|
|
2199
|
+
const enrichedData = await Promise.all(processedData.map((item) => this.enrichBusinessContext(CoreResourceOperation.LIST, item, executionContext)));
|
|
2200
|
+
this.logDebug('List business operation completed (raw)', { count: enrichedData.length, dataMode });
|
|
2201
|
+
return enrichedData;
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
2204
|
+
async search(operation, executionContext, searchQuery, filter, options) {
|
|
2205
|
+
// Extract dataMode from options (default: RAW)
|
|
2206
|
+
const dataMode = options?.dataMode ?? DataMode.RAW;
|
|
2207
|
+
// Resolve operation variant based on dataMode
|
|
2208
|
+
const resolvedOperation = this.resolveOperationVariant(operation, dataMode);
|
|
2209
|
+
this.logDebug('Executing search business operation', { searchQuery, hasFilter: !!filter, dataMode, variantKey: resolvedOperation.variantKey });
|
|
2210
|
+
// 1. Apply business search logic
|
|
2211
|
+
const businessFilter = await this.applyBusinessFilter(filter || {}, executionContext);
|
|
2212
|
+
const enhancedSearchQuery = await this.enhanceSearchQuery(searchQuery, executionContext);
|
|
2213
|
+
// 2. Execute repository operation with resolved variant - search doesn't use id_or_ids_or_filter, pass search data via data parameter
|
|
2214
|
+
const searchData = { query: enhancedSearchQuery, filter: businessFilter };
|
|
2215
|
+
const result = await this.callRepository(resolvedOperation, executionContext, undefined, searchData, options);
|
|
2216
|
+
// 3. Enrich each item with business context
|
|
2217
|
+
const enrichedData = result.data ?
|
|
2218
|
+
await Promise.all(result.data.map(item => this.enrichBusinessContext(CoreResourceOperation.SEARCH, item, executionContext))) :
|
|
2219
|
+
[];
|
|
2220
|
+
// 4. Return result with enriched data (transformation happens in doOperation)
|
|
2221
|
+
const processedResult = { ...result, data: enrichedData };
|
|
2222
|
+
this.logDebug('Search business operation completed', { count: enrichedData.length });
|
|
2223
|
+
return processedResult;
|
|
2224
|
+
}
|
|
2225
|
+
async count(operation, executionContext, filter, options) {
|
|
2226
|
+
this.logDebug('Executing count business operation', { hasFilter: !!filter });
|
|
2227
|
+
// 1. Apply business filtering
|
|
2228
|
+
const businessFilter = await this.applyBusinessFilter(filter || {}, executionContext);
|
|
2229
|
+
// 2. Execute repository operation - count doesn't use id_or_ids_or_filter, pass filter via data parameter
|
|
2230
|
+
const countData = Object.keys(businessFilter).length > 0 ? { filter: businessFilter } : undefined;
|
|
2231
|
+
const result = await this.callRepository(operation, executionContext, undefined, countData, options);
|
|
2232
|
+
this.logDebug('Count business operation completed', { count: result.count });
|
|
2233
|
+
return result;
|
|
2234
|
+
}
|
|
2235
|
+
// ================================
|
|
2236
|
+
// DTO Validation and Transformation Methods
|
|
2237
|
+
// ================================
|
|
2238
|
+
/**
|
|
2239
|
+
* Validate and transform input data using operation's requestDto
|
|
2240
|
+
*/
|
|
2241
|
+
async validateAndTransformInput(executionContext, data) {
|
|
2242
|
+
const operation = executionContext.operation;
|
|
2243
|
+
if (!operation.requestDto) {
|
|
2244
|
+
this.logDebug('No requestDto defined for operation, skipping validation');
|
|
2245
|
+
return data;
|
|
2246
|
+
}
|
|
2247
|
+
try {
|
|
2248
|
+
// Validate and transform input — use loose parse to preserve PREFIX-augmented
|
|
2249
|
+
// persistence fields that are not part of the API's requestDto schema.
|
|
2250
|
+
// Field-level security is enforced at the controller boundary; Mongoose strict
|
|
2251
|
+
// mode strips schema-unknown fields at the repository layer.
|
|
2252
|
+
const validatedData = (operation.requestDto instanceof z.ZodObject)
|
|
2253
|
+
? z.looseObject(operation.requestDto.shape).parse(data)
|
|
2254
|
+
: operation.requestDto.parse(data);
|
|
2255
|
+
this.logDebug('Input validation successful');
|
|
2256
|
+
return validatedData;
|
|
2257
|
+
}
|
|
2258
|
+
catch (error) {
|
|
2259
|
+
if (error instanceof z.ZodError) {
|
|
2260
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
2261
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
2262
|
+
stack: error.stack,
|
|
2263
|
+
context: {
|
|
2264
|
+
operationIdentifier: operation.operationIdentifier,
|
|
2265
|
+
inputData: data,
|
|
2266
|
+
zodIssues: error.issues,
|
|
2267
|
+
}
|
|
2268
|
+
});
|
|
2269
|
+
}
|
|
2270
|
+
throw this.errorBuilder.buildFromStandardError(error instanceof Error ? error : new Error('Unknown validation error'), executionContext, {
|
|
2271
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
2272
|
+
context: {
|
|
2273
|
+
operationIdentifier: operation.operationIdentifier,
|
|
2274
|
+
inputData: data,
|
|
2275
|
+
}
|
|
2276
|
+
});
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
async transformOutput(executionContext, data, dataMode = DataMode.RAW, alreadyResolvedOperation) {
|
|
2280
|
+
const operation = executionContext.operation;
|
|
2281
|
+
// Use already-resolved operation if provided (to avoid double resolution)
|
|
2282
|
+
// Otherwise resolve based on dataMode
|
|
2283
|
+
const resolvedOperation = alreadyResolvedOperation ?? this.resolveOperationVariant(operation, dataMode);
|
|
2284
|
+
this.logDebug('Transform output - using resolved operation', {
|
|
2285
|
+
operationIdentifier: operation.operationIdentifier,
|
|
2286
|
+
dataMode,
|
|
2287
|
+
resolvedVariantKey: resolvedOperation.variantKey,
|
|
2288
|
+
wasAlreadyResolved: !!alreadyResolvedOperation
|
|
2289
|
+
});
|
|
2290
|
+
// Use internalDto for service-layer validation
|
|
2291
|
+
// internalDto MUST exist - it's built by buildAllOperationDtos() for all operations
|
|
2292
|
+
if (!resolvedOperation.internalDto) {
|
|
2293
|
+
throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, {
|
|
2294
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_TRANSFORMATION_FAILED,
|
|
2295
|
+
context: {
|
|
2296
|
+
reason: 'Missing internalDto - this indicates a configuration error in buildAllOperationDtos()',
|
|
2297
|
+
operationIdentifier: resolvedOperation.operationIdentifier,
|
|
2298
|
+
resourceIdentifier: resolvedOperation.resourceIdentifier,
|
|
2299
|
+
variantKey: resolvedOperation.variantKey,
|
|
2300
|
+
dataMode
|
|
2301
|
+
}
|
|
2302
|
+
});
|
|
2303
|
+
}
|
|
2304
|
+
this.logDebug('Service transformOutput - resolved operation', {
|
|
2305
|
+
operationIdentifier: operation.operationIdentifier,
|
|
2306
|
+
dataMode,
|
|
2307
|
+
resolvedVariantKey: resolvedOperation.variantKey,
|
|
2308
|
+
hasInternalDto: !!resolvedOperation.internalDto
|
|
2309
|
+
});
|
|
2310
|
+
this.logDebug('transformOutput - before validation', {
|
|
2311
|
+
dataKeys: data && typeof data === 'object' && !Array.isArray(data) ? Object.keys(data) : 'not plain object',
|
|
2312
|
+
hasUserSelfProfile: data && typeof data === 'object' ? 'userSelfProfile' in data : false,
|
|
2313
|
+
hasUserSelfPreference: data && typeof data === 'object' ? 'userSelfPreference' in data : false,
|
|
2314
|
+
hasOrgMembers: data && typeof data === 'object' ? 'organizationMembers' in data : false
|
|
2315
|
+
});
|
|
2316
|
+
try {
|
|
2317
|
+
// Transform and validate output using resolved operation's internalDto
|
|
2318
|
+
const effectiveOperation = resolvedOperation.resourceOperationLike || resolvedOperation.operationIdentifier;
|
|
2319
|
+
const isBulkArrayOperation = (effectiveOperation === CoreResourceOperation.CREATE_MANY
|
|
2320
|
+
|| effectiveOperation === CoreResourceOperation.UPDATE_MANY);
|
|
2321
|
+
const isCollectionOperation = (effectiveOperation === CoreResourceOperation.LIST
|
|
2322
|
+
|| effectiveOperation === CoreResourceOperation.SEARCH);
|
|
2323
|
+
const collectionItemDto = (Array.isArray(data) && isCollectionOperation)
|
|
2324
|
+
? this.extractCollectionItemDto(resolvedOperation.internalDto) ?? resolvedOperation.repositoryDto
|
|
2325
|
+
: null;
|
|
2326
|
+
const transformedData = (Array.isArray(data) && (isBulkArrayOperation || !!collectionItemDto))
|
|
2327
|
+
? data.map((item) => (collectionItemDto ?? resolvedOperation.internalDto).parse(item))
|
|
2328
|
+
: resolvedOperation.internalDto.parse(data);
|
|
2329
|
+
this.logDebug('transformOutput - after validation', {
|
|
2330
|
+
dataKeys: transformedData && typeof transformedData === 'object' && !Array.isArray(transformedData) ? Object.keys(transformedData) : 'not plain object',
|
|
2331
|
+
hasUserSelfProfile: transformedData && typeof transformedData === 'object' ? 'userSelfProfile' in transformedData : false,
|
|
2332
|
+
hasUserSelfPreference: transformedData && typeof transformedData === 'object' ? 'userSelfPreference' in transformedData : false,
|
|
2333
|
+
hasOrgMembers: transformedData && typeof transformedData === 'object' ? 'organizationMembers' in transformedData : false
|
|
2334
|
+
});
|
|
2335
|
+
this.logDebug('Output transformation successful');
|
|
2336
|
+
return transformedData;
|
|
2337
|
+
}
|
|
2338
|
+
catch (error) {
|
|
2339
|
+
// Output transformation failures are programming/configuration errors.
|
|
2340
|
+
// The DTO doesn't match the actual output structure.
|
|
2341
|
+
const transformationError = this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, {
|
|
2342
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_TRANSFORMATION_FAILED,
|
|
2343
|
+
context: {
|
|
2344
|
+
operationIdentifier: operation.operationIdentifier,
|
|
2345
|
+
resourceIdentifier: operation.resourceIdentifier,
|
|
2346
|
+
outputDataType: Array.isArray(data) ? 'array' : typeof data,
|
|
2347
|
+
outputDataLength: Array.isArray(data) ? data.length : undefined,
|
|
2348
|
+
outputDataKeys: data && typeof data === 'object' && !Array.isArray(data) ? Object.keys(data) : undefined
|
|
2349
|
+
},
|
|
2350
|
+
stack: error instanceof Error ? error.stack : undefined
|
|
2351
|
+
});
|
|
2352
|
+
throw transformationError;
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
extractCollectionItemDto(dto) {
|
|
2356
|
+
if (!(dto instanceof z.ZodObject)) {
|
|
2357
|
+
return null;
|
|
2358
|
+
}
|
|
2359
|
+
const dataField = dto.shape?.data;
|
|
2360
|
+
const paginationField = dto.shape?.pagination;
|
|
2361
|
+
if (!(dataField instanceof z.ZodArray) || !paginationField) {
|
|
2362
|
+
return null;
|
|
2363
|
+
}
|
|
2364
|
+
return dataField.element;
|
|
2365
|
+
}
|
|
2366
|
+
/**
|
|
2367
|
+
* Apply business validation
|
|
2368
|
+
*/
|
|
2369
|
+
async applyBusinessValidation(operation, data, executionContext, currentState) {
|
|
2370
|
+
// Implement business validation logic here
|
|
2371
|
+
// This could include:
|
|
2372
|
+
// - Business rule validation
|
|
2373
|
+
// - Permission checks
|
|
2374
|
+
// - Data consistency validation
|
|
2375
|
+
// - Cross-resource validation
|
|
2376
|
+
return data; // Default: pass through
|
|
2377
|
+
}
|
|
2378
|
+
/**
|
|
2379
|
+
* Execute pre-operation business logic
|
|
2380
|
+
*/
|
|
2381
|
+
async executePreOperationLogic(operation, data, executionContext, currentState) {
|
|
2382
|
+
// Implement pre-operation logic here
|
|
2383
|
+
// This could include:
|
|
2384
|
+
// - Data enrichment
|
|
2385
|
+
// - Related resource updates
|
|
2386
|
+
// - Event preparation
|
|
2387
|
+
// - Cache invalidation preparation
|
|
2388
|
+
return data; // Default: pass through
|
|
2389
|
+
}
|
|
2390
|
+
/**
|
|
2391
|
+
* Execute post-operation business logic using engine lifecycle operations
|
|
2392
|
+
*/
|
|
2393
|
+
async executePostOperationLogic(operation, result, executionContext, currentState) {
|
|
2394
|
+
// Get the current operation configuration
|
|
2395
|
+
const operationConfig = executionContext.operation;
|
|
2396
|
+
const resourceType = operationConfig.resourceIdentifier;
|
|
2397
|
+
// Execute lifecycle operations for DELETE (child deletion based on childOperations config)
|
|
2398
|
+
if (operation === CoreResourceOperation.DELETE || operation === CoreResourceOperation.DELETE_MANY) {
|
|
2399
|
+
await this.executeLifecycleOperations(operation, result, executionContext, currentState);
|
|
2400
|
+
}
|
|
2401
|
+
// Execute other post-operation logic (events, notifications, etc.)
|
|
2402
|
+
await this.executeAdditionalPostOperationLogic(operation, result, executionContext, currentState);
|
|
2403
|
+
return result;
|
|
2404
|
+
}
|
|
2405
|
+
// =============================================================================
|
|
2406
|
+
// NESTED OPERATIONS PROCESSING
|
|
2407
|
+
// =============================================================================
|
|
2408
|
+
getRelationshipFieldNameForCurrentResource(rel) {
|
|
2409
|
+
return Resources_SharedUtils.resolveRelationshipObjectIdentityForResource(rel, this.resourceConfiguration.resourceIdentifier, this.getAllResourceFieldIdentifiers()).objectFieldName;
|
|
2410
|
+
}
|
|
2411
|
+
getRelationshipForBulkAction(relationshipField) {
|
|
2412
|
+
const currentResourceType = this.resourceConfiguration.resourceIdentifier;
|
|
2413
|
+
const candidateRelationships = this.resourcesRegistry
|
|
2414
|
+
.getResourcesRegistry()
|
|
2415
|
+
.resourceRelationships
|
|
2416
|
+
.filter((rel) => rel.isDisabled !== true
|
|
2417
|
+
&& (rel.resourceType1 === currentResourceType || rel.resourceType2 === currentResourceType));
|
|
2418
|
+
const matches = candidateRelationships.filter((rel) => this.getRelationshipFieldNameForCurrentResource(rel) === relationshipField);
|
|
2419
|
+
if (matches.length === 1) {
|
|
2420
|
+
return matches[0];
|
|
2421
|
+
}
|
|
2422
|
+
if (matches.length > 1) {
|
|
2423
|
+
throw new Error(`Bulk relationship field "${relationshipField}" is ambiguous for resource "${this.resourceConfiguration.resourceIdentifier}".`);
|
|
2424
|
+
}
|
|
2425
|
+
throw new Error(`Bulk relationship field "${relationshipField}" does not map to a relationship on resource "${this.resourceConfiguration.resourceIdentifier}".`);
|
|
2426
|
+
}
|
|
2427
|
+
async applyReferenceSetActionMany(executionContext, id_or_ids_or_filter, relationship, relationshipField, targetId, options) {
|
|
2428
|
+
const relatedReadContext = await this.executionContextCreator.createForSubCall(executionContext, relationship.resourceType1, CoreResourceOperation.READ);
|
|
2429
|
+
const relatedTarget = await this.servicesRegistry.read(relationship.resourceType1, relatedReadContext, targetId, options);
|
|
2430
|
+
if (!relatedTarget) {
|
|
2431
|
+
throw this.errorBuilder.buildError(ErrorType.NOT_FOUND, executionContext, {
|
|
2432
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED,
|
|
2433
|
+
context: {
|
|
2434
|
+
relationshipField,
|
|
2435
|
+
action: ResourceRelationshipBulkAction.SET,
|
|
2436
|
+
targetId,
|
|
2437
|
+
relatedResourceType: relationship.resourceType1,
|
|
2438
|
+
},
|
|
2439
|
+
});
|
|
2440
|
+
}
|
|
2441
|
+
if (!Resources_SharedUtils.isRelationshipActiveForParent(relationship, relatedTarget, {
|
|
2442
|
+
onMissingParentResource: 'exclude',
|
|
2443
|
+
onConditionError: 'throw',
|
|
2444
|
+
})) {
|
|
2445
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
2446
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
2447
|
+
context: {
|
|
2448
|
+
relationshipField,
|
|
2449
|
+
action: ResourceRelationshipBulkAction.SET,
|
|
2450
|
+
targetId,
|
|
2451
|
+
reason: 'Reference relationship is inactive for the selected related resource',
|
|
2452
|
+
},
|
|
2453
|
+
});
|
|
2454
|
+
}
|
|
2455
|
+
const updateManyContext = await this.executionContextCreator.createForSubCall(executionContext, this.resourceConfiguration.resourceIdentifier, CoreResourceOperation.UPDATE_MANY);
|
|
2456
|
+
const fkField = this.getFKFieldForRelationship(relationship);
|
|
2457
|
+
const updatedTargets = await this.servicesRegistry.updateMany(this.resourceConfiguration.resourceIdentifier, updateManyContext, id_or_ids_or_filter, { [fkField]: targetId }, options);
|
|
2458
|
+
return {
|
|
2459
|
+
relationshipField,
|
|
2460
|
+
action: ResourceRelationshipBulkAction.SET,
|
|
2461
|
+
matchedTargetIds: this.extractResourceIds(updatedTargets),
|
|
2462
|
+
affectedCount: Array.isArray(updatedTargets) ? updatedTargets.length : 0,
|
|
2463
|
+
results: Array.isArray(updatedTargets) ? updatedTargets : [],
|
|
2464
|
+
};
|
|
2465
|
+
}
|
|
2466
|
+
async applyReferenceClearActionMany(executionContext, id_or_ids_or_filter, relationship, relationshipField, options) {
|
|
2467
|
+
if (relationship.parentResourceRequirement === ResourceParentResourceRequirement.MANDATORY) {
|
|
2468
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
2469
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
2470
|
+
context: {
|
|
2471
|
+
relationshipField,
|
|
2472
|
+
action: ResourceRelationshipBulkAction.CLEAR,
|
|
2473
|
+
reason: 'Cannot clear a mandatory parent relationship through bulk reference mutation',
|
|
2474
|
+
},
|
|
2475
|
+
});
|
|
2476
|
+
}
|
|
2477
|
+
const updateManyContext = await this.executionContextCreator.createForSubCall(executionContext, this.resourceConfiguration.resourceIdentifier, CoreResourceOperation.UPDATE_MANY);
|
|
2478
|
+
const fkField = this.getFKFieldForRelationship(relationship);
|
|
2479
|
+
const updatedTargets = await this.servicesRegistry.updateMany(this.resourceConfiguration.resourceIdentifier, updateManyContext, id_or_ids_or_filter, { [fkField]: null }, options);
|
|
2480
|
+
return {
|
|
2481
|
+
relationshipField,
|
|
2482
|
+
action: ResourceRelationshipBulkAction.CLEAR,
|
|
2483
|
+
matchedTargetIds: this.extractResourceIds(updatedTargets),
|
|
2484
|
+
affectedCount: Array.isArray(updatedTargets) ? updatedTargets.length : 0,
|
|
2485
|
+
results: Array.isArray(updatedTargets) ? updatedTargets : [],
|
|
2486
|
+
};
|
|
2487
|
+
}
|
|
2488
|
+
async applyCompositionCreateActionMany(executionContext, id_or_ids_or_filter, relationship, relationshipField, data, options) {
|
|
2489
|
+
const fkField = this.getFKFieldForRelationship(relationship);
|
|
2490
|
+
if (fkField in data) {
|
|
2491
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
2492
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
2493
|
+
context: {
|
|
2494
|
+
relationshipField,
|
|
2495
|
+
action: ResourceRelationshipBulkAction.CREATE,
|
|
2496
|
+
fkField,
|
|
2497
|
+
reason: 'Bulk composition create payload must not provide the relationship foreign key explicitly',
|
|
2498
|
+
},
|
|
2499
|
+
});
|
|
2500
|
+
}
|
|
2501
|
+
const targetResources = await this.loadBulkTargetResources(executionContext, id_or_ids_or_filter, options);
|
|
2502
|
+
const createdChildren = [];
|
|
2503
|
+
const matchedTargetIds = [];
|
|
2504
|
+
for (const targetResource of targetResources) {
|
|
2505
|
+
if (!Resources_SharedUtils.isRelationshipActiveForParent(relationship, targetResource, {
|
|
2506
|
+
onMissingParentResource: 'exclude',
|
|
2507
|
+
onConditionError: 'throw',
|
|
2508
|
+
})) {
|
|
2509
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
2510
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
2511
|
+
context: {
|
|
2512
|
+
relationshipField,
|
|
2513
|
+
action: ResourceRelationshipBulkAction.CREATE,
|
|
2514
|
+
reason: 'Composition relationship is inactive for one of the matched target resources',
|
|
2515
|
+
targetResourceId: this.getResourceIdValue(targetResource),
|
|
2516
|
+
},
|
|
2517
|
+
});
|
|
2518
|
+
}
|
|
2519
|
+
const targetResourceId = this.getResourceIdValue(targetResource);
|
|
2520
|
+
if (!targetResourceId) {
|
|
2521
|
+
throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, {
|
|
2522
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED,
|
|
2523
|
+
context: {
|
|
2524
|
+
relationshipField,
|
|
2525
|
+
action: ResourceRelationshipBulkAction.CREATE,
|
|
2526
|
+
reason: 'Bulk composition create requires every matched target resource to expose an id',
|
|
2527
|
+
},
|
|
2528
|
+
});
|
|
2529
|
+
}
|
|
2530
|
+
const createContext = await this.executionContextCreator.createForSubCall(executionContext, relationship.resourceType2, CoreResourceOperation.CREATE);
|
|
2531
|
+
const createdChild = await this.servicesRegistry.create(relationship.resourceType2, createContext, {
|
|
2532
|
+
...data,
|
|
2533
|
+
[fkField]: targetResourceId,
|
|
2534
|
+
}, options);
|
|
2535
|
+
matchedTargetIds.push(targetResourceId);
|
|
2536
|
+
createdChildren.push(createdChild);
|
|
2537
|
+
}
|
|
2538
|
+
return {
|
|
2539
|
+
relationshipField,
|
|
2540
|
+
action: ResourceRelationshipBulkAction.CREATE,
|
|
2541
|
+
matchedTargetIds,
|
|
2542
|
+
affectedCount: createdChildren.length,
|
|
2543
|
+
results: createdChildren,
|
|
2544
|
+
};
|
|
2545
|
+
}
|
|
2546
|
+
async applyAssociationLinkActionMany(executionContext, id_or_ids_or_filter, relationship, relationshipField, peerIds, options) {
|
|
2547
|
+
const { jointResourceType, peerResourceType, currentForeignKeyField, peerForeignKeyField, } = this.resolveAssociationBulkIdentity(relationship);
|
|
2548
|
+
const uniquePeerIds = [...new Set(peerIds)];
|
|
2549
|
+
await this.assertAssociationPeerResourcesExist(executionContext, relationshipField, peerResourceType, uniquePeerIds, ResourceRelationshipBulkAction.LINK, options);
|
|
2550
|
+
const targetResources = await this.loadBulkTargetResources(executionContext, id_or_ids_or_filter, options);
|
|
2551
|
+
const matchedTargetIds = [];
|
|
2552
|
+
for (const targetResource of targetResources) {
|
|
2553
|
+
if (!Resources_SharedUtils.isRelationshipActiveForParent(relationship, targetResource, {
|
|
2554
|
+
onMissingParentResource: 'exclude',
|
|
2555
|
+
onConditionError: 'throw',
|
|
2556
|
+
})) {
|
|
2557
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
2558
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
2559
|
+
context: {
|
|
2560
|
+
relationshipField,
|
|
2561
|
+
action: ResourceRelationshipBulkAction.LINK,
|
|
2562
|
+
reason: 'Association relationship is inactive for one of the matched target resources',
|
|
2563
|
+
targetResourceId: this.getResourceIdValue(targetResource),
|
|
2564
|
+
},
|
|
2565
|
+
});
|
|
2566
|
+
}
|
|
2567
|
+
const targetResourceId = this.getResourceIdValue(targetResource);
|
|
2568
|
+
if (!targetResourceId) {
|
|
2569
|
+
throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, {
|
|
2570
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED,
|
|
2571
|
+
context: {
|
|
2572
|
+
relationshipField,
|
|
2573
|
+
action: ResourceRelationshipBulkAction.LINK,
|
|
2574
|
+
reason: 'Bulk association link requires every matched target resource to expose an id',
|
|
2575
|
+
},
|
|
2576
|
+
});
|
|
2577
|
+
}
|
|
2578
|
+
matchedTargetIds.push(targetResourceId);
|
|
2579
|
+
}
|
|
2580
|
+
const existingRows = matchedTargetIds.length > 0
|
|
2581
|
+
? await this.listAssociationRowsByCurrentAndPeerIds(executionContext, jointResourceType, currentForeignKeyField, matchedTargetIds, peerForeignKeyField, uniquePeerIds, options)
|
|
2582
|
+
: [];
|
|
2583
|
+
const existingKeys = new Set(existingRows
|
|
2584
|
+
.map((row) => {
|
|
2585
|
+
const currentId = row?.[currentForeignKeyField];
|
|
2586
|
+
const peerId = row?.[peerForeignKeyField];
|
|
2587
|
+
return typeof currentId === 'string' && typeof peerId === 'string'
|
|
2588
|
+
? `${currentId}::${peerId}`
|
|
2589
|
+
: undefined;
|
|
2590
|
+
})
|
|
2591
|
+
.filter((key) => Boolean(key)));
|
|
2592
|
+
const createdRows = [];
|
|
2593
|
+
for (const targetResourceId of matchedTargetIds) {
|
|
2594
|
+
for (const peerId of uniquePeerIds) {
|
|
2595
|
+
const key = `${targetResourceId}::${peerId}`;
|
|
2596
|
+
if (existingKeys.has(key)) {
|
|
2597
|
+
continue;
|
|
2598
|
+
}
|
|
2599
|
+
const createContext = await this.executionContextCreator.createForSubCall(executionContext, jointResourceType, CoreResourceOperation.CREATE);
|
|
2600
|
+
const createdRow = await this.servicesRegistry.create(jointResourceType, createContext, {
|
|
2601
|
+
[currentForeignKeyField]: targetResourceId,
|
|
2602
|
+
[peerForeignKeyField]: peerId,
|
|
2603
|
+
}, options);
|
|
2604
|
+
createdRows.push(createdRow);
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
return {
|
|
2608
|
+
relationshipField,
|
|
2609
|
+
action: ResourceRelationshipBulkAction.LINK,
|
|
2610
|
+
matchedTargetIds,
|
|
2611
|
+
affectedCount: createdRows.length,
|
|
2612
|
+
results: createdRows,
|
|
2613
|
+
};
|
|
2614
|
+
}
|
|
2615
|
+
async applyAssociationUnlinkActionMany(executionContext, id_or_ids_or_filter, relationship, relationshipField, peerIds, options) {
|
|
2616
|
+
const { jointResourceType, currentForeignKeyField, peerForeignKeyField, } = this.resolveAssociationBulkIdentity(relationship);
|
|
2617
|
+
const uniquePeerIds = [...new Set(peerIds)];
|
|
2618
|
+
const targetResources = await this.loadBulkTargetResources(executionContext, id_or_ids_or_filter, options);
|
|
2619
|
+
const matchedTargetIds = [];
|
|
2620
|
+
for (const targetResource of targetResources) {
|
|
2621
|
+
if (!Resources_SharedUtils.isRelationshipActiveForParent(relationship, targetResource, {
|
|
2622
|
+
onMissingParentResource: 'exclude',
|
|
2623
|
+
onConditionError: 'throw',
|
|
2624
|
+
})) {
|
|
2625
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
2626
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
2627
|
+
context: {
|
|
2628
|
+
relationshipField,
|
|
2629
|
+
action: ResourceRelationshipBulkAction.UNLINK,
|
|
2630
|
+
reason: 'Association relationship is inactive for one of the matched target resources',
|
|
2631
|
+
targetResourceId: this.getResourceIdValue(targetResource),
|
|
2632
|
+
},
|
|
2633
|
+
});
|
|
2634
|
+
}
|
|
2635
|
+
const targetResourceId = this.getResourceIdValue(targetResource);
|
|
2636
|
+
if (!targetResourceId) {
|
|
2637
|
+
throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, {
|
|
2638
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED,
|
|
2639
|
+
context: {
|
|
2640
|
+
relationshipField,
|
|
2641
|
+
action: ResourceRelationshipBulkAction.UNLINK,
|
|
2642
|
+
reason: 'Bulk association unlink requires every matched target resource to expose an id',
|
|
2643
|
+
},
|
|
2644
|
+
});
|
|
2645
|
+
}
|
|
2646
|
+
matchedTargetIds.push(targetResourceId);
|
|
2647
|
+
}
|
|
2648
|
+
if (matchedTargetIds.length === 0 || uniquePeerIds.length === 0) {
|
|
2649
|
+
return {
|
|
2650
|
+
relationshipField,
|
|
2651
|
+
action: ResourceRelationshipBulkAction.UNLINK,
|
|
2652
|
+
matchedTargetIds,
|
|
2653
|
+
affectedCount: 0,
|
|
2654
|
+
results: [],
|
|
2655
|
+
};
|
|
2656
|
+
}
|
|
2657
|
+
const existingRows = await this.listAssociationRowsByCurrentAndPeerIds(executionContext, jointResourceType, currentForeignKeyField, matchedTargetIds, peerForeignKeyField, uniquePeerIds, options);
|
|
2658
|
+
const existingRowIds = existingRows
|
|
2659
|
+
.map((row) => this.getResourceIdValue(row))
|
|
2660
|
+
.filter((rowId) => Boolean(rowId));
|
|
2661
|
+
if (existingRowIds.length !== existingRows.length) {
|
|
2662
|
+
throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, {
|
|
2663
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED,
|
|
2664
|
+
context: {
|
|
2665
|
+
relationshipField,
|
|
2666
|
+
action: ResourceRelationshipBulkAction.UNLINK,
|
|
2667
|
+
reason: 'Bulk association unlink requires every junction row to expose an id',
|
|
2668
|
+
},
|
|
2669
|
+
});
|
|
2670
|
+
}
|
|
2671
|
+
if (existingRowIds.length === 0) {
|
|
2672
|
+
return {
|
|
2673
|
+
relationshipField,
|
|
2674
|
+
action: ResourceRelationshipBulkAction.UNLINK,
|
|
2675
|
+
matchedTargetIds,
|
|
2676
|
+
affectedCount: 0,
|
|
2677
|
+
results: [],
|
|
2678
|
+
};
|
|
2679
|
+
}
|
|
2680
|
+
const deleteManyContext = await this.executionContextCreator.createForSubCall(executionContext, jointResourceType, CoreResourceOperation.DELETE_MANY);
|
|
2681
|
+
const deletedRowIds = await this.servicesRegistry.deleteMany(jointResourceType, deleteManyContext, existingRowIds, options);
|
|
2682
|
+
return {
|
|
2683
|
+
relationshipField,
|
|
2684
|
+
action: ResourceRelationshipBulkAction.UNLINK,
|
|
2685
|
+
matchedTargetIds,
|
|
2686
|
+
affectedCount: Array.isArray(deletedRowIds) ? deletedRowIds.length : 0,
|
|
2687
|
+
results: Array.isArray(deletedRowIds) ? deletedRowIds : [],
|
|
2688
|
+
};
|
|
2689
|
+
}
|
|
2690
|
+
async applyAssociationReplaceActionMany(executionContext, id_or_ids_or_filter, relationship, relationshipField, peerIds, options) {
|
|
2691
|
+
const { jointResourceType, peerResourceType, currentForeignKeyField, peerForeignKeyField, } = this.resolveAssociationBulkIdentity(relationship);
|
|
2692
|
+
const uniquePeerIds = [...new Set(peerIds)];
|
|
2693
|
+
await this.assertAssociationPeerResourcesExist(executionContext, relationshipField, peerResourceType, uniquePeerIds, ResourceRelationshipBulkAction.REPLACE, options);
|
|
2694
|
+
const matchedTargetIds = await this.resolveActiveAssociationBulkTargetIds(executionContext, id_or_ids_or_filter, relationship, relationshipField, ResourceRelationshipBulkAction.REPLACE, options);
|
|
2695
|
+
if (matchedTargetIds.length === 0) {
|
|
2696
|
+
return {
|
|
2697
|
+
relationshipField,
|
|
2698
|
+
action: ResourceRelationshipBulkAction.REPLACE,
|
|
2699
|
+
matchedTargetIds,
|
|
2700
|
+
affectedCount: 0,
|
|
2701
|
+
results: [],
|
|
2702
|
+
};
|
|
2703
|
+
}
|
|
2704
|
+
const existingRows = await this.listAssociationRowsByCurrentIds(executionContext, jointResourceType, currentForeignKeyField, matchedTargetIds, options);
|
|
2705
|
+
const desiredKeys = new Set();
|
|
2706
|
+
for (const targetResourceId of matchedTargetIds) {
|
|
2707
|
+
for (const peerId of uniquePeerIds) {
|
|
2708
|
+
desiredKeys.add(`${targetResourceId}::${peerId}`);
|
|
2709
|
+
}
|
|
2710
|
+
}
|
|
2711
|
+
const rowsToDelete = existingRows.filter((row) => {
|
|
2712
|
+
const currentId = row?.[currentForeignKeyField];
|
|
2713
|
+
const peerId = row?.[peerForeignKeyField];
|
|
2714
|
+
if (typeof currentId !== 'string' || typeof peerId !== 'string') {
|
|
2715
|
+
return false;
|
|
2716
|
+
}
|
|
2717
|
+
return !desiredKeys.has(`${currentId}::${peerId}`);
|
|
2718
|
+
});
|
|
2719
|
+
const deleteRowIds = rowsToDelete
|
|
2720
|
+
.map((row) => this.getResourceIdValue(row))
|
|
2721
|
+
.filter((rowId) => Boolean(rowId));
|
|
2722
|
+
if (deleteRowIds.length !== rowsToDelete.length) {
|
|
2723
|
+
throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, {
|
|
2724
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED,
|
|
2725
|
+
context: {
|
|
2726
|
+
relationshipField,
|
|
2727
|
+
action: ResourceRelationshipBulkAction.REPLACE,
|
|
2728
|
+
reason: 'Bulk association replace requires every junction row to expose an id',
|
|
2729
|
+
},
|
|
2730
|
+
});
|
|
2731
|
+
}
|
|
2732
|
+
const existingKeys = new Set(existingRows
|
|
2733
|
+
.map((row) => {
|
|
2734
|
+
const currentId = row?.[currentForeignKeyField];
|
|
2735
|
+
const peerId = row?.[peerForeignKeyField];
|
|
2736
|
+
return typeof currentId === 'string' && typeof peerId === 'string'
|
|
2737
|
+
? `${currentId}::${peerId}`
|
|
2738
|
+
: undefined;
|
|
2739
|
+
})
|
|
2740
|
+
.filter((key) => Boolean(key)));
|
|
2741
|
+
const createdRows = [];
|
|
2742
|
+
for (const targetResourceId of matchedTargetIds) {
|
|
2743
|
+
for (const peerId of uniquePeerIds) {
|
|
2744
|
+
const key = `${targetResourceId}::${peerId}`;
|
|
2745
|
+
if (existingKeys.has(key)) {
|
|
2746
|
+
continue;
|
|
2747
|
+
}
|
|
2748
|
+
const createContext = await this.executionContextCreator.createForSubCall(executionContext, jointResourceType, CoreResourceOperation.CREATE);
|
|
2749
|
+
const createdRow = await this.servicesRegistry.create(jointResourceType, createContext, {
|
|
2750
|
+
[currentForeignKeyField]: targetResourceId,
|
|
2751
|
+
[peerForeignKeyField]: peerId,
|
|
2752
|
+
}, options);
|
|
2753
|
+
createdRows.push(createdRow);
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
if (deleteRowIds.length > 0) {
|
|
2757
|
+
const deleteManyContext = await this.executionContextCreator.createForSubCall(executionContext, jointResourceType, CoreResourceOperation.DELETE_MANY);
|
|
2758
|
+
await this.servicesRegistry.deleteMany(jointResourceType, deleteManyContext, deleteRowIds, options);
|
|
2759
|
+
}
|
|
2760
|
+
return {
|
|
2761
|
+
relationshipField,
|
|
2762
|
+
action: ResourceRelationshipBulkAction.REPLACE,
|
|
2763
|
+
matchedTargetIds,
|
|
2764
|
+
affectedCount: createdRows.length + deleteRowIds.length,
|
|
2765
|
+
results: [
|
|
2766
|
+
...createdRows,
|
|
2767
|
+
...deleteRowIds,
|
|
2768
|
+
],
|
|
2769
|
+
};
|
|
2770
|
+
}
|
|
2771
|
+
/**
|
|
2772
|
+
* Extract nested field name from relationship using the shared
|
|
2773
|
+
* relationship-object identity rule.
|
|
2774
|
+
*/
|
|
2775
|
+
getNestedFieldName(rel) {
|
|
2776
|
+
return Resources_SharedUtils.resolveRelationshipObjectIdentity(rel, rel.resourceType2, rel.cardinality2, this.getAllResourceFieldIdentifiers()).objectFieldName;
|
|
2777
|
+
}
|
|
2778
|
+
getAllResourceFieldIdentifiers() {
|
|
2779
|
+
const registry = this.resourcesRegistry.getResourcesRegistry();
|
|
2780
|
+
const allResourceFieldIdentifiers = {};
|
|
2781
|
+
for (const resourceType of Object.keys(registry.resourceConfigurations)) {
|
|
2782
|
+
const fieldIdentifier = registry.resourceConfigurations[resourceType]?.resourceFieldIdentifier;
|
|
2783
|
+
if (typeof fieldIdentifier === 'string' && fieldIdentifier.length > 0) {
|
|
2784
|
+
allResourceFieldIdentifiers[resourceType] = fieldIdentifier;
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
2787
|
+
return allResourceFieldIdentifiers;
|
|
2788
|
+
}
|
|
2789
|
+
extractResourceIds(resources) {
|
|
2790
|
+
if (!Array.isArray(resources)) {
|
|
2791
|
+
return [];
|
|
2792
|
+
}
|
|
2793
|
+
return resources
|
|
2794
|
+
.map((resource) => this.getResourceIdValue(resource))
|
|
2795
|
+
.filter((resourceId) => Boolean(resourceId));
|
|
2796
|
+
}
|
|
2797
|
+
/**
|
|
2798
|
+
* Get FK field name for a relationship.
|
|
2799
|
+
* Delegates to the registry so backend services do not improvise their own
|
|
2800
|
+
* FK fallback semantics.
|
|
2801
|
+
*/
|
|
2802
|
+
getFKFieldForRelationship(rel) {
|
|
2803
|
+
return this.resourcesRegistry.resolveForeignKeyField({
|
|
2804
|
+
resourceType1: rel.resourceType1,
|
|
2805
|
+
foreignKeyField: rel.foreignKeyField,
|
|
2806
|
+
});
|
|
2807
|
+
}
|
|
2808
|
+
async resolveActiveAssociationBulkTargetIds(executionContext, id_or_ids_or_filter, relationship, relationshipField, action, options) {
|
|
2809
|
+
const targetResources = await this.loadBulkTargetResources(executionContext, id_or_ids_or_filter, options);
|
|
2810
|
+
const matchedTargetIds = [];
|
|
2811
|
+
for (const targetResource of targetResources) {
|
|
2812
|
+
if (!Resources_SharedUtils.isRelationshipActiveForParent(relationship, targetResource, {
|
|
2813
|
+
onMissingParentResource: 'exclude',
|
|
2814
|
+
onConditionError: 'throw',
|
|
2815
|
+
})) {
|
|
2816
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
2817
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
2818
|
+
context: {
|
|
2819
|
+
relationshipField,
|
|
2820
|
+
action,
|
|
2821
|
+
reason: 'Association relationship is inactive for one of the matched target resources',
|
|
2822
|
+
targetResourceId: this.getResourceIdValue(targetResource),
|
|
2823
|
+
},
|
|
2824
|
+
});
|
|
2825
|
+
}
|
|
2826
|
+
const targetResourceId = this.getResourceIdValue(targetResource);
|
|
2827
|
+
if (!targetResourceId) {
|
|
2828
|
+
throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, {
|
|
2829
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED,
|
|
2830
|
+
context: {
|
|
2831
|
+
relationshipField,
|
|
2832
|
+
action,
|
|
2833
|
+
reason: 'Bulk association mutation requires every matched target resource to expose an id',
|
|
2834
|
+
},
|
|
2835
|
+
});
|
|
2836
|
+
}
|
|
2837
|
+
matchedTargetIds.push(targetResourceId);
|
|
2838
|
+
}
|
|
2839
|
+
return matchedTargetIds;
|
|
2840
|
+
}
|
|
2841
|
+
resolveAssociationBulkIdentity(relationship) {
|
|
2842
|
+
const currentResourceType = this.resourceConfiguration.resourceIdentifier;
|
|
2843
|
+
const perspective = Resources_SharedUtils.getRelationshipPerspectiveForResource(relationship, currentResourceType);
|
|
2844
|
+
if (!perspective || !relationship.jointResourceType) {
|
|
2845
|
+
throw new Error('Association bulk actions require a non-self association relationship with jointResourceType');
|
|
2846
|
+
}
|
|
2847
|
+
const currentForeignKeyField = this.resourcesRegistry.resolveForeignKeyField({
|
|
2848
|
+
resourceType1: currentResourceType,
|
|
2849
|
+
foreignKeyField: perspective === 'resourceType1' ? relationship.foreignKeyField : undefined,
|
|
2850
|
+
});
|
|
2851
|
+
const peerResourceType = perspective === 'resourceType1'
|
|
2852
|
+
? relationship.resourceType2
|
|
2853
|
+
: relationship.resourceType1;
|
|
2854
|
+
const peerForeignKeyField = this.resourcesRegistry.resolveForeignKeyField({
|
|
2855
|
+
resourceType1: peerResourceType,
|
|
2856
|
+
foreignKeyField: perspective === 'resourceType2' ? relationship.foreignKeyField : undefined,
|
|
2857
|
+
});
|
|
2858
|
+
return {
|
|
2859
|
+
jointResourceType: relationship.jointResourceType,
|
|
2860
|
+
peerResourceType,
|
|
2861
|
+
currentForeignKeyField,
|
|
2862
|
+
peerForeignKeyField,
|
|
2863
|
+
};
|
|
2864
|
+
}
|
|
2865
|
+
async assertAssociationPeerResourcesExist(executionContext, relationshipField, peerResourceType, peerIds, action = ResourceRelationshipBulkAction.LINK, options) {
|
|
2866
|
+
for (const peerId of peerIds) {
|
|
2867
|
+
const readContext = await this.executionContextCreator.createForSubCall(executionContext, peerResourceType, CoreResourceOperation.READ);
|
|
2868
|
+
const peerResource = await this.servicesRegistry.read(peerResourceType, readContext, peerId, options);
|
|
2869
|
+
if (!peerResource) {
|
|
2870
|
+
throw this.errorBuilder.buildError(ErrorType.NOT_FOUND, executionContext, {
|
|
2871
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED,
|
|
2872
|
+
context: {
|
|
2873
|
+
relationshipField,
|
|
2874
|
+
action,
|
|
2875
|
+
peerId,
|
|
2876
|
+
peerResourceType,
|
|
2877
|
+
},
|
|
2878
|
+
});
|
|
2879
|
+
}
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
async listAssociationRowsByCurrentAndPeerIds(executionContext, jointResourceType, currentForeignKeyField, currentIds, peerForeignKeyField, peerIds, options) {
|
|
2883
|
+
const existingRows = [];
|
|
2884
|
+
const seenRowIds = new Set();
|
|
2885
|
+
for (const currentId of currentIds) {
|
|
2886
|
+
for (const peerId of peerIds) {
|
|
2887
|
+
const listContext = await this.executionContextCreator.createForSubCall(executionContext, jointResourceType, CoreResourceOperation.LIST);
|
|
2888
|
+
const result = await this.servicesRegistry.list(jointResourceType, listContext, {
|
|
2889
|
+
[currentForeignKeyField]: currentId,
|
|
2890
|
+
[peerForeignKeyField]: peerId,
|
|
2891
|
+
}, undefined, options);
|
|
2892
|
+
const rows = Array.isArray(result) ? result : result.data;
|
|
2893
|
+
for (const row of rows) {
|
|
2894
|
+
const rowId = this.getResourceIdValue(row);
|
|
2895
|
+
if (rowId) {
|
|
2896
|
+
if (seenRowIds.has(rowId)) {
|
|
2897
|
+
continue;
|
|
2898
|
+
}
|
|
2899
|
+
seenRowIds.add(rowId);
|
|
2900
|
+
}
|
|
2901
|
+
existingRows.push(row);
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
return existingRows;
|
|
2906
|
+
}
|
|
2907
|
+
async listAssociationRowsByCurrentIds(executionContext, jointResourceType, currentForeignKeyField, currentIds, options) {
|
|
2908
|
+
const existingRows = [];
|
|
2909
|
+
const seenRowIds = new Set();
|
|
2910
|
+
for (const currentId of currentIds) {
|
|
2911
|
+
const listContext = await this.executionContextCreator.createForSubCall(executionContext, jointResourceType, CoreResourceOperation.LIST);
|
|
2912
|
+
const result = await this.servicesRegistry.list(jointResourceType, listContext, {
|
|
2913
|
+
[currentForeignKeyField]: currentId,
|
|
2914
|
+
}, undefined, options);
|
|
2915
|
+
const rows = Array.isArray(result) ? result : result.data;
|
|
2916
|
+
for (const row of rows) {
|
|
2917
|
+
const rowId = this.getResourceIdValue(row);
|
|
2918
|
+
if (rowId) {
|
|
2919
|
+
if (seenRowIds.has(rowId)) {
|
|
2920
|
+
continue;
|
|
2921
|
+
}
|
|
2922
|
+
seenRowIds.add(rowId);
|
|
2923
|
+
}
|
|
2924
|
+
existingRows.push(row);
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
return existingRows;
|
|
2928
|
+
}
|
|
2929
|
+
getResolvedNestedMutationConfig(rel, operation) {
|
|
2930
|
+
return Resources_SharedUtils.resolveRelationshipNestedMutationConfig(rel, operation);
|
|
2931
|
+
}
|
|
2932
|
+
getResolvedNestedReadConfig(rel) {
|
|
2933
|
+
return Resources_SharedUtils.resolveRelationshipNestedReadConfig(rel);
|
|
2934
|
+
}
|
|
2935
|
+
getResolvedLifecycleOnParentDelete(rel) {
|
|
2936
|
+
return Resources_SharedUtils.resolveRelationshipLifecycleOnParentDeleteConfig(rel);
|
|
2937
|
+
}
|
|
2938
|
+
/**
|
|
2939
|
+
* Extract nested data from request, separating parent data from nested child data.
|
|
2940
|
+
* Returns { parentData, nestedData } where nestedData is keyed by field name.
|
|
2941
|
+
*/
|
|
2942
|
+
extractNestedData(data, relationships, operation) {
|
|
2943
|
+
const parentData = { ...data };
|
|
2944
|
+
const nestedData = {};
|
|
2945
|
+
for (const rel of relationships) {
|
|
2946
|
+
const nestedConfig = this.getResolvedNestedMutationConfig(rel, operation);
|
|
2947
|
+
if (!nestedConfig)
|
|
2948
|
+
continue;
|
|
2949
|
+
const fieldName = this.getNestedFieldName(rel);
|
|
2950
|
+
if (fieldName in parentData) {
|
|
2951
|
+
nestedData[fieldName] = parentData[fieldName];
|
|
2952
|
+
delete parentData[fieldName];
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
return { parentData, nestedData };
|
|
2956
|
+
}
|
|
2957
|
+
/**
|
|
2958
|
+
* Bulk variant of extractNestedData().
|
|
2959
|
+
* Applies the same nested field split to each item independently.
|
|
2960
|
+
*/
|
|
2961
|
+
extractNestedDataArray(dataArray, relationships, operation, executionContext) {
|
|
2962
|
+
if (!Array.isArray(dataArray)) {
|
|
2963
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
2964
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
2965
|
+
context: {
|
|
2966
|
+
operation,
|
|
2967
|
+
reason: 'Bulk create expects an array of parent payloads after validation',
|
|
2968
|
+
receivedType: typeof dataArray,
|
|
2969
|
+
}
|
|
2970
|
+
});
|
|
2971
|
+
}
|
|
2972
|
+
const parentDataArray = [];
|
|
2973
|
+
const nestedDataArray = [];
|
|
2974
|
+
for (const item of dataArray) {
|
|
2975
|
+
const { parentData, nestedData } = this.extractNestedData(item, relationships, operation);
|
|
2976
|
+
parentDataArray.push(parentData);
|
|
2977
|
+
nestedDataArray.push(nestedData);
|
|
2978
|
+
}
|
|
2979
|
+
return { parentDataArray, nestedDataArray };
|
|
2980
|
+
}
|
|
2981
|
+
/**
|
|
2982
|
+
* Normalize bulk create payloads to the array shape expected by the service layer.
|
|
2983
|
+
* Some callers may already pass the raw array, while others may use a `{ data: [] }`
|
|
2984
|
+
* envelope before controller-level extraction.
|
|
2985
|
+
*/
|
|
2986
|
+
normalizeCreateManyInput(validatedData, executionContext) {
|
|
2987
|
+
if (Array.isArray(validatedData)) {
|
|
2988
|
+
return validatedData;
|
|
2989
|
+
}
|
|
2990
|
+
if (validatedData && typeof validatedData === 'object' && Array.isArray(validatedData.data)) {
|
|
2991
|
+
return validatedData.data;
|
|
2992
|
+
}
|
|
2993
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
2994
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
2995
|
+
context: {
|
|
2996
|
+
operation: CoreResourceOperation.CREATE_MANY,
|
|
2997
|
+
reason: 'Bulk create expects either an array payload or an object with a data array',
|
|
2998
|
+
}
|
|
2999
|
+
});
|
|
3000
|
+
}
|
|
3001
|
+
/**
|
|
3002
|
+
* Normalize the CREATE_MANY request shape so service callers may pass either
|
|
3003
|
+
* a raw array or the controller-facing `{ data: [...] }` envelope.
|
|
3004
|
+
*/
|
|
3005
|
+
normalizeCreateManyRequestPayload(data, executionContext) {
|
|
3006
|
+
if (Array.isArray(data)) {
|
|
3007
|
+
return { data };
|
|
3008
|
+
}
|
|
3009
|
+
if (data && typeof data === 'object' && Array.isArray(data.data)) {
|
|
3010
|
+
return { ...data, data: data.data };
|
|
3011
|
+
}
|
|
3012
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
3013
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_VALIDATION_FAILED,
|
|
3014
|
+
context: {
|
|
3015
|
+
operation: CoreResourceOperation.CREATE_MANY,
|
|
3016
|
+
reason: 'Bulk create expects either an array payload or an object with a data array',
|
|
3017
|
+
}
|
|
3018
|
+
});
|
|
3019
|
+
}
|
|
3020
|
+
getResolvedPersistenceAdapter() {
|
|
3021
|
+
return this.resourceConfiguration.persistenceAdapter
|
|
3022
|
+
?? this.appConfigService.config.database.defaultAdapter
|
|
3023
|
+
?? DEFAULT_PERSISTENCE_ADAPTER;
|
|
3024
|
+
}
|
|
3025
|
+
getResolvedPersistenceAdapterForResource(resourceType) {
|
|
3026
|
+
const resourceConfiguration = this.resourcesRegistry.getResourceConfiguration(resourceType);
|
|
3027
|
+
return resourceConfiguration.persistenceAdapter
|
|
3028
|
+
?? this.appConfigService.config.database.defaultAdapter
|
|
3029
|
+
?? DEFAULT_PERSISTENCE_ADAPTER;
|
|
3030
|
+
}
|
|
3031
|
+
/**
|
|
3032
|
+
* The FILES resource is currently the Mongo-backed coordination seam for file
|
|
3033
|
+
* metadata. PostgreSQL-backed resources can coordinate with it, but they cannot
|
|
3034
|
+
* silently inherit the parent SQL transaction.
|
|
3035
|
+
*/
|
|
3036
|
+
assertMongoBackedFilesResource(executionContext, message) {
|
|
3037
|
+
const filesPersistenceAdapter = this.getResolvedPersistenceAdapterForResource(CoreResourceType.FILES);
|
|
3038
|
+
if (filesPersistenceAdapter !== 'mongodb') {
|
|
3039
|
+
throw this.errorBuilder.buildError(ErrorType.CONFIGURATION, executionContext, {
|
|
3040
|
+
customMessageReference: ErrorCustomMessageReference.CONFIGURATION,
|
|
3041
|
+
context: {
|
|
3042
|
+
message,
|
|
3043
|
+
resourceType: this.resourceConfiguration.resourceIdentifier,
|
|
3044
|
+
filesPersistenceAdapter,
|
|
3045
|
+
},
|
|
3046
|
+
});
|
|
3047
|
+
}
|
|
3048
|
+
if (!this.mongoDBService) {
|
|
3049
|
+
throw this.errorBuilder.buildError(ErrorType.CONFIGURATION, executionContext, {
|
|
3050
|
+
customMessageReference: ErrorCustomMessageReference.CONFIGURATION,
|
|
3051
|
+
context: {
|
|
3052
|
+
message: `${message} (MongoDBService is not available)`,
|
|
3053
|
+
resourceType: this.resourceConfiguration.resourceIdentifier,
|
|
3054
|
+
filesPersistenceAdapter,
|
|
3055
|
+
},
|
|
3056
|
+
});
|
|
3057
|
+
}
|
|
3058
|
+
}
|
|
3059
|
+
getResourceDatabaseService(executionContext) {
|
|
3060
|
+
const persistenceAdapter = this.getResolvedPersistenceAdapter();
|
|
3061
|
+
if (persistenceAdapter === 'postgresql') {
|
|
3062
|
+
if (!this.postgreSQLDatabaseService) {
|
|
3063
|
+
throw this.errorBuilder.buildError(ErrorType.CONFIGURATION, executionContext, {
|
|
3064
|
+
customMessageReference: ErrorCustomMessageReference.CONFIGURATION,
|
|
3065
|
+
context: {
|
|
3066
|
+
message: 'PostgreSQLDatabaseService is required for PostgreSQL-backed resource transactions',
|
|
3067
|
+
resourceType: this.resourceConfiguration.resourceIdentifier,
|
|
3068
|
+
persistenceAdapter,
|
|
3069
|
+
},
|
|
3070
|
+
});
|
|
3071
|
+
}
|
|
3072
|
+
return this.postgreSQLDatabaseService;
|
|
3073
|
+
}
|
|
3074
|
+
if (!this.mongoDBService) {
|
|
3075
|
+
throw this.errorBuilder.buildError(ErrorType.CONFIGURATION, executionContext, {
|
|
3076
|
+
customMessageReference: ErrorCustomMessageReference.CONFIGURATION,
|
|
3077
|
+
context: {
|
|
3078
|
+
message: 'MongoDBService is required for MongoDB-backed resource transactions',
|
|
3079
|
+
resourceType: this.resourceConfiguration.resourceIdentifier,
|
|
3080
|
+
persistenceAdapter,
|
|
3081
|
+
},
|
|
3082
|
+
});
|
|
3083
|
+
}
|
|
3084
|
+
return this.mongoDBService;
|
|
3085
|
+
}
|
|
3086
|
+
buildFileRepositoryOptions(options) {
|
|
3087
|
+
if (!options?.transaction || options.transaction.databaseType === 'mongodb') {
|
|
3088
|
+
return options;
|
|
3089
|
+
}
|
|
3090
|
+
const { transaction: _ignoredTransaction, ...fileOptions } = options;
|
|
3091
|
+
return fileOptions;
|
|
3092
|
+
}
|
|
3093
|
+
buildRepositoryOptionsForResource(resourceType, executionContext, options) {
|
|
3094
|
+
if (!options?.transaction) {
|
|
3095
|
+
return options;
|
|
3096
|
+
}
|
|
3097
|
+
const expectedDatabaseType = this.getResolvedPersistenceAdapterForResource(resourceType);
|
|
3098
|
+
if (options.transaction.databaseType === expectedDatabaseType) {
|
|
3099
|
+
return options;
|
|
3100
|
+
}
|
|
3101
|
+
throw this.errorBuilder.buildError(ErrorType.CONFIGURATION, executionContext, {
|
|
3102
|
+
customMessageReference: ErrorCustomMessageReference.CONFIGURATION,
|
|
3103
|
+
context: {
|
|
3104
|
+
message: 'Lifecycle deletes across mixed persistence adapters are not supported within a shared resource transaction',
|
|
3105
|
+
parentResourceType: this.resourceConfiguration.resourceIdentifier,
|
|
3106
|
+
childResourceType: resourceType,
|
|
3107
|
+
parentPersistenceAdapter: options.transaction.databaseType,
|
|
3108
|
+
childPersistenceAdapter: expectedDatabaseType,
|
|
3109
|
+
},
|
|
3110
|
+
});
|
|
3111
|
+
}
|
|
3112
|
+
async executeResourceTransaction(executionContext, callback, options) {
|
|
3113
|
+
const databaseService = this.getResourceDatabaseService(executionContext);
|
|
3114
|
+
return databaseService.executeTransaction(async (transactionContext) => callback({
|
|
3115
|
+
...options,
|
|
3116
|
+
transaction: transactionContext,
|
|
3117
|
+
}), {
|
|
3118
|
+
nestedBehavior: 'reuse',
|
|
3119
|
+
});
|
|
3120
|
+
}
|
|
3121
|
+
/**
|
|
3122
|
+
* Route file metadata work through the FILES resource adapter instead of
|
|
3123
|
+
* leaking the current resource transaction into a different repository backend.
|
|
3124
|
+
*/
|
|
3125
|
+
async executeFileMetadataWork(executionContext, options, callback) {
|
|
3126
|
+
this.assertMongoBackedFilesResource(executionContext, 'File metadata operations currently require MongoDB-backed FILES resources');
|
|
3127
|
+
const fileOptions = this.buildFileRepositoryOptions(options);
|
|
3128
|
+
if (fileOptions?.transaction?.databaseType === 'mongodb') {
|
|
3129
|
+
return callback(fileOptions);
|
|
3130
|
+
}
|
|
3131
|
+
return this.mongoDBService.executeTransaction(async (transactionContext) => callback({
|
|
3132
|
+
...fileOptions,
|
|
3133
|
+
transaction: transactionContext,
|
|
3134
|
+
}), {
|
|
3135
|
+
nestedBehavior: 'reuse',
|
|
3136
|
+
});
|
|
3137
|
+
}
|
|
3138
|
+
assertNestedMutationAdaptersMatchCurrentResource(relationships, executionContext) {
|
|
3139
|
+
const currentPersistenceAdapter = this.getResolvedPersistenceAdapter();
|
|
3140
|
+
const incompatibleNestedResourceTypes = relationships
|
|
3141
|
+
.map((relationship) => relationship.resourceType2)
|
|
3142
|
+
.filter((childResourceType) => {
|
|
3143
|
+
return this.getResolvedPersistenceAdapterForResource(childResourceType) !== currentPersistenceAdapter;
|
|
3144
|
+
});
|
|
3145
|
+
if (incompatibleNestedResourceTypes.length === 0) {
|
|
3146
|
+
return;
|
|
3147
|
+
}
|
|
3148
|
+
throw this.errorBuilder.buildError(ErrorType.CONFIGURATION, executionContext, {
|
|
3149
|
+
customMessageReference: ErrorCustomMessageReference.CONFIGURATION,
|
|
3150
|
+
context: {
|
|
3151
|
+
message: 'Nested mutations across mixed persistence adapters are not supported within a shared resource transaction',
|
|
3152
|
+
resourceType: this.resourceConfiguration.resourceIdentifier,
|
|
3153
|
+
persistenceAdapter: currentPersistenceAdapter,
|
|
3154
|
+
incompatibleNestedResourceTypes,
|
|
3155
|
+
},
|
|
3156
|
+
});
|
|
3157
|
+
}
|
|
3158
|
+
assertMongoBulkTransactionSupport(executionContext, message) {
|
|
3159
|
+
const persistenceAdapter = this.getResolvedPersistenceAdapter();
|
|
3160
|
+
if (persistenceAdapter !== 'mongodb') {
|
|
3161
|
+
throw this.errorBuilder.buildError(ErrorType.CONFIGURATION, executionContext, {
|
|
3162
|
+
customMessageReference: ErrorCustomMessageReference.CONFIGURATION,
|
|
3163
|
+
context: {
|
|
3164
|
+
message,
|
|
3165
|
+
resourceType: this.resourceConfiguration.resourceIdentifier,
|
|
3166
|
+
persistenceAdapter,
|
|
3167
|
+
},
|
|
3168
|
+
});
|
|
3169
|
+
}
|
|
3170
|
+
if (!this.mongoDBService) {
|
|
3171
|
+
throw this.errorBuilder.buildError(ErrorType.CONFIGURATION, executionContext, {
|
|
3172
|
+
customMessageReference: ErrorCustomMessageReference.CONFIGURATION,
|
|
3173
|
+
context: {
|
|
3174
|
+
message: `${message} (MongoDBService is not available)`,
|
|
3175
|
+
resourceType: this.resourceConfiguration.resourceIdentifier,
|
|
3176
|
+
persistenceAdapter,
|
|
3177
|
+
},
|
|
3178
|
+
});
|
|
3179
|
+
}
|
|
3180
|
+
}
|
|
3181
|
+
getResourceIdValue(resource) {
|
|
3182
|
+
if (!resource)
|
|
3183
|
+
return null;
|
|
3184
|
+
const rawId = resource._id ?? resource.id;
|
|
3185
|
+
if (typeof rawId === 'string' && rawId.length > 0) {
|
|
3186
|
+
return rawId;
|
|
3187
|
+
}
|
|
3188
|
+
if (rawId && typeof rawId.toString === 'function') {
|
|
3189
|
+
const stringified = rawId.toString();
|
|
3190
|
+
return stringified.length > 0 ? stringified : null;
|
|
3191
|
+
}
|
|
3192
|
+
return null;
|
|
3193
|
+
}
|
|
3194
|
+
hasExplicitFileFieldMutations(resourceType, data) {
|
|
3195
|
+
const fileFields = this.fileFieldDetection.detectFileFields(resourceType);
|
|
3196
|
+
return fileFields.some(({ fieldName }) => hasExplicitCanonicalFieldMutation(data, fieldName));
|
|
3197
|
+
}
|
|
3198
|
+
async processBulkCreateFileFields(parentResults, parentDataArray, resourceType, executionContext, options) {
|
|
3199
|
+
if (!Array.isArray(parentResults) || parentResults.length !== parentDataArray.length) {
|
|
3200
|
+
throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, {
|
|
3201
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED,
|
|
3202
|
+
context: {
|
|
3203
|
+
operation: CoreResourceOperation.CREATE_MANY,
|
|
3204
|
+
reason: 'Bulk create file processing requires one parent result per input payload',
|
|
3205
|
+
parentResultsCount: Array.isArray(parentResults) ? parentResults.length : 'not-array',
|
|
3206
|
+
payloadCount: parentDataArray.length,
|
|
3207
|
+
},
|
|
3208
|
+
});
|
|
3209
|
+
}
|
|
3210
|
+
for (let index = 0; index < parentResults.length; index += 1) {
|
|
3211
|
+
const parentResult = parentResults[index];
|
|
3212
|
+
const resourceId = this.getResourceIdValue(parentResult);
|
|
3213
|
+
if (!resourceId) {
|
|
3214
|
+
throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, {
|
|
3215
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED,
|
|
3216
|
+
context: {
|
|
3217
|
+
operation: CoreResourceOperation.CREATE_MANY,
|
|
3218
|
+
reason: 'Bulk create file processing requires each created parent to expose an id',
|
|
3219
|
+
index,
|
|
3220
|
+
},
|
|
3221
|
+
});
|
|
3222
|
+
}
|
|
3223
|
+
await this.fileOperationHandler.processFileFieldsForCreate(parentDataArray[index], resourceType, resourceId, executionContext, options);
|
|
3224
|
+
}
|
|
3225
|
+
}
|
|
3226
|
+
async loadBulkParentStateMap(executionContext, id_or_ids_or_filter, options) {
|
|
3227
|
+
const currentStates = await this.loadBulkTargetResources(executionContext, id_or_ids_or_filter, options);
|
|
3228
|
+
return new Map((Array.isArray(currentStates) ? currentStates : [])
|
|
3229
|
+
.map((item) => [this.getResourceIdValue(item), item])
|
|
3230
|
+
.filter((entry) => !!entry[0]));
|
|
3231
|
+
}
|
|
3232
|
+
async loadBulkTargetResources(executionContext, id_or_ids_or_filter, options) {
|
|
3233
|
+
if (!id_or_ids_or_filter) {
|
|
3234
|
+
return [];
|
|
3235
|
+
}
|
|
3236
|
+
const resourceType = this.resourceConfiguration.resourceIdentifier;
|
|
3237
|
+
const repository = this.repositoriesRegistry.getRepositoryOrThrow(resourceType);
|
|
3238
|
+
if (typeof id_or_ids_or_filter === 'string') {
|
|
3239
|
+
const currentState = await repository.read(executionContext, id_or_ids_or_filter, options);
|
|
3240
|
+
return currentState ? [currentState] : [];
|
|
3241
|
+
}
|
|
3242
|
+
const snapshotCandidates = await repository.list(executionContext, id_or_ids_or_filter, options);
|
|
3243
|
+
const snapshotIds = (Array.isArray(snapshotCandidates) ? snapshotCandidates : [])
|
|
3244
|
+
.map((item) => this.getResourceIdValue(item))
|
|
3245
|
+
.filter((id) => !!id);
|
|
3246
|
+
const currentStates = await Promise.all(snapshotIds.map((id) => repository.read(executionContext, id, options)));
|
|
3247
|
+
return (Array.isArray(currentStates) ? currentStates : []).filter(Boolean);
|
|
3248
|
+
}
|
|
3249
|
+
async processBulkUpdateFileFields(parentResults, currentStatesById, parentPatch, resourceType, executionContext, options) {
|
|
3250
|
+
if (!Array.isArray(parentResults)) {
|
|
3251
|
+
throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, {
|
|
3252
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED,
|
|
3253
|
+
context: {
|
|
3254
|
+
operation: CoreResourceOperation.UPDATE_MANY,
|
|
3255
|
+
reason: 'Bulk update file processing requires an array of parent results',
|
|
3256
|
+
},
|
|
3257
|
+
});
|
|
3258
|
+
}
|
|
3259
|
+
for (const parentResult of parentResults) {
|
|
3260
|
+
const resourceId = this.getResourceIdValue(parentResult);
|
|
3261
|
+
if (!resourceId) {
|
|
3262
|
+
throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, {
|
|
3263
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED,
|
|
3264
|
+
context: {
|
|
3265
|
+
operation: CoreResourceOperation.UPDATE_MANY,
|
|
3266
|
+
reason: 'Bulk update file processing requires each updated parent to expose an id',
|
|
3267
|
+
},
|
|
3268
|
+
});
|
|
3269
|
+
}
|
|
3270
|
+
const currentState = currentStatesById.get(resourceId);
|
|
3271
|
+
if (!currentState) {
|
|
3272
|
+
throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, {
|
|
3273
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED,
|
|
3274
|
+
context: {
|
|
3275
|
+
operation: CoreResourceOperation.UPDATE_MANY,
|
|
3276
|
+
reason: 'Bulk update file processing requires a pre-update snapshot for every updated parent',
|
|
3277
|
+
resourceId,
|
|
3278
|
+
},
|
|
3279
|
+
});
|
|
3280
|
+
}
|
|
3281
|
+
await this.fileOperationHandler.processFileFieldsForUpdate(parentPatch, currentState, resourceType, resourceId, executionContext, options);
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
/**
|
|
3285
|
+
* Extract nested data for UPDATE operations, including delete arrays.
|
|
3286
|
+
* Returns { parentData, nestedData, deleteData }.
|
|
3287
|
+
*/
|
|
3288
|
+
extractNestedDataForUpdate(data, relationships) {
|
|
3289
|
+
const parentData = { ...data };
|
|
3290
|
+
const nestedData = {};
|
|
3291
|
+
const deleteData = {};
|
|
3292
|
+
for (const rel of relationships) {
|
|
3293
|
+
const nestedConfig = this.getResolvedNestedMutationConfig(rel, CoreResourceOperation.UPDATE);
|
|
3294
|
+
if (!nestedConfig)
|
|
3295
|
+
continue;
|
|
3296
|
+
const fieldName = this.getNestedFieldName(rel);
|
|
3297
|
+
const deleteFieldName = `_${fieldName}ToDelete`;
|
|
3298
|
+
if (fieldName in parentData) {
|
|
3299
|
+
nestedData[fieldName] = parentData[fieldName];
|
|
3300
|
+
delete parentData[fieldName];
|
|
3301
|
+
}
|
|
3302
|
+
if (nestedConfig.allowDelete && deleteFieldName in parentData) {
|
|
3303
|
+
deleteData[fieldName] = parentData[deleteFieldName] || [];
|
|
3304
|
+
delete parentData[deleteFieldName];
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
return { parentData, nestedData, deleteData };
|
|
3308
|
+
}
|
|
3309
|
+
/**
|
|
3310
|
+
* Filter child relationships by evaluating discriminator/condition against the parent resource.
|
|
3311
|
+
*
|
|
3312
|
+
* This is the central runtime gate for conditional relationships in the services layer.
|
|
3313
|
+
* It ensures that nested CRUD operations and lifecycle cascades only apply to child
|
|
3314
|
+
* relationships whose conditions match the current parent resource's data.
|
|
3315
|
+
*
|
|
3316
|
+
* ## Evaluation Logic
|
|
3317
|
+
*
|
|
3318
|
+
* For each relationship:
|
|
3319
|
+
* 1. If `discriminator` is present: check `String(parentResource[discriminatorField])`
|
|
3320
|
+
* against `values`. If no match → exclude.
|
|
3321
|
+
* 2. If `condition` is present: call `condition(parentResource)`.
|
|
3322
|
+
* If it returns false → exclude.
|
|
3323
|
+
* 3. Relationships without discriminator or condition always pass through.
|
|
3324
|
+
*
|
|
3325
|
+
* When both discriminator and condition are present, AND semantics apply —
|
|
3326
|
+
* discriminator is checked first, then condition.
|
|
3327
|
+
*
|
|
3328
|
+
* ## Application Points
|
|
3329
|
+
*
|
|
3330
|
+
* This method is called at 4 critical points in the CRUD lifecycle:
|
|
3331
|
+
*
|
|
3332
|
+
* 1. **Nested CREATE** (inside transaction): After creating the parent, filters
|
|
3333
|
+
* child relationships using `parentResult` before processing nested creates.
|
|
3334
|
+
* This prevents creating children for relationships that don't apply to this parent.
|
|
3335
|
+
*
|
|
3336
|
+
* 2. **Nested READ**: After reading the parent, filters child relationships using
|
|
3337
|
+
* the read `result` before fetching nested children for the response.
|
|
3338
|
+
*
|
|
3339
|
+
* 3. **Nested UPDATE** (inside transaction): After updating the parent, filters
|
|
3340
|
+
* child relationships using `parentResult` before processing nested updates.
|
|
3341
|
+
*
|
|
3342
|
+
* 4. **Lifecycle DELETE**: Filters lifecycle relationships using pre-delete parent
|
|
3343
|
+
* snapshots to determine which children should cascade-delete.
|
|
3344
|
+
* - `DELETE`: uses the single `currentState`
|
|
3345
|
+
* - `DELETE_MANY`: uses the pre-delete snapshot set loaded for the matched parents,
|
|
3346
|
+
* so discriminator/condition gating still fails closed per deleted parent
|
|
3347
|
+
*
|
|
3348
|
+
* ## String Coercion
|
|
3349
|
+
*
|
|
3350
|
+
* Uses the shared relationship-activation utility in `saas-models`, preserving
|
|
3351
|
+
* the same `String()` coercion semantics used across backend and frontend
|
|
3352
|
+
* runtime evaluation.
|
|
3353
|
+
*
|
|
3354
|
+
* @param relationships - Child relationships to filter
|
|
3355
|
+
* @param parentResource - The parent resource's data to evaluate conditions against
|
|
3356
|
+
* @returns Relationships whose discriminator/condition match the parent (or have no conditions)
|
|
3357
|
+
*/
|
|
3358
|
+
filterRelationshipsByParent(relationships, parentResource) {
|
|
3359
|
+
return Resources_SharedUtils.filterRelationshipsActiveForParent(relationships, parentResource, {
|
|
3360
|
+
onConditionError: 'throw',
|
|
3361
|
+
});
|
|
3362
|
+
}
|
|
3363
|
+
/**
|
|
3364
|
+
* Process nested operations for CREATE/UPDATE.
|
|
3365
|
+
* Handles creating/updating/deleting children and attaching them to parent result.
|
|
3366
|
+
*/
|
|
3367
|
+
async processNestedOperations(operation, parentResult, nestedData, deleteData, relationships, executionContext, options) {
|
|
3368
|
+
const parentId = parentResult._id || parentResult.id;
|
|
3369
|
+
if (!parentId) {
|
|
3370
|
+
this.logDebug('No parent ID found, skipping nested operations');
|
|
3371
|
+
return;
|
|
3372
|
+
}
|
|
3373
|
+
const relationshipsByFieldName = new Map(relationships.map(rel => [this.getNestedFieldName(rel), rel]));
|
|
3374
|
+
// Process deletions first (for UPDATE only)
|
|
3375
|
+
if (operation === CoreResourceOperation.UPDATE || operation === CoreResourceOperation.UPDATE_MANY) {
|
|
3376
|
+
for (const [fieldName, idsToDelete] of Object.entries(deleteData)) {
|
|
3377
|
+
if (!idsToDelete || idsToDelete.length === 0)
|
|
3378
|
+
continue;
|
|
3379
|
+
const rel = relationshipsByFieldName.get(fieldName);
|
|
3380
|
+
if (!rel) {
|
|
3381
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
3382
|
+
customMessageReference: ErrorCustomMessageReference.VALIDATION,
|
|
3383
|
+
context: {
|
|
3384
|
+
parentResourceType: this.resourceConfiguration.resourceIdentifier,
|
|
3385
|
+
fieldName,
|
|
3386
|
+
operation,
|
|
3387
|
+
reason: 'nested delete field is not active for the current parent state or does not map to an allowed relationship',
|
|
3388
|
+
},
|
|
3389
|
+
});
|
|
3390
|
+
}
|
|
3391
|
+
const nestedConfig = this.getResolvedNestedMutationConfig(rel, CoreResourceOperation.UPDATE);
|
|
3392
|
+
if (!nestedConfig?.allowDelete) {
|
|
3393
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
3394
|
+
customMessageReference: ErrorCustomMessageReference.VALIDATION,
|
|
3395
|
+
context: {
|
|
3396
|
+
parentResourceType: this.resourceConfiguration.resourceIdentifier,
|
|
3397
|
+
childResourceType: rel.resourceType2,
|
|
3398
|
+
fieldName,
|
|
3399
|
+
operation,
|
|
3400
|
+
reason: 'nested deletes are not enabled for this relationship',
|
|
3401
|
+
},
|
|
3402
|
+
});
|
|
3403
|
+
}
|
|
3404
|
+
this.logDebug('Deleting nested children', { fieldName, count: idsToDelete.length });
|
|
3405
|
+
for (const childId of idsToDelete) {
|
|
3406
|
+
// Build relationship context for child DELETE
|
|
3407
|
+
const relationshipContext = {
|
|
3408
|
+
resourceType: this.resourceConfiguration.resourceIdentifier,
|
|
3409
|
+
relationshipField: this.getFKFieldForRelationship(rel),
|
|
3410
|
+
resourceId: parentId
|
|
3411
|
+
};
|
|
3412
|
+
// Create sub-call context with correct operation
|
|
3413
|
+
const subContext = await this.executionContextCreator.createForSubCall(executionContext, rel.resourceType2, CoreResourceOperation.DELETE, undefined, childId, relationshipContext);
|
|
3414
|
+
// Authorization: DELETE operation on child resource is checked via enabledCondition
|
|
3415
|
+
// in doByExecutionContext when servicesRegistry.delete is called
|
|
3416
|
+
await this.servicesRegistry.delete(rel.resourceType2, subContext, childId, options);
|
|
3417
|
+
}
|
|
3418
|
+
}
|
|
3419
|
+
}
|
|
3420
|
+
// Process creates and updates
|
|
3421
|
+
for (const [fieldName, items] of Object.entries(nestedData)) {
|
|
3422
|
+
if (!items)
|
|
3423
|
+
continue;
|
|
3424
|
+
const rel = relationshipsByFieldName.get(fieldName);
|
|
3425
|
+
if (!rel) {
|
|
3426
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
3427
|
+
customMessageReference: ErrorCustomMessageReference.VALIDATION,
|
|
3428
|
+
context: {
|
|
3429
|
+
parentResourceType: this.resourceConfiguration.resourceIdentifier,
|
|
3430
|
+
fieldName,
|
|
3431
|
+
operation,
|
|
3432
|
+
reason: 'nested field is not active for the current parent state or does not map to an allowed relationship',
|
|
3433
|
+
},
|
|
3434
|
+
});
|
|
3435
|
+
}
|
|
3436
|
+
const nestedConfig = this.getResolvedNestedMutationConfig(rel, operation);
|
|
3437
|
+
if (!nestedConfig) {
|
|
3438
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
3439
|
+
customMessageReference: ErrorCustomMessageReference.VALIDATION,
|
|
3440
|
+
context: {
|
|
3441
|
+
parentResourceType: this.resourceConfiguration.resourceIdentifier,
|
|
3442
|
+
childResourceType: rel.resourceType2,
|
|
3443
|
+
fieldName,
|
|
3444
|
+
operation,
|
|
3445
|
+
reason: 'nested operations are not enabled for this relationship',
|
|
3446
|
+
},
|
|
3447
|
+
});
|
|
3448
|
+
}
|
|
3449
|
+
const fkField = this.getFKFieldForRelationship(rel);
|
|
3450
|
+
const processedChildren = [];
|
|
3451
|
+
const itemsArray = Array.isArray(items) ? items : [items];
|
|
3452
|
+
const isCreateOperation = operation === CoreResourceOperation.CREATE || operation === CoreResourceOperation.CREATE_MANY;
|
|
3453
|
+
const isUpdateOperation = operation === CoreResourceOperation.UPDATE || operation === CoreResourceOperation.UPDATE_MANY;
|
|
3454
|
+
for (const item of itemsArray) {
|
|
3455
|
+
const hasId = !!(item._id || item.id);
|
|
3456
|
+
if (hasId && nestedConfig.allowUpdate && isUpdateOperation) {
|
|
3457
|
+
// Update existing child
|
|
3458
|
+
const childId = item._id || item.id;
|
|
3459
|
+
const childData = { ...item, [fkField]: parentId };
|
|
3460
|
+
delete childData._id; // Remove _id from update data
|
|
3461
|
+
// Build relationship context for child UPDATE
|
|
3462
|
+
const relationshipContext = {
|
|
3463
|
+
resourceType: this.resourceConfiguration.resourceIdentifier,
|
|
3464
|
+
relationshipField: fkField,
|
|
3465
|
+
resourceId: parentId
|
|
3466
|
+
};
|
|
3467
|
+
// Create sub-call context with correct operation
|
|
3468
|
+
const subContext = await this.executionContextCreator.createForSubCall(executionContext, rel.resourceType2, CoreResourceOperation.UPDATE, undefined, childId, relationshipContext);
|
|
3469
|
+
// Authorization: UPDATE operation on child resource is checked via enabledCondition
|
|
3470
|
+
// in doByExecutionContext when servicesRegistry.update is called
|
|
3471
|
+
const updatedChild = await this.servicesRegistry.update(rel.resourceType2, subContext, childId, childData, options);
|
|
3472
|
+
if (updatedChild) {
|
|
3473
|
+
processedChildren.push(updatedChild);
|
|
3474
|
+
}
|
|
3475
|
+
}
|
|
3476
|
+
else if (!hasId && nestedConfig.allowCreate) {
|
|
3477
|
+
// Create new child
|
|
3478
|
+
const childData = { ...item, [fkField]: parentId };
|
|
3479
|
+
// Build relationship context for child CREATE
|
|
3480
|
+
const relationshipContext = {
|
|
3481
|
+
resourceType: this.resourceConfiguration.resourceIdentifier,
|
|
3482
|
+
relationshipField: fkField,
|
|
3483
|
+
resourceId: parentId
|
|
3484
|
+
};
|
|
3485
|
+
// Create sub-call context with correct operation (no resourceId for CREATE)
|
|
3486
|
+
const subContext = await this.executionContextCreator.createForSubCall(executionContext, rel.resourceType2, CoreResourceOperation.CREATE, undefined, undefined, // No resourceId for CREATE - it doesn't exist yet
|
|
3487
|
+
relationshipContext);
|
|
3488
|
+
// Authorization: CREATE operation on child resource is checked via enabledCondition
|
|
3489
|
+
// in doByExecutionContext when servicesRegistry.create is called
|
|
3490
|
+
const createdChild = await this.servicesRegistry.create(rel.resourceType2, subContext, childData, options);
|
|
3491
|
+
if (createdChild) {
|
|
3492
|
+
processedChildren.push(createdChild);
|
|
3493
|
+
}
|
|
3494
|
+
}
|
|
3495
|
+
else {
|
|
3496
|
+
const action = hasId ? 'update_existing' : 'create_new';
|
|
3497
|
+
const reason = hasId
|
|
3498
|
+
? (isCreateOperation
|
|
3499
|
+
? 'nested create payloads cannot reference existing child ids'
|
|
3500
|
+
: 'nested updates are not enabled for this relationship')
|
|
3501
|
+
: 'nested creates are not enabled for this relationship';
|
|
3502
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, executionContext, {
|
|
3503
|
+
customMessageReference: ErrorCustomMessageReference.VALIDATION,
|
|
3504
|
+
context: {
|
|
3505
|
+
parentResourceType: this.resourceConfiguration.resourceIdentifier,
|
|
3506
|
+
childResourceType: rel.resourceType2,
|
|
3507
|
+
fieldName,
|
|
3508
|
+
action,
|
|
3509
|
+
reason,
|
|
3510
|
+
operation,
|
|
3511
|
+
},
|
|
3512
|
+
});
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
// Attach children to parent result — 1:1 gets single/null, 1:N gets array
|
|
3516
|
+
if (isOneToOneCardinality(rel.cardinality2)) {
|
|
3517
|
+
parentResult[fieldName] = processedChildren[0] || null;
|
|
3518
|
+
}
|
|
3519
|
+
else {
|
|
3520
|
+
parentResult[fieldName] = processedChildren;
|
|
3521
|
+
}
|
|
3522
|
+
}
|
|
3523
|
+
}
|
|
3524
|
+
/**
|
|
3525
|
+
* Bulk variant of processNestedOperations().
|
|
3526
|
+
* Reuses the single-parent orchestration path for each returned parent result,
|
|
3527
|
+
* preserving sub-call execution contexts and relationship activation checks.
|
|
3528
|
+
*
|
|
3529
|
+
* Contract:
|
|
3530
|
+
* - CREATE_MANY expects per-row nested payloads and receives one nested envelope
|
|
3531
|
+
* per created parent result.
|
|
3532
|
+
* - UPDATE_MANY currently uses broadcast semantics for nested create/update payloads:
|
|
3533
|
+
* the same validated nested envelope is replayed for every matched parent result.
|
|
3534
|
+
* - UPDATE_MANY nested deletes are intentionally more restrictive and are rejected
|
|
3535
|
+
* earlier when a shared delete payload would target multiple parents ambiguously.
|
|
3536
|
+
*/
|
|
3537
|
+
async processBulkNestedOperations(operation, parentResults, nestedDataArray, deleteDataArray, relationships, executionContext, options) {
|
|
3538
|
+
if (!Array.isArray(parentResults) || parentResults.length === 0) {
|
|
3539
|
+
return;
|
|
3540
|
+
}
|
|
3541
|
+
if (parentResults.length !== nestedDataArray.length) {
|
|
3542
|
+
throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, {
|
|
3543
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED,
|
|
3544
|
+
context: {
|
|
3545
|
+
operation,
|
|
3546
|
+
parentResultsCount: parentResults.length,
|
|
3547
|
+
nestedPayloadCount: nestedDataArray.length,
|
|
3548
|
+
reason: 'bulk nested orchestration requires one nested payload envelope per parent result',
|
|
3549
|
+
},
|
|
3550
|
+
});
|
|
3551
|
+
}
|
|
3552
|
+
for (let index = 0; index < parentResults.length; index += 1) {
|
|
3553
|
+
const parentResult = parentResults[index];
|
|
3554
|
+
const nestedData = nestedDataArray[index] ?? {};
|
|
3555
|
+
const deleteData = deleteDataArray[index] ?? {};
|
|
3556
|
+
if (!parentResult || (!Object.keys(nestedData).length && !Object.keys(deleteData).length)) {
|
|
3557
|
+
continue;
|
|
3558
|
+
}
|
|
3559
|
+
const activeRelationships = this.filterRelationshipsByParent(relationships, parentResult);
|
|
3560
|
+
if (activeRelationships.length === 0) {
|
|
3561
|
+
continue;
|
|
3562
|
+
}
|
|
3563
|
+
await this.processNestedOperations(operation, parentResult, nestedData, deleteData, activeRelationships, executionContext, options);
|
|
3564
|
+
}
|
|
3565
|
+
}
|
|
3566
|
+
/**
|
|
3567
|
+
* Process nested read operations - include children in READ response.
|
|
3568
|
+
*/
|
|
3569
|
+
async processNestedRead(parentResult, relationships, executionContext, options) {
|
|
3570
|
+
if (!parentResult)
|
|
3571
|
+
return;
|
|
3572
|
+
const parentId = parentResult._id || parentResult.id;
|
|
3573
|
+
if (!parentId)
|
|
3574
|
+
return;
|
|
3575
|
+
for (const rel of relationships) {
|
|
3576
|
+
const readConfig = this.getResolvedNestedReadConfig(rel);
|
|
3577
|
+
if (!readConfig)
|
|
3578
|
+
continue;
|
|
3579
|
+
const fieldName = this.getNestedFieldName(rel);
|
|
3580
|
+
const fkField = this.getFKFieldForRelationship(rel);
|
|
3581
|
+
// Build filter to find children
|
|
3582
|
+
const filter = { [fkField]: parentId };
|
|
3583
|
+
// Apply maxItems limit if specified
|
|
3584
|
+
const limit = readConfig.maxItems;
|
|
3585
|
+
// Build relationship context for child nested fetch
|
|
3586
|
+
const relationshipContext = {
|
|
3587
|
+
resourceType: this.resourceConfiguration.resourceIdentifier,
|
|
3588
|
+
relationshipField: fkField,
|
|
3589
|
+
resourceId: parentId
|
|
3590
|
+
};
|
|
3591
|
+
const childrenOptions = { ...options };
|
|
3592
|
+
childrenOptions.dataMode = readConfig.dataMode;
|
|
3593
|
+
// Attach to parent result — 1:1 gets single/null, 1:N gets array
|
|
3594
|
+
if (isOneToOneCardinality(rel.cardinality2)) {
|
|
3595
|
+
const subContext = await this.executionContextCreator.createForSubCall(executionContext, rel.resourceType2, CoreResourceOperation.READ, { dataMode: readConfig.dataMode }, undefined, relationshipContext);
|
|
3596
|
+
const child = await this.servicesRegistry.read(rel.resourceType2, subContext, filter, childrenOptions);
|
|
3597
|
+
parentResult[fieldName] = child ?? null;
|
|
3598
|
+
}
|
|
3599
|
+
else {
|
|
3600
|
+
const subContext = await this.executionContextCreator.createForSubCall(executionContext, rel.resourceType2, CoreResourceOperation.LIST, { dataMode: readConfig.dataMode }, undefined, relationshipContext);
|
|
3601
|
+
const children = await this.servicesRegistry.list(rel.resourceType2, subContext, filter, limit ? { limit } : undefined, childrenOptions);
|
|
3602
|
+
parentResult[fieldName] = Array.isArray(children) ? children : [];
|
|
3603
|
+
}
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3606
|
+
/**
|
|
3607
|
+
* Execute lifecycle operations for child resources based on relationship configuration.
|
|
3608
|
+
* Handles onParentDelete cascade for all child relationships with lifecycle.onParentDelete.enabled = true.
|
|
3609
|
+
*/
|
|
3610
|
+
async executeLifecycleOperations(operation, result, executionContext, currentState, options) {
|
|
3611
|
+
// Only handle DELETE operations for lifecycle
|
|
3612
|
+
if (operation !== CoreResourceOperation.DELETE && operation !== CoreResourceOperation.DELETE_MANY) {
|
|
3613
|
+
return;
|
|
3614
|
+
}
|
|
3615
|
+
const resourceRelationships = this.resourceConfiguration.resourceRelationships;
|
|
3616
|
+
const childRelationships = getChildDirectionRelationships(resourceRelationships);
|
|
3617
|
+
// Find relationships with lifecycle.onParentDelete.enabled = true
|
|
3618
|
+
let lifecycleRelationships = childRelationships.filter(rel => this.getResolvedLifecycleOnParentDelete(rel)?.enabled === true);
|
|
3619
|
+
if (lifecycleRelationships.length === 0) {
|
|
3620
|
+
return;
|
|
3621
|
+
}
|
|
3622
|
+
// Application point #4: Lifecycle DELETE — filter lifecycle relationships using
|
|
3623
|
+
// the available pre-delete parent snapshots so cascades only apply where the
|
|
3624
|
+
// relationship is active for the concrete parent variant being deleted.
|
|
3625
|
+
if (operation === CoreResourceOperation.DELETE && currentState) {
|
|
3626
|
+
lifecycleRelationships = this.filterRelationshipsByParent(lifecycleRelationships, currentState);
|
|
3627
|
+
if (lifecycleRelationships.length === 0) {
|
|
3628
|
+
return;
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3631
|
+
this.logDebug('Executing lifecycle operations for delete', {
|
|
3632
|
+
operation,
|
|
3633
|
+
relationshipsCount: lifecycleRelationships.length,
|
|
3634
|
+
resourceType: this.resourceConfiguration.resourceIdentifier
|
|
3635
|
+
});
|
|
3636
|
+
// Get parent ID(s) from result
|
|
3637
|
+
const parentIds = operation === CoreResourceOperation.DELETE_MANY
|
|
3638
|
+
? (Array.isArray(result)
|
|
3639
|
+
? result.map((item) => (typeof item === 'string' ? item : this.getResourceIdValue(item))).filter(Boolean)
|
|
3640
|
+
: result?.deletedIds || [])
|
|
3641
|
+
: (() => {
|
|
3642
|
+
if (typeof result === 'string') {
|
|
3643
|
+
return [result];
|
|
3644
|
+
}
|
|
3645
|
+
const resultId = result?._id ?? result?.id;
|
|
3646
|
+
if (resultId) {
|
|
3647
|
+
return [String(resultId)];
|
|
3648
|
+
}
|
|
3649
|
+
const currentStateId = currentState ? this.getResourceIdValue(currentState) : undefined;
|
|
3650
|
+
return currentStateId ? [currentStateId] : [];
|
|
3651
|
+
})();
|
|
3652
|
+
if (parentIds.length === 0) {
|
|
3653
|
+
this.logDebug('No parent IDs found in result, skipping lifecycle operations');
|
|
3654
|
+
return;
|
|
3655
|
+
}
|
|
3656
|
+
// Process each child relationship with lifecycle config
|
|
3657
|
+
for (const relationship of lifecycleRelationships) {
|
|
3658
|
+
const lifecycleConfig = this.getResolvedLifecycleOnParentDelete(relationship);
|
|
3659
|
+
const mode = lifecycleConfig.mode || ChildLifecycleMode.IMMEDIATE;
|
|
3660
|
+
const maxDepth = lifecycleConfig.maxDepth || 1;
|
|
3661
|
+
let relationshipParentIds = parentIds;
|
|
3662
|
+
if (operation === CoreResourceOperation.DELETE_MANY && Array.isArray(currentState)) {
|
|
3663
|
+
const currentStatesById = new Map(currentState
|
|
3664
|
+
.map((item) => [this.getResourceIdValue(item), item])
|
|
3665
|
+
.filter((entry) => !!entry[0]));
|
|
3666
|
+
relationshipParentIds = parentIds.filter((parentId) => {
|
|
3667
|
+
const parentSnapshot = currentStatesById.get(parentId);
|
|
3668
|
+
if (!parentSnapshot) {
|
|
3669
|
+
return false;
|
|
3670
|
+
}
|
|
3671
|
+
return this.filterRelationshipsByParent([relationship], parentSnapshot).length > 0;
|
|
3672
|
+
});
|
|
3673
|
+
}
|
|
3674
|
+
if (relationshipParentIds.length === 0) {
|
|
3675
|
+
continue;
|
|
3676
|
+
}
|
|
3677
|
+
if (mode === ChildLifecycleMode.IMMEDIATE) {
|
|
3678
|
+
await this.deleteChildrenImmediate(relationship, relationshipParentIds, executionContext, 0, // currentDepth
|
|
3679
|
+
maxDepth, new Set(), // visitedResourceIds for circular reference detection
|
|
3680
|
+
options);
|
|
3681
|
+
}
|
|
3682
|
+
else if (mode === ChildLifecycleMode.LAZY) {
|
|
3683
|
+
await this.queueChildDeletion(relationship, relationshipParentIds, executionContext);
|
|
3684
|
+
}
|
|
3685
|
+
}
|
|
3686
|
+
}
|
|
3687
|
+
/**
|
|
3688
|
+
* Delete child resources immediately (synchronous, within same transaction).
|
|
3689
|
+
*
|
|
3690
|
+
* Includes depth tracking and circular reference detection to prevent infinite loops.
|
|
3691
|
+
*
|
|
3692
|
+
* @param relationship - The relationship configuration
|
|
3693
|
+
* @param parentIds - IDs of parent resources being deleted
|
|
3694
|
+
* @param executionContext - Execution context for the operation
|
|
3695
|
+
* @param currentDepth - Current recursion depth (starts at 0)
|
|
3696
|
+
* @param maxDepth - Maximum allowed depth (from lifecycle config, default 1)
|
|
3697
|
+
* @param visitedResourceIds - Set of visited resource IDs to prevent circular references
|
|
3698
|
+
*/
|
|
3699
|
+
async deleteChildrenImmediate(relationship, parentIds, executionContext, currentDepth = 0, maxDepth = 1, visitedResourceIds = new Set(), options) {
|
|
3700
|
+
// Guard 1: Depth limit check
|
|
3701
|
+
if (currentDepth >= maxDepth) {
|
|
3702
|
+
this.logDebug('Max depth reached, stopping lifecycle delete', {
|
|
3703
|
+
currentDepth,
|
|
3704
|
+
maxDepth,
|
|
3705
|
+
childResourceType: relationship.resourceType2
|
|
3706
|
+
});
|
|
3707
|
+
return;
|
|
3708
|
+
}
|
|
3709
|
+
const childResourceType = relationship.resourceType2;
|
|
3710
|
+
const fkField = this.getFKFieldForRelationship(relationship);
|
|
3711
|
+
this.logDebug('Deleting children immediately', {
|
|
3712
|
+
childResourceType,
|
|
3713
|
+
fkField,
|
|
3714
|
+
parentIdsCount: parentIds.length,
|
|
3715
|
+
currentDepth,
|
|
3716
|
+
maxDepth
|
|
3717
|
+
});
|
|
3718
|
+
try {
|
|
3719
|
+
// Get child service from registry
|
|
3720
|
+
const childService = this.servicesRegistry.getService(childResourceType);
|
|
3721
|
+
if (!childService) {
|
|
3722
|
+
this.logDebug('Child service not found, skipping lifecycle delete', { childResourceType });
|
|
3723
|
+
return;
|
|
3724
|
+
}
|
|
3725
|
+
// Build filter to find children with parent FK in parentIds.
|
|
3726
|
+
// Child discovery must stay adapter-neutral: use repository operations
|
|
3727
|
+
// rather than reaching into Mongo-specific model internals.
|
|
3728
|
+
const filter = { [fkField]: { $in: parentIds } };
|
|
3729
|
+
const childRepositoryOptions = this.buildRepositoryOptionsForResource(childResourceType, executionContext, options);
|
|
3730
|
+
// Find children first (we need their IDs for recursive lifecycle)
|
|
3731
|
+
const childRepository = this.repositoriesRegistry.getRepository(childResourceType);
|
|
3732
|
+
let children = [];
|
|
3733
|
+
if (isOneToOneCardinality(relationship.cardinality2)) {
|
|
3734
|
+
if (!childRepository.supportsOperation(CoreResourceOperation.READ)) {
|
|
3735
|
+
throw this.errorBuilder.buildError(ErrorType.CONFIGURATION, executionContext, {
|
|
3736
|
+
customMessageReference: ErrorCustomMessageReference.CONFIGURATION,
|
|
3737
|
+
context: {
|
|
3738
|
+
message: `Lifecycle delete requires READ support on child resource "${childResourceType}" ` +
|
|
3739
|
+
`to discover 1:1 dependents before deletion.`,
|
|
3740
|
+
childResourceType,
|
|
3741
|
+
fkField,
|
|
3742
|
+
relationshipField: this.getNestedFieldName(relationship),
|
|
3743
|
+
},
|
|
3744
|
+
});
|
|
3745
|
+
}
|
|
3746
|
+
const child = await childRepository.read(executionContext, filter, childRepositoryOptions);
|
|
3747
|
+
children = child ? [child] : [];
|
|
3748
|
+
}
|
|
3749
|
+
else {
|
|
3750
|
+
if (!childRepository.supportsOperation(CoreResourceOperation.LIST)) {
|
|
3751
|
+
throw this.errorBuilder.buildError(ErrorType.CONFIGURATION, executionContext, {
|
|
3752
|
+
customMessageReference: ErrorCustomMessageReference.CONFIGURATION,
|
|
3753
|
+
context: {
|
|
3754
|
+
message: `Lifecycle delete requires LIST support on child resource "${childResourceType}" ` +
|
|
3755
|
+
`to discover dependent children before deletion.`,
|
|
3756
|
+
childResourceType,
|
|
3757
|
+
fkField,
|
|
3758
|
+
relationshipField: this.getNestedFieldName(relationship),
|
|
3759
|
+
},
|
|
3760
|
+
});
|
|
3761
|
+
}
|
|
3762
|
+
const listedChildren = await childRepository.list(executionContext, filter, childRepositoryOptions);
|
|
3763
|
+
children = Array.isArray(listedChildren) ? listedChildren : [];
|
|
3764
|
+
}
|
|
3765
|
+
if (!children || children.length === 0) {
|
|
3766
|
+
this.logDebug('No children found to delete', { childResourceType, fkField });
|
|
3767
|
+
return;
|
|
3768
|
+
}
|
|
3769
|
+
const childIds = children.map((c) => c._id?.toString() || c.id);
|
|
3770
|
+
const childSnapshotsById = new Map();
|
|
3771
|
+
for (const child of children) {
|
|
3772
|
+
const childId = child?._id?.toString() || child?.id;
|
|
3773
|
+
if (childId) {
|
|
3774
|
+
childSnapshotsById.set(childId, child);
|
|
3775
|
+
}
|
|
3776
|
+
}
|
|
3777
|
+
// Guard 2: Circular reference detection
|
|
3778
|
+
// Check if any child ID was already visited in this deletion chain.
|
|
3779
|
+
// This prevents infinite loops when deleting resources that reference each other.
|
|
3780
|
+
// Note: This detects same-chain circular refs (A→B→A). Cross-branch circular refs
|
|
3781
|
+
// (A→B→C→A where C is deleted via different parent) are rare and would require
|
|
3782
|
+
// more complex graph traversal to detect fully.
|
|
3783
|
+
const newChildIds = [];
|
|
3784
|
+
for (const childId of childIds) {
|
|
3785
|
+
const resourceKey = `${childResourceType}:${childId}`;
|
|
3786
|
+
if (visitedResourceIds.has(resourceKey)) {
|
|
3787
|
+
this.logDebug('Circular reference detected, skipping child', {
|
|
3788
|
+
childResourceType,
|
|
3789
|
+
childId,
|
|
3790
|
+
resourceKey,
|
|
3791
|
+
note: 'This resource was already processed in this deletion chain, preventing infinite loop'
|
|
3792
|
+
});
|
|
3793
|
+
continue;
|
|
3794
|
+
}
|
|
3795
|
+
visitedResourceIds.add(resourceKey);
|
|
3796
|
+
newChildIds.push(childId);
|
|
3797
|
+
}
|
|
3798
|
+
if (newChildIds.length === 0) {
|
|
3799
|
+
this.logDebug('All children skipped due to circular references', { childResourceType });
|
|
3800
|
+
return;
|
|
3801
|
+
}
|
|
3802
|
+
this.logDebug('Found children to delete', {
|
|
3803
|
+
childResourceType,
|
|
3804
|
+
count: newChildIds.length,
|
|
3805
|
+
skipped: childIds.length - newChildIds.length
|
|
3806
|
+
});
|
|
3807
|
+
const supportsDeleteMany = childRepository.supportsOperation(CoreResourceOperation.DELETE_MANY);
|
|
3808
|
+
const supportsDelete = childRepository.supportsOperation(CoreResourceOperation.DELETE);
|
|
3809
|
+
if (!supportsDeleteMany && !supportsDelete) {
|
|
3810
|
+
throw this.errorBuilder.buildError(ErrorType.CONFIGURATION, executionContext, {
|
|
3811
|
+
customMessageReference: ErrorCustomMessageReference.CONFIGURATION,
|
|
3812
|
+
context: {
|
|
3813
|
+
message: `Lifecycle delete requires DELETE_MANY or DELETE support on child resource "${childResourceType}".`,
|
|
3814
|
+
childResourceType,
|
|
3815
|
+
relationshipField: this.getNestedFieldName(relationship),
|
|
3816
|
+
},
|
|
3817
|
+
});
|
|
3818
|
+
}
|
|
3819
|
+
// Recursively delete grandchildren before mutating the current child level.
|
|
3820
|
+
// This keeps deeper failures from leaving the current child rows already
|
|
3821
|
+
// deleted while descendants remain behind.
|
|
3822
|
+
// Activation must still be evaluated against each deleted child snapshot before we recurse;
|
|
3823
|
+
// otherwise discriminator/condition-gated lifecycle relationships would over-delete deeper
|
|
3824
|
+
// descendants just because the FK chain exists.
|
|
3825
|
+
if (currentDepth + 1 < maxDepth) {
|
|
3826
|
+
const childConfig = this.resourcesRegistry.tryGetResourceConfiguration(childResourceType);
|
|
3827
|
+
if (childConfig?.resourceRelationships) {
|
|
3828
|
+
const grandchildRelationships = getChildDirectionRelationships(childConfig.resourceRelationships).filter((rel) => this.getResolvedLifecycleOnParentDelete(rel)?.enabled === true);
|
|
3829
|
+
for (const grandchildRel of grandchildRelationships) {
|
|
3830
|
+
const grandchildLifecycleConfig = this.getResolvedLifecycleOnParentDelete(grandchildRel);
|
|
3831
|
+
const grandchildMaxDepth = grandchildLifecycleConfig.maxDepth || 1;
|
|
3832
|
+
const activeGrandchildParentIds = newChildIds.filter(childId => {
|
|
3833
|
+
const childSnapshot = childSnapshotsById.get(childId);
|
|
3834
|
+
if (!childSnapshot) {
|
|
3835
|
+
return false;
|
|
3836
|
+
}
|
|
3837
|
+
return this.filterRelationshipsByParent([grandchildRel], childSnapshot).length > 0;
|
|
3838
|
+
});
|
|
3839
|
+
if (activeGrandchildParentIds.length === 0) {
|
|
3840
|
+
continue;
|
|
3841
|
+
}
|
|
3842
|
+
// Recursively delete grandchildren
|
|
3843
|
+
await this.deleteChildrenImmediate(grandchildRel, activeGrandchildParentIds, executionContext, currentDepth + 1, Math.min(maxDepth, grandchildMaxDepth + currentDepth + 1), // Respect both limits
|
|
3844
|
+
visitedResourceIds, // Share visited set to prevent cross-branch circular refs
|
|
3845
|
+
options);
|
|
3846
|
+
}
|
|
3847
|
+
}
|
|
3848
|
+
}
|
|
3849
|
+
// Keep lifecycle depth ownership in this method, but do not bypass the
|
|
3850
|
+
// file cleanup contract. Child resources with file fields must run through
|
|
3851
|
+
// the same file-delete orchestration before their repository delete lands.
|
|
3852
|
+
if (this.fileFieldDetection.hasFileFields(childResourceType)) {
|
|
3853
|
+
for (const childId of newChildIds) {
|
|
3854
|
+
if (childRepositoryOptions?.transaction?.databaseType === 'postgresql') {
|
|
3855
|
+
await this.executeFileMetadataWork(executionContext, childRepositoryOptions, async (fileOptions) => this.fileOperationHandler.processFileFieldsForDelete(childResourceType, childId, executionContext, fileOptions));
|
|
3856
|
+
}
|
|
3857
|
+
else {
|
|
3858
|
+
await this.fileOperationHandler.processFileFieldsForDelete(childResourceType, childId, executionContext, childRepositoryOptions);
|
|
3859
|
+
}
|
|
3860
|
+
}
|
|
3861
|
+
}
|
|
3862
|
+
// The repository call must still stay adapter-agnostic: pass the generic
|
|
3863
|
+
// ids array contract instead of a Mongo-specific `{ _id: { $in: ... } }`
|
|
3864
|
+
// filter shape.
|
|
3865
|
+
if (supportsDeleteMany) {
|
|
3866
|
+
await childRepository.deleteMany(executionContext, newChildIds, childRepositoryOptions);
|
|
3867
|
+
}
|
|
3868
|
+
else if (supportsDelete) {
|
|
3869
|
+
for (const childId of newChildIds) {
|
|
3870
|
+
await childRepository.delete(executionContext, childId, childRepositoryOptions);
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3873
|
+
this.logDebug('Children deleted successfully', {
|
|
3874
|
+
childResourceType,
|
|
3875
|
+
deletedCount: newChildIds.length
|
|
3876
|
+
});
|
|
3877
|
+
}
|
|
3878
|
+
catch (error) {
|
|
3879
|
+
this.logger.error('Failed to delete children in lifecycle operation', {
|
|
3880
|
+
childResourceType,
|
|
3881
|
+
fkField,
|
|
3882
|
+
currentDepth,
|
|
3883
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
3884
|
+
});
|
|
3885
|
+
// Re-throw to ensure parent delete fails if child delete fails
|
|
3886
|
+
throw error;
|
|
3887
|
+
}
|
|
3888
|
+
}
|
|
3889
|
+
/**
|
|
3890
|
+
* Queue child resources for async deletion (eventual consistency).
|
|
3891
|
+
*
|
|
3892
|
+
* LAZY mode provides eventual consistency by queuing deletion operations
|
|
3893
|
+
* for asynchronous processing. This improves performance for bulk deletions
|
|
3894
|
+
* but requires a queue system to be implemented.
|
|
3895
|
+
*
|
|
3896
|
+
* Current implementation: Placeholder that throws NOT_IMPLEMENTED error.
|
|
3897
|
+
*
|
|
3898
|
+
* Future implementation (Phase 6.1-6.2):
|
|
3899
|
+
* When the queue system is implemented, this method should:
|
|
3900
|
+
* 1. Get the DELETE operation for the child resource type
|
|
3901
|
+
* 2. Use `operation.internalDto` for serializing queue payloads
|
|
3902
|
+
* - `internalDto` includes `isBackendOnly` fields needed for backend-to-backend communication
|
|
3903
|
+
* - Date coercion is already applied in `internalDto`
|
|
3904
|
+
* 3. Serialize resource data using `operation.internalDto.parse()` for validation
|
|
3905
|
+
* 4. Enqueue job with validated payload
|
|
3906
|
+
*
|
|
3907
|
+
* Example (when queue system is ready):
|
|
3908
|
+
* ```typescript
|
|
3909
|
+
* const childResourceConfig = this.resourcesRegistry.resourceConfigurations[relationship.resourceType2];
|
|
3910
|
+
* const deleteOperation = childResourceConfig.operations.find(
|
|
3911
|
+
* op => op.operationIdentifier === CoreResourceOperation.DELETE
|
|
3912
|
+
* );
|
|
3913
|
+
* if (!deleteOperation?.internalDto) {
|
|
3914
|
+
* throw new Error('DELETE operation or internalDto not found');
|
|
3915
|
+
* }
|
|
3916
|
+
*
|
|
3917
|
+
* // Validate and serialize using internalDto
|
|
3918
|
+
* const queuePayload = {
|
|
3919
|
+
* resourceType: relationship.resourceType2,
|
|
3920
|
+
* operationIdentifier: CoreResourceOperation.DELETE,
|
|
3921
|
+
* data: deleteOperation.internalDto.parse({ _id: childId, ...otherFields }),
|
|
3922
|
+
* executionContext: { ... },
|
|
3923
|
+
* };
|
|
3924
|
+
*
|
|
3925
|
+
* await this.queueService.enqueueResourceOperation(deleteOperation, queuePayload.data, executionContext);
|
|
3926
|
+
* ```
|
|
3927
|
+
*
|
|
3928
|
+
* @see Phase 6.1 - Use internalDto for Queue Payloads
|
|
3929
|
+
* @see Phase 6.2 - Validate Queue Payloads Against internalDto
|
|
3930
|
+
*/
|
|
3931
|
+
async queueChildDeletion(relationship, parentIds, executionContext) {
|
|
3932
|
+
throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, {
|
|
3933
|
+
customMessageReference: ErrorCustomMessageReference.SERVICE_RESOURCE_OPERATION_FAILED,
|
|
3934
|
+
context: {
|
|
3935
|
+
message: 'LAZY cascade mode requires queue system integration. Queue system implementation pending. See Phase 6.1-6.2 for implementation details.',
|
|
3936
|
+
relationship: relationship.resourceType2,
|
|
3937
|
+
parentIds,
|
|
3938
|
+
},
|
|
3939
|
+
});
|
|
3940
|
+
}
|
|
3941
|
+
/**
|
|
3942
|
+
* Execute additional post-operation logic (non-cascading)
|
|
3943
|
+
*/
|
|
3944
|
+
async executeAdditionalPostOperationLogic(operation, result, executionContext, currentState) {
|
|
3945
|
+
this.logDebug('Executing additional post-operation logic', { operation });
|
|
3946
|
+
// Dispatch post-operation hooks registered on this resource type
|
|
3947
|
+
const resourceType = this.resourceConfiguration.resourceIdentifier;
|
|
3948
|
+
await this.servicesRegistry.dispatchPostOperationHooks(resourceType, operation, result, executionContext);
|
|
3949
|
+
}
|
|
3950
|
+
/**
|
|
3951
|
+
* Enrich business context
|
|
3952
|
+
*/
|
|
3953
|
+
async enrichBusinessContext(operation, data, executionContext) {
|
|
3954
|
+
// Implement business context enrichment here
|
|
3955
|
+
// This could include:
|
|
3956
|
+
// - Adding computed fields
|
|
3957
|
+
// - Loading related resources
|
|
3958
|
+
// - Adding user-specific data
|
|
3959
|
+
// - Permission-based filtering
|
|
3960
|
+
return data; // Default: pass through
|
|
3961
|
+
}
|
|
3962
|
+
/**
|
|
3963
|
+
* Apply business filter
|
|
3964
|
+
*/
|
|
3965
|
+
async applyBusinessFilter(filter, executionContext) {
|
|
3966
|
+
// Implement business filtering logic here
|
|
3967
|
+
// This could include:
|
|
3968
|
+
// - User permission-based filtering
|
|
3969
|
+
// - Organization scope filtering
|
|
3970
|
+
// - Security filtering
|
|
3971
|
+
return filter; // Default: pass through
|
|
3972
|
+
}
|
|
3973
|
+
/**
|
|
3974
|
+
* Enhance search query with business logic
|
|
3975
|
+
*/
|
|
3976
|
+
async enhanceSearchQuery(searchQuery, executionContext) {
|
|
3977
|
+
// Implement search enhancement logic here
|
|
3978
|
+
// This could include:
|
|
3979
|
+
// - Query expansion
|
|
3980
|
+
// - Synonym handling
|
|
3981
|
+
// - Permission-based query modification
|
|
3982
|
+
return searchQuery; // Default: pass through
|
|
3983
|
+
}
|
|
3984
|
+
/**
|
|
3985
|
+
* Validate deletion constraints
|
|
3986
|
+
*/
|
|
3987
|
+
async validateDeletionConstraints(data, executionContext) {
|
|
3988
|
+
// Implement deletion constraint validation here
|
|
3989
|
+
// This could include:
|
|
3990
|
+
// - Dependency checking
|
|
3991
|
+
// - Business rule validation
|
|
3992
|
+
// - Permission validation
|
|
3993
|
+
// Default: allow deletion
|
|
3994
|
+
}
|
|
3995
|
+
// ================================
|
|
3996
|
+
// Notification Methods
|
|
3997
|
+
// ================================
|
|
3998
|
+
/**
|
|
3999
|
+
* Dispatch notifications (email, badge, WebSocket, M2M) based on operation configuration.
|
|
4000
|
+
*
|
|
4001
|
+
* Reads ALL notification config from `executionContext.operation` — which is guaranteed
|
|
4002
|
+
* to be the correct (possibly variant-resolved) operation thanks to Correction Points
|
|
4003
|
+
* 1 and 2 in `doOperation()`. The NotificationDispatcherService also reads
|
|
4004
|
+
* `executionContext.operation` extensively (15+ reads across its sub-methods).
|
|
4005
|
+
*/
|
|
4006
|
+
async dispatchNotifications(executionContext, inputData, currentResult, tokenGenerationResult) {
|
|
4007
|
+
await dispatchPostOperationNotificationsBestEffort({
|
|
4008
|
+
notificationDispatcher: this.notificationDispatcher,
|
|
4009
|
+
populationService: this.populationService,
|
|
4010
|
+
logger: this.logger,
|
|
4011
|
+
logDebug: this.logDebug,
|
|
4012
|
+
}, executionContext, inputData, currentResult, tokenGenerationResult);
|
|
4013
|
+
}
|
|
4014
|
+
}
|
|
4015
|
+
//# sourceMappingURL=services-registry-handler.backend.service.js.map
|