@wildo-ai/saas-backend-lib 1.1.0 → 1.1.2
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/base-classes/services/controllers/controller-resource.backend.service.d.ts +14 -3
- 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 +115 -22
- 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 +3 -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 +8 -3
- package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/field-clearing-partition.backend.d.ts +11 -0
- package/dist/esm/base-classes/services/repositories/field-clearing-partition.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/field-clearing-partition.backend.js +11 -2
- package/dist/esm/base-classes/services/repositories/field-clearing-partition.backend.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-resource-repository.backend.service.d.ts +1 -0
- 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 +6 -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/odata-query-compiler.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/odata-query-compiler.backend.js +16 -0
- package/dist/esm/base-classes/services/repositories/http-api/odata-query-compiler.backend.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/infrastructure-tier-contract.backend.d.ts +20 -6
- 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 +88 -32
- 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 +3 -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-repository.backend.service.js +32 -7
- package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-repository.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-source.backend.port.d.ts +8 -5
- 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/introspection/introspection-resource-source.backend.port.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.d.ts +31 -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 +127 -5
- 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 +71 -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 +62 -2
- package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.d.ts +21 -0
- 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 +126 -4
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-implementation-coverage.backend.utils.d.ts +3 -26
- 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-implementation-coverage.backend.utils.js +3 -68
- package/dist/esm/base-classes/services/services/resource-operation-implementation-coverage.backend.utils.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 +4 -2
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js.map +1 -1
- package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.js +6 -6
- package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.d.ts +38 -0
- 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 +40 -0
- 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 +20 -0
- 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 +28 -0
- package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.js.map +1 -1
- package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.d.ts +12 -0
- package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.js +118 -0
- package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.js.map +1 -0
- 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 +8 -5
- package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.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 +14 -0
- package/dist/esm/compliance/audit-trails/services/utils/ocsf-activity-mapping.backend.utils.js.map +1 -1
- package/dist/esm/config/custom/application-config-controller.backend.service.d.ts.map +1 -1
- package/dist/esm/config/custom/application-config-controller.backend.service.js +7 -1
- package/dist/esm/config/custom/application-config-controller.backend.service.js.map +1 -1
- package/dist/esm/config/models/app-config.backend.schemas.d.ts +4 -0
- package/dist/esm/config/models/app-config.backend.schemas.d.ts.map +1 -1
- package/dist/esm/config/services/app-configuration.backend.utils.d.ts +10 -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 +13 -2
- package/dist/esm/config/services/app-configuration.backend.utils.js.map +1 -1
- package/dist/esm/data-seeding/services/shared/data-seed-scope-iteration.shared.utils.d.ts +2 -2
- package/dist/esm/data-seeding/services/shared/data-seed-scope-iteration.shared.utils.js +2 -2
- package/dist/esm/data-seeding/services/shared/data-seed-scope-iteration.shared.utils.js.map +1 -1
- package/dist/esm/databases/models/filter.backend.schemas.js +2 -2
- package/dist/esm/databases/models/filter.backend.schemas.js.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-authorization.backend.service.js +20 -1
- package/dist/esm/databases/services/aggregation/aggregation-authorization.backend.service.js.map +1 -1
- package/dist/esm/databases/services/redis.service.d.ts +27 -0
- package/dist/esm/databases/services/redis.service.d.ts.map +1 -1
- package/dist/esm/databases/services/redis.service.js +29 -0
- package/dist/esm/databases/services/redis.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 +5 -0
- package/dist/esm/errors/services/error-handler.backend.service.js.map +1 -1
- package/dist/esm/external-data/controllers/external-data-admin.backend.contracts.d.ts +41 -0
- package/dist/esm/external-data/controllers/external-data-admin.backend.contracts.d.ts.map +1 -0
- package/dist/esm/external-data/controllers/external-data-admin.backend.contracts.js +40 -0
- package/dist/esm/external-data/controllers/external-data-admin.backend.contracts.js.map +1 -0
- package/dist/esm/external-data/controllers/external-data-admin.backend.controller.d.ts +64 -0
- package/dist/esm/external-data/controllers/external-data-admin.backend.controller.d.ts.map +1 -0
- package/dist/esm/external-data/controllers/external-data-admin.backend.controller.js +193 -0
- package/dist/esm/external-data/controllers/external-data-admin.backend.controller.js.map +1 -0
- package/dist/esm/external-data/external-data-pipeline-run.backend.service.d.ts +13 -2
- 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 +8 -2
- 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/external-data-transform.backend.js +7 -1
- package/dist/esm/external-data/external-data-transform.backend.js.map +1 -1
- package/dist/esm/external-data/models/external-data-pipeline-state.backend.schemas.d.ts +2 -0
- package/dist/esm/external-data/models/external-data-pipeline-state.backend.schemas.d.ts.map +1 -1
- package/dist/esm/external-data/models/external-data-pipeline-state.backend.schemas.js +13 -0
- package/dist/esm/external-data/models/external-data-pipeline-state.backend.schemas.js.map +1 -1
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts +14 -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 +6 -0
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.js.map +1 -1
- package/dist/esm/files/controllers/file.controller.d.ts +24 -1
- package/dist/esm/files/controllers/file.controller.d.ts.map +1 -1
- package/dist/esm/files/controllers/file.controller.js +66 -2
- package/dist/esm/files/controllers/file.controller.js.map +1 -1
- package/dist/esm/files/handlers/file-upload-route-locals.backend.types.d.ts +17 -0
- package/dist/esm/files/handlers/file-upload-route-locals.backend.types.d.ts.map +1 -0
- package/dist/esm/files/handlers/file-upload-route-locals.backend.types.js +1 -0
- package/dist/esm/files/handlers/file-upload-route-locals.backend.types.js.map +1 -0
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.d.ts +5 -1
- 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 +42 -3
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.js.map +1 -1
- package/dist/esm/files/services/file-operation-handler.backend.service.d.ts +18 -0
- 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 +36 -28
- package/dist/esm/files/services/file-operation-handler.backend.service.js.map +1 -1
- package/dist/esm/files/services/file-upload-grant.backend.service.d.ts +163 -0
- package/dist/esm/files/services/file-upload-grant.backend.service.d.ts.map +1 -0
- package/dist/esm/files/services/file-upload-grant.backend.service.js +442 -0
- package/dist/esm/files/services/file-upload-grant.backend.service.js.map +1 -0
- package/dist/esm/files/services/files.backend.service.d.ts +19 -0
- package/dist/esm/files/services/files.backend.service.d.ts.map +1 -1
- package/dist/esm/files/services/files.backend.service.js +78 -15
- package/dist/esm/files/services/files.backend.service.js.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 +12 -0
- package/dist/esm/files/utils/file-uploader.utils.js.map +1 -1
- package/dist/esm/flows-actors/a2a/services/a2a-task-cancellation.backend.service.js +5 -5
- package/dist/esm/flows-actors/a2a/services/a2a-task-cancellation.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/services/agents.backend.service.d.ts +79 -0
- package/dist/esm/flows-actors/services/agents.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/agents.backend.service.js +319 -42
- package/dist/esm/flows-actors/services/agents.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.d.ts +151 -41
- 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 +300 -139
- package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.js.map +1 -1
- package/dist/esm/index.d.ts +4 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +14 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/inject/models/container.d.ts.map +1 -1
- package/dist/esm/inject/models/container.js +4 -0
- 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 +2 -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 +12 -4
- package/dist/esm/mcp/controllers/mcp.controller.js.map +1 -1
- package/dist/esm/mcp/models/mcp-tool.backend.schemas.d.ts +34 -0
- package/dist/esm/mcp/models/mcp-tool.backend.schemas.d.ts.map +1 -1
- package/dist/esm/mcp/models/mcp-tool.backend.schemas.js +42 -0
- package/dist/esm/mcp/models/mcp-tool.backend.schemas.js.map +1 -1
- package/dist/esm/mcp/services/mcp-server.backend.service.d.ts +29 -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 +131 -3
- 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 +64 -2
- 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 +130 -6
- package/dist/esm/mcp/services/mcp-tool-adapter.backend.service.js.map +1 -1
- package/dist/esm/notifications/services/notifications-dispatcher.backend.service.d.ts +9 -0
- package/dist/esm/notifications/services/notifications-dispatcher.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/services/notifications-dispatcher.backend.service.js +11 -36
- package/dist/esm/notifications/services/notifications-dispatcher.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 +9 -7
- 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 +5 -5
- package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.utils.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.utils.js +14 -13
- package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.utils.js.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.d.ts +2 -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 +2 -2
- package/dist/esm/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.js.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 +9 -7
- package/dist/esm/notifications/webhooks/outbound/services/webhook-config-test-endpoint.custom-impl.backend.service.js.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-custom-implementation.backend.service.js +4 -1
- package/dist/esm/organizations/services/organization-unit-custom-implementation.backend.service.js.map +1 -1
- package/dist/esm/requests/service/websocket.service.d.ts.map +1 -1
- package/dist/esm/requests/service/websocket.service.js +56 -7
- package/dist/esm/requests/service/websocket.service.js.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/services/resource-id.backend.service.js +3 -3
- package/dist/esm/resources/services/resource-id.backend.service.js.map +1 -1
- package/dist/esm/resources/services/resources-registry.backend.service.js +1 -1
- package/dist/esm/resources/services/resources-registry.backend.service.js.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 +13 -7
- package/dist/esm/runtime/services/execution-context-creator.backend.service.js.map +1 -1
- package/dist/esm/runtime/services/start-application.backend.service.d.ts +28 -0
- package/dist/esm/runtime/services/start-application.backend.service.d.ts.map +1 -1
- package/dist/esm/runtime/services/start-application.backend.service.js +82 -0
- package/dist/esm/runtime/services/start-application.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/models/jwt.backend.schemas.d.ts +3 -23
- package/dist/esm/security/authentications/models/jwt.backend.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/models/jwt.backend.schemas.js +20 -45
- package/dist/esm/security/authentications/models/jwt.backend.schemas.js.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.d.ts +9 -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 +9 -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-mfa.backend.service.js +5 -3
- package/dist/esm/security/authentications/services/auth-methods/auth-mfa.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.d.ts +25 -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 +55 -4
- package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.js.map +1 -1
- package/dist/esm/security/authorizations/initiator-organization-confinement.backend.d.ts.map +1 -1
- package/dist/esm/security/authorizations/initiator-organization-confinement.backend.js +24 -1
- package/dist/esm/security/authorizations/initiator-organization-confinement.backend.js.map +1 -1
- package/dist/esm/security/authorizations/privileged-access-review.backend.utils.d.ts +117 -0
- package/dist/esm/security/authorizations/privileged-access-review.backend.utils.d.ts.map +1 -0
- package/dist/esm/security/authorizations/privileged-access-review.backend.utils.js +104 -0
- package/dist/esm/security/authorizations/privileged-access-review.backend.utils.js.map +1 -0
- package/dist/esm/security/authorizations/services/authorizations.backend.service.d.ts +101 -6
- package/dist/esm/security/authorizations/services/authorizations.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authorizations/services/authorizations.backend.service.js +210 -30
- package/dist/esm/security/authorizations/services/authorizations.backend.service.js.map +1 -1
- package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.d.ts +18 -1
- package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.js +110 -74
- package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.js.map +1 -1
- package/dist/esm/security/consumable-tokens/consumable-token-models.exports.d.ts +22 -0
- package/dist/esm/security/consumable-tokens/consumable-token-models.exports.d.ts.map +1 -0
- package/dist/esm/security/consumable-tokens/consumable-token-models.exports.js +22 -0
- package/dist/esm/security/consumable-tokens/consumable-token-models.exports.js.map +1 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.d.ts +17 -3
- 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.backend.resources-config.schemas.js +12 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.d.ts +20 -0
- 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 +58 -5
- package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.js.map +1 -1
- package/dist/esm/security/jwt/services/jwt.backend.service.d.ts.map +1 -1
- package/dist/esm/security/jwt/services/jwt.backend.service.js +1 -18
- package/dist/esm/security/jwt/services/jwt.backend.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +15 -9
- package/dist/esm/.builder.pid +0 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-operation-handler.backend.service.js","sourceRoot":"","sources":["../../../../../src/files/services/file-operation-handler.backend.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;;;;;;;;;;;;;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAgB,SAAS,EAAE,2BAA2B,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACzG,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAC;AAEpF,OAAO,EAAE,0BAA0B,EAAE,MAAM,kEAAkE,CAAC;AAC9G,OAAO,EAAE,2BAA2B,EAAE,MAAM,8EAA8E,CAAC;AAC3H,OAAO,EAAE,gCAAgC,EAAqB,MAAM,wCAAwC,CAAC;AAC7G,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAI9D,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,sDAAsD,CAAC;AACnJ,OAAO,EACL,kCAAkC,EAClC,iCAAiC,EACjC,2BAA2B,GAE5B,MAAM,qEAAqE,CAAC;AAYtE,IAAM,kCAAkC,GAAxC,MAAM,kCAAkC;IAK1B;IAEA;IAEA;IAEA;IAVT,QAAQ,CAA+D;IAEjF,YAEmB,MAAqB,EAErB,YAAwC,EAExC,kBAAoD,EAEpD,YAAiC;QANjC,WAAM,GAAN,MAAM,CAAe;QAErB,iBAAY,GAAZ,YAAY,CAA4B;QAExC,uBAAkB,GAAlB,kBAAkB,CAAkC;QAEpD,iBAAY,GAAZ,YAAY,CAAqB;QAElD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,oCAAoC,CAAC,CAAC;QAC9E,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;IAC/E,CAAC;IAEO,uBAAuB,CAAC,SAA4B;QAC1D,OAAO,SAAS,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,KAAK,oBAAoB,CAAC,YAAY,CAAC;IACzF,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,kCAAkC,CAAC,MAMxC;QACC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,iBAAiB,EAAE,CAAC;YACjE,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAChC,MAAM,CAAC,MAAM,EACb,MAAM,CAAC,gBAAgB,EACvB,MAAM,CAAC,OAAO,CACf,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,mDAAmD,EAAE;gBACpE,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;gBAC3C,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,GAAG,2BAA2B,CAAC,KAAK,CAAC;aACtC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAEO,uCAAuC,CAAC,MAO/C;QACC,IACE,CAAC,IAAI,CAAC,uBAAuB,CAAC,MAAM,CAAC,SAAS,CAAC;eAC5C,CACD,MAAM,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC;mBAC5B,CAAC,iCAAiC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAC/E,EACD,CAAC;YACD,OAAO;QACT,CAAC;QAED,MAAM,cAAc,GAAG,MAAM,CAAC,iBAAiB,EAAE,mCAAmC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACnH,IAAI,cAAc,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,CAAC;YACxC,MAAM,gBAAgB,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE,CACjE,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,gBAAgB,EAAE,IAAI,CAAC,CACrE,CAAC;YACF,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,IAAI,gBAAgB,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;gBAC3F,OAAO;YACT,CAAC;QACH,CAAC;QAED,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAChC,SAAS,CAAC,aAAa,EACvB,MAAM,CAAC,gBAAgB,EACvB;YACE,sBAAsB,EAAE,2BAA2B,CAAC,iCAAiC;YACrF,OAAO,EAAE;gBACP,wBAAwB;gBACxB,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,SAAS;gBACrC,YAAY,EAAE,MAAM,CAAC,YAAY;aAClC;SACF,CACF,CAAC;IACJ,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,2BAA2B,CAC/B,IAAyB,EACzB,YAA0B,EAC1B,gBAAuC,EACvC,OAA2B,EAC3B,iBAAmD;QAEnD,gEAAgE;QAChE,oBAAoB,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,gBAAgB,EAAE,cAAc,CAAC,CAAC;QAExF,oCAAoC;QACpC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,aAAa,CAAC,YAAY,CAAC,EAAE,CAAC;YACzD,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,kBAAkB,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAE1E,IAAI,CAAC,QAAQ,CAAC,mCAAmC,EAAE;YACjD,YAAY;YACZ,eAAe,EAAE,UAAU,CAAC,MAAM;SACnC,CAAC,CAAC;QAEH,kCAAkC;QAClC,MAAM,iBAAiB,GAAa,EAAE,CAAC;QAEvC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,MAAM,WAAW,GAAG,kCAAkC,CAAC,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;YAClF,IAAI,CAAC,uCAAuC,CAAC;gBAC3C,IAAI;gBACJ,SAAS;gBACT,WAAW;gBACX,YAAY;gBACZ,gBAAgB;gBAChB,iBAAiB;aAClB,CAAC,CAAC;YAEH,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;gBACrC,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC;gBAEnF,6DAA6D;gBAC7D,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC,YAAY,CAAC;gBACtD,IAAI,QAAQ,IAAI,QAAQ,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;oBACzE,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAChC,SAAS,CAAC,aAAa,EACvB,gBAAgB,EAChB;wBACE,sBAAsB,EAAE,2BAA2B,CAAC,mBAAmB;wBACvE,OAAO,EAAE;4BACP,wBAAwB;4BACxB,SAAS,EAAE,SAAS,CAAC,SAAS;4BAC9B,gBAAgB,EAAE,UAAU,CAAC,gBAAgB;4BAC7C,YAAY;4BACZ,QAAQ;4BACR,aAAa,EAAE,YAAY,CAAC,MAAM;yBACnC;qBACF,CACF,CAAC;gBACJ,CAAC;gBAED,iBAAiB,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QAED,qBAAqB;QACrB,KAAK,MAAM,MAAM,IAAI,iBAAiB,EAAE,CAAC;YACvC,kFAAkF;YAClF,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,gBAAgB,EAAE,QAAQ,CAAC,CAAC;YAEtE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;YAEhF,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAChC,SAAS,CAAC,SAAS,EACnB,gBAAgB,EAChB;oBACE,sBAAsB,EAAE,2BAA2B,CAAC,cAAc;oBAClE,OAAO,EAAE;wBACP,wBAAwB;wBACxB,MAAM;wBACN,YAAY;qBACb;iBACF,CACF,CAAC;YACJ,CAAC;YAED,yDAAyD;YACzD,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,QAAQ,EAAE,CAAC;gBACxC,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAChC,SAAS,CAAC,aAAa,EACvB,gBAAgB,EAChB;oBACE,sBAAsB,EAAE,2BAA2B,CAAC,2BAA2B;oBAC/E,OAAO,EAAE;wBACP,wBAAwB;wBACxB,MAAM;wBACN,UAAU,EAAE,IAAI,CAAC,MAAM;wBACvB,YAAY;wBACZ,cAAc,EAAE,UAAU,CAAC,QAAQ;qBACpC;iBACF,CACF,CAAC;YACJ,CAAC;YAED,mEAAmE;YACnE,kDAAkD;QACpD,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,6CAA6C,EAAE;YAC3D,YAAY;YACZ,mBAAmB,EAAE,iBAAiB,CAAC,MAAM;SAC9C,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;OAQG;IACH;;;;;;;;;;;;OAYG;IACK,uBAAuB,CAAC,OAA2B;QACzD,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,cAAc,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC;QACrE,MAAM,EAAE,cAAc,EAAE,mBAAmB,EAAE,GAAG,gBAAgB,EAAE,GAAG,OAAO,CAAC;QAC7E,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,0BAA0B,CAC9B,IAAyB,EACzB,YAA0B,EAC1B,UAAkB,EAClB,gBAAuC,EACvC,OAA2B,EAC3B,iBAAmD;QAEnD,gEAAgE;QAChE,oBAAoB,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,gBAAgB,EAAE,cAAc,CAAC,CAAC;QACxF,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,YAAY,EAAE,gBAAgB,EAAE,YAAY,CAAC,CAAC;QAElF,kFAAkF;QAClF,OAAO,GAAG,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC;QAEhD,oCAAoC;QACpC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,aAAa,CAAC,YAAY,CAAC,EAAE,CAAC;YACzD,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,kBAAkB,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAE1E,IAAI,CAAC,QAAQ,CAAC,mCAAmC,EAAE;YACjD,YAAY;YACZ,UAAU;YACV,eAAe,EAAE,UAAU,CAAC,MAAM;SACnC,CAAC,CAAC;QAEH,0BAA0B;QAC1B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,MAAM,oBAAoB,GAAG,kCAAkC,CAAC,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;YAC3F,IAAI,CAAC,uCAAuC,CAAC;gBAC3C,IAAI;gBACJ,SAAS;gBACT,WAAW,EAAE,oBAAoB;gBACjC,YAAY;gBACZ,gBAAgB;gBAChB,iBAAiB;aAClB,CAAC,CAAC;YACH,IACE,IAAI,CAAC,uBAAuB,CAAC,SAAS,CAAC;mBACpC,CAAC,iBAAiB,EAAE,mCAAmC,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,EACjF,CAAC;gBACD,SAAS;YACX,CAAC;YACD,MAAM,WAAW,GAAG,kCAAkC,CAAC,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;YAElF,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;gBACrC,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC;gBACnF,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;oBAClC,MAAM,IAAI,CAAC,kBAAkB,CAC3B,MAAM,EACN,YAAY,EACZ,UAAU,EACV,SAAS,CAAC,SAAS,EACnB,gBAAgB,EAChB,OAAO,CACR,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,6CAA6C,EAAE;YAC3D,YAAY;YACZ,UAAU;SACX,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,0BAA0B,CAC9B,IAAyB,EACzB,gBAAqC,EACrC,YAA0B,EAC1B,UAAkB,EAClB,gBAAuC,EACvC,OAA2B,EAC3B,iBAAmD;QAEnD,gEAAgE;QAChE,oBAAoB,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,gBAAgB,EAAE,cAAc,CAAC,CAAC;QACxF,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,YAAY,EAAE,gBAAgB,EAAE,YAAY,CAAC,CAAC;QAElF,kFAAkF;QAClF,OAAO,GAAG,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC;QAEhD,oCAAoC;QACpC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,aAAa,CAAC,YAAY,CAAC,EAAE,CAAC;YACzD,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,kBAAkB,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAC1E,MAAM,oBAAoB,GAAG,2BAA2B,CAAC,gBAAgB,EAAE,IAAI,CAAwB,CAAC;QAExG,IAAI,CAAC,QAAQ,CAAC,mCAAmC,EAAE;YACjD,YAAY;YACZ,UAAU;YACV,eAAe,EAAE,UAAU,CAAC,MAAM;SACnC,CAAC,CAAC;QAEH,0BAA0B;QAC1B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,MAAM,oBAAoB,GAAG,kCAAkC,CAAC,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;YAC3F,IAAI,CAAC,uCAAuC,CAAC;gBAC3C,IAAI;gBACJ,SAAS;gBACT,WAAW,EAAE,oBAAoB;gBACjC,YAAY;gBACZ,gBAAgB;gBAChB,iBAAiB;aAClB,CAAC,CAAC;YACH,IACE,IAAI,CAAC,uBAAuB,CAAC,SAAS,CAAC;mBACpC,CAAC,iBAAiB,EAAE,mCAAmC,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,EACjF,CAAC;gBACD,SAAS;YACX,CAAC;YACD,MAAM,cAAc,GAAG,IAAI,CAAC,kBAAkB,CAC5C,kCAAkC,CAAC,gBAAgB,EAAE,SAAS,CAAC,SAAS,CAAC,EACzE,gBAAgB,EAChB,KAAK,CACN,CAAC;YACF,MAAM,cAAc,GAAG,IAAI,CAAC,kBAAkB,CAC5C,kCAAkC,CAAC,oBAAoB,EAAE,SAAS,CAAC,SAAS,CAAC,EAC7E,gBAAgB,EAChB,IAAI,CACL,CAAC;YAEF,MAAM,eAAe,GAAG,IAAI,CAAC,gBAAgB,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;YAC9E,IAAI,eAAe,CAAC,yBAAyB,IAAI,SAAS,CAAC,YAAY,CAAC,WAAW,KAAK,KAAK,EAAE,CAAC;gBAC9F,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAChC,SAAS,CAAC,aAAa,EACvB,gBAAgB,EAChB;oBACE,sBAAsB,EAAE,2BAA2B,CAAC,4BAA4B;oBAChF,OAAO,EAAE;wBACP,wBAAwB;wBACxB,SAAS,EAAE,SAAS,CAAC,SAAS;wBAC9B,YAAY;wBACZ,UAAU;qBACX;iBACF,CACF,CAAC;YACJ,CAAC;YAED,KAAK,MAAM,IAAI,IAAI,eAAe,CAAC,KAAK,EAAE,CAAC;gBACzC,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,EAAE,OAAO,IAAI,EAAE,CAAC;gBACrD,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,EAAE,OAAO,IAAI,EAAE,CAAC;gBACrD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;gBACnC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;gBACnC,MAAM,UAAU,GACd,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI;oBAC3B,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBACvC,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;gBAE1C,IAAI,CAAC,UAAU,EAAE,CAAC;oBAChB,SAAS;gBACX,CAAC;gBAED,MAAM,gBAAgB,GAAG,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,gBAAgB;uBACnE,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,gBAAgB,CAAC;gBAErD,wCAAwC;gBACxC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC,YAAY,CAAC;gBACnE,IAAI,WAAW,KAAK,KAAK,EAAE,CAAC;oBAC1B,MAAM,cAAc,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;oBAEhE,IAAI,CAAC,QAAQ,EAAE,CAAC;wBACd,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;4BAC9B,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAChC,SAAS,CAAC,aAAa,EACvB,gBAAgB,EAChB;gCACE,sBAAsB,EAAE,2BAA2B,CAAC,0BAA0B;gCAC9E,OAAO,EAAE;oCACP,wBAAwB;oCACxB,SAAS,EAAE,SAAS,CAAC,SAAS;oCAC9B,gBAAgB;oCAChB,YAAY;oCACZ,UAAU;iCACX;6BACF,CACF,CAAC;wBACJ,CAAC;oBACH,CAAC;yBAAM,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACrC,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAChC,SAAS,CAAC,aAAa,EACvB,gBAAgB,EAChB;4BACE,sBAAsB,EAAE,2BAA2B,CAAC,0BAA0B;4BAC9E,OAAO,EAAE;gCACP,wBAAwB;gCACxB,SAAS,EAAE,SAAS,CAAC,SAAS;gCAC9B,gBAAgB;gCAChB,YAAY;gCACZ,UAAU;gCACV,cAAc;6BACf;yBACF,CACF,CAAC;oBACJ,CAAC;gBACH,CAAC;gBAED,IAAI,QAAQ,IAAI,QAAQ,KAAK,SAAS,IAAI,UAAU,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;oBACvE,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAChC,SAAS,CAAC,aAAa,EACvB,gBAAgB,EAChB;wBACE,sBAAsB,EAAE,2BAA2B,CAAC,mBAAmB;wBACvE,OAAO,EAAE;4BACP,wBAAwB;4BACxB,SAAS,EAAE,SAAS,CAAC,SAAS;4BAC9B,gBAAgB;4BAChB,YAAY;4BACZ,UAAU;4BACV,QAAQ;4BACR,QAAQ,EAAE,UAAU,CAAC,MAAM;yBAC5B;qBACF,CACF,CAAC;gBACJ,CAAC;gBAED,KAAK,MAAM,MAAM,IAAI,UAAU,EAAE,CAAC;oBAChC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC1B,6FAA6F;wBAC3F,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,gBAAgB,EAAE,QAAQ,CAAC,CAAC;wBAEtE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;wBAEhF,IAAI,CAAC,IAAI,EAAE,CAAC;4BACV,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAChC,SAAS,CAAC,SAAS,EACnB,gBAAgB,EAChB;gCACE,sBAAsB,EAAE,2BAA2B,CAAC,cAAc;gCAClE,OAAO,EAAE;oCACP,wBAAwB;oCACxB,MAAM;oCACN,YAAY;oCACZ,UAAU;oCACV,gBAAgB;iCACjB;6BACF,CACF,CAAC;wBACJ,CAAC;wBAED,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,QAAQ,EAAE,CAAC;4BACxC,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAChC,SAAS,CAAC,aAAa,EACvB,gBAAgB,EAChB;gCACE,sBAAsB,EAAE,2BAA2B,CAAC,2BAA2B;gCAC/E,OAAO,EAAE;oCACP,wBAAwB;oCACxB,MAAM;oCACN,UAAU,EAAE,IAAI,CAAC,MAAM;oCACvB,gBAAgB;oCAChB,YAAY;oCACZ,UAAU;oCACV,cAAc,EAAE,UAAU,CAAC,QAAQ;iCACpC;6BACF,CACF,CAAC;wBACJ,CAAC;oBACH,CAAC;gBACH,CAAC;gBAED,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;oBACnC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;wBAC7B,2BAA2B;wBACzB,MAAM,IAAI,CAAC,sBAAsB,CAC/B,SAAS,EACT,SAAS,CAAC,SAAS,EACnB,gBAAgB,EAChB,OAAO,CACR,CAAC;oBACJ,CAAC;gBACH,CAAC;gBAED,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;oBACnC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;wBAC7B,qBAAqB;wBACnB,MAAM,IAAI,CAAC,kBAAkB,CAC3B,SAAS,EACT,YAAY,EACZ,UAAU,EACV,SAAS,CAAC,SAAS,EACnB,gBAAgB,EAChB,OAAO,CACR,CAAC;oBACJ,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,6CAA6C,EAAE;YAC3D,YAAY;YACZ,UAAU;SACX,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACH;;;;;;OAMG;IACK,0BAA0B,CAAC,OAAsC,EAAE,IAAU;QACnF,OAAO;YACL,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;YAClB,sBAAsB,EAAE;gBACtB,aAAa,EAAE,IAAI,CAAC,aAAa;gBACjC,cAAc,EAAE,IAAI,CAAC,cAAc;gBACnC,MAAM,EAAE,IAAI,CAAC,MAAM;aACpB;SACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,0BAA0B,CAC9B,YAA0B,EAC1B,UAAkB,EAClB,gBAAuC,EACvC,OAA2B;QAE3B,8EAA8E;QAC9E,OAAO,GAAG,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC;QAEhD,oCAAoC;QACpC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,aAAa,CAAC,YAAY,CAAC,EAAE,CAAC;YACzD,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,kBAAkB,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAE1E,IAAI,CAAC,QAAQ,CAAC,mCAAmC,EAAE;YACjD,YAAY;YACZ,UAAU;YACV,eAAe,EAAE,UAAU,CAAC,MAAM;SACnC,CAAC,CAAC;QAEH,wCAAwC;QACxC,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,oBAAoB,CAC9D,YAAY,EACZ,UAAU,EACV,SAAS,EAAE,yCAAyC;QACpD,gBAAgB,EAChB,OAAO,CACR,CAAC;QAEF,yEAAyE;QACzE,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAC/B,gGAAgG;YAChG,wFAAwF;YACxF,MAAM,eAAe,GAAG,IAAI,CAAC,0BAA0B,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YACvE,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;gBAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yFAAyF,EAAE;oBAC1G,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,YAAY;oBACZ,UAAU;iBACX,CAAC,CAAC;gBACH,MAAM,IAAI,CAAC,2BAA2B,CACpC,IAAI,CAAC,MAAM,EACX,SAAS,EACT,gBAAgB,EAChB,eAAe,CAChB,CAAC;gBACF,SAAS;YACX,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,CAAC,kBAAkB,CAAC,oBAAoB,CAC5D,YAAY,EACZ,IAAI,CAAC,eAAe,CACrB,CAAC;YAEF,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,iDAAiD;gBACjD,MAAM,IAAI,CAAC,2BAA2B,CACpC,IAAI,CAAC,MAAM,EACX,SAAS,EACT,gBAAgB,EAChB,eAAe,CAChB,CAAC;gBACF,SAAS;YACX,CAAC;YAED,MAAM,cAAc,GAAG,SAAS,CAAC,YAAY,CAAC,cAAc,IAAI,SAAS,CAAC;YAE1E,MAAM,IAAI,CAAC,2BAA2B,CACpC,IAAI,CAAC,MAAM,EACX,cAAc,EACd,gBAAgB,EAChB,eAAe,CAChB,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,6CAA6C,EAAE;YAC3D,YAAY;YACZ,UAAU;YACV,mBAAmB,EAAE,WAAW,CAAC,MAAM;SACxC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0DG;IACH,KAAK,CAAC,iCAAiC,CACrC,YAA0B,EAC1B,UAAkB,EAClB,kBAAqC,EACrC,gBAAuC,EACvC,OAA2B;QAE3B,OAAO,GAAG,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC;QAEhD,IAAI,kBAAkB,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,aAAa,CAAC,YAAY,CAAC,EAAE,CAAC;YAC5F,OAAO;QACT,CAAC;QAED,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,kBAAkB,CAAC,CAAC;QACnD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,oBAAoB,CAC9D,YAAY,EACZ,UAAU,EACV,SAAS,EAAE,4CAA4C;QACvD,gBAAgB,EAChB,OAAO,CACR,CAAC;QAEF,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,IAAI,mBAAmB,GAAG,CAAC,CAAC;QAC5B,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAC/B,8FAA8F;YAC9F,yFAAyF;YACzF,oFAAoF;YACpF,MAAM,gBAAgB,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC;YAC/C,MAAM,eAAe,GAAG,gBAAgB,IAAI,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,eAAgB,CAAC,CAAC;YACtF,IAAI,CAAC,eAAe,EAAE,CAAC;gBACrB,SAAS;YACX,CAAC;YACD,IAAI,gBAAgB,EAAE,CAAC;gBACrB;;;;;;;;mBAQG;gBACH,mBAAmB,IAAI,CAAC,CAAC;gBACzB,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,+FAA+F;sBAC7F,6FAA6F;sBAC7F,+CAA+C,EACjD,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAClD,CAAC;YACJ,CAAC;YACD,gGAAgG;YAChG,mGAAmG;YACnG,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,CAAC,0BAA0B,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;YACjH,WAAW,EAAE,CAAC;QAChB,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,oDAAoD,EAAE;YAClE,YAAY;YACZ,UAAU;YACV,gBAAgB,EAAE,WAAW,CAAC,MAAM;YACpC,WAAW;YACX,aAAa,EAAE,WAAW,CAAC,MAAM,GAAG,WAAW;YAC/C,mBAAmB;SACpB,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACK,cAAc,CAAC,UAAe,EAAE,gBAAwC,EAAE,SAAkB,KAAK;QACvG,IAAI,UAAU,KAAK,IAAI,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YACpD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YACjE,IAAI,QAAQ,IAAI,UAAU,EAAE,CAAC;gBAC3B,OAAO,IAAI,CAAC,cAAc,CAAE,UAAmC,CAAC,MAAM,EAAE,gBAAgB,EAAE,MAAM,CAAC,CAAC;YACpG,CAAC;YAED,IAAI,SAAS,IAAI,UAAU,EAAE,CAAC;gBAC5B,OAAO,IAAI,CAAC,cAAc,CAAE,UAAoC,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,CAAC;YACtG,CAAC;QACH,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9B,MAAM,YAAY,GAAa,EAAE,CAAC;YAClC,KAAK,MAAM,MAAM,IAAI,UAAU,EAAE,CAAC;gBAChC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;oBACvD,IAAI,MAAM,EAAE,CAAC;wBACX,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAChC,SAAS,CAAC,UAAU,EACpB,gBAAgB,EAChB;4BACE,sBAAsB,EAAE,2BAA2B,CAAC,yBAAyB;4BAC7E,OAAO,EAAE;gCACP,wBAAwB;gCACxB,MAAM;gCACN,YAAY,EAAE,OAAO,MAAM;6BAC5B;yBACF,CACF,CAAC;oBACJ,CAAC;oBACD,SAAS;gBACX,CAAC;gBACD,IAAI,CAAC;oBACH,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,gBAAgB,EAAE,QAAQ,CAAC,CAAC;oBACtE,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC5B,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,IAAI,MAAM,EAAE,CAAC;wBACX,MAAM,KAAK,CAAC,CAAC,wDAAwD;oBACvE,CAAC;oBACD,0EAA0E;oBAC1E,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,+CAA+C,EAAE;wBAChE,MAAM;wBACN,GAAG,2BAA2B,CAAC,KAAK,CAAC;qBACtC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YACD,OAAO,YAAY,CAAC;QACtB,CAAC;QAED,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC/D,IAAI,CAAC;gBACH,cAAc,CAAC,UAAU,EAAE,IAAI,CAAC,YAAY,EAAE,gBAAgB,EAAE,QAAQ,CAAC,CAAC;gBAC1E,OAAO,CAAC,UAAU,CAAC,CAAC;YACtB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,KAAK,CAAC;gBACd,CAAC;gBACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,+CAA+C,EAAE;oBAChE,MAAM,EAAE,UAAU;oBAClB,GAAG,2BAA2B,CAAC,KAAK,CAAC;iBACtC,CAAC,CAAC;gBACH,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;QAED,IAAI,MAAM,IAAI,UAAU,KAAK,IAAI,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC9D,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAChC,SAAS,CAAC,UAAU,EACpB,gBAAgB,EAChB;gBACE,sBAAsB,EAAE,2BAA2B,CAAC,wBAAwB;gBAC5E,OAAO,EAAE;oBACP,wBAAwB;oBACxB,YAAY,EAAE,OAAO,UAAU;iBAChC;aACF,CACF,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,kBAAkB,CAC9B,MAAc,EACd,YAA0B,EAC1B,UAAkB,EAClB,SAAiB,EACjB,gBAAuC,EACvC,OAA2B;QAE3B,2EAA2E;QAC3E,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,gBAAgB,EAAE,QAAQ,CAAC,CAAC;QACtE,oBAAoB,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,gBAAgB,EAAE,cAAc,CAAC,CAAC;QACxF,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,YAAY,EAAE,gBAAgB,EAAE,YAAY,CAAC,CAAC;QAClF,iBAAiB,CAAC,SAAS,EAAE,IAAI,CAAC,YAAY,EAAE,gBAAgB,EAAE,WAAW,CAAC,CAAC;QAE/E,mGAAmG;QACnG,6EAA6E;QAC7E,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;QAChF,IAAI,IAAI;YACJ,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,MAAM;YACjC,IAAI,CAAC,kBAAkB,KAAK,YAAY;YACxC,IAAI,CAAC,gBAAgB,KAAK,UAAU;YACpC,IAAI,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;YACvC,sDAAsD;YACtD,IAAI,CAAC,QAAQ,CAAC,gDAAgD,EAAE;gBAC9D,MAAM;gBACN,YAAY;gBACZ,UAAU;gBACV,SAAS;aACV,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,gFAAgF;QAChF,uGAAuG;QACvG,kFAAkF;QAClF,MAAM,IAAI,CAAC,YAAY,CAAC,kBAAkB,CACxC,MAAM,EACN,YAAY,EACZ,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,OAAO,CACR,CAAC;IACJ,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,sBAAsB,CAClC,MAAc,EACd,SAAiB,EACjB,gBAAuC,EACvC,OAA2B;QAE3B,kFAAkF;QAClF,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,gBAAgB,EAAE,QAAQ,CAAC,CAAC;QAEtE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;QAChF,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,MAAM,EAAE,CAAC;YAC/C,wDAAwD;YACxD,OAAO;QACT,CAAC;QAED,wCAAwC;QACxC,MAAM,IAAI,CAAC,YAAY,CAAC,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;IACpF,CAAC;IAED;;;;;;OAMG;IACK,KAAK,CAAC,2BAA2B,CACvC,MAAc,EACd,QAA8C,EAC9C,gBAAuC,EACvC,OAA2B;QAE3B,IAAI,CAAC,QAAQ,CAAC,kCAAkC,EAAE;YAChD,MAAM;YACN,QAAQ;SACT,CAAC,CAAC;QAEH,QAAQ,QAAQ,EAAE,CAAC;YACjB,KAAK,SAAS;gBACZ,0EAA0E;gBAC1E,wEAAwE;gBACxE,kEAAkE;gBAClE,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;gBACtE,MAAM;YAER,KAAK,aAAa;gBAChB,wCAAwC;gBACxC,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;gBACtE,MAAM;YAER,KAAK,QAAQ;gBACX,sDAAsD;gBACtD,MAAM,IAAI,CAAC,YAAY,CAAC,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;gBAClF,MAAM;YAER;gBACE,qBAAqB;gBACrB,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC;IAEO,kBAAkB,CACxB,WAAuC,EACvC,gBAAuC,EACvC,MAAe;QAMf,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE;YACpC,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,KAAK,EAAE,gBAAgB,EAAE,MAAM,CAAC,CAAC;YAChF,OAAO;gBACL,UAAU;gBACV,OAAO;gBACP,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;aAC/C,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,gBAAgB,CACtB,cAIE,EACF,cAIE;QAgBF,MAAM,KAAK,GAWN,EAAE,CAAC;QAER,MAAM,YAAY,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC;QACzC,MAAM,YAAY,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC;QAEzC,MAAM,SAAS,GAAG,IAAI,GAAG,CACvB,CAAC,GAAG,YAAY,EAAE,GAAG,YAAY,CAAC;aAC/B,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC;aAC9C,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CACxF,CAAC;QAEF,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC;YAC/F,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC;YAE/F,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtD,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,EAAG,CAAC;gBACrC,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,EAAG,CAAC;gBACrC,YAAY,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;gBACvD,YAAY,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;gBACvD,KAAK,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,CAAC;YACnE,CAAC;QACH,CAAC;QAED,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAA+B,CAAC;QACnE,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;YACjC,IAAI,KAAK,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC;gBACnC,SAAS;YACX,CAAC;YACD,MAAM,MAAM,GAAG,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;YAC9D,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnB,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACnD,CAAC;QAED,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,YAAY,CAAC,EAAE,CAAC;YACzC,IAAI,QAAQ,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC;gBACtC,SAAS;YACX,CAAC;YAED,MAAM,MAAM,GAAG,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YAC3D,MAAM,QAAQ,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC;YACjC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,SAAS;YACX,CAAC;YAED,YAAY,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;YACvD,YAAY,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;YACvD,KAAK,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,CAAC;QACnE,CAAC;QAED,MAAM,yBAAyB,GAC7B,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC;YAC7D,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;QAEhE,OAAO,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1D,KAAK,CAAC,IAAI,CAAC;gBACT,aAAa,EAAE,YAAY,CAAC,KAAK,EAAE;gBACnC,aAAa,EAAE,YAAY,CAAC,KAAK,EAAE;aACpC,CAAC,CAAC;QACL,CAAC;QAED,OAAO;YACL,KAAK;YACL,yBAAyB;SAC1B,CAAC;IACJ,CAAC;CACF,CAAA;AAxmCY,kCAAkC;IAD9C,UAAU,EAAE;IAKR,WAAA,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAA;IAEjC,WAAA,MAAM,CAAC,kBAAkB,CAAC,mBAAmB,CAAC,CAAA;IAE9C,WAAA,MAAM,CAAC,kBAAkB,CAAC,yBAAyB,CAAC,CAAA;IAEpD,WAAA,MAAM,CAAC,kBAAkB,CAAC,mBAAmB,CAAC,CAAA;+CAHhB,0BAA0B;QAEpB,gCAAgC;QAEtC,mBAAmB;GAXzC,kCAAkC,CAwmC9C","sourcesContent":["/**\n * File Operation Handler Backend Service\n *\n * Handles file field operations during resource CRUD operations.\n * Validates and processes file fields when resources are created, updated, or deleted.\n *\n * Features:\n * - File validation before resource creation/update\n * - File linking/unlinking during resource operations\n * - Cascade behavior on resource deletion\n * - Idempotent operations (safe to retry)\n */\n\nimport { injectable, inject } from 'inversify';\nimport { ResourceType, ErrorType, ErrorCustomMessageReference, FileStatus } from '@wildo-ai/saas-models';\nimport { FileGenerationSource } from '@wildo-ai/zod-decorators';\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 { ErrorBuilderBackendService } from '~wildo-backend-lib/errors/services/error-builder.backend.service';\nimport { projectCaughtErrorLogFields } from '~wildo-backend-lib/errors/utils/error-log-level-classification.backend.utils';\nimport { FileFieldDetectionBackendService, FileFieldMetadata } from './file-field-detection.backend.service';\nimport { FilesBackendService } from './files.backend.service';\nimport { ExecutionContext } from '~wildo-backend-lib/runtime/models/execution-context.backend.schemas';\nimport { RepositoryOptions } from '~wildo-backend-lib/base-classes/models/repositories.backend.schemas';\nimport { File } from '@wildo-ai/saas-models';\nimport { validateFileId, validateResourceType, validateResourceId, validateFieldName } from '~wildo-backend-lib/files/utils/file-validation.utils';\nimport {\n enumerateFileFieldValueOccurrences,\n hasExplicitCanonicalFieldMutation,\n mergeEffectiveResourceState,\n type FileFieldValueOccurrence,\n} from '~wildo-backend-lib/files/utils/file-field-schema-path.backend.utils';\n\ninterface FileFieldWriteProcessingOptions {\n /**\n * Internal-only escape hatch for framework materializers. Public write DTOs\n * still fail closed for generated PDF fields; only the exact generated\n * field/file-id pairs created by the service registry are accepted here.\n */\n frameworkGeneratedPdfFileIdsByField?: Record<string, readonly string[]>;\n}\n\n@injectable()\nexport class FileOperationHandlerBackendService {\n protected logDebug: (message: string, context?: Record<string, unknown>) => void;\n\n constructor(\n @inject(SAAS_SERVICE_TYPES.Logger)\n private readonly logger: LoggerService,\n @inject(SAAS_SERVICE_TYPES.ErrorBuilderService)\n private readonly errorBuilder: ErrorBuilderBackendService,\n @inject(SAAS_SERVICE_TYPES.FileFieldDetectionService)\n private readonly fileFieldDetection: FileFieldDetectionBackendService,\n @inject(SAAS_SERVICE_TYPES.FilesBackendService)\n private readonly filesService: FilesBackendService,\n ) {\n this.logDebug = this.logger.debugByType('FileOperationHandlerBackendService');\n this.logger.setDebugTypeLogging('FileOperationHandlerBackendService', false);\n }\n\n private isGeneratedPdfFileField(fileField: FileFieldMetadata): boolean {\n return fileField.fileMetadata.generation?.source === FileGenerationSource.PDF_TEMPLATE;\n }\n\n /**\n * Best-effort cleanup for the previous generated PDF after REGENERATE.\n *\n * The parent field already points at the newly rendered file when this runs.\n * A cleanup failure must not roll back a successful regeneration; the normal\n * file cleanup path can still pick up the stale generated file later.\n */\n async softDeleteGeneratedFileReplacement(params: {\n fileId: string | undefined;\n replacementFileId: string;\n fieldName: string;\n executionContext: ExecutionContext<any>;\n options?: RepositoryOptions;\n }): Promise<void> {\n if (!params.fileId || params.fileId === params.replacementFileId) {\n return;\n }\n\n try {\n await this.filesService.deleteFile(\n params.fileId,\n params.executionContext,\n params.options,\n );\n } catch (error) {\n this.logger.warn('Failed to soft-delete replaced generated PDF file', {\n fileId: params.fileId,\n replacementFileId: params.replacementFileId,\n fieldName: params.fieldName,\n ...projectCaughtErrorLogFields(error),\n });\n }\n }\n\n private assertGeneratedFileFieldNotUserSupplied(params: {\n data: Record<string, any>;\n fileField: FileFieldMetadata;\n occurrences: FileFieldValueOccurrence[];\n resourceType: ResourceType;\n executionContext: ExecutionContext<any>;\n processingOptions?: FileFieldWriteProcessingOptions;\n }): void {\n if (\n !this.isGeneratedPdfFileField(params.fileField)\n || (\n params.occurrences.length === 0\n && !hasExplicitCanonicalFieldMutation(params.data, params.fileField.fieldName)\n )\n ) {\n return;\n }\n\n const allowedFileIds = params.processingOptions?.frameworkGeneratedPdfFileIdsByField?.[params.fileField.fieldName];\n if (allowedFileIds && params.occurrences.length > 0) {\n const allowed = new Set(allowedFileIds);\n const submittedFileIds = params.occurrences.flatMap((occurrence) =>\n this.extractFileIds(occurrence.value, params.executionContext, true),\n );\n if (submittedFileIds.length > 0 && submittedFileIds.every((fileId) => allowed.has(fileId))) {\n return;\n }\n }\n\n throw this.errorBuilder.buildError(\n ErrorType.BUSINESS_RULE,\n params.executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_GENERATED_FIELD_NOT_WRITABLE,\n context: {\n // diagnostic (log-only)\n fieldName: params.fileField.fieldName,\n resourceType: params.resourceType,\n },\n }\n );\n }\n\n /**\n * Validate file fields before resource creation.\n * Ensures files exist, are in UPLOADED status, and are ready to be linked.\n *\n * @param data - Resource data being created\n * @param resourceType - Resource type\n * @param executionContext - Execution context\n * @param options - Repository options (for transaction support)\n * @throws Error if validation fails (fail fast before resource creation)\n */\n async validateFileFieldsForCreate(\n data: Record<string, any>,\n resourceType: ResourceType,\n executionContext: ExecutionContext<any>,\n options?: RepositoryOptions,\n processingOptions?: FileFieldWriteProcessingOptions,\n ): Promise<void> {\n // Validate inputs (CRITICAL: Prevents invalid data propagation)\n validateResourceType(resourceType, this.errorBuilder, executionContext, 'resourceType');\n\n // Check if resource has file fields\n if (!this.fileFieldDetection.hasFileFields(resourceType)) {\n return;\n }\n\n const fileFields = this.fileFieldDetection.detectFileFields(resourceType);\n\n this.logDebug('Validating file fields for CREATE', {\n resourceType,\n fileFieldsCount: fileFields.length,\n });\n\n // Collect all fileIds to validate\n const fileIdsToValidate: string[] = [];\n\n for (const fileField of fileFields) {\n const occurrences = enumerateFileFieldValueOccurrences(data, fileField.fieldName);\n this.assertGeneratedFileFieldNotUserSupplied({\n data,\n fileField,\n occurrences,\n resourceType,\n executionContext,\n processingOptions,\n });\n\n for (const occurrence of occurrences) {\n const fieldFileIds = this.extractFileIds(occurrence.value, executionContext, true);\n\n // F4-01: Enforce maxFiles constraint per concrete occurrence\n const { maxFiles, multiple } = fileField.fileMetadata;\n if (multiple && maxFiles !== undefined && fieldFileIds.length > maxFiles) {\n throw this.errorBuilder.buildError(\n ErrorType.BUSINESS_RULE,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_TOO_MANY_FILES,\n context: {\n // diagnostic (log-only)\n fieldName: fileField.fieldName,\n runtimeFieldPath: occurrence.runtimeFieldPath,\n resourceType,\n maxFiles,\n receivedCount: fieldFileIds.length,\n },\n }\n );\n }\n\n fileIdsToValidate.push(...fieldFileIds);\n }\n }\n\n // Validate each file\n for (const fileId of fileIdsToValidate) {\n // Validate fileId format (CRITICAL: Prevents query injection and database errors)\n validateFileId(fileId, this.errorBuilder, executionContext, 'fileId');\n\n const file = await this.filesService.getFile(fileId, executionContext, options);\n\n if (!file) {\n throw this.errorBuilder.buildError(\n ErrorType.NOT_FOUND,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_NOT_FOUND,\n context: {\n // diagnostic (log-only)\n fileId,\n resourceType,\n },\n }\n );\n }\n\n // Verify file is in UPLOADED status (ready to be linked)\n if (file.status !== FileStatus.UPLOADED) {\n throw this.errorBuilder.buildError(\n ErrorType.BUSINESS_RULE,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_NOT_IN_UPLOADED_STATUS,\n context: {\n // diagnostic (log-only)\n fileId,\n fileStatus: file.status,\n resourceType,\n expectedStatus: FileStatus.UPLOADED,\n },\n }\n );\n }\n\n // Note: uploadContext validation can be added in Phase 2 if needed\n // For now, we only validate that file is UPLOADED\n }\n\n this.logDebug('File fields validation for CREATE completed', {\n resourceType,\n validatedFilesCount: fileIdsToValidate.length,\n });\n }\n\n /**\n * Process file fields after resource creation.\n * Links files to the newly created resource.\n *\n * @param data - Resource data that was created\n * @param resourceType - Resource type\n * @param resourceId - ID of the created resource\n * @param executionContext - Execution context\n */\n /**\n * Strip the PARENT resource's optimistic-lock version from options before any\n * child-file write.\n *\n * When a resource CREATE/UPDATE links/unlinks a `z_file()` field, the file is a\n * SEPARATE document with its own `_version_db_doc` lifecycle. If the parent request\n * carried an `If-Match` header, its `ifMatchVersion` must NOT fence the file update:\n * the repository would add a `{ _version_db_doc: <parentVersion> }` filter to the\n * FILE query, which (mis)matches the file by the PARENT's version and yields a\n * spurious `version_conflict` (the avatar-save 409: parent `If-Match: 0` leaking onto\n * the internal `files | update`). The transaction context is preserved so the file\n * write still participates in the parent's atomic boundary.\n */\n private stripParentVersionFence(options?: RepositoryOptions): RepositoryOptions | undefined {\n if (!options || options.ifMatchVersion === undefined) return options;\n const { ifMatchVersion: _parentVersionFence, ...fileWriteOptions } = options;\n return fileWriteOptions;\n }\n\n async processFileFieldsForCreate(\n data: Record<string, any>,\n resourceType: ResourceType,\n resourceId: string,\n executionContext: ExecutionContext<any>,\n options?: RepositoryOptions,\n processingOptions?: FileFieldWriteProcessingOptions,\n ): Promise<void> {\n // Validate inputs (CRITICAL: Prevents invalid data propagation)\n validateResourceType(resourceType, this.errorBuilder, executionContext, 'resourceType');\n validateResourceId(resourceId, this.errorBuilder, executionContext, 'resourceId');\n\n // A child-file link/unlink must not inherit the parent's optimistic-lock version.\n options = this.stripParentVersionFence(options);\n\n // Check if resource has file fields\n if (!this.fileFieldDetection.hasFileFields(resourceType)) {\n return;\n }\n\n const fileFields = this.fileFieldDetection.detectFileFields(resourceType);\n\n this.logDebug('Processing file fields for CREATE', {\n resourceType,\n resourceId,\n fileFieldsCount: fileFields.length,\n });\n\n // Process each file field\n for (const fileField of fileFields) {\n const submittedOccurrences = enumerateFileFieldValueOccurrences(data, fileField.fieldName);\n this.assertGeneratedFileFieldNotUserSupplied({\n data,\n fileField,\n occurrences: submittedOccurrences,\n resourceType,\n executionContext,\n processingOptions,\n });\n if (\n this.isGeneratedPdfFileField(fileField)\n && !processingOptions?.frameworkGeneratedPdfFileIdsByField?.[fileField.fieldName]\n ) {\n continue;\n }\n const occurrences = enumerateFileFieldValueOccurrences(data, fileField.fieldName);\n\n for (const occurrence of occurrences) {\n const fieldFileIds = this.extractFileIds(occurrence.value, executionContext, true);\n for (const fileId of fieldFileIds) {\n await this.linkFileToResource(\n fileId,\n resourceType,\n resourceId,\n fileField.fieldName,\n executionContext,\n options\n );\n }\n }\n }\n\n this.logDebug('File fields processing for CREATE completed', {\n resourceType,\n resourceId,\n });\n }\n\n /**\n * Process file fields after resource update.\n * Unlinks old files and links new files.\n * Validates new files BEFORE unlinking old ones (fail fast).\n *\n * Note: This method handles partial updates correctly. If a file field is not present\n * in `data`, it is treated as unchanged (not removed). Only explicit changes to file\n * field values trigger unlinking/linking operations.\n *\n * @param data - Updated resource data (may be partial update - only changed fields)\n * @param existingResource - Existing resource before update (complete state)\n * @param resourceType - Resource type\n * @param resourceId - Resource ID\n * @param executionContext - Execution context\n */\n async processFileFieldsForUpdate(\n data: Record<string, any>,\n existingResource: Record<string, any>,\n resourceType: ResourceType,\n resourceId: string,\n executionContext: ExecutionContext<any>,\n options?: RepositoryOptions,\n processingOptions?: FileFieldWriteProcessingOptions,\n ): Promise<void> {\n // Validate inputs (CRITICAL: Prevents invalid data propagation)\n validateResourceType(resourceType, this.errorBuilder, executionContext, 'resourceType');\n validateResourceId(resourceId, this.errorBuilder, executionContext, 'resourceId');\n\n // A child-file link/unlink must not inherit the parent's optimistic-lock version.\n options = this.stripParentVersionFence(options);\n\n // Check if resource has file fields\n if (!this.fileFieldDetection.hasFileFields(resourceType)) {\n return;\n }\n\n const fileFields = this.fileFieldDetection.detectFileFields(resourceType);\n const effectiveNewResource = mergeEffectiveResourceState(existingResource, data) as Record<string, any>;\n\n this.logDebug('Processing file fields for UPDATE', {\n resourceType,\n resourceId,\n fileFieldsCount: fileFields.length,\n });\n\n // Process each file field\n for (const fileField of fileFields) {\n const submittedOccurrences = enumerateFileFieldValueOccurrences(data, fileField.fieldName);\n this.assertGeneratedFileFieldNotUserSupplied({\n data,\n fileField,\n occurrences: submittedOccurrences,\n resourceType,\n executionContext,\n processingOptions,\n });\n if (\n this.isGeneratedPdfFileField(fileField)\n && !processingOptions?.frameworkGeneratedPdfFileIdsByField?.[fileField.fieldName]\n ) {\n continue;\n }\n const oldOccurrences = this.prepareOccurrences(\n enumerateFileFieldValueOccurrences(existingResource, fileField.fieldName),\n executionContext,\n false,\n );\n const newOccurrences = this.prepareOccurrences(\n enumerateFileFieldValueOccurrences(effectiveNewResource, fileField.fieldName),\n executionContext,\n true,\n );\n\n const occurrencePairs = this.matchOccurrences(oldOccurrences, newOccurrences);\n if (occurrencePairs.requiresAmbiguousFallback && fileField.fileMetadata.overridable === false) {\n throw this.errorBuilder.buildError(\n ErrorType.BUSINESS_RULE,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_NESTED_UPDATE_AMBIGUOUS,\n context: {\n // diagnostic (log-only)\n fieldName: fileField.fieldName,\n resourceType,\n resourceId,\n },\n }\n );\n }\n\n for (const pair of occurrencePairs.pairs) {\n const oldFileIds = pair.oldOccurrence?.fileIds ?? [];\n const newFileIds = pair.newOccurrence?.fileIds ?? [];\n const oldSet = new Set(oldFileIds);\n const newSet = new Set(newFileIds);\n const hasChanged =\n oldSet.size !== newSet.size ||\n !oldFileIds.every(id => newSet.has(id)) ||\n !newFileIds.every(id => oldSet.has(id));\n\n if (!hasChanged) {\n continue;\n }\n\n const runtimeFieldPath = pair.newOccurrence?.occurrence.runtimeFieldPath\n ?? pair.oldOccurrence?.occurrence.runtimeFieldPath;\n\n // F4-02: Enforce overridable constraint\n const { overridable, multiple, maxFiles } = fileField.fileMetadata;\n if (overridable === false) {\n const removedFileIds = oldFileIds.filter(id => !newSet.has(id));\n\n if (!multiple) {\n if (removedFileIds.length > 0) {\n throw this.errorBuilder.buildError(\n ErrorType.BUSINESS_RULE,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_FIELD_NOT_OVERRIDABLE,\n context: {\n // diagnostic (log-only)\n fieldName: fileField.fieldName,\n runtimeFieldPath,\n resourceType,\n resourceId,\n },\n }\n );\n }\n } else if (removedFileIds.length > 0) {\n throw this.errorBuilder.buildError(\n ErrorType.BUSINESS_RULE,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_FIELD_NOT_OVERRIDABLE,\n context: {\n // diagnostic (log-only)\n fieldName: fileField.fieldName,\n runtimeFieldPath,\n resourceType,\n resourceId,\n removedFileIds,\n },\n }\n );\n }\n }\n\n if (multiple && maxFiles !== undefined && newFileIds.length > maxFiles) {\n throw this.errorBuilder.buildError(\n ErrorType.BUSINESS_RULE,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_TOO_MANY_FILES,\n context: {\n // diagnostic (log-only)\n fieldName: fileField.fieldName,\n runtimeFieldPath,\n resourceType,\n resourceId,\n maxFiles,\n newTotal: newFileIds.length,\n },\n }\n );\n }\n\n for (const fileId of newFileIds) {\n if (!oldSet.has(fileId)) {\n // New file - validate fileId format (CRITICAL: Prevents query injection and database errors)\n validateFileId(fileId, this.errorBuilder, executionContext, 'fileId');\n\n const file = await this.filesService.getFile(fileId, executionContext, options);\n\n if (!file) {\n throw this.errorBuilder.buildError(\n ErrorType.NOT_FOUND,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_NOT_FOUND,\n context: {\n // diagnostic (log-only)\n fileId,\n resourceType,\n resourceId,\n runtimeFieldPath,\n },\n }\n );\n }\n\n if (file.status !== FileStatus.UPLOADED) {\n throw this.errorBuilder.buildError(\n ErrorType.BUSINESS_RULE,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_NOT_IN_UPLOADED_STATUS,\n context: {\n // diagnostic (log-only)\n fileId,\n fileStatus: file.status,\n runtimeFieldPath,\n resourceType,\n resourceId,\n expectedStatus: FileStatus.UPLOADED,\n },\n }\n );\n }\n }\n }\n\n for (const oldFileId of oldFileIds) {\n if (!newSet.has(oldFileId)) {\n // File removed - unlink it\n await this.unlinkFileFromResource(\n oldFileId,\n fileField.fieldName,\n executionContext,\n options\n );\n }\n }\n\n for (const newFileId of newFileIds) {\n if (!oldSet.has(newFileId)) {\n // New file - link it\n await this.linkFileToResource(\n newFileId,\n resourceType,\n resourceId,\n fileField.fieldName,\n executionContext,\n options\n );\n }\n }\n }\n }\n\n this.logDebug('File fields processing for UPDATE completed', {\n resourceType,\n resourceId,\n });\n }\n\n /**\n * Process file fields before resource deletion.\n * Applies onParentDelete behavior to all linked files.\n *\n * @param resourceType - Resource type being deleted\n * @param resourceId - Resource ID being deleted\n * @param executionContext - Execution context\n */\n /**\n * Carry the owner ALREADY VERIFIED by `listFilesForResource` (which authorized each returned file\n * against the parent resource's derived scope) onto the options used for the subsequent delete/erase,\n * so the deletion gate (`getFile`'s per-file authorize) checks against that owner rather than the\n * identity-less system-cascade EC — which would otherwise DENY the subject's own file and abort the\n * erasure. Never widens access: `authorizeFileAccess` still matches this against the file's own scope.\n */\n private withAuthoritativeFileScope(options: RepositoryOptions | undefined, file: File): RepositoryOptions {\n return {\n ...(options ?? {}),\n authoritativeFileScope: {\n applicationId: file.applicationId,\n organizationId: file.organizationId,\n userId: file.userId,\n },\n };\n }\n\n async processFileFieldsForDelete(\n resourceType: ResourceType,\n resourceId: string,\n executionContext: ExecutionContext<any>,\n options?: RepositoryOptions\n ): Promise<void> {\n // A child-file cleanup must not inherit the parent's optimistic-lock version.\n options = this.stripParentVersionFence(options);\n\n // Check if resource has file fields\n if (!this.fileFieldDetection.hasFileFields(resourceType)) {\n return;\n }\n\n const fileFields = this.fileFieldDetection.detectFileFields(resourceType);\n\n this.logDebug('Processing file fields for DELETE', {\n resourceType,\n resourceId,\n fileFieldsCount: fileFields.length,\n });\n\n // Get all files linked to this resource\n const linkedFiles = await this.filesService.listFilesForResource(\n resourceType,\n resourceId,\n undefined, // fieldName - undefined means all fields\n executionContext,\n options\n );\n\n // Process each file based on onParentDelete behavior from field metadata\n for (const file of linkedFiles) {\n // Forward the owner `listFilesForResource` already verified for THIS file to the deletion gate,\n // so a system-cascade teardown (identity-less EC) does not deny the subject's own file.\n const teardownOptions = this.withAuthoritativeFileScope(options, file);\n if (!file.linkedFieldName) {\n this.logger.warn('Linked file missing linkedFieldName during parent delete; defaulting to cascade cleanup', {\n fileId: file.fileId,\n resourceType,\n resourceId,\n });\n await this.applyOnParentDeleteBehavior(\n file.fileId,\n 'cascade',\n executionContext,\n teardownOptions\n );\n continue;\n }\n\n const fileField = this.fileFieldDetection.getFileFieldMetadata(\n resourceType,\n file.linkedFieldName\n );\n\n if (!fileField) {\n // Field not found - use default cascade behavior\n await this.applyOnParentDeleteBehavior(\n file.fileId,\n 'cascade',\n executionContext,\n teardownOptions\n );\n continue;\n }\n\n const onParentDelete = fileField.fileMetadata.onParentDelete || 'cascade';\n\n await this.applyOnParentDeleteBehavior(\n file.fileId,\n onParentDelete,\n executionContext,\n teardownOptions\n );\n }\n\n this.logDebug('File fields processing for DELETE completed', {\n resourceType,\n resourceId,\n processedFilesCount: linkedFiles.length,\n });\n }\n\n /**\n * Process file fields when a resource row is IMPERSONALIZED-AND-RETAINED (gate **G-FILE**).\n *\n * The row survives for a legal/audit obligation, so this is NOT the delete cascade — but \"keep the\n * record\" must not become \"keep the personal data\". A field-level scrub cannot reach inside a stored\n * blob (a passport scan stays a passport scan however the row is rewritten), so for a file field the\n * only real erasure is deleting the file.\n *\n * Which files? Exactly the ones whose field the author marked personal with `.impersonalizeWith()` —\n * the SAME author-responsibility contract as ordinary fields, reusing the same vocabulary rather\n * than inventing a second axis. The caller passes the scrub patch's field names:\n * - field IS scrubbed (REMOVE) ⇒ delete the file. The scrub patch nulls the pointer in the same\n * write, so the retained row keeps no dangling reference.\n * - field NOT scrubbed (KEEP / untreated) ⇒ leave the file. This is how a legally-required artifact\n * (an invoice PDF that IS the retained record) survives the erasure.\n *\n * Why deletion is required rather than relying on the row being hidden: the resource-scoped serve\n * route inherits the parent's READ authorization, so a hidden retained row already blocks it — but\n * the GLOBAL `/files/:fileId` route (direct / consumable-token / public-share) is explicitly NOT\n * resource-scoped and re-checks only the file's OWN scope. A file left ACTIVE therefore stays\n * reachable there even though its parent row is invisible.\n *\n * Erasure here goes through `FilesBackendService.eraseFile`, NOT `deleteFile`: besides marking the\n * file DELETED it scrubs the file row's OWN personal data (`originalFilename`, `uploadedBy`) in the\n * same write. Without that, the row's metadata stayed readable on the global metadata route for the\n * weeks until physical cleanup — an \"erasure\" that leaked `passport-jane-doe.pdf` the whole time. A\n * lifecycle delete deliberately keeps that provenance; a privacy erasure must not.\n *\n * Physical storage cleanup stays with the existing cleanup batch, so an erasure never mixes a DB\n * rollback with non-transactional storage side effects.\n *\n * ## The MIDDLE state — keep-but-hide — is deliberately NOT built (decided 2026-08-09)\n *\n * There are only two outcomes above, and the consequence of the second is worth stating plainly: a KEEP\n * file stays ORDINARILY READABLE to the file's own scope (its organization) through the global route,\n * indefinitely, even though its parent row is now invisible. A third state — retained but reachable only\n * through the audited see-through door, mirroring the parent row's posture — was considered and refused\n * for three reasons, in order of weight:\n *\n * 1. **It would contradict a decision already taken.** The concrete case that motivates it is the\n * invoice PDF, and the billing retention decision was explicitly \"retained as audit material, and\n * invoices stay VISIBLE\" for ordinary accounting. Hiding retained invoice documents would reverse\n * that, and the sibling ruling on invoice URLs went the same way: keep the document, close the\n * ordinary door only where the document is not itself the record.\n * 2. **A hiding door is worthless without its reading door, and shipping one alone is worse than\n * neither.** Withholding the file without also building an audited retrieval primitive would make\n * the legally-required artifact unreachable by ANYONE — destroying the very access the retention\n * obligation exists to preserve. (Same pairing rule as the cross-tenant repair doors: a marking\n * door without its release door is a one-way door calling itself a window.)\n * 3. **No shipped resource needs it.** The author already controls both ends per field: mark the field\n * and the file is erased, leave it and the file survives. The gap is only the middle, and nothing in\n * the tree declares a file field that is simultaneously personal, legally required, and must stop\n * being ordinarily visible.\n *\n * **What would trigger building it:** a resource declaring exactly that combination. The shape is then a\n * new `FileStatus` member excluded from `FILE_DOWNLOADABLE_STATUSES` and added to\n * `FILE_METADATA_WITHHELD_STATUSES`, a `FILE_STATUS_TRANSITIONS` entry, and — non-optional — an audited\n * see-through retrieval primitive alongside it. Do not add the status without the door.\n */\n async processFileFieldsForImpersonalize(\n resourceType: ResourceType,\n resourceId: string,\n scrubbedFieldNames: readonly string[],\n executionContext: ExecutionContext<any>,\n options?: RepositoryOptions\n ): Promise<void> {\n options = this.stripParentVersionFence(options);\n\n if (scrubbedFieldNames.length === 0 || !this.fileFieldDetection.hasFileFields(resourceType)) {\n return;\n }\n\n const scrubbedFields = new Set(scrubbedFieldNames);\n const linkedFiles = await this.filesService.listFilesForResource(\n resourceType,\n resourceId,\n undefined, // all fields — we filter by treatment below\n executionContext,\n options\n );\n\n let erasedCount = 0;\n let unattributableCount = 0;\n for (const file of linkedFiles) {\n // Fail-closed on an unattributable file: without `linkedFieldName` we cannot tell whether its\n // field was marked personal, and silently keeping it risks retaining an erased subject's\n // document. The delete cascade defaults such a file to cleanup for the same reason.\n const isUnattributable = !file.linkedFieldName;\n const isScrubbedField = isUnattributable || scrubbedFields.has(file.linkedFieldName!);\n if (!isScrubbedField) {\n continue;\n }\n if (isUnattributable) {\n /**\n * WARN, not debug: this is an irreversible deletion taken on a GUESS.\n *\n * The fail-closed default is right — a file we cannot attribute might be the erased subject's\n * passport scan — but it can equally destroy a file the retention obligation existed to KEEP\n * (an invoice PDF whose link lost its field name). Either way the cause is upstream metadata,\n * so it has to be visible: the sibling delete cascade has warned here since before this path\n * existed, and this one erased silently. Same decision, same audibility.\n */\n unattributableCount += 1;\n this.logger.warn(\n '[Retention] Erasing a linked file with no `linkedFieldName` during impersonalize — it cannot '\n + 'be attributed to a field, so the fail-closed default deletes it. If this file was meant to '\n + 'be RETAINED, its link metadata is the defect.',\n { resourceType, resourceId, fileId: file.fileId },\n );\n }\n // Forward the owner `listFilesForResource` already verified for THIS file to the deletion gate,\n // so a system-cascade (identity-less EC) impersonalize erase does not deny the subject's own file.\n await this.filesService.eraseFile(file.fileId, executionContext, this.withAuthoritativeFileScope(options, file));\n erasedCount++;\n }\n\n this.logDebug('File fields processing for IMPERSONALIZE completed', {\n resourceType,\n resourceId,\n linkedFilesCount: linkedFiles.length,\n erasedCount,\n retainedCount: linkedFiles.length - erasedCount,\n unattributableCount,\n });\n }\n\n /**\n * Extract file IDs from field value (handles single file or array).\n *\n * @param fieldValue - The raw field value from the resource object\n * @param executionContext - Current execution context\n * @param strict - When true (user input / new values), throws on invalid fileIds.\n * When false (existing DB data), silently filters and logs warnings.\n */\n private extractFileIds(fieldValue: any, executionContext?: ExecutionContext<any>, strict: boolean = false): string[] {\n if (fieldValue === null || fieldValue === undefined) {\n return [];\n }\n\n if (typeof fieldValue === 'object' && !Array.isArray(fieldValue)) {\n if ('fileId' in fieldValue) {\n return this.extractFileIds((fieldValue as { fileId?: unknown }).fileId, executionContext, strict);\n }\n\n if ('fileIds' in fieldValue) {\n return this.extractFileIds((fieldValue as { fileIds?: unknown }).fileIds, executionContext, strict);\n }\n }\n\n if (Array.isArray(fieldValue)) {\n const validFileIds: string[] = [];\n for (const fileId of fieldValue) {\n if (typeof fileId !== 'string' || fileId.trim() === '') {\n if (strict) {\n throw this.errorBuilder.buildError(\n ErrorType.VALIDATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_ID_VALIDATION_FAILED,\n context: {\n // diagnostic (log-only)\n fileId,\n receivedType: typeof fileId,\n },\n }\n );\n }\n continue;\n }\n try {\n validateFileId(fileId, this.errorBuilder, executionContext, 'fileId');\n validFileIds.push(fileId);\n } catch (error) {\n if (strict) {\n throw error; // Re-throw in strict mode — user provided invalid input\n }\n // Tolerant mode: filter out and warn (handles corrupt DB data gracefully)\n this.logger.warn('Invalid fileId filtered out during extraction', {\n fileId,\n ...projectCaughtErrorLogFields(error),\n });\n }\n }\n return validFileIds;\n }\n\n if (typeof fieldValue === 'string' && fieldValue.trim() !== '') {\n try {\n validateFileId(fieldValue, this.errorBuilder, executionContext, 'fileId');\n return [fieldValue];\n } catch (error) {\n if (strict) {\n throw error;\n }\n this.logger.warn('Invalid fileId filtered out during extraction', {\n fileId: fieldValue,\n ...projectCaughtErrorLogFields(error),\n });\n return [];\n }\n }\n\n if (strict && fieldValue !== null && fieldValue !== undefined) {\n throw this.errorBuilder.buildError(\n ErrorType.VALIDATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_FIELD_VALUE_INVALID,\n context: {\n // diagnostic (log-only)\n receivedType: typeof fieldValue,\n },\n }\n );\n }\n\n return [];\n }\n\n /**\n * Link a file to a resource.\n * Handles race conditions (idempotent - safe to call multiple times).\n */\n private async linkFileToResource(\n fileId: string,\n resourceType: ResourceType,\n resourceId: string,\n fieldName: string,\n executionContext: ExecutionContext<any>,\n options?: RepositoryOptions\n ): Promise<void> {\n // Validate inputs (CRITICAL: Prevents query injection and database errors)\n validateFileId(fileId, this.errorBuilder, executionContext, 'fileId');\n validateResourceType(resourceType, this.errorBuilder, executionContext, 'resourceType');\n validateResourceId(resourceId, this.errorBuilder, executionContext, 'resourceId');\n validateFieldName(fieldName, this.errorBuilder, executionContext, 'fieldName');\n\n // Check if file is already linked to the same resource (idempotent check - before calling service)\n // This prevents unnecessary service calls and handles idempotent cases early\n const file = await this.filesService.getFile(fileId, executionContext, options);\n if (file &&\n file.status === FileStatus.LINKED &&\n file.linkedResourceType === resourceType &&\n file.linkedResourceId === resourceId &&\n file.linkedFieldName === fieldName) {\n // Already linked to same resource - skip (idempotent)\n this.logDebug('File already linked to same resource, skipping', {\n fileId,\n resourceType,\n resourceId,\n fieldName,\n });\n return;\n }\n\n // Link file - errors propagate to fail the transaction (Decision 2.2: Option A)\n // FilesBackendService.linkFileToResource() handles idempotent cases internally (returns existing file)\n // All other errors (NOT_FOUND, BUSINESS_RULE, INTERNAL) should fail the operation\n await this.filesService.linkFileToResource(\n fileId,\n resourceType,\n resourceId,\n fieldName,\n executionContext,\n options\n );\n }\n\n /**\n * Unlink a file from a resource.\n * Applies onParentDelete behavior.\n */\n private async unlinkFileFromResource(\n fileId: string,\n fieldName: string,\n executionContext: ExecutionContext<any>,\n options?: RepositoryOptions\n ): Promise<void> {\n // Validate fileId format (CRITICAL: Prevents query injection and database errors)\n validateFileId(fileId, this.errorBuilder, executionContext, 'fileId');\n\n const file = await this.filesService.getFile(fileId, executionContext, options);\n if (!file || file.status !== FileStatus.LINKED) {\n // Already unlinked or doesn't exist - skip (idempotent)\n return;\n }\n\n // Unlink file (sets status to ORPHANED)\n await this.filesService.unlinkFileFromResource(fileId, executionContext, options);\n }\n\n /**\n * Apply onParentDelete behavior to a file.\n *\n * @param fileId - File ID\n * @param behavior - Behavior: 'cascade', 'soft-delete', or 'orphan'\n * @param executionContext - Execution context\n */\n private async applyOnParentDeleteBehavior(\n fileId: string,\n behavior: 'cascade' | 'soft-delete' | 'orphan',\n executionContext: ExecutionContext<any>,\n options?: RepositoryOptions\n ): Promise<void> {\n this.logDebug('Applying onParentDelete behavior', {\n fileId,\n behavior,\n });\n\n switch (behavior) {\n case 'cascade':\n // Cascade now marks the file as DELETED only. Physical storage cleanup is\n // intentionally deferred to the cleanup batch so resource deletes never\n // mix Mongo rollback with non-transactional storage side effects.\n await this.filesService.deleteFile(fileId, executionContext, options);\n break;\n\n case 'soft-delete':\n // Soft delete: update status to DELETED\n await this.filesService.deleteFile(fileId, executionContext, options);\n break;\n\n case 'orphan':\n // Unlink: clear parent fields, set status to ORPHANED\n await this.filesService.unlinkFileFromResource(fileId, executionContext, options);\n break;\n\n default:\n // Default to cascade\n await this.filesService.deleteFile(fileId, executionContext, options);\n }\n }\n\n private prepareOccurrences(\n occurrences: FileFieldValueOccurrence[],\n executionContext: ExecutionContext<any>,\n strict: boolean,\n ): Array<{\n occurrence: FileFieldValueOccurrence;\n fileIds: string[];\n signature: string;\n }> {\n return occurrences.map((occurrence) => {\n const fileIds = this.extractFileIds(occurrence.value, executionContext, strict);\n return {\n occurrence,\n fileIds,\n signature: JSON.stringify([...fileIds].sort()),\n };\n });\n }\n\n private matchOccurrences(\n oldOccurrences: Array<{\n occurrence: FileFieldValueOccurrence;\n fileIds: string[];\n signature: string;\n }>,\n newOccurrences: Array<{\n occurrence: FileFieldValueOccurrence;\n fileIds: string[];\n signature: string;\n }>,\n ): {\n pairs: Array<{\n oldOccurrence?: {\n occurrence: FileFieldValueOccurrence;\n fileIds: string[];\n signature: string;\n };\n newOccurrence?: {\n occurrence: FileFieldValueOccurrence;\n fileIds: string[];\n signature: string;\n };\n }>;\n requiresAmbiguousFallback: boolean;\n } {\n const pairs: Array<{\n oldOccurrence?: {\n occurrence: FileFieldValueOccurrence;\n fileIds: string[];\n signature: string;\n };\n newOccurrence?: {\n occurrence: FileFieldValueOccurrence;\n fileIds: string[];\n signature: string;\n };\n }> = [];\n\n const remainingOld = [...oldOccurrences];\n const remainingNew = [...newOccurrences];\n\n const stableIds = new Set(\n [...remainingOld, ...remainingNew]\n .map((entry) => entry.occurrence.ownerStableId)\n .filter((value): value is string => typeof value === 'string' && value.trim() !== ''),\n );\n\n for (const stableId of stableIds) {\n const oldMatches = remainingOld.filter((entry) => entry.occurrence.ownerStableId === stableId);\n const newMatches = remainingNew.filter((entry) => entry.occurrence.ownerStableId === stableId);\n\n while (oldMatches.length > 0 && newMatches.length > 0) {\n const oldEntry = oldMatches.shift()!;\n const newEntry = newMatches.shift()!;\n remainingOld.splice(remainingOld.indexOf(oldEntry), 1);\n remainingNew.splice(remainingNew.indexOf(newEntry), 1);\n pairs.push({ oldOccurrence: oldEntry, newOccurrence: newEntry });\n }\n }\n\n const oldSignatureBuckets = new Map<string, typeof remainingOld>();\n for (const entry of remainingOld) {\n if (entry.occurrence.ownerStableId) {\n continue;\n }\n const bucket = oldSignatureBuckets.get(entry.signature) ?? [];\n bucket.push(entry);\n oldSignatureBuckets.set(entry.signature, bucket);\n }\n\n for (const newEntry of [...remainingNew]) {\n if (newEntry.occurrence.ownerStableId) {\n continue;\n }\n\n const bucket = oldSignatureBuckets.get(newEntry.signature);\n const oldEntry = bucket?.shift();\n if (!oldEntry) {\n continue;\n }\n\n remainingOld.splice(remainingOld.indexOf(oldEntry), 1);\n remainingNew.splice(remainingNew.indexOf(newEntry), 1);\n pairs.push({ oldOccurrence: oldEntry, newOccurrence: newEntry });\n }\n\n const requiresAmbiguousFallback =\n remainingOld.some((entry) => !entry.occurrence.ownerStableId) &&\n remainingNew.some((entry) => !entry.occurrence.ownerStableId);\n\n while (remainingOld.length > 0 || remainingNew.length > 0) {\n pairs.push({\n oldOccurrence: remainingOld.shift(),\n newOccurrence: remainingNew.shift(),\n });\n }\n\n return {\n pairs,\n requiresAmbiguousFallback,\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"file-operation-handler.backend.service.js","sourceRoot":"","sources":["../../../../../src/files/services/file-operation-handler.backend.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * File Operation Handler Backend Service\n *\n * Handles file field operations during resource CRUD operations.\n * Validates and processes file fields when resources are created, updated, or deleted.\n *\n * Features:\n * - File validation before resource creation/update\n * - File linking/unlinking during resource operations\n * - Cascade behavior on resource deletion\n * - Idempotent operations (safe to retry)\n */\n\nimport { injectable, inject } from 'inversify';\nimport { ResourceType, ErrorType, ErrorCustomMessageReference, FileStatus, FILE_LINKABLE_STATUSES } from '@wildo-ai/saas-models';\nimport { FileGenerationSource } from '@wildo-ai/zod-decorators';\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 { ErrorBuilderBackendService } from '~wildo-backend-lib/errors/services/error-builder.backend.service';\nimport { projectCaughtErrorLogFields } from '~wildo-backend-lib/errors/utils/error-log-level-classification.backend.utils';\nimport { FileFieldDetectionBackendService, FileFieldMetadata } from './file-field-detection.backend.service';\nimport { FilesBackendService } from './files.backend.service';\nimport { ExecutionContext } from '~wildo-backend-lib/runtime/models/execution-context.backend.schemas';\nimport { RepositoryOptions } from '~wildo-backend-lib/base-classes/models/repositories.backend.schemas';\nimport { File } from '@wildo-ai/saas-models';\nimport { validateFileId, validateResourceType, validateResourceId, validateFieldName } from '~wildo-backend-lib/files/utils/file-validation.utils';\nimport {\n enumerateFileFieldValueOccurrences,\n hasExplicitCanonicalFieldMutation,\n mergeEffectiveResourceState,\n type FileFieldValueOccurrence,\n} from '~wildo-backend-lib/files/utils/file-field-schema-path.backend.utils';\n\ninterface FileFieldWriteProcessingOptions {\n /**\n * Internal-only escape hatch for framework materializers. Public write DTOs\n * still fail closed for generated PDF fields; only the exact generated\n * field/file-id pairs created by the service registry are accepted here.\n */\n frameworkGeneratedPdfFileIdsByField?: Record<string, readonly string[]>;\n}\n\n@injectable()\nexport class FileOperationHandlerBackendService {\n protected logDebug: (message: string, context?: Record<string, unknown>) => void;\n\n constructor(\n @inject(SAAS_SERVICE_TYPES.Logger)\n private readonly logger: LoggerService,\n @inject(SAAS_SERVICE_TYPES.ErrorBuilderService)\n private readonly errorBuilder: ErrorBuilderBackendService,\n @inject(SAAS_SERVICE_TYPES.FileFieldDetectionService)\n private readonly fileFieldDetection: FileFieldDetectionBackendService,\n @inject(SAAS_SERVICE_TYPES.FilesBackendService)\n private readonly filesService: FilesBackendService,\n ) {\n this.logDebug = this.logger.debugByType('FileOperationHandlerBackendService');\n this.logger.setDebugTypeLogging('FileOperationHandlerBackendService', false);\n }\n\n private isGeneratedPdfFileField(fileField: FileFieldMetadata): boolean {\n return fileField.fileMetadata.generation?.source === FileGenerationSource.PDF_TEMPLATE;\n }\n\n /**\n * The ONE place that decides whether a file's status admits linking (issue #320).\n *\n * Both link-time validators (CREATE and UPDATE) used to compare against the literal\n * `FileStatus.UPLOADED`, so a file the scanner had certified `CLEAN` — a status\n * `FILE_STATUS_TRANSITIONS` explicitly allows to become `LINKED` — was refused with an error\n * naming `UPLOADED` as the expected state. Whether a scanned file could be attached depended on\n * beating the scanner. The admitted set now comes from `FILE_LINKABLE_STATUSES`, the single copy\n * shared with `FilesBackendService.linkFileToResource`.\n *\n * `SCANNING` is named separately: the file is not wrong, it is not yet KNOWN to be safe, so the\n * caller must learn to retry rather than re-upload. Every other non-linkable status (PENDING,\n * FAILED, DELETED, ORPHANED, INFECTED, QUARANTINED, and LINKED-to-something-else, which\n * `linkFileToResource` distinguishes further) is a terminal refusal for this write.\n *\n * @param diagnostics - log-only context; never rendered to the caller.\n */\n private assertFileLinkable(\n file: Pick<File, 'status'>,\n executionContext: ExecutionContext<any>,\n diagnostics: Record<string, unknown>,\n ): void {\n if (FILE_LINKABLE_STATUSES.has(file.status)) {\n return;\n }\n throw this.errorBuilder.buildError(\n ErrorType.BUSINESS_RULE,\n executionContext,\n {\n customMessageReference: file.status === FileStatus.SCANNING\n ? ErrorCustomMessageReference.FILE_SCAN_IN_PROGRESS\n : ErrorCustomMessageReference.FILE_NOT_LINKABLE,\n context: {\n // diagnostic (log-only)\n ...diagnostics,\n fileStatus: file.status,\n linkableStatuses: [...FILE_LINKABLE_STATUSES],\n },\n }\n );\n }\n\n /**\n * Best-effort cleanup for the previous generated PDF after REGENERATE.\n *\n * The parent field already points at the newly rendered file when this runs.\n * A cleanup failure must not roll back a successful regeneration; the normal\n * file cleanup path can still pick up the stale generated file later.\n */\n async softDeleteGeneratedFileReplacement(params: {\n fileId: string | undefined;\n replacementFileId: string;\n fieldName: string;\n executionContext: ExecutionContext<any>;\n options?: RepositoryOptions;\n }): Promise<void> {\n if (!params.fileId || params.fileId === params.replacementFileId) {\n return;\n }\n\n try {\n await this.filesService.deleteFile(\n params.fileId,\n params.executionContext,\n params.options,\n );\n } catch (error) {\n this.logger.warn('Failed to soft-delete replaced generated PDF file', {\n fileId: params.fileId,\n replacementFileId: params.replacementFileId,\n fieldName: params.fieldName,\n ...projectCaughtErrorLogFields(error),\n });\n }\n }\n\n private assertGeneratedFileFieldNotUserSupplied(params: {\n data: Record<string, any>;\n fileField: FileFieldMetadata;\n occurrences: FileFieldValueOccurrence[];\n resourceType: ResourceType;\n executionContext: ExecutionContext<any>;\n processingOptions?: FileFieldWriteProcessingOptions;\n }): void {\n if (\n !this.isGeneratedPdfFileField(params.fileField)\n || (\n params.occurrences.length === 0\n && !hasExplicitCanonicalFieldMutation(params.data, params.fileField.fieldName)\n )\n ) {\n return;\n }\n\n const allowedFileIds = params.processingOptions?.frameworkGeneratedPdfFileIdsByField?.[params.fileField.fieldName];\n if (allowedFileIds && params.occurrences.length > 0) {\n const allowed = new Set(allowedFileIds);\n const submittedFileIds = params.occurrences.flatMap((occurrence) =>\n this.extractFileIds(occurrence.value, params.executionContext, true),\n );\n if (submittedFileIds.length > 0 && submittedFileIds.every((fileId) => allowed.has(fileId))) {\n return;\n }\n }\n\n throw this.errorBuilder.buildError(\n ErrorType.BUSINESS_RULE,\n params.executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_GENERATED_FIELD_NOT_WRITABLE,\n context: {\n // diagnostic (log-only)\n fieldName: params.fileField.fieldName,\n resourceType: params.resourceType,\n },\n }\n );\n }\n\n /**\n * Validate file fields before resource creation.\n * Ensures files exist, are in UPLOADED status, and are ready to be linked.\n *\n * @param data - Resource data being created\n * @param resourceType - Resource type\n * @param executionContext - Execution context\n * @param options - Repository options (for transaction support)\n * @throws Error if validation fails (fail fast before resource creation)\n */\n async validateFileFieldsForCreate(\n data: Record<string, any>,\n resourceType: ResourceType,\n executionContext: ExecutionContext<any>,\n options?: RepositoryOptions,\n processingOptions?: FileFieldWriteProcessingOptions,\n ): Promise<void> {\n // Validate inputs (CRITICAL: Prevents invalid data propagation)\n validateResourceType(resourceType, this.errorBuilder, executionContext, 'resourceType');\n\n // Check if resource has file fields\n if (!this.fileFieldDetection.hasFileFields(resourceType)) {\n return;\n }\n\n const fileFields = this.fileFieldDetection.detectFileFields(resourceType);\n\n this.logDebug('Validating file fields for CREATE', {\n resourceType,\n fileFieldsCount: fileFields.length,\n });\n\n // Collect all fileIds to validate\n const fileIdsToValidate: string[] = [];\n\n for (const fileField of fileFields) {\n const occurrences = enumerateFileFieldValueOccurrences(data, fileField.fieldName);\n this.assertGeneratedFileFieldNotUserSupplied({\n data,\n fileField,\n occurrences,\n resourceType,\n executionContext,\n processingOptions,\n });\n\n for (const occurrence of occurrences) {\n const fieldFileIds = this.extractFileIds(occurrence.value, executionContext, true);\n\n // F4-01: Enforce maxFiles constraint per concrete occurrence\n const { maxFiles, multiple } = fileField.fileMetadata;\n if (multiple && maxFiles !== undefined && fieldFileIds.length > maxFiles) {\n throw this.errorBuilder.buildError(\n ErrorType.BUSINESS_RULE,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_TOO_MANY_FILES,\n context: {\n // diagnostic (log-only)\n fieldName: fileField.fieldName,\n runtimeFieldPath: occurrence.runtimeFieldPath,\n resourceType,\n maxFiles,\n receivedCount: fieldFileIds.length,\n },\n }\n );\n }\n\n fileIdsToValidate.push(...fieldFileIds);\n }\n }\n\n // Validate each file\n for (const fileId of fileIdsToValidate) {\n // Validate fileId format (CRITICAL: Prevents query injection and database errors)\n validateFileId(fileId, this.errorBuilder, executionContext, 'fileId');\n\n const file = await this.filesService.getFile(fileId, executionContext, options);\n\n if (!file) {\n throw this.errorBuilder.buildError(\n ErrorType.NOT_FOUND,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_NOT_FOUND,\n context: {\n // diagnostic (log-only)\n fileId,\n resourceType,\n },\n }\n );\n }\n\n this.assertFileLinkable(file, executionContext, { fileId, resourceType });\n\n // Note: uploadContext validation can be added in Phase 2 if needed\n // For now, we only validate that file is UPLOADED\n }\n\n this.logDebug('File fields validation for CREATE completed', {\n resourceType,\n validatedFilesCount: fileIdsToValidate.length,\n });\n }\n\n /**\n * Process file fields after resource creation.\n * Links files to the newly created resource.\n *\n * @param data - Resource data that was created\n * @param resourceType - Resource type\n * @param resourceId - ID of the created resource\n * @param executionContext - Execution context\n */\n /**\n * Strip the PARENT resource's optimistic-lock version from options before any\n * child-file write.\n *\n * When a resource CREATE/UPDATE links/unlinks a `z_file()` field, the file is a\n * SEPARATE document with its own `_version_db_doc` lifecycle. If the parent request\n * carried an `If-Match` header, its `ifMatchVersion` must NOT fence the file update:\n * the repository would add a `{ _version_db_doc: <parentVersion> }` filter to the\n * FILE query, which (mis)matches the file by the PARENT's version and yields a\n * spurious `version_conflict` (the avatar-save 409: parent `If-Match: 0` leaking onto\n * the internal `files | update`). The transaction context is preserved so the file\n * write still participates in the parent's atomic boundary.\n */\n private stripParentVersionFence(options?: RepositoryOptions): RepositoryOptions | undefined {\n if (!options || options.ifMatchVersion === undefined) return options;\n const { ifMatchVersion: _parentVersionFence, ...fileWriteOptions } = options;\n return fileWriteOptions;\n }\n\n async processFileFieldsForCreate(\n data: Record<string, any>,\n resourceType: ResourceType,\n resourceId: string,\n executionContext: ExecutionContext<any>,\n options?: RepositoryOptions,\n processingOptions?: FileFieldWriteProcessingOptions,\n ): Promise<void> {\n // Validate inputs (CRITICAL: Prevents invalid data propagation)\n validateResourceType(resourceType, this.errorBuilder, executionContext, 'resourceType');\n validateResourceId(resourceId, this.errorBuilder, executionContext, 'resourceId');\n\n // A child-file link/unlink must not inherit the parent's optimistic-lock version.\n options = this.stripParentVersionFence(options);\n\n // Check if resource has file fields\n if (!this.fileFieldDetection.hasFileFields(resourceType)) {\n return;\n }\n\n const fileFields = this.fileFieldDetection.detectFileFields(resourceType);\n\n this.logDebug('Processing file fields for CREATE', {\n resourceType,\n resourceId,\n fileFieldsCount: fileFields.length,\n });\n\n // Process each file field\n for (const fileField of fileFields) {\n const submittedOccurrences = enumerateFileFieldValueOccurrences(data, fileField.fieldName);\n this.assertGeneratedFileFieldNotUserSupplied({\n data,\n fileField,\n occurrences: submittedOccurrences,\n resourceType,\n executionContext,\n processingOptions,\n });\n if (\n this.isGeneratedPdfFileField(fileField)\n && !processingOptions?.frameworkGeneratedPdfFileIdsByField?.[fileField.fieldName]\n ) {\n continue;\n }\n const occurrences = enumerateFileFieldValueOccurrences(data, fileField.fieldName);\n\n for (const occurrence of occurrences) {\n const fieldFileIds = this.extractFileIds(occurrence.value, executionContext, true);\n for (const fileId of fieldFileIds) {\n await this.linkFileToResource(\n fileId,\n resourceType,\n resourceId,\n fileField.fieldName,\n executionContext,\n options\n );\n }\n }\n }\n\n this.logDebug('File fields processing for CREATE completed', {\n resourceType,\n resourceId,\n });\n }\n\n /**\n * Process file fields after resource update.\n * Unlinks old files and links new files.\n * Validates new files BEFORE unlinking old ones (fail fast).\n *\n * Note: This method handles partial updates correctly. If a file field is not present\n * in `data`, it is treated as unchanged (not removed). Only explicit changes to file\n * field values trigger unlinking/linking operations.\n *\n * @param data - Updated resource data (may be partial update - only changed fields)\n * @param existingResource - Existing resource before update (complete state)\n * @param resourceType - Resource type\n * @param resourceId - Resource ID\n * @param executionContext - Execution context\n */\n async processFileFieldsForUpdate(\n data: Record<string, any>,\n existingResource: Record<string, any>,\n resourceType: ResourceType,\n resourceId: string,\n executionContext: ExecutionContext<any>,\n options?: RepositoryOptions,\n processingOptions?: FileFieldWriteProcessingOptions,\n ): Promise<void> {\n // Validate inputs (CRITICAL: Prevents invalid data propagation)\n validateResourceType(resourceType, this.errorBuilder, executionContext, 'resourceType');\n validateResourceId(resourceId, this.errorBuilder, executionContext, 'resourceId');\n\n // A child-file link/unlink must not inherit the parent's optimistic-lock version.\n options = this.stripParentVersionFence(options);\n\n // Check if resource has file fields\n if (!this.fileFieldDetection.hasFileFields(resourceType)) {\n return;\n }\n\n const fileFields = this.fileFieldDetection.detectFileFields(resourceType);\n const effectiveNewResource = mergeEffectiveResourceState(existingResource, data) as Record<string, any>;\n\n this.logDebug('Processing file fields for UPDATE', {\n resourceType,\n resourceId,\n fileFieldsCount: fileFields.length,\n });\n\n // Process each file field\n for (const fileField of fileFields) {\n const submittedOccurrences = enumerateFileFieldValueOccurrences(data, fileField.fieldName);\n this.assertGeneratedFileFieldNotUserSupplied({\n data,\n fileField,\n occurrences: submittedOccurrences,\n resourceType,\n executionContext,\n processingOptions,\n });\n if (\n this.isGeneratedPdfFileField(fileField)\n && !processingOptions?.frameworkGeneratedPdfFileIdsByField?.[fileField.fieldName]\n ) {\n continue;\n }\n const oldOccurrences = this.prepareOccurrences(\n enumerateFileFieldValueOccurrences(existingResource, fileField.fieldName),\n executionContext,\n false,\n );\n const newOccurrences = this.prepareOccurrences(\n enumerateFileFieldValueOccurrences(effectiveNewResource, fileField.fieldName),\n executionContext,\n true,\n );\n\n const occurrencePairs = this.matchOccurrences(oldOccurrences, newOccurrences);\n if (occurrencePairs.requiresAmbiguousFallback && fileField.fileMetadata.overridable === false) {\n throw this.errorBuilder.buildError(\n ErrorType.BUSINESS_RULE,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_NESTED_UPDATE_AMBIGUOUS,\n context: {\n // diagnostic (log-only)\n fieldName: fileField.fieldName,\n resourceType,\n resourceId,\n },\n }\n );\n }\n\n for (const pair of occurrencePairs.pairs) {\n const oldFileIds = pair.oldOccurrence?.fileIds ?? [];\n const newFileIds = pair.newOccurrence?.fileIds ?? [];\n const oldSet = new Set(oldFileIds);\n const newSet = new Set(newFileIds);\n const hasChanged =\n oldSet.size !== newSet.size ||\n !oldFileIds.every(id => newSet.has(id)) ||\n !newFileIds.every(id => oldSet.has(id));\n\n if (!hasChanged) {\n continue;\n }\n\n const runtimeFieldPath = pair.newOccurrence?.occurrence.runtimeFieldPath\n ?? pair.oldOccurrence?.occurrence.runtimeFieldPath;\n\n // F4-02: Enforce overridable constraint\n const { overridable, multiple, maxFiles } = fileField.fileMetadata;\n if (overridable === false) {\n const removedFileIds = oldFileIds.filter(id => !newSet.has(id));\n\n if (!multiple) {\n if (removedFileIds.length > 0) {\n throw this.errorBuilder.buildError(\n ErrorType.BUSINESS_RULE,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_FIELD_NOT_OVERRIDABLE,\n context: {\n // diagnostic (log-only)\n fieldName: fileField.fieldName,\n runtimeFieldPath,\n resourceType,\n resourceId,\n },\n }\n );\n }\n } else if (removedFileIds.length > 0) {\n throw this.errorBuilder.buildError(\n ErrorType.BUSINESS_RULE,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_FIELD_NOT_OVERRIDABLE,\n context: {\n // diagnostic (log-only)\n fieldName: fileField.fieldName,\n runtimeFieldPath,\n resourceType,\n resourceId,\n removedFileIds,\n },\n }\n );\n }\n }\n\n if (multiple && maxFiles !== undefined && newFileIds.length > maxFiles) {\n throw this.errorBuilder.buildError(\n ErrorType.BUSINESS_RULE,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_TOO_MANY_FILES,\n context: {\n // diagnostic (log-only)\n fieldName: fileField.fieldName,\n runtimeFieldPath,\n resourceType,\n resourceId,\n maxFiles,\n newTotal: newFileIds.length,\n },\n }\n );\n }\n\n for (const fileId of newFileIds) {\n if (!oldSet.has(fileId)) {\n // New file - validate fileId format (CRITICAL: Prevents query injection and database errors)\n validateFileId(fileId, this.errorBuilder, executionContext, 'fileId');\n\n const file = await this.filesService.getFile(fileId, executionContext, options);\n\n if (!file) {\n throw this.errorBuilder.buildError(\n ErrorType.NOT_FOUND,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_NOT_FOUND,\n context: {\n // diagnostic (log-only)\n fileId,\n resourceType,\n resourceId,\n runtimeFieldPath,\n },\n }\n );\n }\n\n this.assertFileLinkable(file, executionContext, { fileId, runtimeFieldPath, resourceType, resourceId });\n }\n }\n\n for (const oldFileId of oldFileIds) {\n if (!newSet.has(oldFileId)) {\n // File removed - unlink it\n await this.unlinkFileFromResource(\n oldFileId,\n fileField.fieldName,\n executionContext,\n options\n );\n }\n }\n\n for (const newFileId of newFileIds) {\n if (!oldSet.has(newFileId)) {\n // New file - link it\n await this.linkFileToResource(\n newFileId,\n resourceType,\n resourceId,\n fileField.fieldName,\n executionContext,\n options\n );\n }\n }\n }\n }\n\n this.logDebug('File fields processing for UPDATE completed', {\n resourceType,\n resourceId,\n });\n }\n\n /**\n * Process file fields before resource deletion.\n * Applies onParentDelete behavior to all linked files.\n *\n * @param resourceType - Resource type being deleted\n * @param resourceId - Resource ID being deleted\n * @param executionContext - Execution context\n */\n /**\n * Carry the owner ALREADY VERIFIED by `listFilesForResource` (which authorized each returned file\n * against the parent resource's derived scope) onto the options used for the subsequent delete/erase,\n * so the deletion gate (`getFile`'s per-file authorize) checks against that owner rather than the\n * identity-less system-cascade EC — which would otherwise DENY the subject's own file and abort the\n * erasure. Never widens access: `authorizeFileAccess` still matches this against the file's own scope.\n */\n private withAuthoritativeFileScope(options: RepositoryOptions | undefined, file: File): RepositoryOptions {\n return {\n ...(options ?? {}),\n authoritativeFileScope: {\n applicationId: file.applicationId,\n organizationId: file.organizationId,\n userId: file.userId,\n },\n };\n }\n\n async processFileFieldsForDelete(\n resourceType: ResourceType,\n resourceId: string,\n executionContext: ExecutionContext<any>,\n options?: RepositoryOptions\n ): Promise<void> {\n // A child-file cleanup must not inherit the parent's optimistic-lock version.\n options = this.stripParentVersionFence(options);\n\n // Check if resource has file fields\n if (!this.fileFieldDetection.hasFileFields(resourceType)) {\n return;\n }\n\n const fileFields = this.fileFieldDetection.detectFileFields(resourceType);\n\n this.logDebug('Processing file fields for DELETE', {\n resourceType,\n resourceId,\n fileFieldsCount: fileFields.length,\n });\n\n // Get all files linked to this resource\n const linkedFiles = await this.filesService.listFilesForResource(\n resourceType,\n resourceId,\n undefined, // fieldName - undefined means all fields\n executionContext,\n options\n );\n\n // Process each file based on onParentDelete behavior from field metadata\n for (const file of linkedFiles) {\n // Forward the owner `listFilesForResource` already verified for THIS file to the deletion gate,\n // so a system-cascade teardown (identity-less EC) does not deny the subject's own file.\n const teardownOptions = this.withAuthoritativeFileScope(options, file);\n if (!file.linkedFieldName) {\n this.logger.warn('Linked file missing linkedFieldName during parent delete; defaulting to cascade cleanup', {\n fileId: file.fileId,\n resourceType,\n resourceId,\n });\n await this.applyOnParentDeleteBehavior(\n file.fileId,\n 'cascade',\n executionContext,\n teardownOptions\n );\n continue;\n }\n\n const fileField = this.fileFieldDetection.getFileFieldMetadata(\n resourceType,\n file.linkedFieldName\n );\n\n if (!fileField) {\n // Field not found - use default cascade behavior\n await this.applyOnParentDeleteBehavior(\n file.fileId,\n 'cascade',\n executionContext,\n teardownOptions\n );\n continue;\n }\n\n const onParentDelete = fileField.fileMetadata.onParentDelete || 'cascade';\n\n await this.applyOnParentDeleteBehavior(\n file.fileId,\n onParentDelete,\n executionContext,\n teardownOptions\n );\n }\n\n this.logDebug('File fields processing for DELETE completed', {\n resourceType,\n resourceId,\n processedFilesCount: linkedFiles.length,\n });\n }\n\n /**\n * Process file fields when a resource row is IMPERSONALIZED-AND-RETAINED (gate **G-FILE**).\n *\n * The row survives for a legal/audit obligation, so this is NOT the delete cascade — but \"keep the\n * record\" must not become \"keep the personal data\". A field-level scrub cannot reach inside a stored\n * blob (a passport scan stays a passport scan however the row is rewritten), so for a file field the\n * only real erasure is deleting the file.\n *\n * Which files? Exactly the ones whose field the author marked personal with `.impersonalizeWith()` —\n * the SAME author-responsibility contract as ordinary fields, reusing the same vocabulary rather\n * than inventing a second axis. The caller passes the scrub patch's field names:\n * - field IS scrubbed (REMOVE) ⇒ delete the file. The scrub patch nulls the pointer in the same\n * write, so the retained row keeps no dangling reference.\n * - field NOT scrubbed (KEEP / untreated) ⇒ leave the file. This is how a legally-required artifact\n * (an invoice PDF that IS the retained record) survives the erasure.\n *\n * Why deletion is required rather than relying on the row being hidden: the resource-scoped serve\n * route inherits the parent's READ authorization, so a hidden retained row already blocks it — but\n * the GLOBAL `/files/:fileId` route (direct / consumable-token / public-share) is explicitly NOT\n * resource-scoped and re-checks only the file's OWN scope. A file left ACTIVE therefore stays\n * reachable there even though its parent row is invisible.\n *\n * Erasure here goes through `FilesBackendService.eraseFile`, NOT `deleteFile`: besides marking the\n * file DELETED it scrubs the file row's OWN personal data (`originalFilename`, `uploadedBy`) in the\n * same write. Without that, the row's metadata stayed readable on the global metadata route for the\n * weeks until physical cleanup — an \"erasure\" that leaked `passport-jane-doe.pdf` the whole time. A\n * lifecycle delete deliberately keeps that provenance; a privacy erasure must not.\n *\n * Physical storage cleanup stays with the existing cleanup batch, so an erasure never mixes a DB\n * rollback with non-transactional storage side effects.\n *\n * ## The MIDDLE state — keep-but-hide — is deliberately NOT built (decided 2026-08-09)\n *\n * There are only two outcomes above, and the consequence of the second is worth stating plainly: a KEEP\n * file stays ORDINARILY READABLE to the file's own scope (its organization) through the global route,\n * indefinitely, even though its parent row is now invisible. A third state — retained but reachable only\n * through the audited see-through door, mirroring the parent row's posture — was considered and refused\n * for three reasons, in order of weight:\n *\n * 1. **It would contradict a decision already taken.** The concrete case that motivates it is the\n * invoice PDF, and the billing retention decision was explicitly \"retained as audit material, and\n * invoices stay VISIBLE\" for ordinary accounting. Hiding retained invoice documents would reverse\n * that, and the sibling ruling on invoice URLs went the same way: keep the document, close the\n * ordinary door only where the document is not itself the record.\n * 2. **A hiding door is worthless without its reading door, and shipping one alone is worse than\n * neither.** Withholding the file without also building an audited retrieval primitive would make\n * the legally-required artifact unreachable by ANYONE — destroying the very access the retention\n * obligation exists to preserve. (Same pairing rule as the cross-tenant repair doors: a marking\n * door without its release door is a one-way door calling itself a window.)\n * 3. **No shipped resource needs it.** The author already controls both ends per field: mark the field\n * and the file is erased, leave it and the file survives. The gap is only the middle, and nothing in\n * the tree declares a file field that is simultaneously personal, legally required, and must stop\n * being ordinarily visible.\n *\n * **What would trigger building it:** a resource declaring exactly that combination. The shape is then a\n * new `FileStatus` member excluded from `FILE_DOWNLOADABLE_STATUSES` and added to\n * `FILE_METADATA_WITHHELD_STATUSES`, a `FILE_STATUS_TRANSITIONS` entry, and — non-optional — an audited\n * see-through retrieval primitive alongside it. Do not add the status without the door.\n */\n async processFileFieldsForImpersonalize(\n resourceType: ResourceType,\n resourceId: string,\n scrubbedFieldNames: readonly string[],\n executionContext: ExecutionContext<any>,\n options?: RepositoryOptions\n ): Promise<void> {\n options = this.stripParentVersionFence(options);\n\n if (scrubbedFieldNames.length === 0 || !this.fileFieldDetection.hasFileFields(resourceType)) {\n return;\n }\n\n const scrubbedFields = new Set(scrubbedFieldNames);\n const linkedFiles = await this.filesService.listFilesForResource(\n resourceType,\n resourceId,\n undefined, // all fields — we filter by treatment below\n executionContext,\n options\n );\n\n let erasedCount = 0;\n let unattributableCount = 0;\n for (const file of linkedFiles) {\n // Fail-closed on an unattributable file: without `linkedFieldName` we cannot tell whether its\n // field was marked personal, and silently keeping it risks retaining an erased subject's\n // document. The delete cascade defaults such a file to cleanup for the same reason.\n const isUnattributable = !file.linkedFieldName;\n const isScrubbedField = isUnattributable || scrubbedFields.has(file.linkedFieldName!);\n if (!isScrubbedField) {\n continue;\n }\n if (isUnattributable) {\n /**\n * WARN, not debug: this is an irreversible deletion taken on a GUESS.\n *\n * The fail-closed default is right — a file we cannot attribute might be the erased subject's\n * passport scan — but it can equally destroy a file the retention obligation existed to KEEP\n * (an invoice PDF whose link lost its field name). Either way the cause is upstream metadata,\n * so it has to be visible: the sibling delete cascade has warned here since before this path\n * existed, and this one erased silently. Same decision, same audibility.\n */\n unattributableCount += 1;\n this.logger.warn(\n '[Retention] Erasing a linked file with no `linkedFieldName` during impersonalize — it cannot '\n + 'be attributed to a field, so the fail-closed default deletes it. If this file was meant to '\n + 'be RETAINED, its link metadata is the defect.',\n { resourceType, resourceId, fileId: file.fileId },\n );\n }\n // Forward the owner `listFilesForResource` already verified for THIS file to the deletion gate,\n // so a system-cascade (identity-less EC) impersonalize erase does not deny the subject's own file.\n await this.filesService.eraseFile(file.fileId, executionContext, this.withAuthoritativeFileScope(options, file));\n erasedCount++;\n }\n\n this.logDebug('File fields processing for IMPERSONALIZE completed', {\n resourceType,\n resourceId,\n linkedFilesCount: linkedFiles.length,\n erasedCount,\n retainedCount: linkedFiles.length - erasedCount,\n unattributableCount,\n });\n }\n\n /**\n * Extract file IDs from field value (handles single file or array).\n *\n * @param fieldValue - The raw field value from the resource object\n * @param executionContext - Current execution context\n * @param strict - When true (user input / new values), throws on invalid fileIds.\n * When false (existing DB data), silently filters and logs warnings.\n */\n private extractFileIds(fieldValue: any, executionContext?: ExecutionContext<any>, strict: boolean = false): string[] {\n if (fieldValue === null || fieldValue === undefined) {\n return [];\n }\n\n if (typeof fieldValue === 'object' && !Array.isArray(fieldValue)) {\n if ('fileId' in fieldValue) {\n return this.extractFileIds((fieldValue as { fileId?: unknown }).fileId, executionContext, strict);\n }\n\n if ('fileIds' in fieldValue) {\n return this.extractFileIds((fieldValue as { fileIds?: unknown }).fileIds, executionContext, strict);\n }\n }\n\n if (Array.isArray(fieldValue)) {\n const validFileIds: string[] = [];\n for (const fileId of fieldValue) {\n if (typeof fileId !== 'string' || fileId.trim() === '') {\n if (strict) {\n throw this.errorBuilder.buildError(\n ErrorType.VALIDATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_ID_VALIDATION_FAILED,\n context: {\n // diagnostic (log-only)\n fileId,\n receivedType: typeof fileId,\n },\n }\n );\n }\n continue;\n }\n try {\n validateFileId(fileId, this.errorBuilder, executionContext, 'fileId');\n validFileIds.push(fileId);\n } catch (error) {\n if (strict) {\n throw error; // Re-throw in strict mode — user provided invalid input\n }\n // Tolerant mode: filter out and warn (handles corrupt DB data gracefully)\n this.logger.warn('Invalid fileId filtered out during extraction', {\n fileId,\n ...projectCaughtErrorLogFields(error),\n });\n }\n }\n return validFileIds;\n }\n\n if (typeof fieldValue === 'string' && fieldValue.trim() !== '') {\n try {\n validateFileId(fieldValue, this.errorBuilder, executionContext, 'fileId');\n return [fieldValue];\n } catch (error) {\n if (strict) {\n throw error;\n }\n this.logger.warn('Invalid fileId filtered out during extraction', {\n fileId: fieldValue,\n ...projectCaughtErrorLogFields(error),\n });\n return [];\n }\n }\n\n if (strict && fieldValue !== null && fieldValue !== undefined) {\n throw this.errorBuilder.buildError(\n ErrorType.VALIDATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.FILE_FIELD_VALUE_INVALID,\n context: {\n // diagnostic (log-only)\n receivedType: typeof fieldValue,\n },\n }\n );\n }\n\n return [];\n }\n\n /**\n * Link a file to a resource.\n * Handles race conditions (idempotent - safe to call multiple times).\n */\n private async linkFileToResource(\n fileId: string,\n resourceType: ResourceType,\n resourceId: string,\n fieldName: string,\n executionContext: ExecutionContext<any>,\n options?: RepositoryOptions\n ): Promise<void> {\n // Validate inputs (CRITICAL: Prevents query injection and database errors)\n validateFileId(fileId, this.errorBuilder, executionContext, 'fileId');\n validateResourceType(resourceType, this.errorBuilder, executionContext, 'resourceType');\n validateResourceId(resourceId, this.errorBuilder, executionContext, 'resourceId');\n validateFieldName(fieldName, this.errorBuilder, executionContext, 'fieldName');\n\n // Check if file is already linked to the same resource (idempotent check - before calling service)\n // This prevents unnecessary service calls and handles idempotent cases early\n const file = await this.filesService.getFile(fileId, executionContext, options);\n if (file &&\n file.status === FileStatus.LINKED &&\n file.linkedResourceType === resourceType &&\n file.linkedResourceId === resourceId &&\n file.linkedFieldName === fieldName) {\n // Already linked to same resource - skip (idempotent)\n this.logDebug('File already linked to same resource, skipping', {\n fileId,\n resourceType,\n resourceId,\n fieldName,\n });\n return;\n }\n\n // Link file - errors propagate to fail the transaction (Decision 2.2: Option A)\n // FilesBackendService.linkFileToResource() handles idempotent cases internally (returns existing file)\n // All other errors (NOT_FOUND, BUSINESS_RULE, INTERNAL) should fail the operation\n await this.filesService.linkFileToResource(\n fileId,\n resourceType,\n resourceId,\n fieldName,\n executionContext,\n options\n );\n }\n\n /**\n * Unlink a file from a resource.\n * Applies onParentDelete behavior.\n */\n private async unlinkFileFromResource(\n fileId: string,\n fieldName: string,\n executionContext: ExecutionContext<any>,\n options?: RepositoryOptions\n ): Promise<void> {\n // Validate fileId format (CRITICAL: Prevents query injection and database errors)\n validateFileId(fileId, this.errorBuilder, executionContext, 'fileId');\n\n const file = await this.filesService.getFile(fileId, executionContext, options);\n if (!file || file.status !== FileStatus.LINKED) {\n // Already unlinked or doesn't exist - skip (idempotent)\n return;\n }\n\n // Unlink file (sets status to ORPHANED)\n await this.filesService.unlinkFileFromResource(fileId, executionContext, options);\n }\n\n /**\n * Apply onParentDelete behavior to a file.\n *\n * @param fileId - File ID\n * @param behavior - Behavior: 'cascade', 'soft-delete', or 'orphan'\n * @param executionContext - Execution context\n */\n private async applyOnParentDeleteBehavior(\n fileId: string,\n behavior: 'cascade' | 'soft-delete' | 'orphan',\n executionContext: ExecutionContext<any>,\n options?: RepositoryOptions\n ): Promise<void> {\n this.logDebug('Applying onParentDelete behavior', {\n fileId,\n behavior,\n });\n\n switch (behavior) {\n case 'cascade':\n // Cascade now marks the file as DELETED only. Physical storage cleanup is\n // intentionally deferred to the cleanup batch so resource deletes never\n // mix Mongo rollback with non-transactional storage side effects.\n await this.filesService.deleteFile(fileId, executionContext, options);\n break;\n\n case 'soft-delete':\n // Soft delete: update status to DELETED\n await this.filesService.deleteFile(fileId, executionContext, options);\n break;\n\n case 'orphan':\n // Unlink: clear parent fields, set status to ORPHANED\n await this.filesService.unlinkFileFromResource(fileId, executionContext, options);\n break;\n\n default:\n // Default to cascade\n await this.filesService.deleteFile(fileId, executionContext, options);\n }\n }\n\n private prepareOccurrences(\n occurrences: FileFieldValueOccurrence[],\n executionContext: ExecutionContext<any>,\n strict: boolean,\n ): Array<{\n occurrence: FileFieldValueOccurrence;\n fileIds: string[];\n signature: string;\n }> {\n return occurrences.map((occurrence) => {\n const fileIds = this.extractFileIds(occurrence.value, executionContext, strict);\n return {\n occurrence,\n fileIds,\n signature: JSON.stringify([...fileIds].sort()),\n };\n });\n }\n\n private matchOccurrences(\n oldOccurrences: Array<{\n occurrence: FileFieldValueOccurrence;\n fileIds: string[];\n signature: string;\n }>,\n newOccurrences: Array<{\n occurrence: FileFieldValueOccurrence;\n fileIds: string[];\n signature: string;\n }>,\n ): {\n pairs: Array<{\n oldOccurrence?: {\n occurrence: FileFieldValueOccurrence;\n fileIds: string[];\n signature: string;\n };\n newOccurrence?: {\n occurrence: FileFieldValueOccurrence;\n fileIds: string[];\n signature: string;\n };\n }>;\n requiresAmbiguousFallback: boolean;\n } {\n const pairs: Array<{\n oldOccurrence?: {\n occurrence: FileFieldValueOccurrence;\n fileIds: string[];\n signature: string;\n };\n newOccurrence?: {\n occurrence: FileFieldValueOccurrence;\n fileIds: string[];\n signature: string;\n };\n }> = [];\n\n const remainingOld = [...oldOccurrences];\n const remainingNew = [...newOccurrences];\n\n const stableIds = new Set(\n [...remainingOld, ...remainingNew]\n .map((entry) => entry.occurrence.ownerStableId)\n .filter((value): value is string => typeof value === 'string' && value.trim() !== ''),\n );\n\n for (const stableId of stableIds) {\n const oldMatches = remainingOld.filter((entry) => entry.occurrence.ownerStableId === stableId);\n const newMatches = remainingNew.filter((entry) => entry.occurrence.ownerStableId === stableId);\n\n while (oldMatches.length > 0 && newMatches.length > 0) {\n const oldEntry = oldMatches.shift()!;\n const newEntry = newMatches.shift()!;\n remainingOld.splice(remainingOld.indexOf(oldEntry), 1);\n remainingNew.splice(remainingNew.indexOf(newEntry), 1);\n pairs.push({ oldOccurrence: oldEntry, newOccurrence: newEntry });\n }\n }\n\n const oldSignatureBuckets = new Map<string, typeof remainingOld>();\n for (const entry of remainingOld) {\n if (entry.occurrence.ownerStableId) {\n continue;\n }\n const bucket = oldSignatureBuckets.get(entry.signature) ?? [];\n bucket.push(entry);\n oldSignatureBuckets.set(entry.signature, bucket);\n }\n\n for (const newEntry of [...remainingNew]) {\n if (newEntry.occurrence.ownerStableId) {\n continue;\n }\n\n const bucket = oldSignatureBuckets.get(newEntry.signature);\n const oldEntry = bucket?.shift();\n if (!oldEntry) {\n continue;\n }\n\n remainingOld.splice(remainingOld.indexOf(oldEntry), 1);\n remainingNew.splice(remainingNew.indexOf(newEntry), 1);\n pairs.push({ oldOccurrence: oldEntry, newOccurrence: newEntry });\n }\n\n const requiresAmbiguousFallback =\n remainingOld.some((entry) => !entry.occurrence.ownerStableId) &&\n remainingNew.some((entry) => !entry.occurrence.ownerStableId);\n\n while (remainingOld.length > 0 || remainingNew.length > 0) {\n pairs.push({\n oldOccurrence: remainingOld.shift(),\n newOccurrence: remainingNew.shift(),\n });\n }\n\n return {\n pairs,\n requiresAmbiguousFallback,\n };\n }\n}\n"]}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Upload Grant Backend Service
|
|
3
|
+
*
|
|
4
|
+
* The ONE mint function behind both doors — the REST sibling route (`…/files/<field>/grant`) and the
|
|
5
|
+
* MCP derived tool — plus the route-binding check the upload middleware runs, the public status read,
|
|
6
|
+
* revocation, and the post-redemption write-back. Issue #312.
|
|
7
|
+
*
|
|
8
|
+
* ## What a grant is
|
|
9
|
+
*
|
|
10
|
+
* A `SINGLE_USE` consumable token of type `FILE_UPLOAD_GRANT` that lets whoever holds it perform ONE
|
|
11
|
+
* upload into ONE resource file field with the MINTER's authority. Nothing durable is created at mint
|
|
12
|
+
* but the token. The upload goes through the resource's EXISTING file-upload route: the token becomes
|
|
13
|
+
* an ordinary `CONSUMABLE_TOKEN` execution context (typed fields → identity) and the ordinary
|
|
14
|
+
* authorizer decides. This service never decides "may this principal put a file here" — the upload
|
|
15
|
+
* middleware does, once, for mint and upload alike, which is what makes mint-authority ≡
|
|
16
|
+
* upload-authority by construction.
|
|
17
|
+
*
|
|
18
|
+
* ## Why the route binding lives in `metadata` and is checked HERE
|
|
19
|
+
*
|
|
20
|
+
* `createExecutionContextFromRequest` turns the token's TYPED fields (`userId`, `organizationId`,
|
|
21
|
+
* `roles`, `resourceIdentifier`, `relatedId`) into identity and deliberately reads nothing from
|
|
22
|
+
* `metadata`. Which field, which operation kind, which concrete upload URL — those are ROUTE facts,
|
|
23
|
+
* and the upload middleware asks this service to check them against the route the token was
|
|
24
|
+
* presented on. Identity and route stay separate concerns.
|
|
25
|
+
*/
|
|
26
|
+
import { type FileUploadGrant, type FileUploadGrantMetadata, type FileUploadGrantOperation, type FileUploadGrantStatus, type ResourceConfiguration_Operation, type ResourceType } from '@wildo-ai/saas-models';
|
|
27
|
+
import type { LoggerService } from '../../monitoring/logger/services/logger.service';
|
|
28
|
+
import { ErrorBuilderBackendService } from '../../errors/services/error-builder.backend.service';
|
|
29
|
+
import { AppConfigurationService } from '../../config/services/app-configuration.backend.service';
|
|
30
|
+
import type { ExecutionContext } from '../../runtime/models/execution-context.backend.schemas';
|
|
31
|
+
import { ConsumableTokenBackendService } from '../../security/consumable-tokens/services/consumable-token.backend.service';
|
|
32
|
+
import type { ConsumableToken } from '../../security/consumable-tokens/models/consumable-tokens.shared.schemas';
|
|
33
|
+
import { FileConstraintResolverChain } from '../../files/constraints/file-constraint-resolver-chain.backend.service';
|
|
34
|
+
import { FileFieldDetectionBackendService } from '../../files/services/file-field-detection.backend.service';
|
|
35
|
+
import { ExecutionContextCreatorBackendService } from '../../runtime/services/execution-context-creator.backend.service';
|
|
36
|
+
import { RepositoriesRegistryHandlerBackendService } from '../../base-classes/services/repositories/repositories-registry-handler.backend.service';
|
|
37
|
+
import { type FileUploaderPrincipal } from '../../files/utils/file-uploader.utils';
|
|
38
|
+
import type { AuditLogsBackendService } from '../../compliance/audit-trails/services/audit-logs.backend.service';
|
|
39
|
+
/** The route facts a grant is bound to, as the upload middleware knows them. */
|
|
40
|
+
export interface FileUploadGrantTarget {
|
|
41
|
+
resourceType: ResourceType;
|
|
42
|
+
fieldName: string;
|
|
43
|
+
operation: FileUploadGrantOperation;
|
|
44
|
+
resourceId?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface MintFileUploadGrantParams {
|
|
47
|
+
/** The MINTER's context, produced by the upload route's own authorization middleware. */
|
|
48
|
+
executionContext: ExecutionContext<any>;
|
|
49
|
+
target: FileUploadGrantTarget;
|
|
50
|
+
/** Requested lifetime; the engine ceiling is enforced at `createToken`, rejecting never clamping. */
|
|
51
|
+
expiresInMinutes?: number;
|
|
52
|
+
/** The concrete, absolute URL of the upload route this grant is for (the request's own URL minus `/grant`). */
|
|
53
|
+
uploadUrl: string;
|
|
54
|
+
/** Absolute API base including the mount prefix (e.g. `https://api.example.com/api/v1`), for the status URL. */
|
|
55
|
+
apiBaseUrl: string;
|
|
56
|
+
/** Request provenance for the audit row; never the token. */
|
|
57
|
+
requestProvenance?: {
|
|
58
|
+
ipAddress?: string;
|
|
59
|
+
userAgent?: string;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export declare class FileUploadGrantBackendService {
|
|
63
|
+
private readonly logger;
|
|
64
|
+
private readonly errorBuilder;
|
|
65
|
+
private readonly consumableTokenService;
|
|
66
|
+
private readonly constraintResolver;
|
|
67
|
+
private readonly fileFieldDetection;
|
|
68
|
+
private readonly executionContextCreator;
|
|
69
|
+
private readonly repositoriesRegistry;
|
|
70
|
+
private readonly appConfigService;
|
|
71
|
+
/**
|
|
72
|
+
* Optional so a harness without the audit stack can construct this service; in production the
|
|
73
|
+
* container always binds it. A missing service is logged at WARN on first use, never silent.
|
|
74
|
+
*/
|
|
75
|
+
private readonly auditLogsService?;
|
|
76
|
+
protected logDebug: (message: string, context?: Record<string, unknown>) => void;
|
|
77
|
+
constructor(logger: LoggerService, errorBuilder: ErrorBuilderBackendService, consumableTokenService: ConsumableTokenBackendService, constraintResolver: FileConstraintResolverChain, fileFieldDetection: FileFieldDetectionBackendService, executionContextCreator: ExecutionContextCreatorBackendService, repositoriesRegistry: RepositoriesRegistryHandlerBackendService, appConfigService: AppConfigurationService,
|
|
78
|
+
/**
|
|
79
|
+
* Optional so a harness without the audit stack can construct this service; in production the
|
|
80
|
+
* container always binds it. A missing service is logged at WARN on first use, never silent.
|
|
81
|
+
*/
|
|
82
|
+
auditLogsService?: AuditLogsBackendService);
|
|
83
|
+
/**
|
|
84
|
+
* The operation the upload routes hand to the execution-context creator (issue #312, D4).
|
|
85
|
+
*
|
|
86
|
+
* `tokenAuthentication` lives on the OPERATION, so declaring it on the authored CREATE/UPDATE would
|
|
87
|
+
* let a grant perform the whole JSON write. Instead the `…/files/<field>` and `…/files/<field>/grant`
|
|
88
|
+
* routes — and ONLY those — get this derived copy, which accepts the grant type as an ALTERNATIVE
|
|
89
|
+
* credential beside whatever the author declared. The JSON routes keep the authored operation, so a
|
|
90
|
+
* grant presented there is refused by GATE 1 (`CONSUMABLE_TOKEN_NOT_ACCEPTED_FOR_OPERATION`).
|
|
91
|
+
*
|
|
92
|
+
* An authored ADDITIVE policy is NOT preserved as ADDITIVE here: the upload route's own authorizer
|
|
93
|
+
* decides on the resulting context either way, and an additive token on a multipart upload is not a
|
|
94
|
+
* case any resource declares today. If one appears, this is the seam to widen — do not widen the
|
|
95
|
+
* authored operation.
|
|
96
|
+
*/
|
|
97
|
+
static withUploadGrantAcceptance<T extends ResourceConfiguration_Operation<any, any, any>>(operation: T): T;
|
|
98
|
+
/**
|
|
99
|
+
* Mint a grant for the target the caller has JUST been authorized on.
|
|
100
|
+
*
|
|
101
|
+
* Refuses two minter kinds: a `CONSUMABLE_TOKEN` context (a grant may not mint a grant — no
|
|
102
|
+
* delegation chains) and an `ANONYMOUS_SESSION` (no stable subject to attribute the file to, no
|
|
103
|
+
* roles worth snapshotting). `USER_REQUEST` and both machine principals mint.
|
|
104
|
+
*/
|
|
105
|
+
mint(params: MintFileUploadGrantParams): Promise<FileUploadGrant>;
|
|
106
|
+
/**
|
|
107
|
+
* The upload middleware's question: is the token this context was built from a grant for THIS route?
|
|
108
|
+
*
|
|
109
|
+
* Returns `undefined` when the context is not a grant context at all — a JWT/API-key upload, or an
|
|
110
|
+
* authored non-grant ALTERNATIVE token, which keeps behaving as it did. Throws
|
|
111
|
+
* `FILE_UPLOAD_GRANT_TARGET_MISMATCH` when it IS a grant minted for a different resource, field,
|
|
112
|
+
* operation kind or row. Mirrors `validateFileToken` on the download twin: type pinned AND target
|
|
113
|
+
* pinned; a grant with no binding unlocks nothing.
|
|
114
|
+
*
|
|
115
|
+
* For UPDATE the creator has already coherence-checked `relatedId` against the URL id; the check is
|
|
116
|
+
* repeated here because CREATE has no id, so this is the one place both kinds are decided.
|
|
117
|
+
*/
|
|
118
|
+
assertGrantMatchesRoute(executionContext: ExecutionContext<any>, target: FileUploadGrantTarget): Promise<{
|
|
119
|
+
token: ConsumableToken;
|
|
120
|
+
metadata: FileUploadGrantMetadata;
|
|
121
|
+
} | undefined>;
|
|
122
|
+
/** The uploader the redeemed file is attributed to: the MINTER, from the grant, never the grant itself. */
|
|
123
|
+
resolveUploaderFromGrant(metadata: FileUploadGrantMetadata): FileUploaderPrincipal;
|
|
124
|
+
/**
|
|
125
|
+
* After the one upload landed: write the produced fileId back and audit the redemption. Best-effort
|
|
126
|
+
* by contract — the upload has succeeded; a failure here is logged and the status read degrades to
|
|
127
|
+
* "REDEEMED, file unknown".
|
|
128
|
+
*/
|
|
129
|
+
recordRedemption(grant: {
|
|
130
|
+
token: ConsumableToken;
|
|
131
|
+
metadata: FileUploadGrantMetadata;
|
|
132
|
+
}, file: {
|
|
133
|
+
fileId: string;
|
|
134
|
+
mimeType: string;
|
|
135
|
+
size: number;
|
|
136
|
+
}, executionContext: ExecutionContext<any>): Promise<void>;
|
|
137
|
+
/**
|
|
138
|
+
* Public status read: the token IS the credential, so anyone holding it learns the grant's state,
|
|
139
|
+
* the target and constraints (what the drop page renders), and — after redemption — the `fileId`
|
|
140
|
+
* and file status (what the agent needs). Never the file's name.
|
|
141
|
+
*/
|
|
142
|
+
readStatus(tokenValue: string): Promise<FileUploadGrantStatus>;
|
|
143
|
+
/**
|
|
144
|
+
* Revoke an unredeemed grant — by ID, never by value, and AUTHENTICATED: the minter, or a platform
|
|
145
|
+
* super-administrator. Revoke-by-value on a public route was rejected: anyone holding the link could
|
|
146
|
+
* burn it (harmless) while learning that it existed (not).
|
|
147
|
+
*/
|
|
148
|
+
revoke(grantId: string, executionContext: ExecutionContext<any>): Promise<boolean>;
|
|
149
|
+
/**
|
|
150
|
+
* Read the produced FILES row with no caller context — the status route is public and the token is
|
|
151
|
+
* the credential. Same mechanism as the file controller's token-access download path (an internal
|
|
152
|
+
* system context against the FILES repository, keyed on `_id`); only `fileId` and `status` leave here.
|
|
153
|
+
*/
|
|
154
|
+
private readProducedFile;
|
|
155
|
+
private deriveState;
|
|
156
|
+
/** `null` for a headless application (no frontend service declared) — there is no page to hand a human. */
|
|
157
|
+
private resolveUploadPageUrl;
|
|
158
|
+
/** A plausible file name for the curl example, from the field name and the first allowed MIME type. */
|
|
159
|
+
private suggestFileName;
|
|
160
|
+
private buildNote;
|
|
161
|
+
private audit;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=file-upload-grant.backend.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-upload-grant.backend.service.d.ts","sourceRoot":"","sources":["../../../../../src/files/services/file-upload-grant.backend.service.ts"],"names":[],"mappings":"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"}
|