@wildo-ai/saas-backend-lib 1.1.3 → 1.1.4
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__/fixture-deep-partial.d.ts.map +1 -1
- package/dist/esm/__tests__/integration/redis-integration-gate.d.ts.map +1 -1
- package/dist/esm/__tests__/setup.d.ts.map +1 -1
- package/dist/esm/__tests__/test-container.d.ts.map +1 -1
- package/dist/esm/applications/models/applications.backend.schemas.d.ts.map +1 -1
- package/dist/esm/applications/seeds/application-metadata-defaults.seeds.d.ts.map +1 -1
- package/dist/esm/applications/services/worker-remote-client-factory.backend.service.d.ts.map +1 -1
- package/dist/esm/applications/services/worker-remote-client-factory.backend.service.js.map +1 -1
- package/dist/esm/base-classes/models/manual-controllers.backend.definition.d.ts.map +1 -1
- package/dist/esm/base-classes/models/manual-controllers.backend.definition.js.map +1 -1
- package/dist/esm/base-classes/models/repositories.backend.schemas.d.ts.map +1 -1
- package/dist/esm/base-classes/services/__tests__/mock-resource-operation-helper.service.d.ts +1 -1
- package/dist/esm/base-classes/services/__tests__/mock-resource-operation-helper.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/batches/batches-cronjobs-custom-execution.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/batches/batches-cronjobs-executor.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/batches/batches-cronjobs-resource-execution.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/batches/child-lifecycle-teardown.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/batches/child-lifecycle-teardown.batch.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/batches/credential-expiry-sweep.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/batches/credential-expiry-sweep.batch.backend.service.js +12 -1
- package/dist/esm/base-classes/services/batches/credential-expiry-sweep.batch.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/batches/engine-custom-batch-manifests.d.ts.map +1 -1
- package/dist/esm/base-classes/services/batches/engine-custom-batch-manifests.js.map +1 -1
- package/dist/esm/base-classes/services/batches/resource-retention-sweep.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/batches/suspension-reactivation-sweep.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/controllers/abstract-controller.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/controllers/utils/audit-access-fields.backend.utils.d.ts.map +1 -1
- package/dist/esm/base-classes/services/controllers/utils/operation-response-serializer.backend.utils.d.ts.map +1 -1
- package/dist/esm/base-classes/services/controllers/validate-field-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/__tests__/method-span-scan.guard-helpers.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/__tests__/mock-repositories-registry-handler.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/field-clearing-partition.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-filter-translation.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-provider-access.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-provider-access.backend.js +13 -4
- package/dist/esm/base-classes/services/repositories/http-api/http-api-provider-access.backend.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-query.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-read-client.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-read-client.backend.js +17 -0
- package/dist/esm/base-classes/services/repositories/http-api/http-api-read-client.backend.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-resource-repository.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-resource-repository.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-rest-operation-reference.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-rest-operation-reference.backend.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-row-projection.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-subject-erasure-effect.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-transport.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-transport.backend.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/odata-query-compiler.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/odoo-jsonrpc-compiler.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/rest-json-query-compiler.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/infrastructure-tier-contract.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/infrastructure-tier-contract.backend.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-repository.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-source.backend.port.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.d.ts +57 -0
- package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.js +95 -2
- package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/repository-guarded-mutation.backend.types.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.d.ts +5 -2
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.js +14 -3
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/repository-version-metadata.backend.utils.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/resource-write-integrity.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/seed-row-default-materialization.backend.d.ts +72 -0
- package/dist/esm/base-classes/services/repositories/seed-row-default-materialization.backend.d.ts.map +1 -0
- package/dist/esm/base-classes/services/repositories/seed-row-default-materialization.backend.js +88 -0
- package/dist/esm/base-classes/services/repositories/seed-row-default-materialization.backend.js.map +1 -0
- package/dist/esm/base-classes/services/repositories/unique-constraint-conflict-reference.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/resource-operations-helper.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/__tests__/mock-services-registry-handler.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/__tests__/mock-system-access.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/read-only-field-change.backend.utils.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-audit-emission.backend.utils.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-base.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-base.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-implementation-coverage.backend.utils.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-server-injected-fields.backend.utils.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/services/resource-status-transition.definitions.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-status-transition.definitions.backend.js.map +1 -1
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js +44 -6
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/services/system-access.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/system-access.backend.service.js.map +1 -1
- package/dist/esm/base-classes/utils/backend-type-utils.d.ts.map +1 -1
- package/dist/esm/base-classes/utils/single-subject-addressing.backend.utils.d.ts.map +1 -1
- package/dist/esm/billing/batches/billing-reconciliation.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/billing/batches/billing-reconciliation.batch.backend.service.js.map +1 -1
- package/dist/esm/billing/batches/usage-flush.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/billing/batches/usage-flush.batch.backend.service.js.map +1 -1
- package/dist/esm/billing/models/billing-provider-event-settlement.backend.schemas.d.ts.map +1 -1
- package/dist/esm/billing/models/billing-provider-event-settlement.backend.schemas.js.map +1 -1
- package/dist/esm/billing/services/back-office/abstract-billing.backend.service.d.ts.map +1 -1
- package/dist/esm/billing/services/back-office/billing-feature-sync.backend.service.d.ts.map +1 -1
- package/dist/esm/billing/services/back-office/billing-reconciliation.backend.service.d.ts +1 -1
- package/dist/esm/billing/services/back-office/billing-reconciliation.backend.service.d.ts.map +1 -1
- package/dist/esm/billing/services/back-office/billing-reconciliation.backend.service.js +5 -4
- package/dist/esm/billing/services/back-office/billing-reconciliation.backend.service.js.map +1 -1
- package/dist/esm/billing/services/back-office/billing-state.backend.service.d.ts.map +1 -1
- package/dist/esm/billing/services/back-office/billing-state.backend.service.js +11 -1
- package/dist/esm/billing/services/back-office/billing-state.backend.service.js.map +1 -1
- package/dist/esm/billing/services/back-office/billing-subject-erasure-effect.backend.d.ts.map +1 -1
- package/dist/esm/billing/services/back-office/product-catalog-sync.backend.service.d.ts.map +1 -1
- package/dist/esm/billing/services/back-office/product-catalog-sync.backend.service.js.map +1 -1
- package/dist/esm/billing/services/back-office/usage-metering.backend.service.d.ts.map +1 -1
- package/dist/esm/billing/services/back-office/usage-metering.backend.service.js.map +1 -1
- package/dist/esm/billing/services/billing-adapter-registry.backend.d.ts.map +1 -1
- package/dist/esm/billing/services/billing-adapter-registry.backend.js.map +1 -1
- package/dist/esm/billing/services/billing-checkout-metadata.backend.utils.d.ts.map +1 -1
- package/dist/esm/billing/services/billing-checkout-metadata.backend.utils.js.map +1 -1
- package/dist/esm/billing/services/billing.utils.d.ts.map +1 -1
- package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/billing/services/custom-impl/billing-custom-impl-utils.backend.d.ts +32 -0
- package/dist/esm/billing/services/custom-impl/billing-custom-impl-utils.backend.d.ts.map +1 -1
- package/dist/esm/billing/services/custom-impl/billing-custom-impl-utils.backend.js +32 -1
- package/dist/esm/billing/services/custom-impl/billing-custom-impl-utils.backend.js.map +1 -1
- package/dist/esm/billing/services/custom-impl/billing-custom-implementations.backend.d.ts.map +1 -1
- package/dist/esm/billing/services/custom-impl/billing-custom-implementations.backend.js.map +1 -1
- package/dist/esm/billing/services/custom-impl/credit-pool.custom-ops.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/billing/services/custom-impl/promotion.custom-ops.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/billing/services/custom-impl/promotion.custom-ops.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/billing/services/custom-impl/subscription.mutations.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/billing/services/custom-impl/subscription.mutations.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/billing/services/stripe-standard-billing-provider.backend.service.d.ts +9 -6
- package/dist/esm/billing/services/stripe-standard-billing-provider.backend.service.d.ts.map +1 -1
- package/dist/esm/billing/services/stripe-standard-billing-provider.backend.service.js +9 -6
- package/dist/esm/billing/services/stripe-standard-billing-provider.backend.service.js.map +1 -1
- package/dist/esm/billing/services/webhooks/__tests__/settlement-ledger.test-double.d.ts.map +1 -1
- package/dist/esm/billing/services/webhooks/__tests__/settlement-ledger.test-double.js.map +1 -1
- package/dist/esm/billing/services/webhooks/billing-webhook-adapter.backend.service.d.ts.map +1 -1
- package/dist/esm/billing/services/webhooks/billing-webhook-capability-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/billing/services/webhooks/billing-webhook-event-router.backend.service.d.ts.map +1 -1
- package/dist/esm/billing/services/webhooks/billing-webhook-event-router.backend.service.js +50 -3
- package/dist/esm/billing/services/webhooks/billing-webhook-event-router.backend.service.js.map +1 -1
- package/dist/esm/billing/testing/billing-test-fixtures.d.ts.map +1 -1
- package/dist/esm/billing/testing/mock-billing-provider.d.ts.map +1 -1
- package/dist/esm/billing/testing/mock-billing-provider.js.map +1 -1
- package/dist/esm/charts/controllers/chart.backend.controller.d.ts.map +1 -1
- package/dist/esm/charts/services/chart-registry.backend.service.d.ts +80 -7
- package/dist/esm/charts/services/chart-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/charts/services/chart-registry.backend.service.js +115 -8
- package/dist/esm/charts/services/chart-registry.backend.service.js.map +1 -1
- package/dist/esm/companion-exports.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/audit-logs.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/batches/audit-logs-archive.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/batches/audit-logs-archive.batch.backend.service.js.map +1 -1
- package/dist/esm/compliance/audit-trails/batches/immudb-audit-reconcile.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/batches/siem-webhook-delivery.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/services/__tests__/mock-audit-logs.service.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.js.map +1 -1
- package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.d.ts +107 -4
- package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.js +176 -5
- package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.js.map +1 -1
- package/dist/esm/compliance/audit-trails/services/composite-audit-log-sink.backend.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/services/composite-audit-log-sink.backend.js.map +1 -1
- package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.js.map +1 -1
- package/dist/esm/compliance/audit-trails/services/utils/leased-value-cache.backend.utils.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/services/utils/leased-value-cache.backend.utils.js.map +1 -1
- package/dist/esm/compliance/audit-trails/services/utils/ocsf-activity-mapping.backend.utils.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/services/utils/ocsf-activity-mapping.backend.utils.js +21 -0
- package/dist/esm/compliance/audit-trails/services/utils/ocsf-activity-mapping.backend.utils.js.map +1 -1
- package/dist/esm/compliance/audit-trails/services/utils/ocsf-class-mapping.backend.utils.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/services/utils/siem-dictionary.backend.utils.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/services/utils/siem-ocsf-projection.backend.utils.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/services/utils/siem-projection-contract.backend.utils.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/utils/audit-actor.backend.utils.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/utils/layer2-audit-provider-boot-diagnostic.backend.utils.d.ts.map +1 -1
- package/dist/esm/compliance/index.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/retention-hide-predicate.backend.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/services/subject-erasure-external-effects.backend.service.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/services/subject-session-revocation.backend.service.d.ts.map +1 -1
- package/dist/esm/config/bootstrap/application-runtime-profile.backend.d.ts.map +1 -1
- package/dist/esm/config/bootstrap/application-runtime-profile.backend.js.map +1 -1
- package/dist/esm/config/bootstrap/minion-initialization-projection.backend.d.ts.map +1 -1
- package/dist/esm/config/bootstrap/runtime-principal-attestation.backend.service.d.ts.map +1 -1
- package/dist/esm/config/bootstrap/runtime-principal-attestation.backend.service.js +3 -0
- package/dist/esm/config/bootstrap/runtime-principal-attestation.backend.service.js.map +1 -1
- package/dist/esm/config/bootstrap/runtime-principal.backend.service.d.ts.map +1 -1
- package/dist/esm/config/custom/application-config-controller.backend.service.d.ts.map +1 -1
- package/dist/esm/config/models/app-config-secrets.backend.schemas.d.ts.map +1 -1
- package/dist/esm/config/models/app-config.backend-authored.definitions.d.ts.map +1 -1
- package/dist/esm/config/models/app-config.backend.schemas.d.ts +4 -4
- package/dist/esm/config/models/app-config.backend.schemas.d.ts.map +1 -1
- package/dist/esm/config/models/app-config.backend.schemas.js.map +1 -1
- package/dist/esm/config/models/app-env-config.backend.schemas.d.ts.map +1 -1
- package/dist/esm/config/models/apps-manager-transport.backend.definitions.d.ts +36 -0
- package/dist/esm/config/models/apps-manager-transport.backend.definitions.d.ts.map +1 -0
- package/dist/esm/config/models/apps-manager-transport.backend.definitions.js +36 -0
- package/dist/esm/config/models/apps-manager-transport.backend.definitions.js.map +1 -0
- package/dist/esm/config/models/config-mutation-boundary.utils.d.ts.map +1 -1
- package/dist/esm/config/models/postgresql-env-config.backend.schemas.d.ts.map +1 -1
- package/dist/esm/config/models/provider-runtime-artifact.backend.schemas.d.ts.map +1 -1
- package/dist/esm/config/models/provider-runtime-artifact.backend.schemas.js.map +1 -1
- package/dist/esm/config/models/runtime-topology.backend.contracts.d.ts.map +1 -1
- package/dist/esm/config/services/__tests__/mock-app-configuration.service.d.ts.map +1 -1
- package/dist/esm/config/services/app-configuration-loader.backend.service.d.ts.map +1 -1
- package/dist/esm/config/services/app-configuration-loader.backend.service.js +3 -0
- package/dist/esm/config/services/app-configuration-loader.backend.service.js.map +1 -1
- package/dist/esm/config/services/app-configuration.backend.service.d.ts.map +1 -1
- package/dist/esm/config/services/app-configuration.backend.service.js.map +1 -1
- package/dist/esm/config/services/app-configuration.backend.utils.d.ts.map +1 -1
- package/dist/esm/config/services/app-configuration.backend.utils.js.map +1 -1
- package/dist/esm/config/services/application-startup-config-validator.backend.service.d.ts +12 -0
- package/dist/esm/config/services/application-startup-config-validator.backend.service.d.ts.map +1 -1
- package/dist/esm/config/services/application-startup-config-validator.backend.service.js +28 -0
- package/dist/esm/config/services/application-startup-config-validator.backend.service.js.map +1 -1
- package/dist/esm/data-seeding/batches/data-seeding-run-cleanup.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/data-seeding/batches/data-seeding-scheduled-rerun.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/data-seeding/controllers/data-seeding-admin.backend.contracts.d.ts.map +1 -1
- package/dist/esm/data-seeding/controllers/data-seeding-admin.backend.controller.d.ts.map +1 -1
- package/dist/esm/data-seeding/data-seeding-models.d.ts.map +1 -1
- package/dist/esm/data-seeding/models/business-key-resolver.shared.utils.d.ts.map +1 -1
- package/dist/esm/data-seeding/models/data-seed-execution-context.shared.types.d.ts.map +1 -1
- package/dist/esm/data-seeding/models/data-seed-migrator-runner.shared.utils.d.ts.map +1 -1
- package/dist/esm/data-seeding/models/data-seed-reconciler.shared.utils.d.ts.map +1 -1
- package/dist/esm/data-seeding/models/data-seed-row-metadata.shared.schemas.d.ts.map +1 -1
- package/dist/esm/data-seeding/models/data-seed-row-metadata.shared.utils.d.ts.map +1 -1
- package/dist/esm/data-seeding/models/data-seed-run.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/data-seeding/models/data-seed-run.shared.schemas.d.ts.map +1 -1
- package/dist/esm/data-seeding/models/data-seed-trigger-mode-matrix.shared.utils.d.ts.map +1 -1
- package/dist/esm/data-seeding/models/data-seed.shared.schemas.d.ts.map +1 -1
- package/dist/esm/data-seeding/services/data-seed-application-bootstrap.backend.d.ts.map +1 -1
- package/dist/esm/data-seeding/services/data-seed-dispatcher.backend.service.d.ts.map +1 -1
- package/dist/esm/data-seeding/services/data-seed-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/data-seeding/services/data-seed-scope-resolver-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/data-seeding/services/engines/additive-seed-engine.backend.service.d.ts.map +1 -1
- package/dist/esm/data-seeding/services/engines/lazy-seed-engine.backend.service.d.ts.map +1 -1
- package/dist/esm/data-seeding/services/engines/manual-seed-engine.backend.service.d.ts.map +1 -1
- package/dist/esm/data-seeding/services/engines/sync-seed-engine.backend.service.d.ts.map +1 -1
- package/dist/esm/data-seeding/services/engines/upgrade-seed-engine.backend.service.d.ts.map +1 -1
- package/dist/esm/data-seeding/services/shared/data-seed-business-key.shared.utils.d.ts.map +1 -1
- package/dist/esm/data-seeding/services/shared/data-seed-error.shared.utils.d.ts.map +1 -1
- package/dist/esm/data-seeding/services/shared/data-seed-run-counters.shared.types.d.ts.map +1 -1
- package/dist/esm/data-seeding/services/shared/data-seed-run-ledger.backend.d.ts.map +1 -1
- package/dist/esm/data-seeding/services/shared/data-seed-scope-anchor.shared.types.d.ts.map +1 -1
- package/dist/esm/data-seeding/services/shared/data-seed-scope-iteration.shared.utils.d.ts.map +1 -1
- package/dist/esm/data-seeding/services/shared/data-seed-scope-resolution.backend.d.ts.map +1 -1
- package/dist/esm/databases/models/aggregation.backend.schemas.d.ts.map +1 -1
- package/dist/esm/databases/models/databases.backend.schemas.d.ts.map +1 -1
- package/dist/esm/databases/models/filter.backend.schemas.d.ts.map +1 -1
- package/dist/esm/databases/models/resolve-persistence-adapter.backend.utils.d.ts.map +1 -1
- package/dist/esm/databases/models/sql.backend.schemas.d.ts.map +1 -1
- package/dist/esm/databases/models/transaction.shared.schemas.d.ts.map +1 -1
- package/dist/esm/databases/services/__tests__/mock-mongo-transaction-registry.service.d.ts.map +1 -1
- package/dist/esm/databases/services/__tests__/mock-mongodb.service.d.ts.map +1 -1
- package/dist/esm/databases/services/__tests__/mock-mongoose-model.service.d.ts.map +1 -1
- package/dist/esm/databases/services/__tests__/mock-redis.service.d.ts.map +1 -1
- package/dist/esm/databases/services/__tests__/mock-zod-mongoose-schema-convertor.service.d.ts.map +1 -1
- package/dist/esm/databases/services/aggregation/aggregation-authorization.backend.service.d.ts.map +1 -1
- package/dist/esm/databases/services/aggregation/aggregation-query.backend.service.d.ts.map +1 -1
- package/dist/esm/databases/services/aggregation/computed-measure-evaluator.backend.service.d.ts.map +1 -1
- package/dist/esm/databases/services/aggregation/field-access-validator.backend.service.d.ts.map +1 -1
- package/dist/esm/databases/services/aggregation/time-series-densifier.backend.service.d.ts.map +1 -1
- package/dist/esm/databases/services/aggregation/topn-processor.backend.service.d.ts.map +1 -1
- package/dist/esm/databases/services/aggregation/window-function-processor.backend.service.d.ts.map +1 -1
- package/dist/esm/databases/services/db-utils.d.ts.map +1 -1
- package/dist/esm/databases/services/mongo-aggregation.backend.service.d.ts.map +1 -1
- package/dist/esm/databases/services/mongodb.service.d.ts.map +1 -1
- package/dist/esm/databases/services/postgresql-aggregation.backend.service.d.ts.map +1 -1
- package/dist/esm/databases/services/postgresql-database.backend.service.d.ts.map +1 -1
- package/dist/esm/databases/services/postgresql-development-provisioning.backend.d.ts.map +1 -1
- package/dist/esm/databases/services/postgresql-filter.backend.service.d.ts.map +1 -1
- package/dist/esm/databases/services/postgresql-migration-runner.backend.d.ts.map +1 -1
- package/dist/esm/databases/services/postgresql-schema-ddl.backend.d.ts.map +1 -1
- package/dist/esm/databases/services/postgresql-schema-migration-sql.backend.d.ts.map +1 -1
- package/dist/esm/databases/services/postgresql-schema-plan-diff.backend.d.ts.map +1 -1
- package/dist/esm/databases/services/postgresql-schema-plan-diff.backend.js.map +1 -1
- package/dist/esm/databases/services/postgresql-schema-plan-lockfile.backend.d.ts.map +1 -1
- package/dist/esm/databases/services/redis.service.d.ts.map +1 -1
- package/dist/esm/databases/services/resource-persistence-unit-of-work.backend.service.d.ts.map +1 -1
- package/dist/esm/databases/services/schema-planning-standalone.backend.d.ts.map +1 -1
- package/dist/esm/databases/services/zod-to-mongoose-schema-convertor.backend.service.d.ts.map +1 -1
- package/dist/esm/databases/services/zod-to-sql-hybrid-schema.planner.d.ts.map +1 -1
- package/dist/esm/databases/utils/postgresql-identifier.backend.utils.d.ts.map +1 -1
- package/dist/esm/errors/services/__tests__/mock-error-builder.service.d.ts.map +1 -1
- package/dist/esm/errors/services/error-builder.backend.service.d.ts.map +1 -1
- package/dist/esm/errors/services/error-builder.backend.service.js.map +1 -1
- package/dist/esm/errors/services/error-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/errors/services/error-handler.backend.service.js.map +1 -1
- package/dist/esm/errors/services/rate-limit.backend.service.d.ts.map +1 -1
- package/dist/esm/errors/services/rate-limit.backend.service.js.map +1 -1
- package/dist/esm/errors/utils/error-log-level-classification.backend.utils.d.ts.map +1 -1
- package/dist/esm/errors/utils/error-log-level-classification.backend.utils.js.map +1 -1
- package/dist/esm/errors/utils/rate-limit-environment-relaxation.backend.utils.d.ts.map +1 -1
- package/dist/esm/errors/utils/rate-limit-environment-relaxation.backend.utils.js.map +1 -1
- package/dist/esm/external-data/batches/external-data-pipeline-scheduled-run.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/external-data/controllers/external-data-admin.backend.contracts.d.ts.map +1 -1
- package/dist/esm/external-data/controllers/external-data-admin.backend.controller.d.ts.map +1 -1
- package/dist/esm/external-data/external-data-extraction-source.backend.d.ts.map +1 -1
- package/dist/esm/external-data/external-data-models.exports.d.ts.map +1 -1
- package/dist/esm/external-data/external-data-pipeline-run.backend.service.d.ts.map +1 -1
- package/dist/esm/external-data/external-data-pipeline-run.backend.service.js.map +1 -1
- package/dist/esm/external-data/external-data-transform.backend.d.ts.map +1 -1
- package/dist/esm/external-data/models/external-data-pipeline-state.backend.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/models/external-providers.backend.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/models/provider-selection-resolution-evidence.backend.definitions.d.ts.map +1 -1
- package/dist/esm/external-providers/models/provider-selection-resolution-evidence.backend.definitions.js.map +1 -1
- package/dist/esm/external-providers/operations/provider-operation-executor.backend.service.d.ts +102 -52
- package/dist/esm/external-providers/operations/provider-operation-executor.backend.service.d.ts.map +1 -1
- package/dist/esm/external-providers/operations/provider-operation-executor.backend.service.js +117 -71
- package/dist/esm/external-providers/operations/provider-operation-executor.backend.service.js.map +1 -1
- package/dist/esm/external-providers/operations/provider-operation-request.backend.d.ts.map +1 -1
- package/dist/esm/external-providers/operations/provider-operation-request.backend.js.map +1 -1
- package/dist/esm/external-providers/operations/provider-request-signing.backend.d.ts.map +1 -1
- package/dist/esm/external-providers/operations/provider-request-signing.backend.js +26 -7
- package/dist/esm/external-providers/operations/provider-request-signing.backend.js.map +1 -1
- package/dist/esm/external-providers/operations/provider-rest-call-client.backend.d.ts.map +1 -1
- package/dist/esm/external-providers/operations/provider-rest-call-client.backend.js.map +1 -1
- package/dist/esm/external-providers/services/__tests__/mock-external-providers-registry.service.d.ts.map +1 -1
- package/dist/esm/external-providers/services/__tests__/mock-external-providers-registry.service.js.map +1 -1
- package/dist/esm/external-providers/services/backend-provider-loader.backend.service.d.ts.map +1 -1
- package/dist/esm/external-providers/services/backend-provider-loader.backend.service.js.map +1 -1
- package/dist/esm/external-providers/services/backend-provider-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/external-providers/services/backend-provider-registry.backend.service.js.map +1 -1
- package/dist/esm/external-providers/services/document-extraction.backend.service.d.ts +81 -34
- package/dist/esm/external-providers/services/document-extraction.backend.service.d.ts.map +1 -1
- package/dist/esm/external-providers/services/document-extraction.backend.service.js +179 -98
- package/dist/esm/external-providers/services/document-extraction.backend.service.js.map +1 -1
- package/dist/esm/external-providers/services/embeddings.backend.service.d.ts.map +1 -1
- package/dist/esm/external-providers/services/embeddings.backend.service.js.map +1 -1
- package/dist/esm/external-providers/services/external-api-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts +121 -0
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.js +151 -0
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.js.map +1 -1
- package/dist/esm/external-providers/services/frontend-bootstrap.backend.service.d.ts +15 -1
- package/dist/esm/external-providers/services/frontend-bootstrap.backend.service.d.ts.map +1 -1
- package/dist/esm/external-providers/services/frontend-bootstrap.backend.service.js +60 -4
- package/dist/esm/external-providers/services/frontend-bootstrap.backend.service.js.map +1 -1
- package/dist/esm/features/controllers/features.backend.controller.d.ts.map +1 -1
- package/dist/esm/features/services/__tests__/mock-feature-definition-registry.service.d.ts.map +1 -1
- package/dist/esm/features/services/__tests__/mock-feature-resolution.service.d.ts.map +1 -1
- package/dist/esm/features/services/application-features-admin-write-path.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/features/services/feature-definition-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/features/services/feature-gate.backend.service.d.ts.map +1 -1
- package/dist/esm/features/services/feature-resolution.backend.service.d.ts.map +1 -1
- package/dist/esm/features/services/organization-features-admin-write-path.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/features/services/scope-feature-ledger-relationship.backend.utils.d.ts.map +1 -1
- package/dist/esm/features/services/scope-features-cache-invalidation.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/features/testing/feature-test-utils.d.ts.map +1 -1
- package/dist/esm/files/batches/files-cleanup.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/files/constraints/file-analyzers.types.d.ts.map +1 -1
- package/dist/esm/files/constraints/file-constraint-resolver-chain.backend.service.d.ts.map +1 -1
- package/dist/esm/files/constraints/file-constraint.types.d.ts.map +1 -1
- package/dist/esm/files/constraints/file-validation.backend.service.d.ts.map +1 -1
- package/dist/esm/files/constraints/resource-field-constraint-resolver.backend.service.d.ts.map +1 -1
- package/dist/esm/files/controllers/file.controller.d.ts.map +1 -1
- package/dist/esm/files/controllers/file.controller.js.map +1 -1
- package/dist/esm/files/handlers/file-upload-route-locals.backend.types.d.ts.map +1 -1
- package/dist/esm/files/handlers/file-upload-route-locals.backend.types.js.map +1 -1
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.d.ts +37 -0
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.js +221 -21
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.js.map +1 -1
- package/dist/esm/files/scanning/clamav-scanner.backend.service.d.ts.map +1 -1
- package/dist/esm/files/scanning/file-scan.types.d.ts.map +1 -1
- package/dist/esm/files/scanning/yara-scanner.backend.service.d.ts.map +1 -1
- package/dist/esm/files/scanning/yara-scanner.backend.service.js +20 -2
- package/dist/esm/files/scanning/yara-scanner.backend.service.js.map +1 -1
- package/dist/esm/files/services/__tests__/mock-file-field-detection.service.d.ts.map +1 -1
- package/dist/esm/files/services/__tests__/mock-file-operation-handler.service.d.ts.map +1 -1
- package/dist/esm/files/services/__tests__/mock-file-repository.service.d.ts.map +1 -1
- package/dist/esm/files/services/file-field-detection.backend.service.d.ts.map +1 -1
- package/dist/esm/files/services/file-operation-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/files/services/file-operation-handler.backend.service.js.map +1 -1
- package/dist/esm/files/services/file-population.backend.service.d.ts.map +1 -1
- package/dist/esm/files/services/file-scanning.backend.service.d.ts.map +1 -1
- package/dist/esm/files/services/file-scanning.backend.service.js +5 -0
- package/dist/esm/files/services/file-scanning.backend.service.js.map +1 -1
- package/dist/esm/files/services/file-text-extraction.backend.service.d.ts.map +1 -1
- package/dist/esm/files/services/file-text-extraction.backend.service.js +8 -5
- package/dist/esm/files/services/file-text-extraction.backend.service.js.map +1 -1
- package/dist/esm/files/services/file-upload-grant.backend.service.d.ts.map +1 -1
- package/dist/esm/files/services/file-upload-grant.backend.service.js.map +1 -1
- package/dist/esm/files/services/files.backend.service.d.ts.map +1 -1
- package/dist/esm/files/services/files.backend.service.js +3 -1
- package/dist/esm/files/services/files.backend.service.js.map +1 -1
- package/dist/esm/files/services/rag-source-field-detection.backend.service.d.ts.map +1 -1
- package/dist/esm/files/storage/application-storage-key.backend.utils.d.ts.map +1 -1
- package/dist/esm/files/storage/application-storage-key.backend.utils.js.map +1 -1
- package/dist/esm/files/storage/file-storage-path-resolver.backend.service.d.ts.map +1 -1
- package/dist/esm/files/storage/file-storage-provider.types.d.ts +36 -1
- package/dist/esm/files/storage/file-storage-provider.types.d.ts.map +1 -1
- package/dist/esm/files/storage/file-storage-provider.types.js.map +1 -1
- package/dist/esm/files/storage/file-storage-router.backend.service.d.ts +21 -3
- package/dist/esm/files/storage/file-storage-router.backend.service.d.ts.map +1 -1
- package/dist/esm/files/storage/file-storage-router.backend.service.js +38 -5
- package/dist/esm/files/storage/file-storage-router.backend.service.js.map +1 -1
- package/dist/esm/files/storage/google-drive-storage-provider.backend.service.d.ts +87 -0
- package/dist/esm/files/storage/google-drive-storage-provider.backend.service.d.ts.map +1 -0
- package/dist/esm/files/storage/google-drive-storage-provider.backend.service.js +340 -0
- package/dist/esm/files/storage/google-drive-storage-provider.backend.service.js.map +1 -0
- package/dist/esm/files/storage/local-directory-storage-provider.backend.service.d.ts.map +1 -1
- package/dist/esm/files/storage/local-directory-storage-provider.backend.service.js.map +1 -1
- package/dist/esm/files/storage/storage-credential-provider.backend.utils.d.ts.map +1 -1
- package/dist/esm/files/storage/storage-platform-sts-credential-resolver.backend.utils.d.ts.map +1 -1
- package/dist/esm/files/storage/storage-sts-credential-resolver.backend.utils.d.ts.map +1 -1
- package/dist/esm/files/storage/storage-sts-credential-resolver.backend.utils.js +10 -3
- package/dist/esm/files/storage/storage-sts-credential-resolver.backend.utils.js.map +1 -1
- package/dist/esm/files/storage/wildo-managed-storage-provider.backend.service.d.ts.map +1 -1
- package/dist/esm/files/storage/wildo-managed-storage-provider.backend.service.js.map +1 -1
- package/dist/esm/files/utils/file-field-schema-path.backend.utils.d.ts.map +1 -1
- package/dist/esm/files/utils/file-field-schema-path.backend.utils.js.map +1 -1
- package/dist/esm/files/utils/file-upload.utils.d.ts.map +1 -1
- package/dist/esm/files/utils/file-uploader.utils.d.ts.map +1 -1
- package/dist/esm/files/utils/file-uploader.utils.js.map +1 -1
- package/dist/esm/files/utils/file-validation.utils.d.ts.map +1 -1
- package/dist/esm/files/utils/image-derivation.backend.utils.d.ts.map +1 -1
- package/dist/esm/files/utils/image-thumbnail.backend.utils.d.ts.map +1 -1
- package/dist/esm/files/utils/office-document-text-extraction.backend.utils.d.ts.map +1 -1
- package/dist/esm/files/utils/office-document-text-extraction.backend.utils.js.map +1 -1
- package/dist/esm/files/utils/rag-source-field-schema-path.backend.utils.d.ts.map +1 -1
- package/dist/esm/files/utils/storage-application-identity.backend.utils.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a/batches/a2a-abandoned-task-sweep.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a/batches/a2a-abandoned-task-sweep.batch.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/a2a/batches/a2a-push-delivery.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a/controllers/a2a.controller.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a/controllers/a2a.controller.js.map +1 -1
- package/dist/esm/flows-actors/a2a/models/a2a-dialect.backend.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a/models/a2a-push-notification-delivery.backend.utils.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a/models/a2a-push-notification.backend.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a/models/a2a.backend.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a/models/a2a.backend.schemas.js.map +1 -1
- package/dist/esm/flows-actors/a2a/services/a2a-push-delivery-log.repository.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a/services/a2a-push-dispatcher.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a/services/a2a-task-cancellation.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a/services/a2a-task-cancellation.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/a2a/services/a2a-task.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a/services/a2a-task.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/a2a/services/a2a-token-budget.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a/services/a2a-token-budget.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/a2a/services/a2a.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a/services/a2a.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/controllers/flows-actors.controller.d.ts.map +1 -1
- package/dist/esm/flows-actors/models/agent-catalogs.backend.definitions.d.ts.map +1 -1
- package/dist/esm/flows-actors/models/agent-catalogs.backend.definitions.js.map +1 -1
- package/dist/esm/flows-actors/models/agent-facets.backend.definitions.d.ts.map +1 -1
- package/dist/esm/flows-actors/models/agents.backend.definitions.d.ts.map +1 -1
- package/dist/esm/flows-actors/models/core-facets.backend.definitions.d.ts.map +1 -1
- package/dist/esm/flows-actors/models/core-facets.backend.definitions.js.map +1 -1
- package/dist/esm/flows-actors/models/flows-actors.backend.definitions.d.ts.map +1 -1
- package/dist/esm/flows-actors/models/flows-actors.backend.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/models/flows-actors.backend.schemas.js.map +1 -1
- package/dist/esm/flows-actors/models/function-tools.backend.definitions.d.ts +107 -16
- package/dist/esm/flows-actors/models/function-tools.backend.definitions.d.ts.map +1 -1
- package/dist/esm/flows-actors/models/function-tools.backend.definitions.js +118 -18
- package/dist/esm/flows-actors/models/function-tools.backend.definitions.js.map +1 -1
- package/dist/esm/flows-actors/models/market-generation.actors-system.backend.definitions.d.ts.map +1 -1
- package/dist/esm/flows-actors/models/market-generation.actors-system.backend.definitions.js.map +1 -1
- package/dist/esm/flows-actors/models/mcp-client.backend.definitions.d.ts.map +1 -1
- package/dist/esm/flows-actors/models/mcp-client.backend.definitions.js.map +1 -1
- package/dist/esm/flows-actors/services/__tests__/fixtures/meta-workflow-evaluation-treatment.test-fixture.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/actors-system.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/actors-system.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/services/agent-call-trace-sink.backend.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/agent-facets.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/agents.backend.service.d.ts +104 -5
- package/dist/esm/flows-actors/services/agents.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/agents.backend.service.js +263 -31
- package/dist/esm/flows-actors/services/agents.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/services/context-curation.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/conversational-execution.backend.service.d.ts +46 -1
- package/dist/esm/flows-actors/services/conversational-execution.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/conversational-execution.backend.service.js +193 -6
- package/dist/esm/flows-actors/services/conversational-execution.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/services/flows-actors-registry.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/flows-actors-registry.service.js.map +1 -1
- package/dist/esm/flows-actors/services/flows.backend.services.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/flows.backend.services.js.map +1 -1
- package/dist/esm/flows-actors/services/llm-observability-agent-call-trace-sink.backend.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/llm-observability-agent-call-trace-sink.backend.js.map +1 -1
- package/dist/esm/flows-actors/services/mcp-client.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/mcp-client.backend.service.js +3 -0
- package/dist/esm/flows-actors/services/mcp-client.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/services/mcp-credential-resolver.backend.service.d.ts +99 -0
- package/dist/esm/flows-actors/services/mcp-credential-resolver.backend.service.d.ts.map +1 -0
- package/dist/esm/flows-actors/services/mcp-credential-resolver.backend.service.js +155 -0
- package/dist/esm/flows-actors/services/mcp-credential-resolver.backend.service.js.map +1 -0
- package/dist/esm/flows-actors/services/meta-workflow-evaluation-treatment-compiler.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/meta-workflow-standard-action-contracts.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/meta-workflow-standard-evaluation-contracts.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/meta-workflow-structured-artifact-action-compiler.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/prompt-compiler.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/prompt-compiler.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.d.ts.map +1 -1
- package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.js +9 -0
- package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.js.map +1 -1
- package/dist/esm/flows-actors/utils/bounded-subprocess.backend.utils.d.ts.map +1 -1
- package/dist/esm/flows-actors/utils/flows-actors-frontend-extractor.utils.d.ts.map +1 -1
- package/dist/esm/flows-actors/utils/meta-workflow-canonical-json.backend.utils.d.ts.map +1 -1
- package/dist/esm/flows-actors/utils/meta-workflow-canonical-json.backend.utils.js.map +1 -1
- package/dist/esm/flows-actors/utils/meta-workflow-structured-generation-plan.backend.utils.d.ts.map +1 -1
- package/dist/esm/flows-actors/utils/meta-workflow-structured-generation-plan.backend.utils.js.map +1 -1
- package/dist/esm/flows-actors/utils/prompt-ir-adapters.backend.utils.d.ts.map +1 -1
- package/dist/esm/flows-actors/utils/tool-approval-modification.backend.utils.d.ts +77 -0
- package/dist/esm/flows-actors/utils/tool-approval-modification.backend.utils.d.ts.map +1 -0
- package/dist/esm/flows-actors/utils/tool-approval-modification.backend.utils.js +164 -0
- package/dist/esm/flows-actors/utils/tool-approval-modification.backend.utils.js.map +1 -0
- package/dist/esm/flows-actors/utils/tool-approval-signing.backend.utils.d.ts +48 -0
- package/dist/esm/flows-actors/utils/tool-approval-signing.backend.utils.d.ts.map +1 -0
- package/dist/esm/flows-actors/utils/tool-approval-signing.backend.utils.js +101 -0
- package/dist/esm/flows-actors/utils/tool-approval-signing.backend.utils.js.map +1 -0
- package/dist/esm/guidance/batches/dormancy-detection.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/guidance/services/guidance-trigger-evaluator.backend.service.d.ts.map +1 -1
- package/dist/esm/guidance/services/lifecycle-custom-implementations.backend.d.ts.map +1 -1
- package/dist/esm/guidance/services/lifecycle-evaluator.backend.service.d.ts.map +1 -1
- package/dist/esm/guidance/services/lifecycle-scope-id.backend.utils.d.ts.map +1 -1
- package/dist/esm/guidance/services/milestone-condition-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/guidance/services/milestone-definition-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/guidance/services/milestone-evaluator.backend.service.d.ts.map +1 -1
- package/dist/esm/guidance/services/milestone-evaluator.backend.service.js.map +1 -1
- package/dist/esm/guidance/services/progression-state-store.backend.service.d.ts.map +1 -1
- package/dist/esm/guidance/services/progression-state-store.backend.service.js.map +1 -1
- package/dist/esm/guidance/services/scoped-state-read-custom-implementations.backend.d.ts.map +1 -1
- package/dist/esm/i18n/controllers/i18n-controller.backend.service.d.ts.map +1 -1
- package/dist/esm/i18n/controllers/i18n-controller.backend.service.js.map +1 -1
- package/dist/esm/i18n/services/i18n.backend.service.d.ts.map +1 -1
- package/dist/esm/index.d.ts +0 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +0 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/inject/models/container.d.ts +10 -0
- package/dist/esm/inject/models/container.d.ts.map +1 -1
- package/dist/esm/inject/models/container.js +49 -1
- package/dist/esm/inject/models/container.js.map +1 -1
- package/dist/esm/inject/models/service-types.d.ts +3 -0
- package/dist/esm/inject/models/service-types.d.ts.map +1 -1
- package/dist/esm/inject/models/service-types.js +3 -0
- package/dist/esm/inject/models/service-types.js.map +1 -1
- package/dist/esm/mcp/controllers/mcp.controller.d.ts.map +1 -1
- package/dist/esm/mcp/controllers/mcp.controller.js +50 -3
- package/dist/esm/mcp/controllers/mcp.controller.js.map +1 -1
- package/dist/esm/mcp/models/mcp-protocol.backend.schemas.d.ts.map +1 -1
- package/dist/esm/mcp/models/mcp-tool.backend.schemas.d.ts.map +1 -1
- package/dist/esm/mcp/models/mcp-tool.backend.schemas.js.map +1 -1
- package/dist/esm/mcp/services/mcp-server.backend.service.d.ts.map +1 -1
- package/dist/esm/mcp/services/mcp-server.backend.service.js.map +1 -1
- package/dist/esm/mcp/services/mcp-tool-adapter.backend.service.d.ts.map +1 -1
- package/dist/esm/mcp/services/mcp-tool-adapter.backend.service.js.map +1 -1
- package/dist/esm/mcp/services/resource-server-instances-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/mcp/utils/zod-to-mcp-json-schema.backend.utils.d.ts.map +1 -1
- package/dist/esm/meta-workflow-runtime.exports.d.ts.map +1 -1
- package/dist/esm/monitoring/analytics/controllers/analytics.backend.controller.d.ts.map +1 -1
- package/dist/esm/monitoring/analytics/controllers/analytics.backend.controller.js.map +1 -1
- package/dist/esm/monitoring/analytics/services/value-moment-definition-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/monitoring/analytics/services/value-moment-definition-registry.backend.service.js.map +1 -1
- package/dist/esm/monitoring/analytics/services/value-moment-engine.backend.service.d.ts.map +1 -1
- package/dist/esm/monitoring/analytics/services/value-moment-engine.backend.service.js.map +1 -1
- package/dist/esm/monitoring/analytics/services/value-moment-handler-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/monitoring/analytics/services/value-moment-handler-registry.backend.service.js.map +1 -1
- package/dist/esm/monitoring/logger/models/logger.backend.schemas.d.ts.map +1 -1
- package/dist/esm/monitoring/logger/models/logger.backend.schemas.js.map +1 -1
- package/dist/esm/monitoring/logger/services/__tests__/mock-logger.service.d.ts.map +1 -1
- package/dist/esm/monitoring/logger/services/logger.service.d.ts +12 -0
- package/dist/esm/monitoring/logger/services/logger.service.d.ts.map +1 -1
- package/dist/esm/monitoring/logger/services/logger.service.js +3 -3
- package/dist/esm/monitoring/logger/services/logger.service.js.map +1 -1
- package/dist/esm/monitoring/logger/utils/log-severity-floor.backend.utils.d.ts.map +1 -1
- package/dist/esm/monitoring/logger/utils/log-severity-floor.backend.utils.js.map +1 -1
- package/dist/esm/monitoring/logger/utils/log-value-normalization.backend.utils.d.ts.map +1 -1
- package/dist/esm/monitoring/observability/audit-observation-emission.backend.d.ts +10 -6
- package/dist/esm/monitoring/observability/audit-observation-emission.backend.d.ts.map +1 -1
- package/dist/esm/monitoring/observability/audit-observation-emission.backend.js +10 -6
- package/dist/esm/monitoring/observability/audit-observation-emission.backend.js.map +1 -1
- package/dist/esm/monitoring/observability/models/observability.backend.schemas.d.ts.map +1 -1
- package/dist/esm/monitoring/observability/models/observability.backend.schemas.js.map +1 -1
- package/dist/esm/monitoring/observability/otel-preload.d.ts.map +1 -1
- package/dist/esm/monitoring/observability/otel-sdk-global-handle.d.ts.map +1 -1
- package/dist/esm/monitoring/observability/services/__tests__/mock-metrics.service.d.ts.map +1 -1
- package/dist/esm/monitoring/observability/services/metrics.service.d.ts.map +1 -1
- package/dist/esm/monitoring/observability/services/metrics.service.js.map +1 -1
- package/dist/esm/monitoring/observability/services/observability.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/email/components/email-components.d.ts.map +1 -1
- package/dist/esm/notifications/email/models/email-template-definition.d.ts.map +1 -1
- package/dist/esm/notifications/email/models/email-transport.backend.definitions.d.ts.map +1 -1
- package/dist/esm/notifications/email/services/email-batch-send.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/email/services/email-template-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/email/services/email-template-registry.backend.service.js.map +1 -1
- package/dist/esm/notifications/email/services/email-template-validator.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/email/services/email-template-validator.backend.service.js.map +1 -1
- package/dist/esm/notifications/email/services/email.backend.service.d.ts +47 -6
- package/dist/esm/notifications/email/services/email.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/email/services/email.backend.service.js +86 -36
- package/dist/esm/notifications/email/services/email.backend.service.js.map +1 -1
- package/dist/esm/notifications/email/utils/color-conversion.utils.d.ts.map +1 -1
- package/dist/esm/notifications/email/utils/color-conversion.utils.js.map +1 -1
- package/dist/esm/notifications/email/utils/interpolate-email-label.utils.d.ts.map +1 -1
- package/dist/esm/notifications/email/utils/zod-to-typescript.utils.d.ts.map +1 -1
- package/dist/esm/notifications/services/notification-badge.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/services/notification-badge.backend.service.js.map +1 -1
- package/dist/esm/notifications/services/notifications-dispatcher.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/services/notifications-dispatcher.backend.service.js.map +1 -1
- package/dist/esm/notifications/sms/models/sms-transport.backend.definitions.d.ts +32 -0
- package/dist/esm/notifications/sms/models/sms-transport.backend.definitions.d.ts.map +1 -0
- package/dist/esm/notifications/sms/models/sms-transport.backend.definitions.js +32 -0
- package/dist/esm/notifications/sms/models/sms-transport.backend.definitions.js.map +1 -0
- package/dist/esm/notifications/sms/services/sms.backend.service.d.ts +64 -10
- package/dist/esm/notifications/sms/services/sms.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/sms/services/sms.backend.service.js +277 -82
- package/dist/esm/notifications/sms/services/sms.backend.service.js.map +1 -1
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.js.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.backend.service.js.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.utils.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.js.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/services/m2m-webhook-delivery-log.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/services/m2m-webhook-delivery-log.repository.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/services/m2m-webhook-dispatcher.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/services/webhook-config-public-key.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/services/webhook-config-test-endpoint.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/services/webhook-config-test-endpoint.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/services/webhook-config.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/services/polymorphic-lookup.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/services/webhook-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/services/webhook-handler.backend.service.js.map +1 -1
- package/dist/esm/organizations/batches/organization-member-invitation-sweep.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/organizations/batches/organization-purge.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/organizations/batches/organization-purge.batch.backend.service.js.map +1 -1
- package/dist/esm/organizations/services/authority-change-audit.backend.utils.d.ts.map +1 -1
- package/dist/esm/organizations/services/invitation-acceptance.backend.utils.d.ts.map +1 -1
- package/dist/esm/organizations/services/org-creation-on-registration.backend.utils.d.ts.map +1 -1
- package/dist/esm/organizations/services/org-member-roles-validation.backend.utils.d.ts.map +1 -1
- package/dist/esm/organizations/services/organization-custom-implementation.backend.service.d.ts.map +1 -1
- package/dist/esm/organizations/services/organization-custom-implementation.backend.service.js.map +1 -1
- package/dist/esm/organizations/services/organization-deletion-audit.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/organizations/services/organization-member-custom-implementation.backend.service.d.ts.map +1 -1
- package/dist/esm/organizations/services/organization-onboarding-operation.backend.utils.d.ts.map +1 -1
- package/dist/esm/organizations/services/organization-unit-custom-implementation.backend.service.d.ts.map +1 -1
- package/dist/esm/organizations/services/organization-unit-member-custom-implementation.backend.service.d.ts.map +1 -1
- package/dist/esm/organizations/services/scim-provisioning-gate.backend.utils.d.ts.map +1 -1
- package/dist/esm/organizations/services/user-org-type-grant.backend.utils.d.ts.map +1 -1
- package/dist/esm/organizations/services/user-type-revocation-on-org-leave.backend.utils.d.ts.map +1 -1
- package/dist/esm/pdf-templates/__tests__/fixtures/tiny-pdf-template.fixture.d.ts.map +1 -1
- package/dist/esm/pdf-templates/models/pdf-template-binding.d.ts.map +1 -1
- package/dist/esm/pdf-templates/models/pdf-template-definition.d.ts.map +1 -1
- package/dist/esm/pdf-templates/services/pdf-generated-file-writer.backend.service.d.ts.map +1 -1
- package/dist/esm/pdf-templates/services/pdf-generation-orchestrator.backend.service.d.ts.map +1 -1
- package/dist/esm/pdf-templates/services/pdf-renderer.backend.service.d.ts.map +1 -1
- package/dist/esm/pdf-templates/services/pdf-template-binding.backend.service.d.ts.map +1 -1
- package/dist/esm/queue/adapters/in-memory-queue-adapter.backend.service.d.ts.map +1 -1
- package/dist/esm/queue/adapters/in-memory-queue-adapter.backend.service.js.map +1 -1
- package/dist/esm/queue/adapters/queue-adapter.backend.binding.d.ts.map +1 -1
- package/dist/esm/queue/adapters/queue-adapter.backend.binding.js.map +1 -1
- package/dist/esm/queue/adapters/queue-adapter.backend.interface.d.ts.map +1 -1
- package/dist/esm/queue/adapters/queue-adapter.backend.interface.js.map +1 -1
- package/dist/esm/queue/adapters/queue-adapter.backend.options.d.ts.map +1 -1
- package/dist/esm/queue/adapters/queue-adapter.backend.options.js.map +1 -1
- package/dist/esm/queue/adapters/rabbitmq-adapter.backend.service.d.ts.map +1 -1
- package/dist/esm/queue/adapters/rabbitmq-adapter.backend.service.js.map +1 -1
- package/dist/esm/queue/apps-crontabs-manager.backend.service.d.ts.map +1 -1
- package/dist/esm/queue/cron-job-sync.backend.service.d.ts.map +1 -1
- package/dist/esm/queue/domain-queue-consumer.backend.service.d.ts.map +1 -1
- package/dist/esm/queue/domain-queue-consumer.backend.service.js.map +1 -1
- package/dist/esm/queue/job-completion-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/queue/job-consumer.backend.service.d.ts.map +1 -1
- package/dist/esm/queue/job-consumer.backend.service.js.map +1 -1
- package/dist/esm/queue/job-executor.backend.service.d.ts.map +1 -1
- package/dist/esm/queue/job-executor.backend.service.js.map +1 -1
- package/dist/esm/queue/job-payload-storage.backend.service.d.ts.map +1 -1
- package/dist/esm/queue/job-status-tracking.backend.service.d.ts.map +1 -1
- package/dist/esm/queue/queue-monitoring.backend.service.d.ts.map +1 -1
- package/dist/esm/queue/queue-monitoring.backend.service.js.map +1 -1
- package/dist/esm/queue/queue-worker-initializer.backend.service.d.ts.map +1 -1
- package/dist/esm/queue/queue-worker-initializer.backend.service.js.map +1 -1
- package/dist/esm/queue/queue.backend.service.d.ts.map +1 -1
- package/dist/esm/queue/queue.backend.service.js.map +1 -1
- package/dist/esm/queue/scheduled-message-verifier.backend.service.d.ts.map +1 -1
- package/dist/esm/queue/worker-shutdown-manager.backend.service.d.ts.map +1 -1
- package/dist/esm/queue/worker-shutdown-manager.backend.service.js.map +1 -1
- package/dist/esm/rag/batches/rag-embedding-drain.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/rag/batches/rag-reconciliation-sweep.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/rag/models/rag-chunk-store.backend.types.d.ts.map +1 -1
- package/dist/esm/rag/models/rag-retrieval.backend.types.d.ts.map +1 -1
- package/dist/esm/rag/services/mongodb-rag-chunk-store.backend.service.d.ts.map +1 -1
- package/dist/esm/rag/services/postgresql-rag-chunk-store.backend.service.d.ts.map +1 -1
- package/dist/esm/rag/services/rag-chunk-collection.mongodb-ddl.backend.d.ts.map +1 -1
- package/dist/esm/rag/services/rag-chunk-retrieval.mongodb-query.backend.d.ts.map +1 -1
- package/dist/esm/rag/services/rag-chunk-retrieval.postgresql-query.backend.d.ts.map +1 -1
- package/dist/esm/rag/services/rag-chunk-store.backend.service.d.ts.map +1 -1
- package/dist/esm/rag/services/rag-chunk-table.postgresql-ddl.backend.d.ts.map +1 -1
- package/dist/esm/rag/services/rag-ingestion.backend.service.d.ts.map +1 -1
- package/dist/esm/rag/services/rag-retrieval.backend.service.d.ts.map +1 -1
- package/dist/esm/rag/utils/rag-chunk-fusion.backend.utils.d.ts.map +1 -1
- package/dist/esm/rag/utils/rag-chunk-removal.backend.utils.d.ts.map +1 -1
- package/dist/esm/rag/utils/rag-chunk-row-shaping.backend.utils.d.ts.map +1 -1
- package/dist/esm/rag/utils/rag-chunking.backend.utils.d.ts.map +1 -1
- package/dist/esm/rag/utils/rag-chunking.backend.utils.js.map +1 -1
- package/dist/esm/rag/utils/rag-context-assembly.backend.utils.d.ts.map +1 -1
- package/dist/esm/rag/utils/rag-context-assembly.backend.utils.js.map +1 -1
- package/dist/esm/rag/utils/rag-ingestion-trigger.backend.utils.d.ts.map +1 -1
- package/dist/esm/rag/utils/rag-retrieval-scope.backend.utils.d.ts.map +1 -1
- package/dist/esm/rag/utils/rag-source-field-value.backend.utils.d.ts.map +1 -1
- package/dist/esm/requests/models/api-routes.backend.defintions.d.ts.map +1 -1
- package/dist/esm/requests/models/requests.backend.schemas.d.ts.map +1 -1
- package/dist/esm/requests/service/platform-mutualized-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/requests/service/platform-requests.backend.utils.d.ts.map +1 -1
- package/dist/esm/requests/service/remote-client-base.backend.service.d.ts.map +1 -1
- package/dist/esm/requests/service/serverless-services-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/requests/service/websocket.service.d.ts.map +1 -1
- package/dist/esm/requests/service/websocket.service.js +49 -1
- package/dist/esm/requests/service/websocket.service.js.map +1 -1
- package/dist/esm/resources/backend-resource-registry.exports.d.ts.map +1 -1
- package/dist/esm/resources/models/custom-service-implementations.backend.definition.d.ts.map +1 -1
- package/dist/esm/resources/models/custom-service-implementations.backend.definition.js +2 -0
- package/dist/esm/resources/models/custom-service-implementations.backend.definition.js.map +1 -1
- package/dist/esm/resources/models/index.d.ts.map +1 -1
- package/dist/esm/resources/models/resources-operations.backend.definitions.d.ts.map +1 -1
- package/dist/esm/resources/models/resources-operations.backend.definitions.js.map +1 -1
- package/dist/esm/resources/models/resources-relationships.backend.definitions.d.ts.map +1 -1
- package/dist/esm/resources/models/resources-relationships.backend.definitions.js.map +1 -1
- package/dist/esm/resources/models/resources-types.backend.schemas.d.ts.map +1 -1
- package/dist/esm/resources/models/resources-types.backend.schemas.js.map +1 -1
- package/dist/esm/resources/models/resources.backend.schemas.d.ts.map +1 -1
- package/dist/esm/resources/models/virtual-fields.backend.types.d.ts.map +1 -1
- package/dist/esm/resources/services/__tests__/mock-resources-registry.service.d.ts.map +1 -1
- package/dist/esm/resources/services/resource-context.backend.service.d.ts.map +1 -1
- package/dist/esm/resources/services/resource-id.backend.service.d.ts.map +1 -1
- package/dist/esm/resources/services/resource-population.backend.service.d.ts +17 -2
- package/dist/esm/resources/services/resource-population.backend.service.d.ts.map +1 -1
- package/dist/esm/resources/services/resource-population.backend.service.js +74 -18
- package/dist/esm/resources/services/resource-population.backend.service.js.map +1 -1
- package/dist/esm/resources/services/resources-registry.backend.service.d.ts +23 -0
- package/dist/esm/resources/services/resources-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/resources/services/resources-registry.backend.service.js +31 -0
- package/dist/esm/resources/services/resources-registry.backend.service.js.map +1 -1
- package/dist/esm/resources/services/virtual-fields.backend.service.d.ts.map +1 -1
- package/dist/esm/resources/utils/resource-retention.backend.utils.d.ts.map +1 -1
- package/dist/esm/runtime/controllers/health-controller.backend.service.d.ts.map +1 -1
- package/dist/esm/runtime/controllers/health-controller.backend.service.js.map +1 -1
- package/dist/esm/runtime/domain-module.backend.definitions.d.ts.map +1 -1
- package/dist/esm/runtime/domain-module.backend.definitions.js.map +1 -1
- package/dist/esm/runtime/models/execution-context.backend.schemas.d.ts.map +1 -1
- package/dist/esm/runtime/models/request-context.als.backend.d.ts.map +1 -1
- package/dist/esm/runtime/models/runtime.backend.schemas.d.ts.map +1 -1
- package/dist/esm/runtime/services/execution-context-creator.backend.service.d.ts.map +1 -1
- package/dist/esm/runtime/services/execution-context-creator.backend.service.js.map +1 -1
- package/dist/esm/runtime/services/execution-context-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/runtime/services/health-readiness-contributor.backend.interface.d.ts.map +1 -1
- package/dist/esm/runtime/services/health-readiness-contributor.backend.interface.js.map +1 -1
- package/dist/esm/runtime/services/http-server.backend.service.d.ts.map +1 -1
- package/dist/esm/runtime/services/http-server.backend.service.js +10 -0
- package/dist/esm/runtime/services/http-server.backend.service.js.map +1 -1
- package/dist/esm/runtime/services/start-application.backend.service.d.ts.map +1 -1
- package/dist/esm/runtime/services/start-application.backend.service.js +26 -12
- package/dist/esm/runtime/services/start-application.backend.service.js.map +1 -1
- package/dist/esm/runtime/services/utils/oauth-body-cap.backend.utils.d.ts.map +1 -1
- package/dist/esm/runtime/testing/execution-context-test-fixtures.d.ts.map +1 -1
- package/dist/esm/runtime/testing/mock-execution-context-creator.service.d.ts.map +1 -1
- package/dist/esm/runtime/utils/application-startup-config-access.backend.utils.d.ts.map +1 -1
- package/dist/esm/runtime/utils/feature-gated-core-resource-exclusions.backend.utils.d.ts.map +1 -1
- package/dist/esm/runtime/utils/request-client-ip.utils.d.ts.map +1 -1
- package/dist/esm/runtime/utils/scan-default-exports.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/api-keys/api-key-generation.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/api-keys/api-keys.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/security/api-keys/api-keys.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/batches/anonymous-session-cleanup.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/batches/anonymous-session-cleanup.batch.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/controllers/auth-method-management-controller.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/controllers/authentication-controller.backend.service.d.ts +22 -0
- package/dist/esm/security/authentications/controllers/authentication-controller.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/controllers/authentication-controller.backend.service.js +84 -0
- package/dist/esm/security/authentications/controllers/authentication-controller.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/controllers/oauth-provider-controller.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/controllers/oauth-provider-controller.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/models/auth-constants.backend.d.ts.map +1 -1
- package/dist/esm/security/authentications/models/authentications.backend.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/models/authorization-client.backend.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/models/cimd.backend.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/models/cimd.backend.schemas.js.map +1 -1
- package/dist/esm/security/authentications/models/federated-auth-transport.backend.definitions.d.ts +37 -0
- package/dist/esm/security/authentications/models/federated-auth-transport.backend.definitions.d.ts.map +1 -0
- package/dist/esm/security/authentications/models/federated-auth-transport.backend.definitions.js +37 -0
- package/dist/esm/security/authentications/models/federated-auth-transport.backend.definitions.js.map +1 -0
- package/dist/esm/security/authentications/models/identity-persistence-boundaries.backend.d.ts.map +1 -1
- package/dist/esm/security/authentications/models/jwt.backend.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/models/oauth2-connection.backend.schemas.d.ts +15 -0
- package/dist/esm/security/authentications/models/oauth2-connection.backend.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/models/oauth2-connection.backend.schemas.js.map +1 -1
- package/dist/esm/security/authentications/models/saml-authentication.backend.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/models/sso-connection.backend.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/models/user-authorization-version.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authentications/seeds/enterprise-config-defaults.seeds.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/__tests__/mock-auth-execution-context-factory.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/__tests__/mock-auth-token-issuer.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/__tests__/oauth-provider-audit-spies.mock.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-domain-to-org-lookup.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-enterprise-user-provisioning.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/admin-config/auth-organization-configuration.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/admin-config/auth-organization-configuration.service.js.map +1 -1
- package/dist/esm/security/authentications/services/admin-config/domain-to-org-lookup.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/admin-config/domain-to-org-lookup.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/admin-config/domain-verification.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/admin-config/domain-verification.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/admin-config/enterprise-user-provisioning.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/admin-config/enterprise-user-provisioning.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/admin-config/oidc-discovery.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/admin-config/oidc-discovery.backend.service.js +2 -1
- package/dist/esm/security/authentications/services/admin-config/oidc-discovery.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/anonymous-session.backend.service.d.ts +9 -2
- package/dist/esm/security/authentications/services/anonymous-session.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/anonymous-session.backend.service.js +9 -2
- package/dist/esm/security/authentications/services/anonymous-session.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/auth-credential-verifier.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-execution-context-factory.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-mfa.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-phone-verification.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-registration.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-registration.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/oauth2-authentication.backend.service.d.ts +97 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-authentication.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/oauth2-authentication.backend.service.js +218 -26
- package/dist/esm/security/authentications/services/auth-methods/oauth2-authentication.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service.d.ts +14 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service.js +36 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/saml-assertion-validator.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/saml-authentication.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/saml-metadata.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/saml-replay-guard.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/webauthn.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/webauthn.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/auth-session-store.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/authentication-orchestrator.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/authentication-orchestrator.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/cimd-client-metadata.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/cimd-client-metadata.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/auth-custom-implementations.backend.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/auth-custom-implementations.backend.js.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/scim-tokens.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.js +57 -1
- package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/sso-config.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/sso-config.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/sso-connection.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/sso-connection.custom-impl.backend.service.js +11 -1
- package/dist/esm/security/authentications/services/custom-impls/sso-connection.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/email-verification-initiator.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/machine-token-issuer.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/oauth-provider-token.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/oauth-provider-token.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/oidc-authorization-code.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/oidc-authorization-code.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/oidc-user-claims.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/resolve-active-member-orgs.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/utils/__tests__/mock-auth-user-lookup.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/utils/auth-controller.utils.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/utils/auth-credential-ops.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/utils/auth-policy-resolution.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/utils/auth-policy-resolution.backend.utils.js.map +1 -1
- package/dist/esm/security/authentications/services/utils/auth-response-helper.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/utils/auth-user-lookup.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/utils/auth-user-lookup.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/utils/concurrent-session-eviction.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/utils/ensure-user-profile.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/utils/external-turn-rate-limit.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/utils/external-turn-rate-limit.backend.utils.js.map +1 -1
- package/dist/esm/security/authentications/services/utils/machine-auth-rate-limit.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/utils/pkce.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/utils/saml-java-availability.d.ts.map +1 -1
- package/dist/esm/security/authentications/utils/application-auth-policy-audit.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authentications/utils/enterprise-sso-enforcement.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authentications/utils/enterprise-sso-enforcement.backend.utils.js.map +1 -1
- package/dist/esm/security/authentications/utils/one-off-session-lifetime.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authentications/utils/social-oauth2-purpose.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authorizations/access-grant-decision.factory.backend.d.ts +59 -0
- package/dist/esm/security/authorizations/access-grant-decision.factory.backend.d.ts.map +1 -0
- package/dist/esm/security/authorizations/access-grant-decision.factory.backend.js +111 -0
- package/dist/esm/security/authorizations/access-grant-decision.factory.backend.js.map +1 -0
- package/dist/esm/security/authorizations/access-grant-lifecycle-audit.backend.d.ts +57 -0
- package/dist/esm/security/authorizations/access-grant-lifecycle-audit.backend.d.ts.map +1 -0
- package/dist/esm/security/authorizations/access-grant-lifecycle-audit.backend.js +133 -0
- package/dist/esm/security/authorizations/access-grant-lifecycle-audit.backend.js.map +1 -0
- package/dist/esm/security/authorizations/application-access-grant-custom-implementation.backend.service.d.ts +41 -0
- package/dist/esm/security/authorizations/application-access-grant-custom-implementation.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authorizations/application-access-grant-custom-implementation.backend.service.js +157 -0
- package/dist/esm/security/authorizations/application-access-grant-custom-implementation.backend.service.js.map +1 -0
- package/dist/esm/security/authorizations/application-wide-read-admission.backend.d.ts +84 -0
- package/dist/esm/security/authorizations/application-wide-read-admission.backend.d.ts.map +1 -0
- package/dist/esm/security/authorizations/application-wide-read-admission.backend.js +99 -0
- package/dist/esm/security/authorizations/application-wide-read-admission.backend.js.map +1 -0
- package/dist/esm/security/authorizations/authorization-denial-audit.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authorizations/cross-tenant-read-observation.backend.d.ts.map +1 -1
- package/dist/esm/security/authorizations/cross-tenant-read-observation.backend.js.map +1 -1
- package/dist/esm/security/authorizations/initiator-organization-confinement.backend.d.ts.map +1 -1
- package/dist/esm/security/authorizations/junction-scope-resolution.backend.d.ts.map +1 -1
- package/dist/esm/security/authorizations/organization-owner-floor.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authorizations/organization-owner-floor.backend.utils.js.map +1 -1
- package/dist/esm/security/authorizations/organization-unit-narrowing-enforcement.backend.d.ts.map +1 -1
- package/dist/esm/security/authorizations/platform-access-grant-custom-implementation.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authorizations/platform-access-grant-custom-implementation.backend.service.js +20 -181
- package/dist/esm/security/authorizations/platform-access-grant-custom-implementation.backend.service.js.map +1 -1
- package/dist/esm/security/authorizations/privileged-access-review.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authorizations/relationship-foreign-key-filter.backend.d.ts.map +1 -1
- package/dist/esm/security/authorizations/role-ceiling.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authorizations/role-ceiling.backend.utils.js.map +1 -1
- package/dist/esm/security/authorizations/role-conferral.backend.utils.d.ts +40 -0
- package/dist/esm/security/authorizations/role-conferral.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authorizations/role-conferral.backend.utils.js +43 -1
- package/dist/esm/security/authorizations/role-conferral.backend.utils.js.map +1 -1
- package/dist/esm/security/authorizations/scope-root-collection-confinement.backend.d.ts +27 -17
- package/dist/esm/security/authorizations/scope-root-collection-confinement.backend.d.ts.map +1 -1
- package/dist/esm/security/authorizations/scope-root-collection-confinement.backend.js +27 -17
- package/dist/esm/security/authorizations/scope-root-collection-confinement.backend.js.map +1 -1
- package/dist/esm/security/authorizations/services/authorizations.backend.service.d.ts +72 -0
- package/dist/esm/security/authorizations/services/authorizations.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authorizations/services/authorizations.backend.service.js +153 -10
- package/dist/esm/security/authorizations/services/authorizations.backend.service.js.map +1 -1
- package/dist/esm/security/authorizations/super-admin-floor.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authorizations/super-admin-floor.backend.utils.js.map +1 -1
- package/dist/esm/security/connected-accounts/connection-target-authorization.backend.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/connection-target-authorization.backend.js.map +1 -1
- package/dist/esm/security/connected-accounts/controllers/provider-connection.controller.backend.service.d.ts +139 -1
- package/dist/esm/security/connected-accounts/controllers/provider-connection.controller.backend.service.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/controllers/provider-connection.controller.backend.service.js +474 -33
- package/dist/esm/security/connected-accounts/controllers/provider-connection.controller.backend.service.js.map +1 -1
- package/dist/esm/security/connected-accounts/organization-provider-credential-resolver.port.d.ts +40 -0
- package/dist/esm/security/connected-accounts/organization-provider-credential-resolver.port.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/organization-provider-credential-resolver.port.js.map +1 -1
- package/dist/esm/security/connected-accounts/provider-oauth2-refresher.port.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/provider-oauth2-refresher.port.js.map +1 -1
- package/dist/esm/security/connected-accounts/services/organization-provider-credential-store.backend.service.d.ts +19 -0
- package/dist/esm/security/connected-accounts/services/organization-provider-credential-store.backend.service.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/services/organization-provider-credential-store.backend.service.js +38 -0
- package/dist/esm/security/connected-accounts/services/organization-provider-credential-store.backend.service.js.map +1 -1
- package/dist/esm/security/connected-accounts/services/organization-provider-credentials.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/services/organization-provider-credentials.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/security/connected-accounts/services/provider-oauth2-exchange.backend.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/services/provider-oauth2-exchange.backend.js +17 -1
- package/dist/esm/security/connected-accounts/services/provider-oauth2-exchange.backend.js.map +1 -1
- package/dist/esm/security/connected-accounts/services/provider-oauth2-pending-authorization.backend.service.d.ts +14 -0
- package/dist/esm/security/connected-accounts/services/provider-oauth2-pending-authorization.backend.service.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/services/provider-oauth2-pending-authorization.backend.service.js +16 -0
- package/dist/esm/security/connected-accounts/services/provider-oauth2-pending-authorization.backend.service.js.map +1 -1
- package/dist/esm/security/connected-accounts/services/provider-oauth2-refresher.backend.service.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/services/provider-oauth2-refresher.backend.service.js +1 -1
- package/dist/esm/security/connected-accounts/services/provider-oauth2-refresher.backend.service.js.map +1 -1
- package/dist/esm/security/connected-accounts/services/user-provider-credential-store.backend.service.d.ts +19 -0
- package/dist/esm/security/connected-accounts/services/user-provider-credential-store.backend.service.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/services/user-provider-credential-store.backend.service.js +45 -2
- package/dist/esm/security/connected-accounts/services/user-provider-credential-store.backend.service.js.map +1 -1
- package/dist/esm/security/connected-accounts/services/user-provider-credentials.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/services/user-provider-credentials.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/security/connected-accounts/user-provider-credential-resolver.port.d.ts +37 -1
- package/dist/esm/security/connected-accounts/user-provider-credential-resolver.port.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/user-provider-credential-resolver.port.js.map +1 -1
- package/dist/esm/security/connected-accounts/utils/provider-credential-envelope.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/utils/provider-credential-envelope.backend.utils.js.map +1 -1
- package/dist/esm/security/connected-accounts/utils/stored-credential-value.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/utils/stored-credential-value.backend.utils.js.map +1 -1
- package/dist/esm/security/connected-accounts/utils/user-delegated-access-token-slot.backend.utils.d.ts +34 -0
- package/dist/esm/security/connected-accounts/utils/user-delegated-access-token-slot.backend.utils.d.ts.map +1 -0
- package/dist/esm/security/connected-accounts/utils/user-delegated-access-token-slot.backend.utils.js +39 -0
- package/dist/esm/security/connected-accounts/utils/user-delegated-access-token-slot.backend.utils.js.map +1 -0
- package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/security/consumable-tokens/consumable-token-models.exports.d.ts.map +1 -1
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/consumable-tokens/models/index.d.ts.map +1 -1
- package/dist/esm/security/consumable-tokens/services/__tests__/mock-consumable-token.service.d.ts.map +1 -1
- package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.d.ts.map +1 -1
- package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.js.map +1 -1
- package/dist/esm/security/credential-rotation-grace.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/credential-rotation-grace.backend.utils.js.map +1 -1
- package/dist/esm/security/jwt/services/auth-jwt-guard.backend.service.d.ts.map +1 -1
- package/dist/esm/security/jwt/services/jwt.backend.service.d.ts.map +1 -1
- package/dist/esm/security/jwt/services/wildo-worker-bootstrap-client.backend.service.d.ts +13 -0
- package/dist/esm/security/jwt/services/wildo-worker-bootstrap-client.backend.service.d.ts.map +1 -1
- package/dist/esm/security/jwt/services/wildo-worker-bootstrap-client.backend.service.js +14 -0
- package/dist/esm/security/jwt/services/wildo-worker-bootstrap-client.backend.service.js.map +1 -1
- package/dist/esm/security/jwt/utils/jwt-verification-error-classification.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-client-generation.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-client-generation.backend.utils.js.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/security/outbound/outbound-request-deadline.backend.utils.d.ts +39 -0
- package/dist/esm/security/outbound/outbound-request-deadline.backend.utils.d.ts.map +1 -0
- package/dist/esm/security/outbound/outbound-request-deadline.backend.utils.js +60 -0
- package/dist/esm/security/outbound/outbound-request-deadline.backend.utils.js.map +1 -0
- package/dist/esm/security/outbound/outbound-request-headers.backend.utils.d.ts +66 -0
- package/dist/esm/security/outbound/outbound-request-headers.backend.utils.d.ts.map +1 -0
- package/dist/esm/security/outbound/outbound-request-headers.backend.utils.js +75 -0
- package/dist/esm/security/outbound/outbound-request-headers.backend.utils.js.map +1 -0
- package/dist/esm/security/scim/controllers/scim.backend.controller.d.ts.map +1 -1
- package/dist/esm/security/scim/controllers/scim.backend.controller.js.map +1 -1
- package/dist/esm/security/scim/models/scim-protocol.backend.schemas.d.ts.map +1 -1
- package/dist/esm/security/scim/models/scim-protocol.backend.schemas.js.map +1 -1
- package/dist/esm/security/scim/utils/scim-attribute-path-resolver.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/scim/utils/scim-filter-parser.d.ts.map +1 -1
- package/dist/esm/security/scim/utils/scim-response-formatter.d.ts.map +1 -1
- package/dist/esm/security/session-invalidation-fence.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/ssrf/outbound-target-guard.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/ssrf/outbound-target-guard.backend.utils.js.map +1 -1
- package/dist/esm/security/ssrf/pinned-outbound-fetch.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/ssrf/pinned-outbound-fetch.backend.utils.js.map +1 -1
- package/dist/esm/security/token-invalidation-fence.backend.utils.d.ts.map +1 -1
- package/dist/esm/testing.d.ts.map +1 -1
- package/dist/esm/users/services/inbound-contact-custom-implementation.backend.service.d.ts.map +1 -1
- package/dist/esm/users/services/user-deletion-audit.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/users/services/user-force-password-reset.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/users/services/user-read-retained.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/users/services/user-read-retained.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/users/services/user-role-administration.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/users/services/user-self-custom-implementations.backend.d.ts.map +1 -1
- package/dist/esm/users/services/user-super-admin-floor.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/dist/esm/external-providers/services/flow-actor-design.backend.service.d.ts +0 -45
- package/dist/esm/external-providers/services/flow-actor-design.backend.service.d.ts.map +0 -1
- package/dist/esm/external-providers/services/flow-actor-design.backend.service.js +0 -22
- package/dist/esm/external-providers/services/flow-actor-design.backend.service.js.map +0 -1
- package/dist/esm/notifications/email/models/email-context-provider.interface.d.ts +0 -0
- package/dist/esm/notifications/email/models/email-context-provider.interface.d.ts.map +0 -0
- package/dist/esm/notifications/email/models/email-context-provider.interface.js +0 -0
- package/dist/esm/notifications/email/models/email-context-provider.interface.js.map +0 -0
- package/dist/esm/notifications/email/services/email-context-provider-registry.backend.service.d.ts +0 -0
- package/dist/esm/notifications/email/services/email-context-provider-registry.backend.service.d.ts.map +0 -0
- package/dist/esm/notifications/email/services/email-context-provider-registry.backend.service.js +0 -0
- package/dist/esm/notifications/email/services/email-context-provider-registry.backend.service.js.map +0 -0
- package/dist/esm/notifications/email/services/email-template-compiler.backend.service.d.ts +0 -0
- package/dist/esm/notifications/email/services/email-template-compiler.backend.service.d.ts.map +0 -0
- package/dist/esm/notifications/email/services/email-template-compiler.backend.service.js +0 -0
- package/dist/esm/notifications/email/services/email-template-compiler.backend.service.js.map +0 -0
- package/dist/esm/notifications/email/services/email-template-sandbox.backend.service.d.ts +0 -0
- package/dist/esm/notifications/email/services/email-template-sandbox.backend.service.d.ts.map +0 -0
- package/dist/esm/notifications/email/services/email-template-sandbox.backend.service.js +0 -0
- package/dist/esm/notifications/email/services/email-template-sandbox.backend.service.js.map +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-oauth2-pending-authorization.backend.service.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"provider-oauth2-pending-authorization.backend.service.js","sourceRoot":"","sources":["../../../../../src/security/connected-accounts/services/provider-oauth2-pending-authorization.backend.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;;;;;;;;;;;;;AAEH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAG/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAC;AAIpF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,mCAAmC,GAAG,GAAG,CAAC;AAEvD,MAAM,UAAU,GAAG,gBAAgB,CAAC;AA0C7B,IAAM,gDAAgD,GAAtD,MAAM,gDAAgD;IAEC;IACN;IAFtD,YAC4D,KAAmB,EACzB,MAAqB;QADf,UAAK,GAAL,KAAK,CAAc;QACzB,WAAM,GAAN,MAAM,CAAe;IACxE,CAAC;IAEJ;;;;;OAKG;IACI,KAAK,CAAC,QAAQ,CAAC,KAAa,EAAE,OAA2C;QAC9E,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,mCAAmC,EAAE,CAAC,CAAC;QAChG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,iDAAiD,EAAE;YACrE,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU;YACrC,6FAA6F;YAC7F,0DAA0D;SAC3D,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,OAAO,CAAC,KAAa;QAChC,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAqC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACnF,CAAC;IAED;;;;;;;;;;;;OAYG;IACI,KAAK,CAAC,IAAI,CAAC,KAAa;QAC7B,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAqC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAChF,CAAC;IAED;;;;;;OAMG;IACK,MAAM,CAAC,KAAa;QAC1B,OAAO,GAAG,UAAU,IAAI,KAAK,EAAE,CAAC;IAClC,CAAC;CACF,CAAA;AA5DY,gDAAgD;IAD5D,UAAU,EAAE;IAGR,WAAA,MAAM,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAA;IACvC,WAAA,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAA;;GAHzB,gDAAgD,CA4D5D","sourcesContent":["/**\n * The record of ONE in-flight authorization attempt, from the redirect out to the callback back.\n *\n * ## Why this is ephemeral state and not a resource\n *\n * It exists for the seconds a person spends on a vendor's consent screen and is worthless\n * afterwards. Deleting the whole store costs those people one retry and nothing else — the test\n * `one-source-of-truth.md` applies: losing it costs TIME, never TRUTH, so it is a cache and must not\n * become a table. A resource would also mean three migrations, a retention policy and an erasure\n * question, for data whose correct lifetime is ten minutes.\n *\n * ## Single-use BY CONSTRUCTION, not by a flag\n *\n * Consumption is `GETDEL` — one round trip that returns the record and removes it atomically. So a\n * replayed callback finds nothing, and there is no window in which two concurrent callbacks both\n * read a record and both proceed. A `consumed: true` flag would have that window, and the attack it\n * opens is real: an authorization code delivered twice is how a stolen code gets grafted onto a\n * legitimate attempt.\n *\n * ## What it holds, and what it must never hold\n *\n * It holds the PKCE verifier, which is a secret for the length of the flow, and the connection\n * target — whose account is being connected. It holds no token, because none exists yet.\n *\n * The TARGET is here rather than in the callback's query string for the reason the whole `state`\n * mechanism exists: everything that comes back from the vendor arrives through the person's own\n * browser and is therefore attacker-controllable. A callback that read the owner from its own URL\n * would let somebody choose whose account a grant is stored against.\n *\n * assurance-control: WILDO.IDENTITY.DELEGATED_AUTHORIZATION — the authorization attempt is bound to\n * the principal who started it.\n */\n\nimport { inject, injectable } from 'inversify';\nimport type { ExternalProvider_ConnectionTarget } from '@wildo-ai/external-connectors-models';\n\nimport { SAAS_SERVICE_TYPES } from '~wildo-backend-lib/inject/models/service-types';\nimport type { RedisService } from '~wildo-backend-lib/databases/services/redis.service';\nimport type { LoggerService } from '~wildo-backend-lib/monitoring/logger/services/logger.service';\n\n/**\n * Ten minutes.\n *\n * Long enough for somebody to read a consent screen, find the right account and sign in to the\n * vendor if they were signed out. Short enough that an abandoned attempt — and the PKCE verifier\n * inside it — does not sit in the cache for a day. Every major vendor's own authorization codes\n * expire in this range, so a longer window would keep a record whose code is already dead.\n */\nexport const PROVIDER_OAUTH2_PENDING_TTL_SECONDS = 600;\n\nconst KEY_PREFIX = 'oauth2-connect';\n\nexport interface ProviderOAuth2PendingAuthorization {\n /** Which provider is being connected. */\n readonly providerRef: string;\n /** The slot in the provider's secrets contract this grant will satisfy. */\n readonly secretSlug: string;\n /** WHOSE account is being connected. Never read back from the callback's URL. */\n readonly target: ExternalProvider_ConnectionTarget;\n /** The PKCE verifier, presented at the token exchange. Secret for the life of the record. */\n readonly pkceVerifier: string;\n /** The redirect URI sent at authorize; re-sent at the exchange and verified by the vendor. */\n readonly redirectUri: string;\n /** Values for the endpoints' `{placeholders}`, needed again to build the token URL. */\n readonly connectionParameters?: Readonly<Record<string, string>>;\n /**\n * Who started the attempt, for the audit trail and for the callback's own authorization check.\n *\n * The callback re-checks that the person completing the flow is the person who began it. Without\n * it, somebody who obtained a valid `state` could complete a connection while signed in as\n * themselves and have the grant stored against the original initiator's target.\n */\n readonly initiatedByUserId?: string;\n /**\n * WHICH frontend the person came from, so the callback can send them back to it.\n *\n * Captured at START and carried here because the two legs reach the backend differently: the start\n * leg is a FETCH from the application and carries Wildo's own headers, while the callback is a\n * BROWSER NAVIGATION arriving from the vendor with none of them. Resolving the return URL at the\n * callback from a header would therefore resolve nothing, and answering the browser with JSON —\n * which this flow did until the omission was noticed — shows a person a raw payload instead of\n * their settings screen.\n *\n * Optional because a caller that omits the header still gets a working CONNECTION; it only loses\n * the redirect home, which is a worse experience rather than a broken one.\n */\n readonly frontendServiceName?: string;\n /** When it was started, as an ISO instant — so an audit event can state how long consent took. */\n readonly startedAt: string;\n}\n\n@injectable()\nexport class ProviderOAuth2PendingAuthorizationBackendService {\n constructor(\n @inject(SAAS_SERVICE_TYPES.RedisService) private readonly redis: RedisService,\n @inject(SAAS_SERVICE_TYPES.Logger) private readonly logger: LoggerService,\n ) {}\n\n /**\n * Remember one attempt against its `state`.\n *\n * The `state` IS the key. It is 32 random bytes, so it is unguessable, and using it directly means\n * there is no second identifier that could get out of step with the one the vendor echoes back.\n */\n public async remember(state: string, pending: ProviderOAuth2PendingAuthorization): Promise<void> {\n await this.redis.set(this.keyFor(state), pending, { ttl: PROVIDER_OAUTH2_PENDING_TTL_SECONDS });\n this.logger.debug?.('[oauth2-connect] authorization attempt recorded', {\n providerRef: pending.providerRef,\n ownerScope: pending.target.ownerScope,\n // Never the state and never the verifier: both are secrets for the life of the record, and a\n // debug log is the one place a secret most often escapes.\n });\n }\n\n /**\n * Take the attempt, removing it in the same round trip.\n *\n * `null` covers three situations a caller must treat identically — expired, already used, or never\n * existed — and they MUST NOT be distinguished in any answer that reaches a browser. Telling an\n * attacker that a `state` was valid but expired confirms they hold a real one.\n */\n public async consume(state: string): Promise<ProviderOAuth2PendingAuthorization | null> {\n return this.redis.getDel<ProviderOAuth2PendingAuthorization>(this.keyFor(state));\n }\n\n /**\n * Read the attempt WITHOUT taking it — for the callback, which must not consume.\n *\n * The callback authenticates nobody and finishes nothing; all it needs is the frontend to send the\n * person back to, which is recorded here. Consuming there would burn the attempt before the\n * authenticated half could redeem it, and that is not hypothetical: while the callback both\n * consumed and authenticated, a failed authentication left the person unable even to retry — the\n * state was already gone.\n *\n * The single-use guarantee is UNCHANGED and still lives in {@link consume}, which the completion\n * route calls. This one hands back a copy and defends nothing on its own, so treat what it returns\n * as unverified: it says an attempt with that `state` exists, never that this caller may finish it.\n */\n public async peek(state: string): Promise<ProviderOAuth2PendingAuthorization | null> {\n return this.redis.get<ProviderOAuth2PendingAuthorization>(this.keyFor(state));\n }\n\n /**\n * Namespaced, so nothing else in the cache can be addressed by supplying a crafted `state`.\n *\n * The state is used verbatim rather than hashed: it is already high-entropy and opaque, and\n * hashing would only obscure which record a diagnostic is about while protecting nothing that the\n * TTL does not already bound.\n */\n private keyFor(state: string): string {\n return `${KEY_PREFIX}:${state}`;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-oauth2-refresher.backend.service.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"provider-oauth2-refresher.backend.service.d.ts","sourceRoot":"","sources":["../../../../../src/security/connected-accounts/services/provider-oauth2-refresher.backend.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAGjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8DAA8D,CAAC;AAClG,OAAO,KAAK,EAAE,uCAAuC,EAAE,MAAM,4FAA4F,CAAC;AAO1J,OAAO,KAAK,EACV,4BAA4B,EAC5B,2BAA2B,EAC5B,MAAM,mCAAmC,CAAC;AAE3C,qBACa,qCAAsC,YAAW,2BAA2B;IAUlD,OAAO,CAAC,QAAQ,CAAC,MAAM;IAE1D,OAAO,CAAC,QAAQ,CAAC,yBAAyB;IAX5C;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmD;gBAGtB,MAAM,EAAE,aAAa,EAExD,yBAAyB,EAAE,uCAAuC;IAGxE,YAAY,CAAC,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAAC,mBAAmB,CAAC;YAkBhF,cAAc;IAoE5B;;;;;OAKG;IACH,OAAO,CAAC,YAAY;CASrB"}
|
package/dist/esm/security/connected-accounts/services/provider-oauth2-refresher.backend.service.js
CHANGED
|
@@ -140,7 +140,7 @@ let ProviderOAuth2RefresherBackendService = class ProviderOAuth2RefresherBackend
|
|
|
140
140
|
request.target.delegation,
|
|
141
141
|
request.providerRef,
|
|
142
142
|
request.secretSlug,
|
|
143
|
-
].join('
|
|
143
|
+
].join('\u0000');
|
|
144
144
|
}
|
|
145
145
|
};
|
|
146
146
|
ProviderOAuth2RefresherBackendService = __decorate([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-oauth2-refresher.backend.service.js","sourceRoot":"","sources":["../../../../../../src/security/connected-accounts/services/provider-oauth2-refresher.backend.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The token refresher — the port implementation over the provider registry.\n *\n * It reads the provider's OAuth2 contract and the application's client registration, performs the\n * refresh exchange, and hands the renewed grant back. It persists nothing: the store that asked owns\n * the table.\n *\n * ## Single-flight, and why it is not an optimisation\n *\n * Concurrent calls for the SAME connection collapse onto one exchange. Skipping this would be a\n * correctness defect, not a performance one, for vendors that ROTATE the refresh token: two\n * simultaneous refreshes both present the same refresh token, the vendor issues two grants and\n * invalidates the first, and whichever write lands second stores a token the vendor has already\n * revoked. The connection then fails on its next call, with two successful-looking refreshes in the\n * log and nothing saying which one broke it.\n *\n * ## What it does NOT cover, stated rather than implied\n *\n * The flight is IN-PROCESS. Two backend instances refreshing the same connection at the same instant\n * still race, and against a rotating vendor one of them still loses. Closing that needs a\n * distributed lock, which is a Redis round trip on a path that runs before every outbound call — a\n * cost worth paying only once a real deployment shows the collision. The narrower in-process case is\n * the common one by a wide margin, because a burst of calls for one connection almost always arrives\n * at one instance.\n *\n * assurance-control: WILDO.IDENTITY.DELEGATED_AUTHORIZATION — delegated authority is renewed without\n * a new act of consent, so the renewal is bounded by what the original grant carried.\n */\n\nimport { inject, injectable } from 'inversify';\nimport { ExternalProvider_ExchangeProtocol_Kind, ProviderProtocolRuntimeKind } from '@wildo-ai/external-connectors-models';\nimport type { ProviderOAuth2Grant } from '@wildo-ai/saas-models';\n\nimport { SAAS_SERVICE_TYPES } from '~wildo-backend-lib/inject/models/service-types';\nimport type { LoggerService } from '~wildo-backend-lib/monitoring/logger/services/logger.service';\nimport type { ExternalProvidersRegistryBackendService } from '~wildo-backend-lib/external-providers/services/external-providers-registry.backend.service';\nimport { describeCaughtError } from '~wildo-backend-lib/errors/utils/error-log-level-classification.backend.utils';\n\nimport {\n ProviderOAuth2ExchangeError,\n refreshProviderOAuth2Grant,\n} from './provider-oauth2-exchange.backend';\nimport type {\n ProviderOAuth2RefreshRequest,\n ProviderOAuth2RefresherPort,\n} from '../provider-oauth2-refresher.port';\n\n@injectable()\nexport class ProviderOAuth2RefresherBackendService implements ProviderOAuth2RefresherPort {\n /**\n * One in-flight exchange per connection, keyed by the whole identity.\n *\n * Entries are removed in a `finally`, so a failed refresh does not wedge the connection — the next\n * call starts a fresh attempt rather than awaiting a promise that already rejected.\n */\n private readonly inFlight = new Map<string, Promise<ProviderOAuth2Grant>>();\n\n constructor(\n @inject(SAAS_SERVICE_TYPES.Logger) private readonly logger: LoggerService,\n @inject(SAAS_SERVICE_TYPES.ExternalProvidersRegistryService)\n private readonly externalProvidersRegistry: ExternalProvidersRegistryBackendService,\n ) {}\n\n public async refreshGrant(request: ProviderOAuth2RefreshRequest): Promise<ProviderOAuth2Grant> {\n const key = this.flightKeyFor(request);\n const existing = this.inFlight.get(key);\n if (existing !== undefined) {\n this.logger.debug?.('[oauth2-refresh] joining an in-flight refresh', {\n providerRef: request.providerRef,\n ownerScope: request.target.ownerScope,\n });\n return existing;\n }\n\n const flight = this.performRefresh(request).finally(() => {\n this.inFlight.delete(key);\n });\n this.inFlight.set(key, flight);\n return flight;\n }\n\n private async performRefresh(request: ProviderOAuth2RefreshRequest): Promise<ProviderOAuth2Grant> {\n const contract = this.externalProvidersRegistry.getProviderRuntimeContract(\n request.providerRef,\n ExternalProvider_ExchangeProtocol_Kind.REST_API,\n );\n if (contract?.kind !== ProviderProtocolRuntimeKind.REST || contract.oauth2 === undefined) {\n throw new ProviderOAuth2ExchangeError(\n `Provider '${request.providerRef}' holds an OAuth2 grant but declares no OAuth2 contract, so there `\n + 'is no token endpoint to refresh against. The stored grant was written against a different '\n + 'provider definition than the one loaded now.',\n );\n }\n\n // The application's registration with the vendor — the two values an operator genuinely pastes.\n // They identify the INTEGRATION, never the end user, so they come from the deployment environment\n // for every owner scope and are not per-connection.\n const { clientIdSecretRef, clientSecretSecretRef } = contract.oauth2;\n const clientId = clientIdSecretRef === undefined\n ? undefined\n : this.externalProvidersRegistry.getProviderSecret(\n request.providerRef, ExternalProvider_ExchangeProtocol_Kind.REST_API, clientIdSecretRef,\n );\n const clientSecret = clientSecretSecretRef === undefined\n ? undefined\n : this.externalProvidersRegistry.getProviderSecret(\n request.providerRef, ExternalProvider_ExchangeProtocol_Kind.REST_API, clientSecretSecretRef,\n );\n\n if (!clientId || !clientSecret) {\n // Names the ENVIRONMENT, not the connection. A person whose token cannot be renewed because an\n // operator has not configured the application's registration must not be told to reconnect —\n // reconnecting would fail at the same step, for the same reason, having sent them to a vendor.\n throw new ProviderOAuth2ExchangeError(\n `Provider '${request.providerRef}' cannot refresh a grant: the application's own OAuth2 registration `\n + `is not configured. Set '${clientIdSecretRef ?? '(no client id declared)'}' and `\n + `'${clientSecretSecretRef ?? '(no client secret declared)'}' in the deployment environment. `\n + 'This is an application configuration gap, not a problem with the stored connection.',\n );\n }\n\n try {\n const renewed = await refreshProviderOAuth2Grant({\n oauth2: contract.oauth2,\n providerRef: request.providerRef,\n clientId,\n clientSecret,\n connectionParameters: request.connectionParameters,\n grant: request.grant,\n });\n this.logger.debug?.('[oauth2-refresh] grant renewed', {\n providerRef: request.providerRef,\n ownerScope: request.target.ownerScope,\n // Whether the vendor rotated the refresh token — the fact that decides whether this\n // connection survives its next renewal, and it is invisible anywhere else.\n refreshTokenRotated: renewed.refreshToken !== request.grant.refreshToken,\n });\n return renewed;\n } catch (error) {\n this.logger.warn?.('[oauth2-refresh] refresh failed', {\n providerRef: request.providerRef,\n ownerScope: request.target.ownerScope,\n secretSlug: request.secretSlug,\n error: describeCaughtError(error),\n });\n throw error;\n }\n }\n\n /**\n * The whole connection identity, so two owners of the same provider never share a flight.\n *\n * Keying on the provider alone would make one tenant's refresh satisfy another's call and return\n * the wrong account's token — the exact cross-owner substitution the resolution path refuses.\n */\n private flightKeyFor(request: ProviderOAuth2RefreshRequest): string {\n return [\n request.target.ownerScope,\n request.target.ownerId ?? '-',\n request.target.delegation,\n request.providerRef,\n request.secretSlug,\n ].join('\u0000');\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"provider-oauth2-refresher.backend.service.js","sourceRoot":"","sources":["../../../../../src/security/connected-accounts/services/provider-oauth2-refresher.backend.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The token refresher — the port implementation over the provider registry.\n *\n * It reads the provider's OAuth2 contract and the application's client registration, performs the\n * refresh exchange, and hands the renewed grant back. It persists nothing: the store that asked owns\n * the table.\n *\n * ## Single-flight, and why it is not an optimisation\n *\n * Concurrent calls for the SAME connection collapse onto one exchange. Skipping this would be a\n * correctness defect, not a performance one, for vendors that ROTATE the refresh token: two\n * simultaneous refreshes both present the same refresh token, the vendor issues two grants and\n * invalidates the first, and whichever write lands second stores a token the vendor has already\n * revoked. The connection then fails on its next call, with two successful-looking refreshes in the\n * log and nothing saying which one broke it.\n *\n * ## What it does NOT cover, stated rather than implied\n *\n * The flight is IN-PROCESS. Two backend instances refreshing the same connection at the same instant\n * still race, and against a rotating vendor one of them still loses. Closing that needs a\n * distributed lock, which is a Redis round trip on a path that runs before every outbound call — a\n * cost worth paying only once a real deployment shows the collision. The narrower in-process case is\n * the common one by a wide margin, because a burst of calls for one connection almost always arrives\n * at one instance.\n *\n * assurance-control: WILDO.IDENTITY.DELEGATED_AUTHORIZATION — delegated authority is renewed without\n * a new act of consent, so the renewal is bounded by what the original grant carried.\n */\n\nimport { inject, injectable } from 'inversify';\nimport { ExternalProvider_ExchangeProtocol_Kind, ProviderProtocolRuntimeKind } from '@wildo-ai/external-connectors-models';\nimport type { ProviderOAuth2Grant } from '@wildo-ai/saas-models';\n\nimport { SAAS_SERVICE_TYPES } from '~wildo-backend-lib/inject/models/service-types';\nimport type { LoggerService } from '~wildo-backend-lib/monitoring/logger/services/logger.service';\nimport type { ExternalProvidersRegistryBackendService } from '~wildo-backend-lib/external-providers/services/external-providers-registry.backend.service';\nimport { describeCaughtError } from '~wildo-backend-lib/errors/utils/error-log-level-classification.backend.utils';\n\nimport {\n ProviderOAuth2ExchangeError,\n refreshProviderOAuth2Grant,\n} from './provider-oauth2-exchange.backend';\nimport type {\n ProviderOAuth2RefreshRequest,\n ProviderOAuth2RefresherPort,\n} from '../provider-oauth2-refresher.port';\n\n@injectable()\nexport class ProviderOAuth2RefresherBackendService implements ProviderOAuth2RefresherPort {\n /**\n * One in-flight exchange per connection, keyed by the whole identity.\n *\n * Entries are removed in a `finally`, so a failed refresh does not wedge the connection — the next\n * call starts a fresh attempt rather than awaiting a promise that already rejected.\n */\n private readonly inFlight = new Map<string, Promise<ProviderOAuth2Grant>>();\n\n constructor(\n @inject(SAAS_SERVICE_TYPES.Logger) private readonly logger: LoggerService,\n @inject(SAAS_SERVICE_TYPES.ExternalProvidersRegistryService)\n private readonly externalProvidersRegistry: ExternalProvidersRegistryBackendService,\n ) {}\n\n public async refreshGrant(request: ProviderOAuth2RefreshRequest): Promise<ProviderOAuth2Grant> {\n const key = this.flightKeyFor(request);\n const existing = this.inFlight.get(key);\n if (existing !== undefined) {\n this.logger.debug?.('[oauth2-refresh] joining an in-flight refresh', {\n providerRef: request.providerRef,\n ownerScope: request.target.ownerScope,\n });\n return existing;\n }\n\n const flight = this.performRefresh(request).finally(() => {\n this.inFlight.delete(key);\n });\n this.inFlight.set(key, flight);\n return flight;\n }\n\n private async performRefresh(request: ProviderOAuth2RefreshRequest): Promise<ProviderOAuth2Grant> {\n const contract = this.externalProvidersRegistry.getProviderRuntimeContract(\n request.providerRef,\n ExternalProvider_ExchangeProtocol_Kind.REST_API,\n );\n if (contract?.kind !== ProviderProtocolRuntimeKind.REST || contract.oauth2 === undefined) {\n throw new ProviderOAuth2ExchangeError(\n `Provider '${request.providerRef}' holds an OAuth2 grant but declares no OAuth2 contract, so there `\n + 'is no token endpoint to refresh against. The stored grant was written against a different '\n + 'provider definition than the one loaded now.',\n );\n }\n\n // The application's registration with the vendor — the two values an operator genuinely pastes.\n // They identify the INTEGRATION, never the end user, so they come from the deployment environment\n // for every owner scope and are not per-connection.\n const { clientIdSecretRef, clientSecretSecretRef } = contract.oauth2;\n const clientId = clientIdSecretRef === undefined\n ? undefined\n : this.externalProvidersRegistry.getProviderSecret(\n request.providerRef, ExternalProvider_ExchangeProtocol_Kind.REST_API, clientIdSecretRef,\n );\n const clientSecret = clientSecretSecretRef === undefined\n ? undefined\n : this.externalProvidersRegistry.getProviderSecret(\n request.providerRef, ExternalProvider_ExchangeProtocol_Kind.REST_API, clientSecretSecretRef,\n );\n\n if (!clientId || !clientSecret) {\n // Names the ENVIRONMENT, not the connection. A person whose token cannot be renewed because an\n // operator has not configured the application's registration must not be told to reconnect —\n // reconnecting would fail at the same step, for the same reason, having sent them to a vendor.\n throw new ProviderOAuth2ExchangeError(\n `Provider '${request.providerRef}' cannot refresh a grant: the application's own OAuth2 registration `\n + `is not configured. Set '${clientIdSecretRef ?? '(no client id declared)'}' and `\n + `'${clientSecretSecretRef ?? '(no client secret declared)'}' in the deployment environment. `\n + 'This is an application configuration gap, not a problem with the stored connection.',\n );\n }\n\n try {\n const renewed = await refreshProviderOAuth2Grant({\n oauth2: contract.oauth2,\n providerRef: request.providerRef,\n clientId,\n clientSecret,\n connectionParameters: request.connectionParameters,\n grant: request.grant,\n });\n this.logger.debug?.('[oauth2-refresh] grant renewed', {\n providerRef: request.providerRef,\n ownerScope: request.target.ownerScope,\n // Whether the vendor rotated the refresh token — the fact that decides whether this\n // connection survives its next renewal, and it is invisible anywhere else.\n refreshTokenRotated: renewed.refreshToken !== request.grant.refreshToken,\n });\n return renewed;\n } catch (error) {\n this.logger.warn?.('[oauth2-refresh] refresh failed', {\n providerRef: request.providerRef,\n ownerScope: request.target.ownerScope,\n secretSlug: request.secretSlug,\n error: describeCaughtError(error),\n });\n throw error;\n }\n }\n\n /**\n * The whole connection identity, so two owners of the same provider never share a flight.\n *\n * Keying on the provider alone would make one tenant's refresh satisfy another's call and return\n * the wrong account's token — the exact cross-owner substitution the resolution path refuses.\n */\n private flightKeyFor(request: ProviderOAuth2RefreshRequest): string {\n return [\n request.target.ownerScope,\n request.target.ownerId ?? '-',\n request.target.delegation,\n request.providerRef,\n request.secretSlug,\n ].join('\\u0000');\n }\n}\n"]}
|
|
@@ -129,6 +129,25 @@ export declare class UserProviderCredentialStoreBackendService implements UserPr
|
|
|
129
129
|
* @returns the credential row's id, so the caller can name it in an audit event.
|
|
130
130
|
*/
|
|
131
131
|
storeGrant(query: UserProviderCredentialQuery, grant: ProviderOAuth2Grant, connectionParameters?: Readonly<Record<string, string>>): Promise<string>;
|
|
132
|
+
/**
|
|
133
|
+
* Store a credential somebody TYPED, as opposed to one an exchange minted.
|
|
134
|
+
*
|
|
135
|
+
* The other half of `storeGrant`, and separate from it because the two differ in every way that
|
|
136
|
+
* matters: a grant is a JSON document with an expiry and a refresh token, this is one opaque value;
|
|
137
|
+
* a grant arrives from a vendor, this arrives from a person; a grant can be renewed, this can only
|
|
138
|
+
* be replaced. Serialising a typed key through the grant envelope would put
|
|
139
|
+
* `wildo-oauth2-grant:{...}` on the wire as a bearer token.
|
|
140
|
+
*
|
|
141
|
+
* PLAINTEXT to the write door, which seals. Handing a pre-sealed value to `createAsSystem` reaches
|
|
142
|
+
* the service tier where the sealing hook refuses to double-seal — so the write would throw after
|
|
143
|
+
* the person had already typed their key.
|
|
144
|
+
*
|
|
145
|
+
* Replaces rather than duplicates: the business key is (owner, provider, slug), so re-entering a
|
|
146
|
+
* rotated key is the ordinary case and a second create would violate the index. Re-entering also
|
|
147
|
+
* RE-ENABLES and clears any validation mark, because somebody who has just supplied a working key
|
|
148
|
+
* should not be shown a broken connection.
|
|
149
|
+
*/
|
|
150
|
+
storeDeclaredSecret(query: UserProviderCredentialQuery, secretValue: string): Promise<string>;
|
|
132
151
|
/**
|
|
133
152
|
* Renew the grant, and RETIRE the connection when the vendor says it is finished.
|
|
134
153
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-provider-credential-store.backend.service.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"user-provider-credential-store.backend.service.d.ts","sourceRoot":"","sources":["../../../../../src/security/connected-accounts/services/user-provider-credential-store.backend.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EAKL,KAAK,mBAAmB,EAEzB,MAAM,uBAAuB,CAAC;AAK/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8DAA8D,CAAC;AAClG,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sEAAsE,CAAC;AACpH,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iFAAiF,CAAC;AAClI,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gFAAgF,CAAC;AAG9H,OAAO,EACL,+BAA+B,EAEhC,MAAM,qDAAqD,CAAC;AAG7D,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,mCAAmC,CAAC;AACrF,OAAO,KAAK,EACV,2BAA2B,EAC3B,gCAAgC,EAChC,kCAAkC,EACnC,MAAM,2CAA2C,CAAC;AAEnD,qBACa,yCAA0C,YAAW,kCAAkC;IAE7D,OAAO,CAAC,QAAQ,CAAC,MAAM;IACb,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IAC9B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7E;;;;OAIG;IACsD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;IACpF;;;;;;;OAOG;IAC6D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAjBvC,MAAM,EAAE,aAAa,EACX,gBAAgB,EAAE,uBAAuB,EACtC,YAAY,EAAE,0BAA0B;IACzG;;;;OAIG;IACuE,SAAS,CAAC,EAAE,uBAAuB;IAC7G;;;;;;;OAOG;IAC8E,SAAS,CAAC,EAAE,2BAA2B;IAG1H;;;;OAIG;IACU,qBAAqB,CAChC,KAAK,EAAE,2BAA2B,GACjC,OAAO,CAAC,gCAAgC,GAAG,SAAS,CAAC;IAkExD;;;;;;;;OAQG;YACW,iBAAiB;IAc/B;;;;;;OAMG;IACU,mBAAmB,CAAC,GAAG,EAAE;QACpC,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,uFAAuF;QACvF,OAAO,CAAC,EAAE;YAAE,QAAQ,EAAE,OAAO,CAAC;YAAC,eAAe,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;KAC3D,GAAG,OAAO,CAAC,IAAI,CAAC;YAwDH,YAAY;IAgC1B;;;;;;;;;;;;;;;;OAgBG;IACU,UAAU,CACrB,KAAK,EAAE,2BAA2B,EAClC,KAAK,EAAE,mBAAmB,EAC1B,oBAAoB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACtD,OAAO,CAAC,MAAM,CAAC;IA2ClB;;;;;;;;;;;;;;;;;OAiBG;IACU,mBAAmB,CAAC,KAAK,EAAE,2BAA2B,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAgC1G;;;;;;;;;;;;;;;;;;;;OAoBG;YACW,aAAa;IAuC3B;;;;;;;;;;;OAWG;YACW,qBAAqB;IA2BnC;;;;;;;;;;;;;;;;;OAiBG;YACW,mBAAmB;IAajC;;;;;;OAMG;WACW,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,+BAA+B;CAG/F"}
|
|
@@ -116,9 +116,14 @@ let UserProviderCredentialStoreBackendService = class UserProviderCredentialStor
|
|
|
116
116
|
connectionParameters: row.connectionParameters,
|
|
117
117
|
});
|
|
118
118
|
await this.persistRenewedGrant(query, row._id, renewed);
|
|
119
|
-
return { value: renewed.accessToken, credentialId: row._id };
|
|
119
|
+
return { value: renewed.accessToken, credentialId: row._id, expiresAt: renewed.expiresAt, grantedScopes: renewed.grantedScopes };
|
|
120
120
|
}
|
|
121
|
-
return {
|
|
121
|
+
return {
|
|
122
|
+
value: resolved.wireValue,
|
|
123
|
+
credentialId: row._id,
|
|
124
|
+
expiresAt: resolved.grant?.expiresAt,
|
|
125
|
+
grantedScopes: resolved.grant?.grantedScopes,
|
|
126
|
+
};
|
|
122
127
|
}
|
|
123
128
|
/**
|
|
124
129
|
* The scoped read.
|
|
@@ -260,6 +265,44 @@ let UserProviderCredentialStoreBackendService = class UserProviderCredentialStor
|
|
|
260
265
|
await this.emitConnectionGranted(query, grant, created._id, false);
|
|
261
266
|
return created._id;
|
|
262
267
|
}
|
|
268
|
+
/**
|
|
269
|
+
* Store a credential somebody TYPED, as opposed to one an exchange minted.
|
|
270
|
+
*
|
|
271
|
+
* The other half of `storeGrant`, and separate from it because the two differ in every way that
|
|
272
|
+
* matters: a grant is a JSON document with an expiry and a refresh token, this is one opaque value;
|
|
273
|
+
* a grant arrives from a vendor, this arrives from a person; a grant can be renewed, this can only
|
|
274
|
+
* be replaced. Serialising a typed key through the grant envelope would put
|
|
275
|
+
* `wildo-oauth2-grant:{...}` on the wire as a bearer token.
|
|
276
|
+
*
|
|
277
|
+
* PLAINTEXT to the write door, which seals. Handing a pre-sealed value to `createAsSystem` reaches
|
|
278
|
+
* the service tier where the sealing hook refuses to double-seal — so the write would throw after
|
|
279
|
+
* the person had already typed their key.
|
|
280
|
+
*
|
|
281
|
+
* Replaces rather than duplicates: the business key is (owner, provider, slug), so re-entering a
|
|
282
|
+
* rotated key is the ordinary case and a second create would violate the index. Re-entering also
|
|
283
|
+
* RE-ENABLES and clears any validation mark, because somebody who has just supplied a working key
|
|
284
|
+
* should not be shown a broken connection.
|
|
285
|
+
*/
|
|
286
|
+
async storeDeclaredSecret(query, secretValue) {
|
|
287
|
+
const existing = await this.readCredentialRow(query);
|
|
288
|
+
const scopeContext = { userId: query.userId };
|
|
289
|
+
if (existing) {
|
|
290
|
+
await this.systemAccess.updateAsSystem(CoreResourceType.USER_PROVIDER_CREDENTIALS, existing._id, {
|
|
291
|
+
secretValue,
|
|
292
|
+
enabled: true,
|
|
293
|
+
validationState: ProviderCredentialValidationState.UNVALIDATED,
|
|
294
|
+
validationError: undefined,
|
|
295
|
+
}, { scopeContext, preserveServerInjectedFields: ['validationError'] });
|
|
296
|
+
return existing._id;
|
|
297
|
+
}
|
|
298
|
+
const created = await this.systemAccess.createAsSystem(CoreResourceType.USER_PROVIDER_CREDENTIALS, {
|
|
299
|
+
userId: query.userId,
|
|
300
|
+
providerRef: query.providerRef,
|
|
301
|
+
secretSlug: query.secretSlug,
|
|
302
|
+
secretValue,
|
|
303
|
+
}, { scopeContext });
|
|
304
|
+
return created._id;
|
|
305
|
+
}
|
|
263
306
|
/**
|
|
264
307
|
* Renew the grant, and RETIRE the connection when the vendor says it is finished.
|
|
265
308
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-provider-credential-store.backend.service.js","sourceRoot":"","sources":["../../../../../../src/security/connected-accounts/services/user-provider-credential-store.backend.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The user-provider-credential STORE — the port implementation the registry consults for a PERSON's\n * own credential.\n *\n * ## What makes the isolation structural rather than a filter\n *\n * The same three independent mechanisms as the organization store, and none of them is a predicate\n * somebody has to remember to write at each call site:\n *\n * 1. **The owner FK is injected by the context machinery.** The read goes through `readAsSystem`\n * with the user in the system scope map, so `buildContextualFilter` adds the clause itself. A\n * caller cannot omit it, because the caller never writes it.\n * 2. **The filter names the user explicitly as well.** Belt and braces, deliberately: the contextual\n * filter is injected by a mechanism that exists TWICE (a Mongo implementation and a PostgreSQL\n * one), so a regression in one adapter is a bypass in that adapter alone. The explicit clause is\n * adapter-independent and would still scope the read.\n * 3. **The envelope is BOUND to the row identity, under a key derived for the USER scope.** Even a\n * read that returned another person's row — or a tenant's — would fail to OPEN it. This is the\n * one that holds when the other two are wrong, which is why it exists.\n *\n * ## Why this is a separate service rather than the organization store with an owner parameter\n *\n * The read is the same shape and everything around it differs. There is no fallback (a person who\n * has connected nothing gets a refusal, never the deployment's shared principal). There is no\n * administrative variant, so the actor and the subject are always the same identity and the audit\n * events say so. And the resource is a composition under `USERS` rather than under `ORGANIZATIONS`,\n * so the scope map, the cascade and the erasure semantics are a different set throughout.\n *\n * A single service parameterised by owner would carry every one of those as a branch, and the\n * branch a reader most needs to trust — \"is a fallback reachable from here?\" — would be the one\n * spelled as an `if`.\n *\n * assurance-control: WILDO.IDENTITY.DELEGATED_AUTHORIZATION — a user's delegated authority toward a\n * third party is read only for that user.\n */\n\nimport { inject, injectable, optional } from 'inversify';\nimport {\n CoreResourceType,\n ProviderCredentialResolutionSource,\n ProviderCredentialValidationState,\n serializeProviderOAuth2Grant,\n type ProviderOAuth2Grant,\n type UserProviderCredential,\n} from '@wildo-ai/saas-models';\n\nimport { ExternalProvider_Connection_DelegationMode, ExternalProvider_Connection_OwnerScope } from '@wildo-ai/external-connectors-models';\n\nimport { SAAS_SERVICE_TYPES } from '~wildo-backend-lib/inject/models/service-types';\nimport type { LoggerService } from '~wildo-backend-lib/monitoring/logger/services/logger.service';\nimport type { AppConfigurationService } from '~wildo-backend-lib/config/services/app-configuration.backend.service';\nimport type { SystemAccessBackendService } from '~wildo-backend-lib/base-classes/services/services/system-access.backend.service';\nimport type { AuditLogsBackendService } from '~wildo-backend-lib/compliance/audit-trails/services/audit-logs.backend.service';\nimport { describeCaughtError } from '~wildo-backend-lib/errors/utils/error-log-level-classification.backend.utils';\n\nimport {\n ProviderCredentialEnvelopeError,\n openProviderCredential,\n} from '../utils/provider-credential-envelope.backend.utils';\nimport { resolveStoredCredentialValue } from '../utils/stored-credential-value.backend.utils';\nimport { providerOAuth2GrantWasPermanentlyRejected } from './provider-oauth2-exchange.backend';\nimport type { ProviderOAuth2RefresherPort } from '../provider-oauth2-refresher.port';\nimport type {\n UserProviderCredentialQuery,\n UserProviderCredentialResolution,\n UserProviderCredentialResolverPort,\n} from '../user-provider-credential-resolver.port';\n\n@injectable()\nexport class UserProviderCredentialStoreBackendService implements UserProviderCredentialResolverPort {\n constructor(\n @inject(SAAS_SERVICE_TYPES.Logger) private readonly logger: LoggerService,\n @inject(SAAS_SERVICE_TYPES.AppConfigService) private readonly appConfigService: AppConfigurationService,\n @inject(SAAS_SERVICE_TYPES.SystemAccessService) private readonly systemAccess: SystemAccessBackendService,\n /**\n * OPTIONAL and lazily used, mirroring `SystemAccessBackendService`'s own treatment of it: audit\n * emission must never be the reason a provider call fails, and a minimal test container must\n * still be able to construct this service.\n */\n @inject(SAAS_SERVICE_TYPES.AuditLogsService) @optional() private readonly auditLogs?: AuditLogsBackendService,\n /**\n * Appended LAST, deliberately: a parameter inserted mid-signature silently reassigns every\n * positional argument after it, and this constructor is called positionally by several harnesses.\n *\n * OPTIONAL, and its absence is not a degradation — a store without one resolves every pasted\n * credential and every non-expiring token exactly as before. Only an EXPIRING grant needs it, and\n * that case refuses by name rather than sending a stale token.\n */\n @inject(SAAS_SERVICE_TYPES.ProviderOAuth2Refresher) @optional() private readonly refresher?: ProviderOAuth2RefresherPort,\n ) {}\n\n /**\n * The person's own credential, opened, or `undefined` when they have not connected this provider.\n *\n * See the port's JSDoc for why \"absent\" returns and \"present but unopenable\" throws.\n */\n public async resolveUserCredential(\n query: UserProviderCredentialQuery,\n ): Promise<UserProviderCredentialResolution | undefined> {\n const row = await this.readCredentialRow(query);\n if (!row) {\n return undefined;\n }\n\n // A disabled credential is treated as absent — which here means the call REFUSES, because there\n // is nothing to fall through to. That is the intended shape: someone who switches their own\n // connection off is asking the application to stop acting as them, and the honest outcome is an\n // integration that stops rather than one that quietly continues under another identity.\n if (row.enabled === false) {\n this.logger.debug?.(\n '[user-provider-credential] credential is disabled; treating as absent',\n { userId: query.userId, providerRef: query.providerRef, secretSlug: query.secretSlug },\n );\n return undefined;\n }\n\n const plaintext = openProviderCredential(\n row.secretValue,\n this.appConfigService.secrets.security.session.encryptionKey,\n {\n ownerScope: ExternalProvider_Connection_OwnerScope.USER,\n ownerId: query.userId,\n providerRef: query.providerRef,\n secretSlug: query.secretSlug,\n },\n );\n\n // What is STORED is not always what goes on the wire: an OAuth2 grant is a JSON document whose\n // access token is one field. Returning the plaintext directly would put that document on the\n // wire as a bearer token, and the vendor's 401 would name a credential problem rather than a\n // serialization one. One shared resolver, because both stores hold both shapes.\n const describeRow = `user '${query.userId}', provider '${query.providerRef}', slug '${query.secretSlug}'`;\n const resolved = resolveStoredCredentialValue(plaintext, describeRow, this.refresher !== undefined);\n if (resolved.needsRefresh) {\n // The renewal round trip and the write-back, in that order. The exchange belongs to the\n // refresher (it needs the contract and the application's registration); persisting belongs\n // here (it needs the table, the envelope key and the scope map). Neither half is where the\n // other's inputs are, which is why this is two components rather than one.\n const renewed = await this.renewOrRetire(row._id, query, {\n providerRef: query.providerRef,\n secretSlug: query.secretSlug,\n target: {\n ownerScope: ExternalProvider_Connection_OwnerScope.USER,\n ownerId: query.userId,\n delegation: ExternalProvider_Connection_DelegationMode.SERVICE,\n },\n grant: resolved.grant!,\n // From the ROW. The authorization record that first held these expired ten minutes after\n // the connect; a templated token URL is still templated an hour later, so without this a\n // Microsoft or regional connection renews into `needs a value for 'cloud'`.\n connectionParameters: row.connectionParameters,\n });\n await this.persistRenewedGrant(query, row._id, renewed);\n return { value: renewed.accessToken, credentialId: row._id };\n }\n\n return { value: resolved.wireValue, credentialId: row._id };\n }\n\n /**\n * The scoped read.\n *\n * `readAsSystem` rather than an ordinary repository read, for the reason the organization sibling\n * documents: a provider call legitimately happens on a batch, a queue consumer or a webhook return\n * leg, none of which carries the person's own session, and all of which must still resolve their\n * credential. The user travels in the system scope map, which is the channel the contextual filter\n * actually consumes.\n */\n private async readCredentialRow(\n query: UserProviderCredentialQuery,\n ): Promise<UserProviderCredential | null> {\n return this.systemAccess.readAsSystem<UserProviderCredential>(\n CoreResourceType.USER_PROVIDER_CREDENTIALS,\n {\n userId: query.userId,\n providerRef: query.providerRef,\n secretSlug: query.secretSlug,\n },\n { scopeContext: { userId: query.userId } },\n );\n }\n\n /**\n * Record that a credential was spent, and what the provider thought of it.\n *\n * Best-effort in both halves and deliberately so: the outbound provider call has already happened\n * by the time this runs, and failing the caller because a bookkeeping write did not land would\n * turn a successful integration into an error. Every failure is logged with the row named.\n */\n public async recordCredentialUse(use: {\n userId: string;\n providerRef: string;\n secretSlug: string;\n credentialId: string;\n /** What the provider said. Absent means the outcome is not yet known to the caller. */\n outcome?: { accepted: boolean; providerMessage?: string };\n }): Promise<void> {\n await this.emitUseAudit(use);\n\n const now = new Date();\n const patch: Record<string, unknown> = { lastUsedAt: now };\n if (use.outcome) {\n patch.validationState = use.outcome.accepted\n ? ProviderCredentialValidationState.VALID\n : ProviderCredentialValidationState.INVALID;\n patch.lastValidatedAt = now;\n // Truncated to the schema's own bound. The provider's message describes the CREDENTIAL's\n // status and must never be derived from the credential itself — a caller passing the secret\n // here would publish it to a client-readable field, which is why this is documented at the\n // one place a provider string enters the row.\n patch.validationError = use.outcome.accepted\n ? undefined\n : (use.outcome.providerMessage ?? '').slice(0, 500) || undefined;\n }\n\n try {\n await this.systemAccess.updateAsSystem(\n CoreResourceType.USER_PROVIDER_CREDENTIALS,\n use.credentialId,\n patch,\n {\n scopeContext: { userId: use.userId },\n /*\n * `lastUsedAt`, `lastValidatedAt` and `validationError` are all\n * `.excludeFromCreate().excludeFromUpdate()`, so the repository's strict `requestDto.parse`\n * drops them before persistence unless they are allow-listed here.\n *\n * The automatic diff that populates this list covers fields a custom-impl PREFIX hook\n * injected — which is how `secretSetAt` reaches the row on a write. Nothing populates it\n * for a payload a caller passes directly, which is what this is, so the omission was\n * silent in the worst way: `validationState` is NOT excluded and moved correctly, so the\n * row went INVALID while the timestamp and the provider's explanation of WHY vanished.\n * A person looking at a credential marked invalid with no reason and no last-use time is\n * being told less than the code believes it recorded.\n */\n preserveServerInjectedFields: ['lastUsedAt', 'lastValidatedAt', 'validationError'],\n },\n );\n } catch (error) {\n this.logger.warn?.(\n '[user-provider-credential] failed to record credential use',\n {\n userId: use.userId,\n providerRef: use.providerRef,\n secretSlug: use.secretSlug,\n credentialId: use.credentialId,\n error: describeCaughtError(error),\n },\n );\n }\n }\n\n private async emitUseAudit(use: {\n userId: string;\n providerRef: string;\n secretSlug: string;\n credentialId: string;\n }): Promise<void> {\n if (!this.auditLogs) {\n return;\n }\n try {\n await this.auditLogs.logUserProviderCredentialUsed({\n userId: use.userId,\n providerRef: use.providerRef,\n secretSlug: use.secretSlug,\n // Constant rather than a parameter: there is exactly one place a person's credential can come\n // from. Threading it through the caller would invite a future one to pass something else.\n resolvedFrom: ProviderCredentialResolutionSource.USER_CREDENTIAL,\n credentialId: use.credentialId,\n });\n } catch (error) {\n this.logger.warn?.(\n '[user-provider-credential] failed to emit credential-use audit event',\n {\n userId: use.userId,\n providerRef: use.providerRef,\n error: describeCaughtError(error),\n },\n );\n }\n }\n\n\n /**\n * Record a grant the authorization exchange just minted, replacing one already stored.\n *\n * The plaintext goes in and the resource's own WRITE DOOR seals it — the same hook that seals a\n * credential a person types, and the same reason `persistRenewedGrant` hands over plaintext:\n * `createAsSystem` / `updateAsSystem` reach the SERVICE tier, so a pre-sealed value arrives at\n * that hook and the envelope refuses to double-seal.\n *\n * ## Reconnecting REPLACES rather than adding a second row\n *\n * The business key is (userId, providerRef, secretSlug) and it is UNIQUE, so a second connect would\n * violate the index. Read-then-write is a race, and the honest statement is that the index is what\n * decides it: two simultaneous connects mean one of them loses, which is the correct outcome —\n * a person who authorized twice gets one connection, not two half-connections.\n *\n * @returns the credential row's id, so the caller can name it in an audit event.\n */\n public async storeGrant(\n query: UserProviderCredentialQuery,\n grant: ProviderOAuth2Grant,\n connectionParameters?: Readonly<Record<string, string>>,\n ): Promise<string> {\n const existing = await this.readCredentialRow(query);\n const secretValue = serializeProviderOAuth2Grant(grant);\n const scopeContext = { userId: query.userId };\n\n if (existing) {\n // `connectionParameters` is `.excludeFromUpdate()` — it describes the ACCOUNT the grant is\n // for, and re-authorizing against a different directory is a different connection. A\n // reconnect that changed them would point the refresh somewhere the token was not issued.\n await this.systemAccess.updateAsSystem(\n CoreResourceType.USER_PROVIDER_CREDENTIALS,\n existing._id,\n {\n secretValue,\n enabled: true,\n // Clearing the mark is part of reconnecting, not a separate concern. A row retired by\n // `renewOrRetire` would otherwise keep `validationState: INVALID` forever — so somebody\n // who did exactly what the screen told them to do would reconnect successfully and still\n // be shown a broken connection.\n validationState: ProviderCredentialValidationState.UNVALIDATED,\n validationError: undefined,\n },\n { scopeContext, preserveServerInjectedFields: ['validationError'] },\n );\n await this.emitConnectionGranted(query, grant, existing._id, true);\n return existing._id;\n }\n\n const created = await this.systemAccess.createAsSystem<UserProviderCredential>(\n CoreResourceType.USER_PROVIDER_CREDENTIALS,\n {\n userId: query.userId,\n providerRef: query.providerRef,\n secretSlug: query.secretSlug,\n secretValue,\n ...(connectionParameters === undefined ? {} : { connectionParameters }),\n },\n { scopeContext },\n );\n await this.emitConnectionGranted(query, grant, created._id, false);\n return created._id;\n }\n\n /**\n * Renew the grant, and RETIRE the connection when the vendor says it is finished.\n *\n * Without this the refresh call was unguarded, and the failure was slow and silent in the worst\n * direction. A vendor that permanently rejects a refresh token — the person removed the app at the\n * vendor, an administrator revoked it, the token aged past its absolute lifetime — throws, the\n * error propagates out of the resolve, and NOTHING touches the row. `validationState` stays where\n * it was, so the connected-accounts screen goes on showing the account as connected, every call\n * fails identically forever, and the person is never told the one thing they could act on.\n *\n * Only `invalid_grant` retires a connection, and the exclusions are the substantive part. A\n * transport failure, a bare 500 or an unparseable body means the vendor said NOTHING about the\n * grant, and retiring a working connection because we could not reach a vendor for thirty seconds\n * would be a self-inflicted outage. `invalid_client` is excluded for a different reason: it is the\n * APPLICATION's own registration being rejected, one operator's misconfiguration affecting every\n * connection at once — marking each person's account invalid would blame all of them for something\n * none of them can fix.\n *\n * The mark is best-effort and the ORIGINAL error is always re-thrown: the caller needs the real\n * cause, and a bookkeeping write that failed must not replace it with a different story.\n */\n private async renewOrRetire(\n credentialId: string,\n query: UserProviderCredentialQuery,\n request: Parameters<ProviderOAuth2RefresherPort['refreshGrant']>[0],\n ): Promise<ProviderOAuth2Grant> {\n try {\n return await this.refresher!.refreshGrant(request);\n } catch (error) {\n if (providerOAuth2GrantWasPermanentlyRejected(error)) {\n try {\n await this.systemAccess.updateAsSystem(\n CoreResourceType.USER_PROVIDER_CREDENTIALS,\n credentialId,\n {\n validationState: ProviderCredentialValidationState.INVALID,\n lastValidatedAt: new Date(),\n // The vendor's own code, and nothing derived from the credential. This field is\n // CLIENT-READABLE, so anything token-shaped reaching it would publish a secret onto\n // the screen that displays it.\n validationError: 'The provider rejected the stored authorization (invalid_grant). Reconnect the account.',\n },\n {\n scopeContext: { userId: query.userId },\n // Both of these are `.excludeFromUpdate()`; without the allow-list the row would go\n // INVALID carrying no reason and no timestamp — see `recordCredentialUse`.\n preserveServerInjectedFields: ['lastValidatedAt', 'validationError'],\n },\n );\n } catch (markError) {\n this.logger.warn?.(\n '[user-provider-credential] a grant was permanently rejected and the row could not be marked',\n { providerRef: query.providerRef, secretSlug: query.secretSlug, credentialId, error: describeCaughtError(markError) },\n );\n }\n }\n throw error;\n }\n }\n\n /**\n * Record that a delegated authorization was GRANTED, distinct from the row's own `_SET` event.\n *\n * Emitted HERE and nowhere else, because this is the only place that holds the three facts an\n * auditor wants and the row does not: the scopes the vendor actually issued, which account they\n * were issued for, and whether this replaced a connection that already existed. By the time the\n * resource's own write hook sees the row, the value is sealed and none of it is recoverable.\n *\n * Best-effort, like every other emission on this path. The grant is already stored and the person\n * has already authorized it; failing their connection because a trail write did not land would\n * turn a completed authorization into an error and invite them to grant it a second time.\n */\n private async emitConnectionGranted(\n query: UserProviderCredentialQuery,\n grant: ProviderOAuth2Grant,\n credentialId: string,\n replacedExistingConnection: boolean,\n ): Promise<void> {\n if (!this.auditLogs) {\n return;\n }\n try {\n await this.auditLogs.logUserProviderConnectionGranted({\n userId: query.userId,\n providerRef: query.providerRef,\n secretSlug: query.secretSlug,\n credentialId,\n grantedScopes: grant.grantedScopes,\n accountRef: grant.accountRef,\n replacedExistingConnection,\n });\n } catch (error) {\n this.logger.warn?.(\n '[user-provider-credential] a connection was granted and the audit event could not be emitted',\n { providerRef: query.providerRef, secretSlug: query.secretSlug, credentialId, error: describeCaughtError(error) },\n );\n }\n }\n\n /**\n * Persist a renewed grant through the resource's own WRITE door.\n *\n * The plaintext goes in and the CUSTOM IMPLEMENTATION seals it — the same hook that seals a\n * credential a person types. Sealing here instead would be a second sealing site for one\n * invariant, and it does not merely duplicate: `updateAsSystem` reaches the service tier, so a\n * pre-sealed value arrives at that hook and the envelope REFUSES it (\"double-sealing would hand\n * the envelope itself to the provider\"). Every refresh would have thrown at the write-back.\n *\n * `secretSetAt` therefore moves, and that is correct rather than tolerated: the field is defined\n * as \"when the stored VALUE last changed\", and a renewal changes it. An earlier version of this\n * method held it still on the theory that it should mean \"when a HUMAN last supplied a value\" —\n * that is a different field, and inventing the behaviour without the field was the error.\n *\n * NOT best-effort. A refresh that is not persisted happens again on every call, and against a\n * vendor that rotates the refresh token each one invalidates the last — so the connection breaks\n * while every individual exchange succeeds.\n */\n private async persistRenewedGrant(\n query: UserProviderCredentialQuery,\n credentialId: string,\n renewed: ProviderOAuth2Grant,\n ): Promise<void> {\n await this.systemAccess.updateAsSystem(\n CoreResourceType.USER_PROVIDER_CREDENTIALS,\n credentialId,\n { secretValue: serializeProviderOAuth2Grant(renewed) },\n { scopeContext: { userId: query.userId } },\n );\n }\n\n /**\n * Turn an envelope failure into the operator-facing statement.\n *\n * Exposed so the registry can distinguish \"this person has no credential\" from \"they HAVE one and\n * it is broken\" without importing the envelope's error type and re-deriving the distinction. One\n * definition, one meaning.\n */\n public static isUnopenableCredential(error: unknown): error is ProviderCredentialEnvelopeError {\n return error instanceof ProviderCredentialEnvelopeError;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"user-provider-credential-store.backend.service.js","sourceRoot":"","sources":["../../../../../src/security/connected-accounts/services/user-provider-credential-store.backend.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The user-provider-credential STORE — the port implementation the registry consults for a PERSON's\n * own credential.\n *\n * ## What makes the isolation structural rather than a filter\n *\n * The same three independent mechanisms as the organization store, and none of them is a predicate\n * somebody has to remember to write at each call site:\n *\n * 1. **The owner FK is injected by the context machinery.** The read goes through `readAsSystem`\n * with the user in the system scope map, so `buildContextualFilter` adds the clause itself. A\n * caller cannot omit it, because the caller never writes it.\n * 2. **The filter names the user explicitly as well.** Belt and braces, deliberately: the contextual\n * filter is injected by a mechanism that exists TWICE (a Mongo implementation and a PostgreSQL\n * one), so a regression in one adapter is a bypass in that adapter alone. The explicit clause is\n * adapter-independent and would still scope the read.\n * 3. **The envelope is BOUND to the row identity, under a key derived for the USER scope.** Even a\n * read that returned another person's row — or a tenant's — would fail to OPEN it. This is the\n * one that holds when the other two are wrong, which is why it exists.\n *\n * ## Why this is a separate service rather than the organization store with an owner parameter\n *\n * The read is the same shape and everything around it differs. There is no fallback (a person who\n * has connected nothing gets a refusal, never the deployment's shared principal). There is no\n * administrative variant, so the actor and the subject are always the same identity and the audit\n * events say so. And the resource is a composition under `USERS` rather than under `ORGANIZATIONS`,\n * so the scope map, the cascade and the erasure semantics are a different set throughout.\n *\n * A single service parameterised by owner would carry every one of those as a branch, and the\n * branch a reader most needs to trust — \"is a fallback reachable from here?\" — would be the one\n * spelled as an `if`.\n *\n * assurance-control: WILDO.IDENTITY.DELEGATED_AUTHORIZATION — a user's delegated authority toward a\n * third party is read only for that user.\n */\n\nimport { inject, injectable, optional } from 'inversify';\nimport {\n CoreResourceType,\n ProviderCredentialResolutionSource,\n ProviderCredentialValidationState,\n serializeProviderOAuth2Grant,\n type ProviderOAuth2Grant,\n type UserProviderCredential,\n} from '@wildo-ai/saas-models';\n\nimport { ExternalProvider_Connection_DelegationMode, ExternalProvider_Connection_OwnerScope } from '@wildo-ai/external-connectors-models';\n\nimport { SAAS_SERVICE_TYPES } from '~wildo-backend-lib/inject/models/service-types';\nimport type { LoggerService } from '~wildo-backend-lib/monitoring/logger/services/logger.service';\nimport type { AppConfigurationService } from '~wildo-backend-lib/config/services/app-configuration.backend.service';\nimport type { SystemAccessBackendService } from '~wildo-backend-lib/base-classes/services/services/system-access.backend.service';\nimport type { AuditLogsBackendService } from '~wildo-backend-lib/compliance/audit-trails/services/audit-logs.backend.service';\nimport { describeCaughtError } from '~wildo-backend-lib/errors/utils/error-log-level-classification.backend.utils';\n\nimport {\n ProviderCredentialEnvelopeError,\n openProviderCredential,\n} from '../utils/provider-credential-envelope.backend.utils';\nimport { resolveStoredCredentialValue } from '../utils/stored-credential-value.backend.utils';\nimport { providerOAuth2GrantWasPermanentlyRejected } from './provider-oauth2-exchange.backend';\nimport type { ProviderOAuth2RefresherPort } from '../provider-oauth2-refresher.port';\nimport type {\n UserProviderCredentialQuery,\n UserProviderCredentialResolution,\n UserProviderCredentialResolverPort,\n} from '../user-provider-credential-resolver.port';\n\n@injectable()\nexport class UserProviderCredentialStoreBackendService implements UserProviderCredentialResolverPort {\n constructor(\n @inject(SAAS_SERVICE_TYPES.Logger) private readonly logger: LoggerService,\n @inject(SAAS_SERVICE_TYPES.AppConfigService) private readonly appConfigService: AppConfigurationService,\n @inject(SAAS_SERVICE_TYPES.SystemAccessService) private readonly systemAccess: SystemAccessBackendService,\n /**\n * OPTIONAL and lazily used, mirroring `SystemAccessBackendService`'s own treatment of it: audit\n * emission must never be the reason a provider call fails, and a minimal test container must\n * still be able to construct this service.\n */\n @inject(SAAS_SERVICE_TYPES.AuditLogsService) @optional() private readonly auditLogs?: AuditLogsBackendService,\n /**\n * Appended LAST, deliberately: a parameter inserted mid-signature silently reassigns every\n * positional argument after it, and this constructor is called positionally by several harnesses.\n *\n * OPTIONAL, and its absence is not a degradation — a store without one resolves every pasted\n * credential and every non-expiring token exactly as before. Only an EXPIRING grant needs it, and\n * that case refuses by name rather than sending a stale token.\n */\n @inject(SAAS_SERVICE_TYPES.ProviderOAuth2Refresher) @optional() private readonly refresher?: ProviderOAuth2RefresherPort,\n ) {}\n\n /**\n * The person's own credential, opened, or `undefined` when they have not connected this provider.\n *\n * See the port's JSDoc for why \"absent\" returns and \"present but unopenable\" throws.\n */\n public async resolveUserCredential(\n query: UserProviderCredentialQuery,\n ): Promise<UserProviderCredentialResolution | undefined> {\n const row = await this.readCredentialRow(query);\n if (!row) {\n return undefined;\n }\n\n // A disabled credential is treated as absent — which here means the call REFUSES, because there\n // is nothing to fall through to. That is the intended shape: someone who switches their own\n // connection off is asking the application to stop acting as them, and the honest outcome is an\n // integration that stops rather than one that quietly continues under another identity.\n if (row.enabled === false) {\n this.logger.debug?.(\n '[user-provider-credential] credential is disabled; treating as absent',\n { userId: query.userId, providerRef: query.providerRef, secretSlug: query.secretSlug },\n );\n return undefined;\n }\n\n const plaintext = openProviderCredential(\n row.secretValue,\n this.appConfigService.secrets.security.session.encryptionKey,\n {\n ownerScope: ExternalProvider_Connection_OwnerScope.USER,\n ownerId: query.userId,\n providerRef: query.providerRef,\n secretSlug: query.secretSlug,\n },\n );\n\n // What is STORED is not always what goes on the wire: an OAuth2 grant is a JSON document whose\n // access token is one field. Returning the plaintext directly would put that document on the\n // wire as a bearer token, and the vendor's 401 would name a credential problem rather than a\n // serialization one. One shared resolver, because both stores hold both shapes.\n const describeRow = `user '${query.userId}', provider '${query.providerRef}', slug '${query.secretSlug}'`;\n const resolved = resolveStoredCredentialValue(plaintext, describeRow, this.refresher !== undefined);\n if (resolved.needsRefresh) {\n // The renewal round trip and the write-back, in that order. The exchange belongs to the\n // refresher (it needs the contract and the application's registration); persisting belongs\n // here (it needs the table, the envelope key and the scope map). Neither half is where the\n // other's inputs are, which is why this is two components rather than one.\n const renewed = await this.renewOrRetire(row._id, query, {\n providerRef: query.providerRef,\n secretSlug: query.secretSlug,\n target: {\n ownerScope: ExternalProvider_Connection_OwnerScope.USER,\n ownerId: query.userId,\n delegation: ExternalProvider_Connection_DelegationMode.SERVICE,\n },\n grant: resolved.grant!,\n // From the ROW. The authorization record that first held these expired ten minutes after\n // the connect; a templated token URL is still templated an hour later, so without this a\n // Microsoft or regional connection renews into `needs a value for 'cloud'`.\n connectionParameters: row.connectionParameters,\n });\n await this.persistRenewedGrant(query, row._id, renewed);\n return { value: renewed.accessToken, credentialId: row._id, expiresAt: renewed.expiresAt, grantedScopes: renewed.grantedScopes };\n }\n\n return {\n value: resolved.wireValue,\n credentialId: row._id,\n expiresAt: resolved.grant?.expiresAt,\n grantedScopes: resolved.grant?.grantedScopes,\n };\n }\n\n /**\n * The scoped read.\n *\n * `readAsSystem` rather than an ordinary repository read, for the reason the organization sibling\n * documents: a provider call legitimately happens on a batch, a queue consumer or a webhook return\n * leg, none of which carries the person's own session, and all of which must still resolve their\n * credential. The user travels in the system scope map, which is the channel the contextual filter\n * actually consumes.\n */\n private async readCredentialRow(\n query: UserProviderCredentialQuery,\n ): Promise<UserProviderCredential | null> {\n return this.systemAccess.readAsSystem<UserProviderCredential>(\n CoreResourceType.USER_PROVIDER_CREDENTIALS,\n {\n userId: query.userId,\n providerRef: query.providerRef,\n secretSlug: query.secretSlug,\n },\n { scopeContext: { userId: query.userId } },\n );\n }\n\n /**\n * Record that a credential was spent, and what the provider thought of it.\n *\n * Best-effort in both halves and deliberately so: the outbound provider call has already happened\n * by the time this runs, and failing the caller because a bookkeeping write did not land would\n * turn a successful integration into an error. Every failure is logged with the row named.\n */\n public async recordCredentialUse(use: {\n userId: string;\n providerRef: string;\n secretSlug: string;\n credentialId: string;\n /** What the provider said. Absent means the outcome is not yet known to the caller. */\n outcome?: { accepted: boolean; providerMessage?: string };\n }): Promise<void> {\n await this.emitUseAudit(use);\n\n const now = new Date();\n const patch: Record<string, unknown> = { lastUsedAt: now };\n if (use.outcome) {\n patch.validationState = use.outcome.accepted\n ? ProviderCredentialValidationState.VALID\n : ProviderCredentialValidationState.INVALID;\n patch.lastValidatedAt = now;\n // Truncated to the schema's own bound. The provider's message describes the CREDENTIAL's\n // status and must never be derived from the credential itself — a caller passing the secret\n // here would publish it to a client-readable field, which is why this is documented at the\n // one place a provider string enters the row.\n patch.validationError = use.outcome.accepted\n ? undefined\n : (use.outcome.providerMessage ?? '').slice(0, 500) || undefined;\n }\n\n try {\n await this.systemAccess.updateAsSystem(\n CoreResourceType.USER_PROVIDER_CREDENTIALS,\n use.credentialId,\n patch,\n {\n scopeContext: { userId: use.userId },\n /*\n * `lastUsedAt`, `lastValidatedAt` and `validationError` are all\n * `.excludeFromCreate().excludeFromUpdate()`, so the repository's strict `requestDto.parse`\n * drops them before persistence unless they are allow-listed here.\n *\n * The automatic diff that populates this list covers fields a custom-impl PREFIX hook\n * injected — which is how `secretSetAt` reaches the row on a write. Nothing populates it\n * for a payload a caller passes directly, which is what this is, so the omission was\n * silent in the worst way: `validationState` is NOT excluded and moved correctly, so the\n * row went INVALID while the timestamp and the provider's explanation of WHY vanished.\n * A person looking at a credential marked invalid with no reason and no last-use time is\n * being told less than the code believes it recorded.\n */\n preserveServerInjectedFields: ['lastUsedAt', 'lastValidatedAt', 'validationError'],\n },\n );\n } catch (error) {\n this.logger.warn?.(\n '[user-provider-credential] failed to record credential use',\n {\n userId: use.userId,\n providerRef: use.providerRef,\n secretSlug: use.secretSlug,\n credentialId: use.credentialId,\n error: describeCaughtError(error),\n },\n );\n }\n }\n\n private async emitUseAudit(use: {\n userId: string;\n providerRef: string;\n secretSlug: string;\n credentialId: string;\n }): Promise<void> {\n if (!this.auditLogs) {\n return;\n }\n try {\n await this.auditLogs.logUserProviderCredentialUsed({\n userId: use.userId,\n providerRef: use.providerRef,\n secretSlug: use.secretSlug,\n // Constant rather than a parameter: there is exactly one place a person's credential can come\n // from. Threading it through the caller would invite a future one to pass something else.\n resolvedFrom: ProviderCredentialResolutionSource.USER_CREDENTIAL,\n credentialId: use.credentialId,\n });\n } catch (error) {\n this.logger.warn?.(\n '[user-provider-credential] failed to emit credential-use audit event',\n {\n userId: use.userId,\n providerRef: use.providerRef,\n error: describeCaughtError(error),\n },\n );\n }\n }\n\n\n /**\n * Record a grant the authorization exchange just minted, replacing one already stored.\n *\n * The plaintext goes in and the resource's own WRITE DOOR seals it — the same hook that seals a\n * credential a person types, and the same reason `persistRenewedGrant` hands over plaintext:\n * `createAsSystem` / `updateAsSystem` reach the SERVICE tier, so a pre-sealed value arrives at\n * that hook and the envelope refuses to double-seal.\n *\n * ## Reconnecting REPLACES rather than adding a second row\n *\n * The business key is (userId, providerRef, secretSlug) and it is UNIQUE, so a second connect would\n * violate the index. Read-then-write is a race, and the honest statement is that the index is what\n * decides it: two simultaneous connects mean one of them loses, which is the correct outcome —\n * a person who authorized twice gets one connection, not two half-connections.\n *\n * @returns the credential row's id, so the caller can name it in an audit event.\n */\n public async storeGrant(\n query: UserProviderCredentialQuery,\n grant: ProviderOAuth2Grant,\n connectionParameters?: Readonly<Record<string, string>>,\n ): Promise<string> {\n const existing = await this.readCredentialRow(query);\n const secretValue = serializeProviderOAuth2Grant(grant);\n const scopeContext = { userId: query.userId };\n\n if (existing) {\n // `connectionParameters` is `.excludeFromUpdate()` — it describes the ACCOUNT the grant is\n // for, and re-authorizing against a different directory is a different connection. A\n // reconnect that changed them would point the refresh somewhere the token was not issued.\n await this.systemAccess.updateAsSystem(\n CoreResourceType.USER_PROVIDER_CREDENTIALS,\n existing._id,\n {\n secretValue,\n enabled: true,\n // Clearing the mark is part of reconnecting, not a separate concern. A row retired by\n // `renewOrRetire` would otherwise keep `validationState: INVALID` forever — so somebody\n // who did exactly what the screen told them to do would reconnect successfully and still\n // be shown a broken connection.\n validationState: ProviderCredentialValidationState.UNVALIDATED,\n validationError: undefined,\n },\n { scopeContext, preserveServerInjectedFields: ['validationError'] },\n );\n await this.emitConnectionGranted(query, grant, existing._id, true);\n return existing._id;\n }\n\n const created = await this.systemAccess.createAsSystem<UserProviderCredential>(\n CoreResourceType.USER_PROVIDER_CREDENTIALS,\n {\n userId: query.userId,\n providerRef: query.providerRef,\n secretSlug: query.secretSlug,\n secretValue,\n ...(connectionParameters === undefined ? {} : { connectionParameters }),\n },\n { scopeContext },\n );\n await this.emitConnectionGranted(query, grant, created._id, false);\n return created._id;\n }\n\n /**\n * Store a credential somebody TYPED, as opposed to one an exchange minted.\n *\n * The other half of `storeGrant`, and separate from it because the two differ in every way that\n * matters: a grant is a JSON document with an expiry and a refresh token, this is one opaque value;\n * a grant arrives from a vendor, this arrives from a person; a grant can be renewed, this can only\n * be replaced. Serialising a typed key through the grant envelope would put\n * `wildo-oauth2-grant:{...}` on the wire as a bearer token.\n *\n * PLAINTEXT to the write door, which seals. Handing a pre-sealed value to `createAsSystem` reaches\n * the service tier where the sealing hook refuses to double-seal — so the write would throw after\n * the person had already typed their key.\n *\n * Replaces rather than duplicates: the business key is (owner, provider, slug), so re-entering a\n * rotated key is the ordinary case and a second create would violate the index. Re-entering also\n * RE-ENABLES and clears any validation mark, because somebody who has just supplied a working key\n * should not be shown a broken connection.\n */\n public async storeDeclaredSecret(query: UserProviderCredentialQuery, secretValue: string): Promise<string> {\n const existing = await this.readCredentialRow(query);\n const scopeContext = { userId: query.userId };\n\n if (existing) {\n await this.systemAccess.updateAsSystem(\n CoreResourceType.USER_PROVIDER_CREDENTIALS,\n existing._id,\n {\n secretValue,\n enabled: true,\n validationState: ProviderCredentialValidationState.UNVALIDATED,\n validationError: undefined,\n },\n { scopeContext, preserveServerInjectedFields: ['validationError'] },\n );\n return existing._id;\n }\n\n const created = await this.systemAccess.createAsSystem<UserProviderCredential>(\n CoreResourceType.USER_PROVIDER_CREDENTIALS,\n {\n userId: query.userId,\n providerRef: query.providerRef,\n secretSlug: query.secretSlug,\n secretValue,\n },\n { scopeContext },\n );\n return created._id;\n }\n\n /**\n * Renew the grant, and RETIRE the connection when the vendor says it is finished.\n *\n * Without this the refresh call was unguarded, and the failure was slow and silent in the worst\n * direction. A vendor that permanently rejects a refresh token — the person removed the app at the\n * vendor, an administrator revoked it, the token aged past its absolute lifetime — throws, the\n * error propagates out of the resolve, and NOTHING touches the row. `validationState` stays where\n * it was, so the connected-accounts screen goes on showing the account as connected, every call\n * fails identically forever, and the person is never told the one thing they could act on.\n *\n * Only `invalid_grant` retires a connection, and the exclusions are the substantive part. A\n * transport failure, a bare 500 or an unparseable body means the vendor said NOTHING about the\n * grant, and retiring a working connection because we could not reach a vendor for thirty seconds\n * would be a self-inflicted outage. `invalid_client` is excluded for a different reason: it is the\n * APPLICATION's own registration being rejected, one operator's misconfiguration affecting every\n * connection at once — marking each person's account invalid would blame all of them for something\n * none of them can fix.\n *\n * The mark is best-effort and the ORIGINAL error is always re-thrown: the caller needs the real\n * cause, and a bookkeeping write that failed must not replace it with a different story.\n */\n private async renewOrRetire(\n credentialId: string,\n query: UserProviderCredentialQuery,\n request: Parameters<ProviderOAuth2RefresherPort['refreshGrant']>[0],\n ): Promise<ProviderOAuth2Grant> {\n try {\n return await this.refresher!.refreshGrant(request);\n } catch (error) {\n if (providerOAuth2GrantWasPermanentlyRejected(error)) {\n try {\n await this.systemAccess.updateAsSystem(\n CoreResourceType.USER_PROVIDER_CREDENTIALS,\n credentialId,\n {\n validationState: ProviderCredentialValidationState.INVALID,\n lastValidatedAt: new Date(),\n // The vendor's own code, and nothing derived from the credential. This field is\n // CLIENT-READABLE, so anything token-shaped reaching it would publish a secret onto\n // the screen that displays it.\n validationError: 'The provider rejected the stored authorization (invalid_grant). Reconnect the account.',\n },\n {\n scopeContext: { userId: query.userId },\n // Both of these are `.excludeFromUpdate()`; without the allow-list the row would go\n // INVALID carrying no reason and no timestamp — see `recordCredentialUse`.\n preserveServerInjectedFields: ['lastValidatedAt', 'validationError'],\n },\n );\n } catch (markError) {\n this.logger.warn?.(\n '[user-provider-credential] a grant was permanently rejected and the row could not be marked',\n { providerRef: query.providerRef, secretSlug: query.secretSlug, credentialId, error: describeCaughtError(markError) },\n );\n }\n }\n throw error;\n }\n }\n\n /**\n * Record that a delegated authorization was GRANTED, distinct from the row's own `_SET` event.\n *\n * Emitted HERE and nowhere else, because this is the only place that holds the three facts an\n * auditor wants and the row does not: the scopes the vendor actually issued, which account they\n * were issued for, and whether this replaced a connection that already existed. By the time the\n * resource's own write hook sees the row, the value is sealed and none of it is recoverable.\n *\n * Best-effort, like every other emission on this path. The grant is already stored and the person\n * has already authorized it; failing their connection because a trail write did not land would\n * turn a completed authorization into an error and invite them to grant it a second time.\n */\n private async emitConnectionGranted(\n query: UserProviderCredentialQuery,\n grant: ProviderOAuth2Grant,\n credentialId: string,\n replacedExistingConnection: boolean,\n ): Promise<void> {\n if (!this.auditLogs) {\n return;\n }\n try {\n await this.auditLogs.logUserProviderConnectionGranted({\n userId: query.userId,\n providerRef: query.providerRef,\n secretSlug: query.secretSlug,\n credentialId,\n grantedScopes: grant.grantedScopes,\n accountRef: grant.accountRef,\n replacedExistingConnection,\n });\n } catch (error) {\n this.logger.warn?.(\n '[user-provider-credential] a connection was granted and the audit event could not be emitted',\n { providerRef: query.providerRef, secretSlug: query.secretSlug, credentialId, error: describeCaughtError(error) },\n );\n }\n }\n\n /**\n * Persist a renewed grant through the resource's own WRITE door.\n *\n * The plaintext goes in and the CUSTOM IMPLEMENTATION seals it — the same hook that seals a\n * credential a person types. Sealing here instead would be a second sealing site for one\n * invariant, and it does not merely duplicate: `updateAsSystem` reaches the service tier, so a\n * pre-sealed value arrives at that hook and the envelope REFUSES it (\"double-sealing would hand\n * the envelope itself to the provider\"). Every refresh would have thrown at the write-back.\n *\n * `secretSetAt` therefore moves, and that is correct rather than tolerated: the field is defined\n * as \"when the stored VALUE last changed\", and a renewal changes it. An earlier version of this\n * method held it still on the theory that it should mean \"when a HUMAN last supplied a value\" —\n * that is a different field, and inventing the behaviour without the field was the error.\n *\n * NOT best-effort. A refresh that is not persisted happens again on every call, and against a\n * vendor that rotates the refresh token each one invalidates the last — so the connection breaks\n * while every individual exchange succeeds.\n */\n private async persistRenewedGrant(\n query: UserProviderCredentialQuery,\n credentialId: string,\n renewed: ProviderOAuth2Grant,\n ): Promise<void> {\n await this.systemAccess.updateAsSystem(\n CoreResourceType.USER_PROVIDER_CREDENTIALS,\n credentialId,\n { secretValue: serializeProviderOAuth2Grant(renewed) },\n { scopeContext: { userId: query.userId } },\n );\n }\n\n /**\n * Turn an envelope failure into the operator-facing statement.\n *\n * Exposed so the registry can distinguish \"this person has no credential\" from \"they HAVE one and\n * it is broken\" without importing the envelope's error type and re-deriving the distinction. One\n * definition, one meaning.\n */\n public static isUnopenableCredential(error: unknown): error is ProviderCredentialEnvelopeError {\n return error instanceof ProviderCredentialEnvelopeError;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-provider-credentials.custom-impl.backend.service.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"user-provider-credentials.custom-impl.backend.service.d.ts","sourceRoot":"","sources":["../../../../../src/security/connected-accounts/services/user-provider-credentials.custom-impl.backend.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAkBH,OAAO,EAEL,KAAK,0CAA0C,EAChD,MAAM,4GAA4G,CAAC;AAwUpH,iEAAiE;AACjE,wBAAgB,qCAAqC,IAAI,0CAA0C,EAAE,CAMpG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-provider-credentials.custom-impl.backend.service.js","sourceRoot":"","sources":["../../../../../../src/security/connected-accounts/services/user-provider-credentials.custom-impl.backend.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The WRITE path for a PERSON's own provider credential: seal on the way in, audit on the way out.\n *\n * ## Without this file the resource stores plaintext\n *\n * The schema declares `secretValue` as `.isWriteOnlySecret()`, which governs how the value is\n * PRESENTED (redacted at the client boundary, and a round-tripped mask means \"keep the stored\n * secret\"). It says nothing about how the value is STORED — a write-only-secret field lands in the\n * database exactly as the client typed it. Sealing it is this hook's job, and it is the only place\n * that job is done, so a credential reaching persistence unsealed means this registration did not\n * resolve.\n *\n * ⚠️ A custom implementation resolves by an EXACT operation-path key embedding the resource, the\n * operation, the variant TYPE and the default/variant-key slot. A registration naming a combination\n * the resource configuration does not declare resolves nothing and silently never runs, while the\n * route still answers 200 — here that would mean every person's third-party key persisted in\n * plaintext behind a green suite. The pins assert these registrations against the REAL resource\n * configuration for that reason.\n *\n * ## What differs from the organization sibling, and why each difference is substantive\n *\n * - **No `setByUserId`.** The organization's row records WHICH administrator wrote it, because\n * several can. This resource declares no administrative variant at all, so the author is always\n * the owner and a separate field could only ever repeat `userId` — while inviting a future reader\n * to believe the two can differ.\n * - **The DELETE reason is `OWNER_REVOKED`, not `ADMINISTRATOR_REVOKED`.** Same door, different\n * meaning: nobody but the holder can reach it.\n * - **The cascade door destroys evidence that matters more.** When a subject is erased, the\n * `USERS → USER_PROVIDER_CREDENTIALS` composition removes these rows through the RAW repository,\n * bypassing the service tier exactly as the organization purge does. The consequence is sharper\n * here: the deletion event is what an operator produces when asked whether an erasure reached the\n * person's third-party credentials, and the cascade cannot emit one. `USER_DELETED` records that\n * the subject was erased; what is missing is the enumeration of WHICH vendors they had connected.\n * This is the SAME defect as the organization purge's, at a second site — one cascade-tier audit\n * hook fixes both — and it is recorded on issue #365 rather than left for a reader to discover\n * from an absence. `ProviderCredentialDeletionReason.USER_ERASED` exists for the event that hook\n * will emit; nothing can emit it today.\n *\n * assurance-control: WILDO.IDENTITY.DELEGATED_AUTHORIZATION — a user authorizes, rotates and\n * withdraws delegated access to a named third party.\n */\n\nimport type { Container } from 'inversify';\nimport {\n CoreAuditableEventType,\n CoreResourceOperation,\n CoreResourceType,\n ErrorType,\n ErrorCustomMessageReference,\n ProviderCredentialDeletionReason,\n ResourceOperationVariantType,\n WRITE_ONLY_SECRET_MASK,\n coreResourceShared_FieldIdentifier,\n type UserProviderCredential,\n} from '@wildo-ai/saas-models';\n\nimport { ExternalProvider_Connection_OwnerScope } from '@wildo-ai/external-connectors-models';\n\nimport {\n createResourceCustomServiceImplementation,\n type ResourceCustomServiceImplementationFactory,\n} from '~wildo-backend-lib/base-classes/services/services/resource-operation-custom-implementation.factory.backend';\nimport type { ResourceOperation_CustomImplementation_Utils } from '~wildo-backend-lib/base-classes/services/services/resource-operation-custom-implementation-base.backend.service';\nimport type { ResourcesRegistryBackendService } from '~wildo-backend-lib/resources/services/resources-registry.backend.service';\nimport type { ExecutionContext } from '~wildo-backend-lib/runtime/models/execution-context.backend.schemas';\nimport { SAAS_SERVICE_TYPES } from '~wildo-backend-lib/inject/models/service-types';\nimport type { AppConfigurationService } from '~wildo-backend-lib/config/services/app-configuration.backend.service';\nimport type { AuditLogsBackendService } from '~wildo-backend-lib/compliance/audit-trails/services/audit-logs.backend.service';\nimport { projectCaughtErrorLogFields } from '~wildo-backend-lib/errors/utils/error-log-level-classification.backend.utils';\n\nimport { sealProviderCredential } from '../utils/provider-credential-envelope.backend.utils';\n\n/** The row identity the seal binds to, resolved from whichever channel actually carries each part. */\ninterface UserCredentialWriteIdentity {\n userId: string;\n providerRef: string;\n secretSlug: string;\n}\n\n/**\n * Resolve the identity the seal binds to.\n *\n * Two sources, and the request BODY is deliberately not one of them. On UPDATE the stored row is\n * authoritative — it is what the framework already persisted. On CREATE the execution context's\n * context-resource map is, because that is the same channel `enrichDataWithContext` reads when it\n * injects the scope FK, so the seal binds to the person the row will actually be stored under.\n *\n * A `payload.userId` fallback is absent for the organization sibling's reason: it would fail safe\n * (a seal bound to a body-supplied owner is simply unopenable later, so the outcome is a denial\n * rather than a disclosure) but it is still the REQUEST choosing what the seal binds to, which is\n * exactly the authorship this hook exists to keep out of a caller's hands.\n */\nfunction resolveWriteIdentity(\n input: Record<string, unknown> | undefined,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils,\n): UserCredentialWriteIdentity {\n const current = utils.currentObject as UserProviderCredential | undefined;\n\n const userId =\n (typeof current?.userId === 'string' && current.userId)\n || executionContext.getContextResourceId?.(coreResourceShared_FieldIdentifier[CoreResourceType.USERS] as never);\n\n const providerRef =\n (typeof input?.providerRef === 'string' && input.providerRef)\n || (typeof current?.providerRef === 'string' ? current.providerRef : undefined);\n\n const secretSlug =\n (typeof input?.secretSlug === 'string' && input.secretSlug)\n || (typeof current?.secretSlug === 'string' ? current.secretSlug : undefined);\n\n if (typeof userId !== 'string' || !userId || !providerRef || !secretSlug) {\n // Fail CLOSED. Sealing under a partial identity would produce a credential bound to the wrong\n // row — unopenable at resolution time, and indistinguishable then from a tampered one.\n throw utils.errorBuilder.buildError(ErrorType.CONFIGURATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.CONFIGURATION,\n context: {\n message:\n 'Cannot seal a user provider credential: the row identity is incomplete. All three of userId, '\n + 'providerRef and secretSlug must be resolvable, because the seal is bound to them. The user is '\n + 'read from the execution scope or the stored row, never from the request body.',\n hasUserId: Boolean(userId),\n hasProviderRef: Boolean(providerRef),\n hasSecretSlug: Boolean(secretSlug),\n },\n });\n }\n\n return { userId, providerRef, secretSlug };\n}\n\n/**\n * Seal an incoming secret, or return nothing when the write carries none.\n *\n * The mask is what makes an ordinary metadata edit safe: a client that read the row back received\n * `WRITE_ONLY_SECRET_MASK` in place of the value, and sending it back means \"keep what is stored\".\n * Sealing the mask would replace a working credential with the literal string of bullet characters.\n */\nfunction sealIncomingSecret(\n input: Record<string, unknown> | undefined,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils,\n container: Container,\n): Record<string, unknown> | undefined {\n const incoming = input?.secretValue;\n if (typeof incoming !== 'string' || incoming.length === 0 || incoming === WRITE_ONLY_SECRET_MASK) {\n return undefined;\n }\n\n const identity = resolveWriteIdentity(input, executionContext, utils);\n const appConfig = container.get<AppConfigurationService>(SAAS_SERVICE_TYPES.AppConfigService);\n\n return {\n ...input,\n secretValue: sealProviderCredential(\n incoming,\n appConfig.secrets.security.session.encryptionKey,\n {\n ownerScope: ExternalProvider_Connection_OwnerScope.USER,\n ownerId: identity.userId,\n providerRef: identity.providerRef,\n secretSlug: identity.secretSlug,\n },\n ),\n // Server-owned provenance. `.excludeFromCreate().excludeFromUpdate()`, so returning it here is\n // what carries it past the strict re-parse, declared explicitly in `authoritativeFields` below.\n secretSetAt: new Date(),\n };\n}\n\n/**\n * Emit the lifecycle event for a completed write.\n *\n * Best-effort in the same posture as every other audit emission in the engine: the credential has\n * already been written, and turning a logging failure into a 500 would tell the person their write\n * failed when it did not.\n */\nasync function emitCredentialWriteAudit(\n container: Container,\n eventType:\n | typeof CoreAuditableEventType.USER_PROVIDER_CREDENTIAL_SET\n | typeof CoreAuditableEventType.USER_PROVIDER_CREDENTIAL_ROTATED,\n row: UserProviderCredential | undefined,\n previousSecretSetAt: Date | undefined,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils,\n): Promise<void> {\n if (!row || typeof row._id !== 'string' || typeof row.userId !== 'string') {\n utils.logger.error?.(\n 'A user provider credential was written but the row could not be identified — audit event not emitted',\n { eventType },\n );\n return;\n }\n\n try {\n const auditLogs = container.get<AuditLogsBackendService>(SAAS_SERVICE_TYPES.AuditLogsService);\n // `userId` is taken from the ROW, not from the initiator. They are the same identity here by\n // construction, and reading the row is what keeps that true if a future variant ever lets them\n // differ: the event must name whose credential it is, never who happened to make the call.\n const common = {\n userId: row.userId,\n providerRef: row.providerRef,\n secretSlug: row.secretSlug,\n credentialId: row._id,\n };\n if (eventType === CoreAuditableEventType.USER_PROVIDER_CREDENTIAL_SET) {\n await auditLogs.logUserProviderCredentialSet(common, executionContext);\n } else {\n await auditLogs.logUserProviderCredentialRotated(\n { ...common, previousSecretSetAt: previousSecretSetAt?.toISOString() },\n executionContext,\n );\n }\n } catch (error) {\n utils.logger.error?.('Failed to emit the user provider credential audit event', {\n eventType,\n credentialId: row._id,\n ...projectCaughtErrorLogFields(error),\n });\n }\n}\n\n/** CREATE — the person connects an account at a third party for the first time. */\nfunction createCredentialCreateFactory(): ResourceCustomServiceImplementationFactory {\n const factory = (_registry: ResourcesRegistryBackendService, container: Container) =>\n createResourceCustomServiceImplementation({\n operationPath: {\n resourceIdentifier: CoreResourceType.USER_PROVIDER_CREDENTIALS,\n operationIdentifier: CoreResourceOperation.CREATE,\n variantType: ResourceOperationVariantType.API_CALL,\n isOperationDefault: true,\n },\n debugLabel: 'userProviderCredentials.create.seal-and-audit',\n /**\n * The two fields this hook OWNS, declared rather than inferred.\n *\n * `preserveServerInjectedFields` is normally derived by diffing the prefix output against a\n * snapshot of the payload keys taken BEFORE the prefix ran, so only keys the hook INTRODUCED\n * survive the repository's strict re-parse. That inference has a documented hole: a caller\n * reaching the service tier with the key already present puts it into the snapshot, the hook's\n * value is then not classified as introduced, and the repository strips it while the operation\n * answers success.\n *\n * For `secretValue` the declaration says the thing that matters most in this file: whatever a\n * caller sent, what reaches persistence is the POST-prefix value — the sealed envelope — and\n * never the plaintext they supplied.\n */\n authoritativeFields: ['secretValue', 'secretSetAt'],\n handlers: {\n prefixCoreOperations: async (_id, input, executionContext, _operationPath, utils) =>\n sealIncomingSecret(input as Record<string, unknown> | undefined, executionContext, utils, container),\n postfixCoreOperations: async (_id, created, executionContext, _operationPath, utils) => {\n await emitCredentialWriteAudit(\n container,\n CoreAuditableEventType.USER_PROVIDER_CREDENTIAL_SET,\n created as UserProviderCredential | undefined,\n undefined,\n executionContext,\n utils,\n );\n return created;\n },\n },\n });\n return factory as unknown as ResourceCustomServiceImplementationFactory;\n}\n\n/**\n * UPDATE — a rotation, or an ordinary metadata edit.\n *\n * The two are distinguished by whether the write actually carried a NEW secret. An edit that only\n * toggles `enabled` emits nothing: a rotation event on a metadata change would make the one signal\n * a compromise investigation depends on unusable.\n */\nfunction createCredentialUpdateFactory(): ResourceCustomServiceImplementationFactory {\n const factory = (_registry: ResourcesRegistryBackendService, container: Container) =>\n createResourceCustomServiceImplementation({\n operationPath: {\n resourceIdentifier: CoreResourceType.USER_PROVIDER_CREDENTIALS,\n operationIdentifier: CoreResourceOperation.UPDATE,\n variantType: ResourceOperationVariantType.API_CALL,\n isOperationDefault: true,\n },\n debugLabel: 'userProviderCredentials.update.seal-and-audit',\n authoritativeFields: ['secretValue', 'secretSetAt'],\n handlers: {\n prefixCoreOperations: async (_id, input, executionContext, _operationPath, utils) => {\n const sealed = sealIncomingSecret(\n input as Record<string, unknown> | undefined,\n executionContext,\n utils,\n container,\n );\n // Bridge to the postfix, keyed by this operation's execution context. Carries only WHETHER\n // the value moved and WHEN the previous one was set — never a secret, in either direction.\n ROTATION_BRIDGE_BY_EC.set(executionContext, {\n rotated: sealed?.secretValue !== undefined,\n previousSecretSetAt: (utils.currentObject as UserProviderCredential | undefined)?.secretSetAt,\n });\n return sealed;\n },\n postfixCoreOperations: async (_id, updated, executionContext, _operationPath, utils) => {\n const bridge = ROTATION_BRIDGE_BY_EC.get(executionContext);\n ROTATION_BRIDGE_BY_EC.delete(executionContext);\n if (bridge?.rotated) {\n await emitCredentialWriteAudit(\n container,\n CoreAuditableEventType.USER_PROVIDER_CREDENTIAL_ROTATED,\n updated as UserProviderCredential | undefined,\n bridge.previousSecretSetAt,\n executionContext,\n utils,\n );\n }\n return updated;\n },\n },\n });\n return factory as unknown as ResourceCustomServiceImplementationFactory;\n}\n\n/**\n * DELETE — the person disconnecting their own account.\n *\n * `OWNER_REVOKED` unconditionally, and that is CORRECT rather than an assumption: the erasure\n * cascade never reaches this hook (see the module header), so every delete that arrives here is a\n * deliberate service-tier revocation by the only party who can reach the door. If a future change\n * routed a cascade through the service tier, this constant would become a lie — which is why the\n * door table above is pinned by a test rather than left as prose.\n */\nfunction createCredentialDeleteFactory(): ResourceCustomServiceImplementationFactory {\n const factory = (_registry: ResourcesRegistryBackendService, container: Container) =>\n createResourceCustomServiceImplementation({\n operationPath: {\n resourceIdentifier: CoreResourceType.USER_PROVIDER_CREDENTIALS,\n operationIdentifier: CoreResourceOperation.DELETE,\n variantType: ResourceOperationVariantType.API_CALL,\n isOperationDefault: true,\n },\n debugLabel: 'userProviderCredentials.delete.audit',\n handlers: {\n postfixCoreOperations: async (id, result, executionContext, _operationPath, utils) => {\n // The pre-deletion snapshot: after the row is gone, the provider and slug are unrecoverable,\n // so an event naming only the id would identify nothing.\n const snapshot = utils.currentObject as UserProviderCredential | undefined;\n const credentialId = snapshot?._id ?? (typeof id === 'string' ? id : undefined);\n\n if (!snapshot?.userId || !credentialId) {\n utils.logger.error?.(\n 'A user provider credential was deleted but the subject could not be resolved — audit event not emitted',\n { addressedIdType: Array.isArray(id) ? 'array' : typeof id },\n );\n return result;\n }\n\n try {\n const auditLogs = container.get<AuditLogsBackendService>(SAAS_SERVICE_TYPES.AuditLogsService);\n await auditLogs.logUserProviderCredentialDeleted(\n {\n userId: snapshot.userId,\n providerRef: snapshot.providerRef,\n secretSlug: snapshot.secretSlug,\n credentialId,\n reason: ProviderCredentialDeletionReason.OWNER_REVOKED,\n },\n executionContext,\n );\n } catch (error) {\n utils.logger.error?.('Failed to emit the user provider credential deletion audit event', {\n credentialId,\n ...projectCaughtErrorLogFields(error),\n });\n }\n return result;\n },\n },\n });\n return factory as unknown as ResourceCustomServiceImplementationFactory;\n}\n\n/**\n * Prefix→postfix bridge for the UPDATE hook, keyed by the per-operation execution-context instance.\n *\n * A `WeakMap` so an abandoned operation cannot retain the entry, mirroring the api-key mint bridge.\n * It deliberately carries no secret: only a boolean and a timestamp cross it.\n */\nconst ROTATION_BRIDGE_BY_EC = new WeakMap<object, { rotated: boolean; previousSecretSetAt?: Date }>();\n\n/** Every write door of the user-provider-credential resource. */\nexport function createUserProviderCredentialFactories(): ResourceCustomServiceImplementationFactory[] {\n return [\n createCredentialCreateFactory(),\n createCredentialUpdateFactory(),\n createCredentialDeleteFactory(),\n ];\n}\n"]}
|
|
1
|
+
{"version":3,"file":"user-provider-credentials.custom-impl.backend.service.js","sourceRoot":"","sources":["../../../../../src/security/connected-accounts/services/user-provider-credentials.custom-impl.backend.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The WRITE path for a PERSON's own provider credential: seal on the way in, audit on the way out.\n *\n * ## Without this file the resource stores plaintext\n *\n * The schema declares `secretValue` as `.isWriteOnlySecret()`, which governs how the value is\n * PRESENTED (redacted at the client boundary, and a round-tripped mask means \"keep the stored\n * secret\"). It says nothing about how the value is STORED — a write-only-secret field lands in the\n * database exactly as the client typed it. Sealing it is this hook's job, and it is the only place\n * that job is done, so a credential reaching persistence unsealed means this registration did not\n * resolve.\n *\n * ⚠️ A custom implementation resolves by an EXACT operation-path key embedding the resource, the\n * operation, the variant TYPE and the default/variant-key slot. A registration naming a combination\n * the resource configuration does not declare resolves nothing and silently never runs, while the\n * route still answers 200 — here that would mean every person's third-party key persisted in\n * plaintext behind a green suite. The pins assert these registrations against the REAL resource\n * configuration for that reason.\n *\n * ## What differs from the organization sibling, and why each difference is substantive\n *\n * - **No `setByUserId`.** The organization's row records WHICH administrator wrote it, because\n * several can. This resource declares no administrative variant at all, so the author is always\n * the owner and a separate field could only ever repeat `userId` — while inviting a future reader\n * to believe the two can differ.\n * - **The DELETE reason is `OWNER_REVOKED`, not `ADMINISTRATOR_REVOKED`.** Same door, different\n * meaning: nobody but the holder can reach it.\n * - **The cascade door destroys evidence that matters more.** When a subject is erased, the\n * `USERS → USER_PROVIDER_CREDENTIALS` composition removes these rows through the RAW repository,\n * bypassing the service tier exactly as the organization purge does. The consequence is sharper\n * here: the deletion event is what an operator produces when asked whether an erasure reached the\n * person's third-party credentials, and the cascade cannot emit one. `USER_DELETED` records that\n * the subject was erased; what is missing is the enumeration of WHICH vendors they had connected.\n * This is the SAME defect as the organization purge's, at a second site — one cascade-tier audit\n * hook fixes both — and it is recorded on issue #365 rather than left for a reader to discover\n * from an absence. `ProviderCredentialDeletionReason.USER_ERASED` exists for the event that hook\n * will emit; nothing can emit it today.\n *\n * assurance-control: WILDO.IDENTITY.DELEGATED_AUTHORIZATION — a user authorizes, rotates and\n * withdraws delegated access to a named third party.\n */\n\nimport type { Container } from 'inversify';\nimport {\n CoreAuditableEventType,\n CoreResourceOperation,\n CoreResourceType,\n ErrorType,\n ErrorCustomMessageReference,\n ProviderCredentialDeletionReason,\n ResourceOperationVariantType,\n WRITE_ONLY_SECRET_MASK,\n coreResourceShared_FieldIdentifier,\n type UserProviderCredential,\n} from '@wildo-ai/saas-models';\n\nimport { ExternalProvider_Connection_OwnerScope } from '@wildo-ai/external-connectors-models';\n\nimport {\n createResourceCustomServiceImplementation,\n type ResourceCustomServiceImplementationFactory,\n} from '~wildo-backend-lib/base-classes/services/services/resource-operation-custom-implementation.factory.backend';\nimport type { ResourceOperation_CustomImplementation_Utils } from '~wildo-backend-lib/base-classes/services/services/resource-operation-custom-implementation-base.backend.service';\nimport type { ResourcesRegistryBackendService } from '~wildo-backend-lib/resources/services/resources-registry.backend.service';\nimport type { ExecutionContext } from '~wildo-backend-lib/runtime/models/execution-context.backend.schemas';\nimport { SAAS_SERVICE_TYPES } from '~wildo-backend-lib/inject/models/service-types';\nimport type { AppConfigurationService } from '~wildo-backend-lib/config/services/app-configuration.backend.service';\nimport type { AuditLogsBackendService } from '~wildo-backend-lib/compliance/audit-trails/services/audit-logs.backend.service';\nimport { projectCaughtErrorLogFields } from '~wildo-backend-lib/errors/utils/error-log-level-classification.backend.utils';\n\nimport { sealProviderCredential } from '../utils/provider-credential-envelope.backend.utils';\n\n/** The row identity the seal binds to, resolved from whichever channel actually carries each part. */\ninterface UserCredentialWriteIdentity {\n userId: string;\n providerRef: string;\n secretSlug: string;\n}\n\n/**\n * Resolve the identity the seal binds to.\n *\n * Two sources, and the request BODY is deliberately not one of them. On UPDATE the stored row is\n * authoritative — it is what the framework already persisted. On CREATE the execution context's\n * context-resource map is, because that is the same channel `enrichDataWithContext` reads when it\n * injects the scope FK, so the seal binds to the person the row will actually be stored under.\n *\n * A `payload.userId` fallback is absent for the organization sibling's reason: it would fail safe\n * (a seal bound to a body-supplied owner is simply unopenable later, so the outcome is a denial\n * rather than a disclosure) but it is still the REQUEST choosing what the seal binds to, which is\n * exactly the authorship this hook exists to keep out of a caller's hands.\n */\nfunction resolveWriteIdentity(\n input: Record<string, unknown> | undefined,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils,\n): UserCredentialWriteIdentity {\n const current = utils.currentObject as UserProviderCredential | undefined;\n\n const userId =\n (typeof current?.userId === 'string' && current.userId)\n || executionContext.getContextResourceId?.(coreResourceShared_FieldIdentifier[CoreResourceType.USERS] as never);\n\n const providerRef =\n (typeof input?.providerRef === 'string' && input.providerRef)\n || (typeof current?.providerRef === 'string' ? current.providerRef : undefined);\n\n const secretSlug =\n (typeof input?.secretSlug === 'string' && input.secretSlug)\n || (typeof current?.secretSlug === 'string' ? current.secretSlug : undefined);\n\n if (typeof userId !== 'string' || !userId || !providerRef || !secretSlug) {\n // Fail CLOSED. Sealing under a partial identity would produce a credential bound to the wrong\n // row — unopenable at resolution time, and indistinguishable then from a tampered one.\n throw utils.errorBuilder.buildError(ErrorType.CONFIGURATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.CONFIGURATION,\n context: {\n message:\n 'Cannot seal a user provider credential: the row identity is incomplete. All three of userId, '\n + 'providerRef and secretSlug must be resolvable, because the seal is bound to them. The user is '\n + 'read from the execution scope or the stored row, never from the request body.',\n hasUserId: Boolean(userId),\n hasProviderRef: Boolean(providerRef),\n hasSecretSlug: Boolean(secretSlug),\n },\n });\n }\n\n return { userId, providerRef, secretSlug };\n}\n\n/**\n * Seal an incoming secret, or return nothing when the write carries none.\n *\n * The mask is what makes an ordinary metadata edit safe: a client that read the row back received\n * `WRITE_ONLY_SECRET_MASK` in place of the value, and sending it back means \"keep what is stored\".\n * Sealing the mask would replace a working credential with the literal string of bullet characters.\n */\nfunction sealIncomingSecret(\n input: Record<string, unknown> | undefined,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils,\n container: Container,\n): Record<string, unknown> | undefined {\n const incoming = input?.secretValue;\n if (typeof incoming !== 'string' || incoming.length === 0 || incoming === WRITE_ONLY_SECRET_MASK) {\n return undefined;\n }\n\n const identity = resolveWriteIdentity(input, executionContext, utils);\n const appConfig = container.get<AppConfigurationService>(SAAS_SERVICE_TYPES.AppConfigService);\n\n return {\n ...input,\n secretValue: sealProviderCredential(\n incoming,\n appConfig.secrets.security.session.encryptionKey,\n {\n ownerScope: ExternalProvider_Connection_OwnerScope.USER,\n ownerId: identity.userId,\n providerRef: identity.providerRef,\n secretSlug: identity.secretSlug,\n },\n ),\n // Server-owned provenance. `.excludeFromCreate().excludeFromUpdate()`, so returning it here is\n // what carries it past the strict re-parse, declared explicitly in `authoritativeFields` below.\n secretSetAt: new Date(),\n };\n}\n\n/**\n * Emit the lifecycle event for a completed write.\n *\n * Best-effort in the same posture as every other audit emission in the engine: the credential has\n * already been written, and turning a logging failure into a 500 would tell the person their write\n * failed when it did not.\n */\nasync function emitCredentialWriteAudit(\n container: Container,\n eventType:\n | typeof CoreAuditableEventType.USER_PROVIDER_CREDENTIAL_SET\n | typeof CoreAuditableEventType.USER_PROVIDER_CREDENTIAL_ROTATED,\n row: UserProviderCredential | undefined,\n previousSecretSetAt: Date | undefined,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils,\n): Promise<void> {\n if (!row || typeof row._id !== 'string' || typeof row.userId !== 'string') {\n utils.logger.error?.(\n 'A user provider credential was written but the row could not be identified — audit event not emitted',\n { eventType },\n );\n return;\n }\n\n try {\n const auditLogs = container.get<AuditLogsBackendService>(SAAS_SERVICE_TYPES.AuditLogsService);\n // `userId` is taken from the ROW, not from the initiator. They are the same identity here by\n // construction, and reading the row is what keeps that true if a future variant ever lets them\n // differ: the event must name whose credential it is, never who happened to make the call.\n const common = {\n userId: row.userId,\n providerRef: row.providerRef,\n secretSlug: row.secretSlug,\n credentialId: row._id,\n };\n if (eventType === CoreAuditableEventType.USER_PROVIDER_CREDENTIAL_SET) {\n await auditLogs.logUserProviderCredentialSet(common, executionContext);\n } else {\n await auditLogs.logUserProviderCredentialRotated(\n { ...common, previousSecretSetAt: previousSecretSetAt?.toISOString() },\n executionContext,\n );\n }\n } catch (error) {\n utils.logger.error?.('Failed to emit the user provider credential audit event', {\n eventType,\n credentialId: row._id,\n ...projectCaughtErrorLogFields(error),\n });\n }\n}\n\n/** CREATE — the person connects an account at a third party for the first time. */\nfunction createCredentialCreateFactory(): ResourceCustomServiceImplementationFactory {\n const factory = (_registry: ResourcesRegistryBackendService, container: Container) =>\n createResourceCustomServiceImplementation({\n operationPath: {\n resourceIdentifier: CoreResourceType.USER_PROVIDER_CREDENTIALS,\n operationIdentifier: CoreResourceOperation.CREATE,\n variantType: ResourceOperationVariantType.API_CALL,\n isOperationDefault: true,\n },\n debugLabel: 'userProviderCredentials.create.seal-and-audit',\n /**\n * The two fields this hook OWNS, declared rather than inferred.\n *\n * `preserveServerInjectedFields` is normally derived by diffing the prefix output against a\n * snapshot of the payload keys taken BEFORE the prefix ran, so only keys the hook INTRODUCED\n * survive the repository's strict re-parse. That inference has a documented hole: a caller\n * reaching the service tier with the key already present puts it into the snapshot, the hook's\n * value is then not classified as introduced, and the repository strips it while the operation\n * answers success.\n *\n * For `secretValue` the declaration says the thing that matters most in this file: whatever a\n * caller sent, what reaches persistence is the POST-prefix value — the sealed envelope — and\n * never the plaintext they supplied.\n */\n authoritativeFields: ['secretValue', 'secretSetAt'],\n handlers: {\n prefixCoreOperations: async (_id, input, executionContext, _operationPath, utils) =>\n sealIncomingSecret(input as Record<string, unknown> | undefined, executionContext, utils, container),\n postfixCoreOperations: async (_id, created, executionContext, _operationPath, utils) => {\n await emitCredentialWriteAudit(\n container,\n CoreAuditableEventType.USER_PROVIDER_CREDENTIAL_SET,\n created as UserProviderCredential | undefined,\n undefined,\n executionContext,\n utils,\n );\n return created;\n },\n },\n });\n return factory as unknown as ResourceCustomServiceImplementationFactory;\n}\n\n/**\n * UPDATE — a rotation, or an ordinary metadata edit.\n *\n * The two are distinguished by whether the write actually carried a NEW secret. An edit that only\n * toggles `enabled` emits nothing: a rotation event on a metadata change would make the one signal\n * a compromise investigation depends on unusable.\n */\nfunction createCredentialUpdateFactory(): ResourceCustomServiceImplementationFactory {\n const factory = (_registry: ResourcesRegistryBackendService, container: Container) =>\n createResourceCustomServiceImplementation({\n operationPath: {\n resourceIdentifier: CoreResourceType.USER_PROVIDER_CREDENTIALS,\n operationIdentifier: CoreResourceOperation.UPDATE,\n variantType: ResourceOperationVariantType.API_CALL,\n isOperationDefault: true,\n },\n debugLabel: 'userProviderCredentials.update.seal-and-audit',\n authoritativeFields: ['secretValue', 'secretSetAt'],\n handlers: {\n prefixCoreOperations: async (_id, input, executionContext, _operationPath, utils) => {\n const sealed = sealIncomingSecret(\n input as Record<string, unknown> | undefined,\n executionContext,\n utils,\n container,\n );\n // Bridge to the postfix, keyed by this operation's execution context. Carries only WHETHER\n // the value moved and WHEN the previous one was set — never a secret, in either direction.\n ROTATION_BRIDGE_BY_EC.set(executionContext, {\n rotated: sealed?.secretValue !== undefined,\n previousSecretSetAt: (utils.currentObject as UserProviderCredential | undefined)?.secretSetAt,\n });\n return sealed;\n },\n postfixCoreOperations: async (_id, updated, executionContext, _operationPath, utils) => {\n const bridge = ROTATION_BRIDGE_BY_EC.get(executionContext);\n ROTATION_BRIDGE_BY_EC.delete(executionContext);\n if (bridge?.rotated) {\n await emitCredentialWriteAudit(\n container,\n CoreAuditableEventType.USER_PROVIDER_CREDENTIAL_ROTATED,\n updated as UserProviderCredential | undefined,\n bridge.previousSecretSetAt,\n executionContext,\n utils,\n );\n }\n return updated;\n },\n },\n });\n return factory as unknown as ResourceCustomServiceImplementationFactory;\n}\n\n/**\n * DELETE — the person disconnecting their own account.\n *\n * `OWNER_REVOKED` unconditionally, and that is CORRECT rather than an assumption: the erasure\n * cascade never reaches this hook (see the module header), so every delete that arrives here is a\n * deliberate service-tier revocation by the only party who can reach the door. If a future change\n * routed a cascade through the service tier, this constant would become a lie — which is why the\n * door table above is pinned by a test rather than left as prose.\n */\nfunction createCredentialDeleteFactory(): ResourceCustomServiceImplementationFactory {\n const factory = (_registry: ResourcesRegistryBackendService, container: Container) =>\n createResourceCustomServiceImplementation({\n operationPath: {\n resourceIdentifier: CoreResourceType.USER_PROVIDER_CREDENTIALS,\n operationIdentifier: CoreResourceOperation.DELETE,\n variantType: ResourceOperationVariantType.API_CALL,\n isOperationDefault: true,\n },\n debugLabel: 'userProviderCredentials.delete.audit',\n handlers: {\n postfixCoreOperations: async (id, result, executionContext, _operationPath, utils) => {\n // The pre-deletion snapshot: after the row is gone, the provider and slug are unrecoverable,\n // so an event naming only the id would identify nothing.\n const snapshot = utils.currentObject as UserProviderCredential | undefined;\n const credentialId = snapshot?._id ?? (typeof id === 'string' ? id : undefined);\n\n if (!snapshot?.userId || !credentialId) {\n utils.logger.error?.(\n 'A user provider credential was deleted but the subject could not be resolved — audit event not emitted',\n { addressedIdType: Array.isArray(id) ? 'array' : typeof id },\n );\n return result;\n }\n\n try {\n const auditLogs = container.get<AuditLogsBackendService>(SAAS_SERVICE_TYPES.AuditLogsService);\n await auditLogs.logUserProviderCredentialDeleted(\n {\n userId: snapshot.userId,\n providerRef: snapshot.providerRef,\n secretSlug: snapshot.secretSlug,\n credentialId,\n reason: ProviderCredentialDeletionReason.OWNER_REVOKED,\n },\n executionContext,\n );\n } catch (error) {\n utils.logger.error?.('Failed to emit the user provider credential deletion audit event', {\n credentialId,\n ...projectCaughtErrorLogFields(error),\n });\n }\n return result;\n },\n },\n });\n return factory as unknown as ResourceCustomServiceImplementationFactory;\n}\n\n/**\n * Prefix→postfix bridge for the UPDATE hook, keyed by the per-operation execution-context instance.\n *\n * A `WeakMap` so an abandoned operation cannot retain the entry, mirroring the api-key mint bridge.\n * It deliberately carries no secret: only a boolean and a timestamp cross it.\n */\nconst ROTATION_BRIDGE_BY_EC = new WeakMap<object, { rotated: boolean; previousSecretSetAt?: Date }>();\n\n/** Every write door of the user-provider-credential resource. */\nexport function createUserProviderCredentialFactories(): ResourceCustomServiceImplementationFactory[] {\n return [\n createCredentialCreateFactory(),\n createCredentialUpdateFactory(),\n createCredentialDeleteFactory(),\n ];\n}\n"]}
|
|
@@ -41,10 +41,21 @@ export interface UserProviderCredentialQuery {
|
|
|
41
41
|
}
|
|
42
42
|
/** A credential that was found, opened, and is spendable. */
|
|
43
43
|
export interface UserProviderCredentialResolution {
|
|
44
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* The plaintext credential. Never logged, never stored — and returned to a client by exactly ONE
|
|
46
|
+
* door, the access-token route, which hands a person their own OAuth2 access token so a vendor's
|
|
47
|
+
* picker can open as them (#394 P4). Every other caller keeps it server-side.
|
|
48
|
+
*/
|
|
45
49
|
value: string;
|
|
46
50
|
/** The row it came from, for the audit trail. */
|
|
47
51
|
credentialId: string;
|
|
52
|
+
/**
|
|
53
|
+
* When the vendor said the access token expires — carried out for an OAuth2 grant so a browser
|
|
54
|
+
* handed the token knows when to ask again, absent for a pasted credential.
|
|
55
|
+
*/
|
|
56
|
+
expiresAt?: string;
|
|
57
|
+
/** What the vendor granted, when it stated it. Lets a picker refuse to open with a scope it lacks rather than fail inside. */
|
|
58
|
+
grantedScopes?: readonly string[];
|
|
48
59
|
}
|
|
49
60
|
export interface UserProviderCredentialResolverPort {
|
|
50
61
|
/**
|
|
@@ -53,6 +64,31 @@ export interface UserProviderCredentialResolverPort {
|
|
|
53
64
|
* See the module JSDoc for why absence returns and unopenability throws.
|
|
54
65
|
*/
|
|
55
66
|
resolveUserCredential(query: UserProviderCredentialQuery): Promise<UserProviderCredentialResolution | undefined>;
|
|
67
|
+
/**
|
|
68
|
+
* Stamp the person's row with what the provider said about the credential it just spent.
|
|
69
|
+
*
|
|
70
|
+
* Required, and on this port rather than a port of its own, for the reasons the organization port
|
|
71
|
+
* states at its own member: the store that was READ must be the store that is STAMPED, and an
|
|
72
|
+
* optional method would leave "resolves credentials, records nothing" representable — which is
|
|
73
|
+
* exactly the state this subsystem shipped in.
|
|
74
|
+
*
|
|
75
|
+
* `credentialId` is REQUIRED here and optional on the organization's, and the asymmetry is the
|
|
76
|
+
* fallback: an organization's resolution may legitimately have come from the deployment
|
|
77
|
+
* environment, which has no row. A person's never can — there is nothing for a person to fall
|
|
78
|
+
* through to — so a recorded use without a row to name would describe a resolution that cannot
|
|
79
|
+
* happen.
|
|
80
|
+
*/
|
|
81
|
+
recordCredentialUse(use: {
|
|
82
|
+
userId: string;
|
|
83
|
+
providerRef: string;
|
|
84
|
+
secretSlug: string;
|
|
85
|
+
credentialId: string;
|
|
86
|
+
/** What the provider said. Absent means the outcome is not yet known to the caller. */
|
|
87
|
+
outcome?: {
|
|
88
|
+
accepted: boolean;
|
|
89
|
+
providerMessage?: string;
|
|
90
|
+
};
|
|
91
|
+
}): Promise<void>;
|
|
56
92
|
}
|
|
57
93
|
/**
|
|
58
94
|
* Re-exported for the registry's own signatures so a consumer reading the resolution result does not
|
package/dist/esm/security/connected-accounts/user-provider-credential-resolver.port.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-provider-credential-resolver.port.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"user-provider-credential-resolver.port.d.ts","sourceRoot":"","sources":["../../../../src/security/connected-accounts/user-provider-credential-resolver.port.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,uBAAuB,CAAC;AAEhF,kGAAkG;AAClG,MAAM,WAAW,2BAA2B;IAC1C;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,kGAAkG;IAClG,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,6DAA6D;AAC7D,MAAM,WAAW,gCAAgC;IAC/C;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,YAAY,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8HAA8H;IAC9H,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,kCAAkC;IACjD;;;;OAIG;IACH,qBAAqB,CACnB,KAAK,EAAE,2BAA2B,GACjC,OAAO,CAAC,gCAAgC,GAAG,SAAS,CAAC,CAAC;IAEzD;;;;;;;;;;;;;OAaG;IACH,mBAAmB,CAAC,GAAG,EAAE;QACvB,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,uFAAuF;QACvF,OAAO,CAAC,EAAE;YAAE,QAAQ,EAAE,OAAO,CAAC;YAAC,eAAe,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;KAC3D,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnB;AAED;;;GAGG;AACH,YAAY,EAAE,kCAAkC,EAAE,CAAC"}
|