@wildo-ai/saas-backend-lib 1.1.12 → 1.1.13
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/models/manual-controllers.backend.definition.d.ts.map +1 -1
- package/dist/esm/base-classes/models/manual-controllers.backend.definition.js +2 -0
- package/dist/esm/base-classes/models/manual-controllers.backend.definition.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/stored-field-omission.backend.d.ts +4 -0
- package/dist/esm/base-classes/services/repositories/stored-field-omission.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/stored-field-omission.backend.js +20 -5
- package/dist/esm/base-classes/services/repositories/stored-field-omission.backend.js.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.d.ts +3 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.js +10 -1
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.d.ts +22 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.js +25 -1
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.js.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.d.ts +38 -3
- package/dist/esm/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.js +68 -5
- package/dist/esm/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.js.map +1 -1
- package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.d.ts +2 -2
- package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.js +6 -3
- package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.d.ts +83 -0
- 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 +217 -14
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seal-currency.backend.d.ts +32 -0
- package/dist/esm/compliance/approval-seals/approval-seal-currency.backend.d.ts.map +1 -0
- package/dist/esm/compliance/approval-seals/approval-seal-currency.backend.js +36 -0
- package/dist/esm/compliance/approval-seals/approval-seal-currency.backend.js.map +1 -0
- package/dist/esm/compliance/approval-seals/approval-seal-on-record.backend.d.ts +38 -0
- package/dist/esm/compliance/approval-seals/approval-seal-on-record.backend.d.ts.map +1 -0
- package/dist/esm/compliance/approval-seals/approval-seal-on-record.backend.js +83 -0
- package/dist/esm/compliance/approval-seals/approval-seal-on-record.backend.js.map +1 -0
- package/dist/esm/compliance/approval-seals/approval-seal-presentation-read.backend.d.ts +36 -0
- package/dist/esm/compliance/approval-seals/approval-seal-presentation-read.backend.d.ts.map +1 -0
- package/dist/esm/compliance/approval-seals/approval-seal-presentation-read.backend.js +51 -0
- package/dist/esm/compliance/approval-seals/approval-seal-presentation-read.backend.js.map +1 -0
- package/dist/esm/compliance/approval-seals/approval-seal-relay-store.backend.d.ts +46 -0
- package/dist/esm/compliance/approval-seals/approval-seal-relay-store.backend.d.ts.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seal-relay-store.backend.js +68 -0
- package/dist/esm/compliance/approval-seals/approval-seal-relay-store.backend.js.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seal-store.backend.d.ts +27 -0
- package/dist/esm/compliance/approval-seals/approval-seal-store.backend.d.ts.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seal-store.backend.js +42 -3
- package/dist/esm/compliance/approval-seals/approval-seal-store.backend.js.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.contracts.d.ts +26 -1
- package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.contracts.d.ts.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.contracts.js +10 -0
- package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.contracts.js.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.controller.d.ts +10 -1
- package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.controller.d.ts.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.controller.js +60 -28
- package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.controller.js.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seals-on-record.backend.controller.d.ts +90 -0
- package/dist/esm/compliance/approval-seals/approval-seals-on-record.backend.controller.d.ts.map +1 -0
- package/dist/esm/compliance/approval-seals/approval-seals-on-record.backend.controller.js +373 -0
- package/dist/esm/compliance/approval-seals/approval-seals-on-record.backend.controller.js.map +1 -0
- package/dist/esm/compliance/approval-seals/decision-presentation.backend.d.ts +29 -2
- package/dist/esm/compliance/approval-seals/decision-presentation.backend.d.ts.map +1 -1
- package/dist/esm/compliance/approval-seals/decision-presentation.backend.js +40 -3
- package/dist/esm/compliance/approval-seals/decision-presentation.backend.js.map +1 -1
- package/dist/esm/compliance/electronic-signatures/pdf-signature-structure.backend.d.ts.map +1 -1
- package/dist/esm/compliance/electronic-signatures/pdf-signature-structure.backend.js +34 -6
- package/dist/esm/compliance/electronic-signatures/pdf-signature-structure.backend.js.map +1 -1
- package/dist/esm/compliance/electronic-signatures/signature-request-evidence-files.backend.d.ts +30 -6
- package/dist/esm/compliance/electronic-signatures/signature-request-evidence-files.backend.d.ts.map +1 -1
- package/dist/esm/compliance/electronic-signatures/signature-request-evidence-files.backend.js +67 -22
- package/dist/esm/compliance/electronic-signatures/signature-request-evidence-files.backend.js.map +1 -1
- package/dist/esm/compliance/electronic-signatures/signature-request-poll.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/compliance/electronic-signatures/signature-request-poll.batch.backend.service.js +18 -1
- package/dist/esm/compliance/electronic-signatures/signature-request-poll.batch.backend.service.js.map +1 -1
- package/dist/esm/compliance/electronic-signatures/signature-requests.backend.service.d.ts +66 -1
- package/dist/esm/compliance/electronic-signatures/signature-requests.backend.service.d.ts.map +1 -1
- package/dist/esm/compliance/electronic-signatures/signature-requests.backend.service.js +161 -14
- package/dist/esm/compliance/electronic-signatures/signature-requests.backend.service.js.map +1 -1
- package/dist/esm/compliance/electronic-signatures/signed-document-validation.backend.d.ts +47 -0
- package/dist/esm/compliance/electronic-signatures/signed-document-validation.backend.d.ts.map +1 -1
- package/dist/esm/compliance/electronic-signatures/signed-document-validation.backend.js.map +1 -1
- package/dist/esm/external-providers/services/content-safety.backend.service.d.ts +27 -2
- package/dist/esm/external-providers/services/content-safety.backend.service.d.ts.map +1 -1
- package/dist/esm/external-providers/services/content-safety.backend.service.js +46 -1
- package/dist/esm/external-providers/services/content-safety.backend.service.js.map +1 -1
- package/dist/esm/external-providers/services/embeddings.backend.service.d.ts.map +1 -1
- package/dist/esm/external-providers/services/embeddings.backend.service.js +2 -0
- package/dist/esm/external-providers/services/embeddings.backend.service.js.map +1 -1
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts +11 -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 +23 -0
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.js.map +1 -1
- package/dist/esm/external-providers/services/provider-service-account-token.backend.d.ts +19 -1
- package/dist/esm/external-providers/services/provider-service-account-token.backend.d.ts.map +1 -1
- package/dist/esm/external-providers/services/provider-service-account-token.backend.js +41 -1
- package/dist/esm/external-providers/services/provider-service-account-token.backend.js.map +1 -1
- package/dist/esm/files/utils/file-parent-read-context.backend.d.ts +27 -2
- package/dist/esm/files/utils/file-parent-read-context.backend.d.ts.map +1 -1
- package/dist/esm/files/utils/file-parent-read-context.backend.js +23 -4
- package/dist/esm/files/utils/file-parent-read-context.backend.js.map +1 -1
- package/dist/esm/flows-actors/content-guardrails/classifier-availability.backend.utils.d.ts +26 -0
- package/dist/esm/flows-actors/content-guardrails/classifier-availability.backend.utils.d.ts.map +1 -1
- package/dist/esm/flows-actors/content-guardrails/classifier-availability.backend.utils.js +100 -8
- package/dist/esm/flows-actors/content-guardrails/classifier-availability.backend.utils.js.map +1 -1
- package/dist/esm/flows-actors/content-guardrails/record-owner-policy.backend.d.ts +3 -1
- package/dist/esm/flows-actors/content-guardrails/record-owner-policy.backend.d.ts.map +1 -1
- package/dist/esm/flows-actors/content-guardrails/record-owner-policy.backend.js +8 -2
- package/dist/esm/flows-actors/content-guardrails/record-owner-policy.backend.js.map +1 -1
- package/dist/esm/flows-actors/models/function-tools.backend.definitions.d.ts +43 -0
- package/dist/esm/flows-actors/models/function-tools.backend.definitions.d.ts.map +1 -1
- package/dist/esm/flows-actors/models/function-tools.backend.definitions.js +37 -0
- package/dist/esm/flows-actors/models/function-tools.backend.definitions.js.map +1 -1
- package/dist/esm/flows-actors/services/agent-work-decisions.backend.service.d.ts +7 -0
- package/dist/esm/flows-actors/services/agent-work-decisions.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/agent-work-decisions.backend.service.js +8 -3
- package/dist/esm/flows-actors/services/agent-work-decisions.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/services/agents.backend.service.d.ts +31 -6
- package/dist/esm/flows-actors/services/agents.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/agents.backend.service.js +78 -30
- package/dist/esm/flows-actors/services/agents.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/services/autonomous-agent-turn.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/autonomous-agent-turn.backend.service.js +4 -0
- package/dist/esm/flows-actors/services/autonomous-agent-turn.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/services/conversational-execution.backend.service.d.ts +28 -2
- package/dist/esm/flows-actors/services/conversational-execution.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/conversational-execution.backend.service.js +132 -22
- package/dist/esm/flows-actors/services/conversational-execution.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/services/flow-actor-executions.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/flow-actor-executions.custom-impl.backend.service.js +12 -8
- package/dist/esm/flows-actors/services/flow-actor-executions.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/services/flows-actors-registry.service.d.ts +5 -0
- package/dist/esm/flows-actors/services/flows-actors-registry.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/flows-actors-registry.service.js +18 -2
- package/dist/esm/flows-actors/services/flows-actors-registry.service.js.map +1 -1
- package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.d.ts +33 -0
- 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 +58 -0
- package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.js.map +1 -1
- package/dist/esm/inbound/services/inbound-delivery-dispatch.backend.service.d.ts +12 -1
- package/dist/esm/inbound/services/inbound-delivery-dispatch.backend.service.d.ts.map +1 -1
- package/dist/esm/inbound/services/inbound-delivery-dispatch.backend.service.js +23 -4
- package/dist/esm/inbound/services/inbound-delivery-dispatch.backend.service.js.map +1 -1
- package/dist/esm/inbound/services/inbound-delivery-receiver.backend.service.d.ts +12 -1
- package/dist/esm/inbound/services/inbound-delivery-receiver.backend.service.d.ts.map +1 -1
- package/dist/esm/inbound/services/inbound-delivery-receiver.backend.service.js +55 -17
- package/dist/esm/inbound/services/inbound-delivery-receiver.backend.service.js.map +1 -1
- package/dist/esm/inbound/services/inbound-delivery-store.backend.service.d.ts +22 -1
- package/dist/esm/inbound/services/inbound-delivery-store.backend.service.d.ts.map +1 -1
- package/dist/esm/inbound/services/inbound-delivery-store.backend.service.js +52 -9
- package/dist/esm/inbound/services/inbound-delivery-store.backend.service.js.map +1 -1
- package/dist/esm/inbound/services/inbound-delivery-stored-body.backend.service.d.ts +79 -0
- package/dist/esm/inbound/services/inbound-delivery-stored-body.backend.service.d.ts.map +1 -0
- package/dist/esm/inbound/services/inbound-delivery-stored-body.backend.service.js +211 -0
- package/dist/esm/inbound/services/inbound-delivery-stored-body.backend.service.js.map +1 -0
- package/dist/esm/inbound/services/inbound-delivery-subject-erasure-severance.backend.d.ts +2 -2
- package/dist/esm/inbound/services/inbound-delivery-subject-erasure-severance.backend.d.ts.map +1 -1
- package/dist/esm/inbound/services/inbound-delivery-subject-erasure-severance.backend.js +9 -1
- package/dist/esm/inbound/services/inbound-delivery-subject-erasure-severance.backend.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- 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 +6 -0
- package/dist/esm/inject/models/container.js.map +1 -1
- package/dist/esm/inject/models/service-types.d.ts +5 -0
- package/dist/esm/inject/models/service-types.d.ts.map +1 -1
- package/dist/esm/inject/models/service-types.js +3 -0
- package/dist/esm/inject/models/service-types.js.map +1 -1
- package/dist/esm/monitoring/observability/models/observability.backend.schemas.d.ts +5 -0
- package/dist/esm/monitoring/observability/models/observability.backend.schemas.d.ts.map +1 -1
- package/dist/esm/monitoring/observability/models/observability.backend.schemas.js.map +1 -1
- package/dist/esm/monitoring/observability/services/metrics.service.d.ts +34 -1
- package/dist/esm/monitoring/observability/services/metrics.service.d.ts.map +1 -1
- package/dist/esm/monitoring/observability/services/metrics.service.js +49 -0
- package/dist/esm/monitoring/observability/services/metrics.service.js.map +1 -1
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.d.ts +6 -1
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.js +15 -4
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.js.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/services/m2m-webhook-delivery-log.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/services/m2m-webhook-delivery-log.custom-impl.backend.service.js +3 -1
- package/dist/esm/notifications/webhooks/outbound/services/m2m-webhook-delivery-log.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/runtime/services/http-server.backend.service.d.ts +3 -1
- package/dist/esm/runtime/services/http-server.backend.service.d.ts.map +1 -1
- package/dist/esm/runtime/services/http-server.backend.service.js +11 -3
- package/dist/esm/runtime/services/http-server.backend.service.js.map +1 -1
- package/dist/esm/runtime/services/utils/inbound-endpoint-raw-body.backend.utils.d.ts +22 -0
- package/dist/esm/runtime/services/utils/inbound-endpoint-raw-body.backend.utils.d.ts.map +1 -1
- package/dist/esm/runtime/services/utils/inbound-endpoint-raw-body.backend.utils.js +54 -0
- package/dist/esm/runtime/services/utils/inbound-endpoint-raw-body.backend.utils.js.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.d.ts +51 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.js +87 -15
- package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.js +5 -2
- package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.js +65 -24
- package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/security/authorizations/super-admin-floor.backend.utils.d.ts +64 -1
- package/dist/esm/security/authorizations/super-admin-floor.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authorizations/super-admin-floor.backend.utils.js +84 -2
- package/dist/esm/security/authorizations/super-admin-floor.backend.utils.js.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.d.ts +14 -0
- package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.js +13 -5
- package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/users/services/anonymous-consent.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/users/services/anonymous-consent.custom-impl.backend.service.js +6 -2
- package/dist/esm/users/services/anonymous-consent.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/users/services/user-force-password-reset.custom-impl.backend.service.d.ts +7 -0
- package/dist/esm/users/services/user-force-password-reset.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/users/services/user-force-password-reset.custom-impl.backend.service.js +65 -20
- package/dist/esm/users/services/user-force-password-reset.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/users/services/user-role-administration.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/users/services/user-role-administration.custom-impl.backend.service.js +11 -4
- package/dist/esm/users/services/user-role-administration.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/users/services/user-self-custom-implementations.backend.d.ts.map +1 -1
- package/dist/esm/users/services/user-self-custom-implementations.backend.js +4 -2
- package/dist/esm/users/services/user-self-custom-implementations.backend.js.map +1 -1
- package/dist/esm/users/services/user-super-admin-floor.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/users/services/user-super-admin-floor.custom-impl.backend.service.js +16 -0
- package/dist/esm/users/services/user-super-admin-floor.custom-impl.backend.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +10 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-seal-relay-store.backend.js","sourceRoot":"","sources":["../../../../src/compliance/approval-seals/approval-seal-relay-store.backend.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * # Approval seals: the relay's side of the outbox (#2903)\n *\n * A decision writes its seal PENDING ({@link ApprovalSealStore.insertPending}); the relay finds it, leases it, asks the\n * custodian to sign it and settles it. This store is those transitions, on the billing-effect-outbox's shape, with one\n * difference that is the point of the seal: **it never drops a row and never gives up on its own.** A refusal asking\n * again can cure (a rate limit, a custodian down, a network failure) is retried with a backoff capped at one hour, for as\n * long as it takes: a seal older than the custodian's late bound is still signed, flagged late. Only a refusal asking\n * again cannot cure goes DEAD, and a DEAD seal is re-driven by an operator, justified and audited (`wildo seal retry`).\n *\n * ## Every transition is a compare-and-swap on `_id` + `status` + `attemptCount`\n *\n * A lease INCREMENTS `attemptCount`, which is the fencing token: a relay whose lease expired and was taken over cannot\n * settle the row, because the takeover moved the count. The filter names no optional field, so it means the same on both\n * adapters. A lease that expires (a relay died mid-request) is leased again: signing is idempotent, since the custodian\n * answers the same claims with the same signature for seven days, and signs them anew, with the same identity, after.\n *\n * ## Order within a decision\n *\n * A seal that supersedes another is not leased while the one it supersedes is still unsealed: the later answer is sealed\n * after the earlier, so the chain a verifier reads never points at a seal that does not exist yet.\n *\n * ## A seal its approver's erasure froze before it was signed (#3000)\n *\n * The erasure removes the approver's disclosure and retains the row, which hides it from every ordinary read and write.\n * The decision was committed, so its seal is still owed: this store finds such seals and settles them through the two\n * doors that reach retained rows (`findRetainedForCompletionForInfrastructure`, `completeRetainedRowForInfrastructure`),\n * which write only `APPROVAL_SEAL_RELAY_FIELDS`, the seal's declared `retainedRowCompletion`. A seal read that way is\n * marked `retained`, and every later write on it takes the same door. A seal frozen between this store's read and its\n * write is lost for that attempt, and the next run finds it retained.\n */\nimport {\n ApprovalSealSchema,\n ApprovalSealStatus as Status,\n CoreAuditableEventType,\n CoreResourceType,\n SortOrder,\n type ApprovalSeal,\n type ApprovalSealPresentationFile,\n type CryptoKey_SignatureRefusal,\n type ResourceType,\n} from '@wildo-ai/saas-models';\nimport { sealClaimsDigestOf, type SignatureResponse } from '@wildo-ai/platform-config-lib';\nimport type { RepositoriesRegistryHandlerBackendService } from '../../base-classes/services/repositories/repositories-registry-handler.backend.service';\nimport { approvalEvidenceDestroyedAuditEventId } from '../audit-trails/services/audit-logs.backend.service';\n\nconst SEALS = CoreResourceType.APPROVAL_SEALS as ResourceType;\n\n/** How long a relay holds a leased seal before another may take it: one custodian request, with its retries, fits in it. */\nexport const APPROVAL_SEAL_LEASE_MS = 2 * 60_000;\n/** The first retry's delay, doubled per attempt. */\nexport const APPROVAL_SEAL_RETRY_BASE_MS = 30_000;\n/** The longest a refused seal waits before it is asked for again: a seal is retried for ever, never less often than this. */\nexport const APPROVAL_SEAL_RETRY_CAP_MS = 60 * 60_000;\n\n/** When a seal refused on its `attemptCount`-th attempt is asked for again: 30 s, 1 min, 2 min, … capped at one hour. */\nexport function approvalSealRetryDelayMs(attemptCount: number): number {\n const exponent = Math.max(0, attemptCount - 1);\n // Past 2^7 the cap is reached; the exponent is bounded so the arithmetic never overflows.\n return Math.min(APPROVAL_SEAL_RETRY_BASE_MS * 2 ** Math.min(exponent, 20), APPROVAL_SEAL_RETRY_CAP_MS);\n}\n\n/** What leasing one seal produced. */\nexport enum ApprovalSealLeaseOutcome {\n /** This relay holds the seal until its lease expires, and must settle it. */\n LEASED = 'leased',\n /** Another relay moved the seal first. */\n LOST = 'lost',\n /** Not this relay's to take now: waiting out its backoff, leased by another, final, or behind the seal it supersedes. */\n NOT_DUE = 'not_due',\n}\n\nexport type ApprovalSealLeaseResult =\n | { readonly outcome: ApprovalSealLeaseOutcome.LEASED; readonly row: ApprovalSealRelayRow }\n | { readonly outcome: ApprovalSealLeaseOutcome.LOST }\n | { readonly outcome: ApprovalSealLeaseOutcome.NOT_DUE };\n\n/** A due seal this version cannot read: reported, never killed (a newer version may read it). */\nexport interface ApprovalSealUnreadableRow {\n readonly rowId: string;\n readonly reason: string;\n}\n\ntype Registry = Pick<\n RepositoriesRegistryHandlerBackendService,\n 'findManyForInfrastructure' | 'atomicGuardedMutation' | 'readUnscopedByKey' | 'findRetainedForCompletionForInfrastructure' | 'completeRetainedRowForInfrastructure'\n>;\n\n/**\n * A seal as the relay holds it: `retained` when its approver's erasure froze it (#3000), so its writes take the retained\n * door. Not a stored field: it says which door the row was read through.\n */\nexport type ApprovalSealRelayRow = ApprovalSeal & { readonly retained?: true };\n\n/** The seal fields the relay writes, and which it clears. */\nconst SETTLED_CLEARS = ['leaseExpiresAt'] as const;\n\nfunction parseSeal(row: Record<string, unknown>, retained = false): ApprovalSealRelayRow {\n const seal = ApprovalSealSchema.parse(row);\n return retained ? { ...seal, retained: true } : seal;\n}\n\n/** A stored seal's identity, as the signing-log reconciliation reads it (#2932). */\nexport interface SealIdentity {\n readonly sealId: string;\n readonly decisionPayloadDigest: string;\n /**\n * The digest of the claims the stored signature covers, COMPUTED from the stored JWS (never the row's `claimsDigest`,\n * which a relay sealed before #2932's review stored as the custodian reported it); absent until the seal is signed.\n */\n readonly claimsDigest?: string;\n readonly status: Status;\n}\n\n/** A seal destroyed with the record it attested (#2924), as its `APPROVAL_EVIDENCE_DESTROYED` row names it. */\nexport interface DestroyedSealIdentity {\n readonly jti: string;\n readonly decisionPayloadDigest?: string;\n /** The digest of the claims its signature covered; absent when it was destroyed before it was signed. */\n readonly claimsDigest?: string;\n}\n\nfunction jwsPart(jws: string, index: 0 | 1): Record<string, unknown> | null {\n try {\n const value: unknown = JSON.parse(Buffer.from(jws.split('.')[index] ?? '', 'base64url').toString('utf8'));\n return value !== null && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : null;\n } catch {\n return null;\n }\n}\n\n/**\n * What a signature says about itself, read from the JWS: its key (header `kid`), its issuer and instant, and the digest\n * of the claims it signs. A seal stores THESE, never the custodian's account of them, so a stored seal's identity is the\n * signature it holds (#2932 review M2). Each is absent when the JWS does not carry it.\n */\nexport function signedFactsOfJws(jws: string): { readonly kid?: string; readonly iss?: string; readonly iat?: number; readonly claimsDigest?: string } {\n const header = jwsPart(jws, 0);\n const payload = jwsPart(jws, 1);\n let claimsDigest: string | undefined;\n try {\n claimsDigest = payload ? sealClaimsDigestOf(payload) : undefined;\n } catch {\n claimsDigest = undefined;\n }\n return {\n ...(typeof header?.kid === 'string' ? { kid: header.kid } : {}),\n ...(typeof payload?.iss === 'string' ? { iss: payload.iss } : {}),\n ...(typeof payload?.iat === 'number' ? { iat: payload.iat } : {}),\n ...(claimsDigest ? { claimsDigest } : {}),\n };\n}\n\n/** See the file's header. */\nexport class ApprovalSealRelayStore {\n constructor(\n private readonly repositoriesRegistry: Registry,\n private readonly clock: () => Date = () => new Date(),\n ) {}\n\n /** The `files` row a frozen presentation names (#2903 S7). */\n async readFile(fileId: string): Promise<Record<string, unknown> | null> {\n return this.repositoriesRegistry.readUnscopedByKey<Record<string, unknown>>(CoreResourceType.FILES as ResourceType, { fileId });\n }\n\n /** One live seal by id. A seal an erasure retained is not returned: revealing one to a reader is the attributed reveal's. */\n async read(sealId: string): Promise<ApprovalSeal | null> {\n const row = await this.repositoriesRegistry.readUnscopedByKey<Record<string, unknown>>(SEALS, { _id: sealId });\n return row ? parseSeal(row) : null;\n }\n\n /**\n * One seal by id, a frozen one included (#3000), marked `retained`. For the relay and the operator's re-drive, which\n * finish a seal's signing and hand no field of it to anyone; an export reads through {@link read} and the reveal.\n */\n async readIncludingRetained(sealId: string): Promise<ApprovalSealRelayRow | null> {\n const live = await this.read(sealId);\n if (live) return live;\n const [retained] = await this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<Record<string, unknown>>(SEALS, { _id: sealId });\n return retained ? parseSeal(retained, true) : null;\n }\n\n /**\n * Seals a relay should handle now, oldest due first: PENDING seals whose next attempt is due, and IN_FLIGHT seals whose\n * lease expired. Two simple queries, each bounded and ordered by its due instant then `_id`. A due row this version\n * cannot parse is reported and skipped, never thrown (one row must not stop every seal) and never killed.\n */\n async findDue(limit: number): Promise<{ readonly due: ApprovalSealRelayRow[]; readonly unreadable: ApprovalSealUnreadableRow[] }> {\n if (!Number.isInteger(limit) || limit < 1) throw new Error('Approval seal due-row limit must be a positive integer');\n const now = this.clock();\n const pendingFilter = { status: Status.PENDING, nextAttemptAt: { $lte: now } };\n const pendingBounds = { sort: [{ field: 'nextAttemptAt', order: SortOrder.ASC }, { field: '_id', order: SortOrder.ASC }], limit };\n const expiredFilter = { status: Status.IN_FLIGHT, leaseExpiresAt: { $lte: now } };\n const expiredBounds = { sort: [{ field: 'leaseExpiresAt', order: SortOrder.ASC }, { field: '_id', order: SortOrder.ASC }], limit };\n // The live seals, and those an erasure froze before they were signed (#3000): four bounded queries, each ordered.\n const [pending, expired, retainedPending, retainedExpired] = await Promise.all([\n this.repositoriesRegistry.findManyForInfrastructure<Record<string, unknown>>(SEALS, pendingFilter, undefined, undefined, pendingBounds),\n this.repositoriesRegistry.findManyForInfrastructure<Record<string, unknown>>(SEALS, expiredFilter, undefined, undefined, expiredBounds),\n this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<Record<string, unknown>>(SEALS, pendingFilter, undefined, undefined, pendingBounds),\n this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<Record<string, unknown>>(SEALS, expiredFilter, undefined, undefined, expiredBounds),\n ]);\n const due: ApprovalSealRelayRow[] = [];\n const unreadable: ApprovalSealUnreadableRow[] = [];\n const rows = [...pending.map((row) => ({ row, retained: false })), ...expired.map((row) => ({ row, retained: false })),\n ...retainedPending.map((row) => ({ row, retained: true })), ...retainedExpired.map((row) => ({ row, retained: true }))];\n for (const { row, retained } of rows) {\n const parsed = ApprovalSealSchema.safeParse(row);\n if (parsed.success) due.push(retained ? { ...parsed.data, retained: true } : parsed.data);\n else unreadable.push({ rowId: String(row._id), reason: parsed.error.message.slice(0, 2_000) });\n }\n const dueAt = (seal: ApprovalSeal) => (seal.status === Status.IN_FLIGHT ? seal.leaseExpiresAt! : seal.nextAttemptAt).getTime();\n due.sort((first, second) => dueAt(first) - dueAt(second) || first._id.localeCompare(second._id));\n return { due: due.slice(0, limit), unreadable };\n }\n\n /**\n * When the oldest seal not yet signed was written: PENDING or IN_FLIGHT, whatever its next attempt (#2903 review M2).\n * During a custodian outage every seal waits out its backoff, so a measure over due rows alone would read zero exactly\n * when the alert matters. Undefined when every seal is settled.\n */\n async oldestUnsealedCreatedAt(): Promise<Date | undefined> {\n const bounds = { sort: [{ field: 'createdAt', order: SortOrder.ASC }, { field: '_id', order: SortOrder.ASC }], limit: 1 };\n const oldestOf = async (status: Status) => (await this.repositoriesRegistry.findManyForInfrastructure<Record<string, unknown>>(SEALS, { status }, undefined, undefined, bounds))[0];\n // A frozen seal waiting for its signature is unsigned too (#3000).\n const oldestRetainedOf = async (status: Status) => (await this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<Record<string, unknown>>(SEALS, { status }, undefined, undefined, bounds))[0];\n const instants = (await Promise.all([oldestOf(Status.PENDING), oldestOf(Status.IN_FLIGHT), oldestRetainedOf(Status.PENDING), oldestRetainedOf(Status.IN_FLIGHT)]))\n .flatMap((row) => (row ? [new Date((row.createdAt ?? row.decidedAt) as Date | string)] : []));\n return instants.length > 0 ? new Date(Math.min(...instants.map((instant) => instant.getTime()))) : undefined;\n }\n\n /**\n * The seals, live and retained, whose committed decision has one of these digests (#2932): what a logged signature is\n * reconciled against. Only the identity of each is read: its id, the digest, the digest of the claims it was signed\n * with (when signed) and its status.\n */\n async findByDecisionPayloadDigests(digests: readonly string[]): Promise<SealIdentity[]> {\n const unique = [...new Set(digests)];\n if (unique.length === 0) return [];\n const filter = { decisionPayloadDigest: { $in: unique } };\n // One seal per digest (its claims carry its own jti); the bound leaves room for a reopened decision's seals.\n const bounds = { sort: [{ field: '_id', order: SortOrder.ASC }], limit: unique.length * 4 };\n const [live, retained] = await Promise.all([\n this.repositoriesRegistry.findManyForInfrastructure<Record<string, unknown>>(SEALS, filter, undefined, undefined, bounds),\n this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<Record<string, unknown>>(SEALS, filter, undefined, undefined, bounds),\n ]);\n return [...live, ...retained].map((row) => ({\n sealId: String(row._id),\n decisionPayloadDigest: String(row.decisionPayloadDigest),\n ...(typeof row.jws === 'string' && signedFactsOfJws(row.jws).claimsDigest ? { claimsDigest: signedFactsOfJws(row.jws).claimsDigest } : {}),\n status: row.status as Status,\n }));\n }\n\n /**\n * The seals destroyed with their record whose `jti` is one of these (#2924): what tells the signing log's reconciliation\n * a seal went on purpose. Read from the audit trail by the rows' deterministic ids (`approvalEvidenceDestroyedAuditEventId`\n * keys a seal by its `jti`), so the lookup is the trail's unique `eventId` index on both adapters.\n */\n async findDestroyedSealsByJti(jtis: readonly string[]): Promise<DestroyedSealIdentity[]> {\n const unique = [...new Set(jtis.filter((jti) => jti.length > 0))];\n if (unique.length === 0) return [];\n const eventIds = unique.map((jti) => approvalEvidenceDestroyedAuditEventId({ evidenceResourceType: SEALS, evidenceId: jti, jti }));\n const rows = await this.repositoriesRegistry.findManyForInfrastructure<Record<string, unknown>>(CoreResourceType.AUDIT_LOGS as ResourceType, {\n eventId: { $in: eventIds },\n eventType: CoreAuditableEventType.APPROVAL_EVIDENCE_DESTROYED,\n });\n return rows.flatMap((row) => {\n const data = row.eventData as Record<string, unknown> | undefined;\n if (typeof data?.jti !== 'string') return [];\n return [{\n jti: data.jti,\n ...(typeof data.decisionPayloadDigest === 'string' ? { decisionPayloadDigest: data.decisionPayloadDigest } : {}),\n ...(typeof data.claimsDigest === 'string' ? { claimsDigest: data.claimsDigest } : {}),\n }];\n });\n }\n\n /** The DEAD seals, oldest death first: what an operator reviews before re-driving one. */\n /** A frozen DEAD seal is listed too (#3000): an operator re-drives it like any other. */\n async listDead(limit: number): Promise<ApprovalSealRelayRow[]> {\n const bounds = { sort: [{ field: 'deadAt', order: SortOrder.ASC }, { field: '_id', order: SortOrder.ASC }], limit };\n const [live, retained] = await Promise.all([\n this.repositoriesRegistry.findManyForInfrastructure<Record<string, unknown>>(SEALS, { status: Status.DEAD }, undefined, undefined, bounds),\n this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<Record<string, unknown>>(SEALS, { status: Status.DEAD }, undefined, undefined, bounds),\n ]);\n const seals = [...live.map((row) => ({ row, retained: false })), ...retained.map((row) => ({ row, retained: true }))].flatMap(({ row, retained: isRetained }) => {\n const parsed = ApprovalSealSchema.safeParse(row);\n return parsed.success ? [isRetained ? { ...parsed.data, retained: true as const } : parsed.data] : [];\n });\n seals.sort((first, second) => (first.deadAt?.getTime() ?? 0) - (second.deadAt?.getTime() ?? 0) || first._id.localeCompare(second._id));\n return seals.slice(0, limit);\n }\n\n /** Lease one due seal. Writes nothing for a seal that is not due now, or one behind the seal it supersedes. */\n async lease(due: ApprovalSealRelayRow): Promise<ApprovalSealLeaseResult> {\n const now = this.clock().getTime();\n const isDue = due.status === Status.PENDING\n ? due.nextAttemptAt.getTime() <= now\n : due.status === Status.IN_FLIGHT && due.leaseExpiresAt !== undefined && due.leaseExpiresAt.getTime() <= now;\n if (!isDue) return { outcome: ApprovalSealLeaseOutcome.NOT_DUE };\n if (due.supersedesSealId) {\n // A frozen earlier seal is still signed (#3000), so a later answer still waits for it.\n const earlier = await this.readIncludingRetained(due.supersedesSealId);\n if (earlier && earlier.status !== Status.SEALED && earlier.status !== Status.DEAD) return { outcome: ApprovalSealLeaseOutcome.NOT_DUE };\n }\n const row = await this.guardedWrite(due,\n { _id: due._id, status: due.status, attemptCount: due.attemptCount },\n { set: { status: Status.IN_FLIGHT, leaseExpiresAt: new Date(now + APPROVAL_SEAL_LEASE_MS) }, increment: { attemptCount: 1 } },\n );\n return row ? { outcome: ApprovalSealLeaseOutcome.LEASED, row } : { outcome: ApprovalSealLeaseOutcome.LOST };\n }\n\n /**\n * #2903 S6b: the leased seal's presentation, over the inline ceiling, now held in a frozen file. Written under the lease\n * (the same compare-and-swap a settle uses, without moving `attemptCount`), BEFORE the seal is signed, so a SEALED seal\n * is still never written again. Null when this relay no longer holds the lease; the file then belongs to no seal and\n * the next holder writes its own.\n */\n async externalizePresentation(leased: ApprovalSealRelayRow, file: ApprovalSealPresentationFile): Promise<ApprovalSealRelayRow | null> {\n // A frozen seal keeps its presentation in the row: the presentation is not a field its completion may write (#3000).\n if (!leased.presentation?.content || leased.retained) return leased;\n const { content: _content, ...kept } = leased.presentation;\n const row = await this.repositoriesRegistry.atomicGuardedMutation<Record<string, unknown>>(SEALS,\n { _id: leased._id, status: Status.IN_FLIGHT, attemptCount: leased.attemptCount },\n // The top-level id is the seal's attested file reference: it freezes the file (#2903 review F1).\n { set: { presentation: { ...kept, file }, presentationFileId: file.fileId } },\n );\n return row ? parseSeal(row) : null;\n }\n\n /**\n * The custodian signed the leased seal. Null when this relay no longer holds the lease. A SEALED seal is final, so the\n * deliverable's manifested copy (#2907), made from the signature, is named in this same write.\n */\n markSealed(leased: ApprovalSealRelayRow, signature: SignatureResponse, manifestedCopy?: { readonly fileId: string; readonly at: Date }): Promise<ApprovalSealRelayRow | null> {\n // The JWS's own account of itself, the custodian's only where the JWS is silent (#2932 review M2).\n const signed = signedFactsOfJws(signature.jws);\n return this.settle(leased, {\n set: {\n status: Status.SEALED, jws: signature.jws, kid: signed.kid ?? signature.kid, iss: signed.iss ?? signature.iss, iat: signed.iat ?? signature.iat,\n claimsDigest: signed.claimsDigest ?? signature.claimsDigest, lateSeal: signature.lateSeal, sealedAt: this.clock(),\n // Never on a frozen seal: its completion writes only the relay's fields, and its approver's name is gone (#3000).\n ...(manifestedCopy && !leased.retained ? { manifestedCopy: { fileId: manifestedCopy.fileId, updatedAt: manifestedCopy.at }, manifestedCopyAt: manifestedCopy.at } : {}),\n },\n clear: [...SETTLED_CLEARS, 'lastRefusal'],\n });\n }\n\n /**\n * An operator's rebuild names a new manifested copy on a SEALED seal (#2907): the one write a SEALED seal takes after\n * it is signed, and it touches only the copy and its instant, which the signature does not cover. Guarded on the\n * status and on `attemptCount`, the row's write fence, which it advances, so of two rebuilds racing one wins and the\n * other's copy is discarded. A live seal only: one its approver's erasure retained is not found by this door.\n */\n replaceManifestedCopy(sealed: ApprovalSealRelayRow, copy: { readonly fileId: string; readonly at: Date }): Promise<ApprovalSealRelayRow | null> {\n if (sealed.retained || sealed.status !== Status.SEALED) return Promise.resolve(null);\n return this.guardedWrite(sealed, { _id: sealed._id, status: Status.SEALED, attemptCount: sealed.attemptCount }, {\n set: { manifestedCopy: { fileId: copy.fileId, updatedAt: copy.at }, manifestedCopyAt: copy.at },\n increment: { attemptCount: 1 },\n });\n }\n\n /** A refusal asking again can cure: back to PENDING, asked again after the backoff of this attempt. */\n markRetry(leased: ApprovalSealRelayRow, refusal: CryptoKey_SignatureRefusal | null): Promise<ApprovalSealRelayRow | null> {\n const nextAttemptAt = new Date(this.clock().getTime() + approvalSealRetryDelayMs(leased.attemptCount));\n return this.settle(leased, {\n set: { status: Status.PENDING, nextAttemptAt, ...(refusal ? { lastRefusal: refusal } : {}) },\n clear: [...SETTLED_CLEARS, ...(refusal ? [] : ['lastRefusal'])],\n });\n }\n\n /** A refusal asking again cannot cure: DEAD, until an operator re-drives it. */\n markDead(leased: ApprovalSealRelayRow, refusal: CryptoKey_SignatureRefusal | null): Promise<ApprovalSealRelayRow | null> {\n return this.settle(leased, {\n set: { status: Status.DEAD, deadAt: this.clock(), ...(refusal ? { lastRefusal: refusal } : {}) },\n clear: [...SETTLED_CLEARS, ...(refusal ? [] : ['lastRefusal'])],\n });\n }\n\n /**\n * An operator re-drives a DEAD seal (#2903 S4): back to PENDING, due now. Its decision instant, claims and identity are\n * untouched, so the seal the custodian then signs says when the person decided, and the verifier shows it late.\n */\n revive(dead: ApprovalSealRelayRow): Promise<ApprovalSealRelayRow | null> {\n if (dead.status !== Status.DEAD) return Promise.resolve(null);\n return this.settle(dead, { set: { status: Status.PENDING, nextAttemptAt: this.clock() }, clear: ['deadAt'] }, Status.DEAD);\n }\n\n private settle(\n held: ApprovalSealRelayRow,\n mutation: { readonly set: Record<string, unknown>; readonly clear?: readonly string[] },\n expectedStatus: Status = Status.IN_FLIGHT,\n ): Promise<ApprovalSealRelayRow | null> {\n return this.guardedWrite(held, { _id: held._id, status: expectedStatus, attemptCount: held.attemptCount }, mutation);\n }\n\n /** One compare-and-swap, through the door the seal was read through: the retained one for a frozen seal (#3000). */\n private async guardedWrite(\n held: ApprovalSealRelayRow,\n filter: Record<string, unknown>,\n mutation: { readonly set?: Record<string, unknown>; readonly clear?: readonly string[]; readonly increment?: Record<string, number> },\n ): Promise<ApprovalSealRelayRow | null> {\n const row = held.retained\n ? await this.repositoriesRegistry.completeRetainedRowForInfrastructure<Record<string, unknown>>(SEALS, filter, mutation)\n : await this.repositoriesRegistry.atomicGuardedMutation<Record<string, unknown>>(SEALS, filter, mutation);\n return row ? parseSeal(row, held.retained === true) : null;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"approval-seal-relay-store.backend.js","sourceRoot":"","sources":["../../../../src/compliance/approval-seals/approval-seal-relay-store.backend.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * # Approval seals: the relay's side of the outbox (#2903)\n *\n * A decision writes its seal PENDING ({@link ApprovalSealStore.insertPending}); the relay finds it, leases it, asks the\n * custodian to sign it and settles it. This store is those transitions, on the billing-effect-outbox's shape, with one\n * difference that is the point of the seal: **it never drops a row and never gives up on its own.** A refusal asking\n * again can cure (a rate limit, a custodian down, a network failure) is retried with a backoff capped at one hour, for as\n * long as it takes: a seal older than the custodian's late bound is still signed, flagged late. Only a refusal asking\n * again cannot cure goes DEAD, and a DEAD seal is re-driven by an operator, justified and audited (`wildo seal retry`).\n *\n * ## Every transition is a compare-and-swap on `_id` + `status` + `attemptCount`\n *\n * A lease INCREMENTS `attemptCount`, which is the fencing token: a relay whose lease expired and was taken over cannot\n * settle the row, because the takeover moved the count. The filter names no optional field, so it means the same on both\n * adapters. A lease that expires (a relay died mid-request) is leased again: signing is idempotent, since the custodian\n * answers the same claims with the same signature for seven days, and signs them anew, with the same identity, after.\n *\n * ## Order within a decision\n *\n * A seal that supersedes another is not leased while the one it supersedes is still unsealed: the later answer is sealed\n * after the earlier, so the chain a verifier reads never points at a seal that does not exist yet.\n *\n * ## A seal its approver's erasure froze before it was signed (#3000)\n *\n * The erasure removes the approver's disclosure and retains the row, which hides it from every ordinary read and write.\n * The decision was committed, so its seal is still owed: this store finds such seals and settles them through the two\n * doors that reach retained rows (`findRetainedForCompletionForInfrastructure`, `completeRetainedRowForInfrastructure`),\n * which write only `APPROVAL_SEAL_RELAY_FIELDS`, the seal's declared `retainedRowCompletion`. A seal read that way is\n * marked `retained`, and every later write on it takes the same door. A seal frozen between this store's read and its\n * write is lost for that attempt, and the next run finds it retained.\n */\nimport {\n ApprovalSealSchema,\n ApprovalSealStatus as Status,\n CoreAuditableEventType,\n CoreResourceType,\n SortOrder,\n type ApprovalSeal,\n type ApprovalSealPresentationFile,\n type CryptoKey_SignatureRefusal,\n type ResourceType,\n} from '@wildo-ai/saas-models';\nimport { sealClaimsDigestOf, type SignatureResponse } from '@wildo-ai/platform-config-lib';\nimport type { RepositoriesRegistryHandlerBackendService } from '../../base-classes/services/repositories/repositories-registry-handler.backend.service';\nimport { approvalEvidenceDestroyedAuditEventId } from '../audit-trails/services/audit-logs.backend.service';\n\nconst SEALS = CoreResourceType.APPROVAL_SEALS as ResourceType;\n\n/** How long a relay holds a leased seal before another may take it: one custodian request, with its retries, fits in it. */\nexport const APPROVAL_SEAL_LEASE_MS = 2 * 60_000;\n/** The first retry's delay, doubled per attempt. */\nexport const APPROVAL_SEAL_RETRY_BASE_MS = 30_000;\n/** The longest a refused seal waits before it is asked for again: a seal is retried for ever, never less often than this. */\nexport const APPROVAL_SEAL_RETRY_CAP_MS = 60 * 60_000;\n\n/** When a seal refused on its `attemptCount`-th attempt is asked for again: 30 s, 1 min, 2 min, … capped at one hour. */\nexport function approvalSealRetryDelayMs(attemptCount: number): number {\n const exponent = Math.max(0, attemptCount - 1);\n // Past 2^7 the cap is reached; the exponent is bounded so the arithmetic never overflows.\n return Math.min(APPROVAL_SEAL_RETRY_BASE_MS * 2 ** Math.min(exponent, 20), APPROVAL_SEAL_RETRY_CAP_MS);\n}\n\n/** What leasing one seal produced. */\nexport enum ApprovalSealLeaseOutcome {\n /** This relay holds the seal until its lease expires, and must settle it. */\n LEASED = 'leased',\n /** Another relay moved the seal first. */\n LOST = 'lost',\n /** Not this relay's to take now: waiting out its backoff, leased by another, final, or behind the seal it supersedes. */\n NOT_DUE = 'not_due',\n}\n\nexport type ApprovalSealLeaseResult =\n | { readonly outcome: ApprovalSealLeaseOutcome.LEASED; readonly row: ApprovalSealRelayRow }\n | { readonly outcome: ApprovalSealLeaseOutcome.LOST }\n | { readonly outcome: ApprovalSealLeaseOutcome.NOT_DUE };\n\n/** A due seal this version cannot read: reported, never killed (a newer version may read it). */\nexport interface ApprovalSealUnreadableRow {\n readonly rowId: string;\n readonly reason: string;\n}\n\ntype Registry = Pick<\n RepositoriesRegistryHandlerBackendService,\n 'findManyForInfrastructure' | 'atomicGuardedMutation' | 'readUnscopedByKey' | 'findRetainedForCompletionForInfrastructure' | 'completeRetainedRowForInfrastructure'\n>;\n\n/**\n * A seal as the relay holds it: `retained` when its approver's erasure froze it (#3000), so its writes take the retained\n * door. Not a stored field: it says which door the row was read through.\n */\nexport type ApprovalSealRelayRow = ApprovalSeal & { readonly retained?: true };\n\n/** The seal fields the relay writes, and which it clears. */\nconst SETTLED_CLEARS = ['leaseExpiresAt'] as const;\n\nfunction parseSeal(row: Record<string, unknown>, retained = false): ApprovalSealRelayRow {\n const seal = ApprovalSealSchema.parse(row);\n return retained ? { ...seal, retained: true } : seal;\n}\n\n/** A stored seal's identity, as the signing-log reconciliation reads it (#2932). */\nexport interface SealIdentity {\n readonly sealId: string;\n readonly decisionPayloadDigest: string;\n /**\n * The digest of the claims the stored signature covers, COMPUTED from the stored JWS (never the row's `claimsDigest`,\n * which a relay sealed before #2932's review stored as the custodian reported it); absent until the seal is signed.\n */\n readonly claimsDigest?: string;\n readonly status: Status;\n}\n\n/** A seal destroyed with the record it attested (#2924), as its `APPROVAL_EVIDENCE_DESTROYED` row names it. */\nexport interface DestroyedSealIdentity {\n readonly jti: string;\n readonly decisionPayloadDigest?: string;\n /** The digest of the claims its signature covered; absent when it was destroyed before it was signed. */\n readonly claimsDigest?: string;\n}\n\nfunction jwsPart(jws: string, index: 0 | 1): Record<string, unknown> | null {\n try {\n const value: unknown = JSON.parse(Buffer.from(jws.split('.')[index] ?? '', 'base64url').toString('utf8'));\n return value !== null && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : null;\n } catch {\n return null;\n }\n}\n\n/**\n * What a signature says about itself, read from the JWS: its key (header `kid`), its issuer and instant, and the digest\n * of the claims it signs. A seal stores THESE, never the custodian's account of them, so a stored seal's identity is the\n * signature it holds (#2932 review M2). Each is absent when the JWS does not carry it.\n */\nexport function signedFactsOfJws(jws: string): { readonly kid?: string; readonly iss?: string; readonly iat?: number; readonly claimsDigest?: string } {\n const header = jwsPart(jws, 0);\n const payload = jwsPart(jws, 1);\n let claimsDigest: string | undefined;\n try {\n claimsDigest = payload ? sealClaimsDigestOf(payload) : undefined;\n } catch {\n claimsDigest = undefined;\n }\n return {\n ...(typeof header?.kid === 'string' ? { kid: header.kid } : {}),\n ...(typeof payload?.iss === 'string' ? { iss: payload.iss } : {}),\n ...(typeof payload?.iat === 'number' ? { iat: payload.iat } : {}),\n ...(claimsDigest ? { claimsDigest } : {}),\n };\n}\n\n/** See the file's header. */\n/** How many seals of one file the file's view reads to find the one its record stores (#2913). */\nexport const ATTESTING_SEAL_SCAN_LIMIT = 10;\n\nexport class ApprovalSealRelayStore {\n constructor(\n private readonly repositoriesRegistry: Registry,\n private readonly clock: () => Date = () => new Date(),\n ) {}\n\n /** The `files` row a frozen presentation names (#2903 S7). */\n async readFile(fileId: string): Promise<Record<string, unknown> | null> {\n return this.repositoriesRegistry.readUnscopedByKey<Record<string, unknown>>(CoreResourceType.FILES as ResourceType, { fileId });\n }\n\n /** One live seal by id. A seal an erasure retained is not returned: revealing one to a reader is the attributed reveal's. */\n async read(sealId: string): Promise<ApprovalSeal | null> {\n const row = await this.repositoriesRegistry.readUnscopedByKey<Record<string, unknown>>(SEALS, { _id: sealId });\n return row ? parseSeal(row) : null;\n }\n\n /**\n * One seal by id, a frozen one included (#3000), marked `retained`. For the relay and the operator's re-drive, which\n * finish a seal's signing and hand no field of it to anyone; an export reads through {@link read} and the reveal.\n */\n async readIncludingRetained(sealId: string): Promise<ApprovalSealRelayRow | null> {\n const live = await this.read(sealId);\n if (live) return live;\n const [retained] = await this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<Record<string, unknown>>(SEALS, { _id: sealId });\n return retained ? parseSeal(retained, true) : null;\n }\n\n /**\n * The record a seal its approver's erasure RETAINED is about, and nothing else of it (#2913): what a record's view of\n * its seal needs to say \"approver erased\" only to a reader of that very record. No field of the retained row but its\n * subject leaves this method, which is what keeps the record's view outside the reasons the completion door is\n * unaudited (`retained-completion-door-callers.guard.test.ts`).\n */\n async retainedSubjectOf(sealId: string): Promise<{ readonly resourceType: string; readonly resourceId: string } | null> {\n const [retained] = await this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<Record<string, unknown>>(SEALS, { _id: sealId }, undefined, undefined, { sort: [{ field: '_id', order: SortOrder.ASC }], limit: 1 });\n if (!retained || typeof retained.linkedResourceType !== 'string' || typeof retained.linkedResourceId !== 'string') return null;\n return { resourceType: retained.linkedResourceType, resourceId: retained.linkedResourceId };\n }\n\n /**\n * The seal that superseded one (#2913): a later decision on the same record whose seal names it in `supersedesSealId`.\n * The id of a live successor; `retained: true` without an id for one its own approver's erasure retained, so nothing of\n * a retained row leaves but the fact that it exists. Null when nothing superseded it. Asked within the seal's own record\n * (the indexed subject fields): what a record shows is whether IT was approved again, and a successor about another\n * record (a reopened decision whose answer named another row) is not that record's supersession.\n */\n async successorOf(\n sealId: string,\n subject: { readonly resourceType: string; readonly resourceId: string },\n ): Promise<{ readonly sealId?: string; readonly retained?: true } | null> {\n const filter = { linkedResourceType: subject.resourceType, linkedResourceId: subject.resourceId, supersedesSealId: sealId };\n const [live] = await this.repositoriesRegistry.findManyForInfrastructure<Record<string, unknown>>(SEALS, filter, undefined, undefined, { sort: [{ field: 'decidedAt', order: SortOrder.DESC }], limit: 1 });\n if (live) return { sealId: String(live._id) };\n const [retained] = await this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<Record<string, unknown>>(SEALS, filter, undefined, undefined, { sort: [{ field: 'decidedAt', order: SortOrder.DESC }], limit: 1 });\n return retained ? { retained: true } : null;\n }\n\n /**\n * The live seals that attest a file as their deliverable (#2913, `deliverableFileId`, indexed), latest decision first:\n * what a file's view of its seal chooses from. Bounded: a file is attested by a handful of decisions at most.\n */\n async attestingFile(fileId: string, limit = ATTESTING_SEAL_SCAN_LIMIT): Promise<ApprovalSeal[]> {\n const rows = await this.repositoriesRegistry.findManyForInfrastructure<Record<string, unknown>>(SEALS, { deliverableFileId: fileId }, undefined, undefined, {\n sort: [{ field: 'decidedAt', order: SortOrder.DESC }, { field: 'sequence', order: SortOrder.DESC }], limit,\n });\n return rows.flatMap((row) => {\n const parsed = ApprovalSealSchema.safeParse(row);\n return parsed.success ? [parsed.data] : [];\n });\n }\n\n /**\n * The seals its approver's erasure RETAINED that attest a file, as their ids and subjects only (#2913): enough for a\n * file's view to say \"approver erased\" to a reader of the file's record, after checking the seal's own record stores it.\n * No other field of a retained row leaves this method.\n */\n async retainedAttestingFile(fileId: string, limit = ATTESTING_SEAL_SCAN_LIMIT): Promise<Array<{ readonly sealId: string; readonly resourceType: string; readonly resourceId: string }>> {\n const rows = await this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<Record<string, unknown>>(SEALS, { deliverableFileId: fileId }, undefined, undefined, {\n sort: [{ field: 'decidedAt', order: SortOrder.DESC }], limit,\n });\n return rows.flatMap((row) => typeof row.linkedResourceType === 'string' && typeof row.linkedResourceId === 'string'\n ? [{ sealId: String(row._id), resourceType: row.linkedResourceType, resourceId: row.linkedResourceId }]\n : []);\n }\n\n /**\n * The latest live seal of one decision whose approver is `approverUserId` (#2913): the decider's own view of the seal of\n * their act. Another person's seal of the same decision is never returned.\n */\n async latestOfDecisionBy(decisionRef: string, approverUserId: string): Promise<ApprovalSeal | null> {\n const [row] = await this.repositoriesRegistry.findManyForInfrastructure<Record<string, unknown>>(SEALS, { decisionRef, approverUserId }, undefined, undefined, {\n sort: [{ field: 'sequence', order: SortOrder.DESC }, { field: 'decidedAt', order: SortOrder.DESC }], limit: 1,\n });\n if (!row) return null;\n const parsed = ApprovalSealSchema.safeParse(row);\n return parsed.success ? parsed.data : null;\n }\n\n /**\n * Seals a relay should handle now, oldest due first: PENDING seals whose next attempt is due, and IN_FLIGHT seals whose\n * lease expired. Two simple queries, each bounded and ordered by its due instant then `_id`. A due row this version\n * cannot parse is reported and skipped, never thrown (one row must not stop every seal) and never killed.\n */\n async findDue(limit: number): Promise<{ readonly due: ApprovalSealRelayRow[]; readonly unreadable: ApprovalSealUnreadableRow[] }> {\n if (!Number.isInteger(limit) || limit < 1) throw new Error('Approval seal due-row limit must be a positive integer');\n const now = this.clock();\n const pendingFilter = { status: Status.PENDING, nextAttemptAt: { $lte: now } };\n const pendingBounds = { sort: [{ field: 'nextAttemptAt', order: SortOrder.ASC }, { field: '_id', order: SortOrder.ASC }], limit };\n const expiredFilter = { status: Status.IN_FLIGHT, leaseExpiresAt: { $lte: now } };\n const expiredBounds = { sort: [{ field: 'leaseExpiresAt', order: SortOrder.ASC }, { field: '_id', order: SortOrder.ASC }], limit };\n // The live seals, and those an erasure froze before they were signed (#3000): four bounded queries, each ordered.\n const [pending, expired, retainedPending, retainedExpired] = await Promise.all([\n this.repositoriesRegistry.findManyForInfrastructure<Record<string, unknown>>(SEALS, pendingFilter, undefined, undefined, pendingBounds),\n this.repositoriesRegistry.findManyForInfrastructure<Record<string, unknown>>(SEALS, expiredFilter, undefined, undefined, expiredBounds),\n this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<Record<string, unknown>>(SEALS, pendingFilter, undefined, undefined, pendingBounds),\n this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<Record<string, unknown>>(SEALS, expiredFilter, undefined, undefined, expiredBounds),\n ]);\n const due: ApprovalSealRelayRow[] = [];\n const unreadable: ApprovalSealUnreadableRow[] = [];\n const rows = [...pending.map((row) => ({ row, retained: false })), ...expired.map((row) => ({ row, retained: false })),\n ...retainedPending.map((row) => ({ row, retained: true })), ...retainedExpired.map((row) => ({ row, retained: true }))];\n for (const { row, retained } of rows) {\n const parsed = ApprovalSealSchema.safeParse(row);\n if (parsed.success) due.push(retained ? { ...parsed.data, retained: true } : parsed.data);\n else unreadable.push({ rowId: String(row._id), reason: parsed.error.message.slice(0, 2_000) });\n }\n const dueAt = (seal: ApprovalSeal) => (seal.status === Status.IN_FLIGHT ? seal.leaseExpiresAt! : seal.nextAttemptAt).getTime();\n due.sort((first, second) => dueAt(first) - dueAt(second) || first._id.localeCompare(second._id));\n return { due: due.slice(0, limit), unreadable };\n }\n\n /**\n * When the oldest seal not yet signed was written: PENDING or IN_FLIGHT, whatever its next attempt (#2903 review M2).\n * During a custodian outage every seal waits out its backoff, so a measure over due rows alone would read zero exactly\n * when the alert matters. Undefined when every seal is settled.\n */\n async oldestUnsealedCreatedAt(): Promise<Date | undefined> {\n const bounds = { sort: [{ field: 'createdAt', order: SortOrder.ASC }, { field: '_id', order: SortOrder.ASC }], limit: 1 };\n const oldestOf = async (status: Status) => (await this.repositoriesRegistry.findManyForInfrastructure<Record<string, unknown>>(SEALS, { status }, undefined, undefined, bounds))[0];\n // A frozen seal waiting for its signature is unsigned too (#3000).\n const oldestRetainedOf = async (status: Status) => (await this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<Record<string, unknown>>(SEALS, { status }, undefined, undefined, bounds))[0];\n const instants = (await Promise.all([oldestOf(Status.PENDING), oldestOf(Status.IN_FLIGHT), oldestRetainedOf(Status.PENDING), oldestRetainedOf(Status.IN_FLIGHT)]))\n .flatMap((row) => (row ? [new Date((row.createdAt ?? row.decidedAt) as Date | string)] : []));\n return instants.length > 0 ? new Date(Math.min(...instants.map((instant) => instant.getTime()))) : undefined;\n }\n\n /**\n * The seals, live and retained, whose committed decision has one of these digests (#2932): what a logged signature is\n * reconciled against. Only the identity of each is read: its id, the digest, the digest of the claims it was signed\n * with (when signed) and its status.\n */\n async findByDecisionPayloadDigests(digests: readonly string[]): Promise<SealIdentity[]> {\n const unique = [...new Set(digests)];\n if (unique.length === 0) return [];\n const filter = { decisionPayloadDigest: { $in: unique } };\n // One seal per digest (its claims carry its own jti); the bound leaves room for a reopened decision's seals.\n const bounds = { sort: [{ field: '_id', order: SortOrder.ASC }], limit: unique.length * 4 };\n const [live, retained] = await Promise.all([\n this.repositoriesRegistry.findManyForInfrastructure<Record<string, unknown>>(SEALS, filter, undefined, undefined, bounds),\n this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<Record<string, unknown>>(SEALS, filter, undefined, undefined, bounds),\n ]);\n return [...live, ...retained].map((row) => ({\n sealId: String(row._id),\n decisionPayloadDigest: String(row.decisionPayloadDigest),\n ...(typeof row.jws === 'string' && signedFactsOfJws(row.jws).claimsDigest ? { claimsDigest: signedFactsOfJws(row.jws).claimsDigest } : {}),\n status: row.status as Status,\n }));\n }\n\n /**\n * The seals destroyed with their record whose `jti` is one of these (#2924): what tells the signing log's reconciliation\n * a seal went on purpose. Read from the audit trail by the rows' deterministic ids (`approvalEvidenceDestroyedAuditEventId`\n * keys a seal by its `jti`), so the lookup is the trail's unique `eventId` index on both adapters.\n */\n async findDestroyedSealsByJti(jtis: readonly string[]): Promise<DestroyedSealIdentity[]> {\n const unique = [...new Set(jtis.filter((jti) => jti.length > 0))];\n if (unique.length === 0) return [];\n const eventIds = unique.map((jti) => approvalEvidenceDestroyedAuditEventId({ evidenceResourceType: SEALS, evidenceId: jti, jti }));\n const rows = await this.repositoriesRegistry.findManyForInfrastructure<Record<string, unknown>>(CoreResourceType.AUDIT_LOGS as ResourceType, {\n eventId: { $in: eventIds },\n eventType: CoreAuditableEventType.APPROVAL_EVIDENCE_DESTROYED,\n });\n return rows.flatMap((row) => {\n const data = row.eventData as Record<string, unknown> | undefined;\n if (typeof data?.jti !== 'string') return [];\n return [{\n jti: data.jti,\n ...(typeof data.decisionPayloadDigest === 'string' ? { decisionPayloadDigest: data.decisionPayloadDigest } : {}),\n ...(typeof data.claimsDigest === 'string' ? { claimsDigest: data.claimsDigest } : {}),\n }];\n });\n }\n\n /** The DEAD seals, oldest death first: what an operator reviews before re-driving one. */\n /** A frozen DEAD seal is listed too (#3000): an operator re-drives it like any other. */\n async listDead(limit: number): Promise<ApprovalSealRelayRow[]> {\n const bounds = { sort: [{ field: 'deadAt', order: SortOrder.ASC }, { field: '_id', order: SortOrder.ASC }], limit };\n const [live, retained] = await Promise.all([\n this.repositoriesRegistry.findManyForInfrastructure<Record<string, unknown>>(SEALS, { status: Status.DEAD }, undefined, undefined, bounds),\n this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<Record<string, unknown>>(SEALS, { status: Status.DEAD }, undefined, undefined, bounds),\n ]);\n const seals = [...live.map((row) => ({ row, retained: false })), ...retained.map((row) => ({ row, retained: true }))].flatMap(({ row, retained: isRetained }) => {\n const parsed = ApprovalSealSchema.safeParse(row);\n return parsed.success ? [isRetained ? { ...parsed.data, retained: true as const } : parsed.data] : [];\n });\n seals.sort((first, second) => (first.deadAt?.getTime() ?? 0) - (second.deadAt?.getTime() ?? 0) || first._id.localeCompare(second._id));\n return seals.slice(0, limit);\n }\n\n /** Lease one due seal. Writes nothing for a seal that is not due now, or one behind the seal it supersedes. */\n async lease(due: ApprovalSealRelayRow): Promise<ApprovalSealLeaseResult> {\n const now = this.clock().getTime();\n const isDue = due.status === Status.PENDING\n ? due.nextAttemptAt.getTime() <= now\n : due.status === Status.IN_FLIGHT && due.leaseExpiresAt !== undefined && due.leaseExpiresAt.getTime() <= now;\n if (!isDue) return { outcome: ApprovalSealLeaseOutcome.NOT_DUE };\n if (due.supersedesSealId) {\n // A frozen earlier seal is still signed (#3000), so a later answer still waits for it.\n const earlier = await this.readIncludingRetained(due.supersedesSealId);\n if (earlier && earlier.status !== Status.SEALED && earlier.status !== Status.DEAD) return { outcome: ApprovalSealLeaseOutcome.NOT_DUE };\n }\n const row = await this.guardedWrite(due,\n { _id: due._id, status: due.status, attemptCount: due.attemptCount },\n { set: { status: Status.IN_FLIGHT, leaseExpiresAt: new Date(now + APPROVAL_SEAL_LEASE_MS) }, increment: { attemptCount: 1 } },\n );\n return row ? { outcome: ApprovalSealLeaseOutcome.LEASED, row } : { outcome: ApprovalSealLeaseOutcome.LOST };\n }\n\n /**\n * #2903 S6b: the leased seal's presentation, over the inline ceiling, now held in a frozen file. Written under the lease\n * (the same compare-and-swap a settle uses, without moving `attemptCount`), BEFORE the seal is signed, so a SEALED seal\n * is still never written again. Null when this relay no longer holds the lease; the file then belongs to no seal and\n * the next holder writes its own.\n */\n async externalizePresentation(leased: ApprovalSealRelayRow, file: ApprovalSealPresentationFile): Promise<ApprovalSealRelayRow | null> {\n // A frozen seal keeps its presentation in the row: the presentation is not a field its completion may write (#3000).\n if (!leased.presentation?.content || leased.retained) return leased;\n const { content: _content, ...kept } = leased.presentation;\n const row = await this.repositoriesRegistry.atomicGuardedMutation<Record<string, unknown>>(SEALS,\n { _id: leased._id, status: Status.IN_FLIGHT, attemptCount: leased.attemptCount },\n // The top-level id is the seal's attested file reference: it freezes the file (#2903 review F1).\n { set: { presentation: { ...kept, file }, presentationFileId: file.fileId } },\n );\n return row ? parseSeal(row) : null;\n }\n\n /**\n * The custodian signed the leased seal. Null when this relay no longer holds the lease. A SEALED seal is final, so the\n * deliverable's manifested copy (#2907), made from the signature, is named in this same write.\n */\n markSealed(leased: ApprovalSealRelayRow, signature: SignatureResponse, manifestedCopy?: { readonly fileId: string; readonly at: Date }): Promise<ApprovalSealRelayRow | null> {\n // The JWS's own account of itself, the custodian's only where the JWS is silent (#2932 review M2).\n const signed = signedFactsOfJws(signature.jws);\n return this.settle(leased, {\n set: {\n status: Status.SEALED, jws: signature.jws, kid: signed.kid ?? signature.kid, iss: signed.iss ?? signature.iss, iat: signed.iat ?? signature.iat,\n claimsDigest: signed.claimsDigest ?? signature.claimsDigest, lateSeal: signature.lateSeal, sealedAt: this.clock(),\n // Never on a frozen seal: its completion writes only the relay's fields, and its approver's name is gone (#3000).\n ...(manifestedCopy && !leased.retained ? { manifestedCopy: { fileId: manifestedCopy.fileId, updatedAt: manifestedCopy.at }, manifestedCopyAt: manifestedCopy.at } : {}),\n },\n clear: [...SETTLED_CLEARS, 'lastRefusal'],\n });\n }\n\n /**\n * An operator's rebuild names a new manifested copy on a SEALED seal (#2907): the one write a SEALED seal takes after\n * it is signed, and it touches only the copy and its instant, which the signature does not cover. Guarded on the\n * status and on `attemptCount`, the row's write fence, which it advances, so of two rebuilds racing one wins and the\n * other's copy is discarded. A live seal only: one its approver's erasure retained is not found by this door.\n */\n replaceManifestedCopy(sealed: ApprovalSealRelayRow, copy: { readonly fileId: string; readonly at: Date }): Promise<ApprovalSealRelayRow | null> {\n if (sealed.retained || sealed.status !== Status.SEALED) return Promise.resolve(null);\n return this.guardedWrite(sealed, { _id: sealed._id, status: Status.SEALED, attemptCount: sealed.attemptCount }, {\n set: { manifestedCopy: { fileId: copy.fileId, updatedAt: copy.at }, manifestedCopyAt: copy.at },\n increment: { attemptCount: 1 },\n });\n }\n\n /** A refusal asking again can cure: back to PENDING, asked again after the backoff of this attempt. */\n markRetry(leased: ApprovalSealRelayRow, refusal: CryptoKey_SignatureRefusal | null): Promise<ApprovalSealRelayRow | null> {\n const nextAttemptAt = new Date(this.clock().getTime() + approvalSealRetryDelayMs(leased.attemptCount));\n return this.settle(leased, {\n set: { status: Status.PENDING, nextAttemptAt, ...(refusal ? { lastRefusal: refusal } : {}) },\n clear: [...SETTLED_CLEARS, ...(refusal ? [] : ['lastRefusal'])],\n });\n }\n\n /** A refusal asking again cannot cure: DEAD, until an operator re-drives it. */\n markDead(leased: ApprovalSealRelayRow, refusal: CryptoKey_SignatureRefusal | null): Promise<ApprovalSealRelayRow | null> {\n return this.settle(leased, {\n set: { status: Status.DEAD, deadAt: this.clock(), ...(refusal ? { lastRefusal: refusal } : {}) },\n clear: [...SETTLED_CLEARS, ...(refusal ? [] : ['lastRefusal'])],\n });\n }\n\n /**\n * An operator re-drives a DEAD seal (#2903 S4): back to PENDING, due now. Its decision instant, claims and identity are\n * untouched, so the seal the custodian then signs says when the person decided, and the verifier shows it late.\n */\n revive(dead: ApprovalSealRelayRow): Promise<ApprovalSealRelayRow | null> {\n if (dead.status !== Status.DEAD) return Promise.resolve(null);\n return this.settle(dead, { set: { status: Status.PENDING, nextAttemptAt: this.clock() }, clear: ['deadAt'] }, Status.DEAD);\n }\n\n private settle(\n held: ApprovalSealRelayRow,\n mutation: { readonly set: Record<string, unknown>; readonly clear?: readonly string[] },\n expectedStatus: Status = Status.IN_FLIGHT,\n ): Promise<ApprovalSealRelayRow | null> {\n return this.guardedWrite(held, { _id: held._id, status: expectedStatus, attemptCount: held.attemptCount }, mutation);\n }\n\n /** One compare-and-swap, through the door the seal was read through: the retained one for a frozen seal (#3000). */\n private async guardedWrite(\n held: ApprovalSealRelayRow,\n filter: Record<string, unknown>,\n mutation: { readonly set?: Record<string, unknown>; readonly clear?: readonly string[]; readonly increment?: Record<string, number> },\n ): Promise<ApprovalSealRelayRow | null> {\n const row = held.retained\n ? await this.repositoriesRegistry.completeRetainedRowForInfrastructure<Record<string, unknown>>(SEALS, filter, mutation)\n : await this.repositoriesRegistry.atomicGuardedMutation<Record<string, unknown>>(SEALS, filter, mutation);\n return row ? parseSeal(row, held.retained === true) : null;\n }\n}\n"]}
|
|
@@ -114,6 +114,14 @@ export interface DecisionSealServices {
|
|
|
114
114
|
export type DecisionSealFacts = Omit<PendingApprovalSealInput, 'applicationId' | 'approver' | 'requester'> & {
|
|
115
115
|
readonly approverUserId: string;
|
|
116
116
|
readonly requester?: Pick<HumanDecision_Requester, 'kind' | 'ref' | 'clientId'>;
|
|
117
|
+
/**
|
|
118
|
+
* #2914: this decision REPLACES the latest earlier approval made through the same tool on the same record (its tool
|
|
119
|
+
* declares `approvalReplacesEarlierApprovalOfRow`): a month signed off again after a reopen is a new decision, and its
|
|
120
|
+
* seal must still name the sign-off it replaces. Honoured only when the decision supersedes none of its own seals.
|
|
121
|
+
*/
|
|
122
|
+
readonly replacesEarlierApprovalOfSubject?: {
|
|
123
|
+
readonly toolName: string;
|
|
124
|
+
};
|
|
117
125
|
};
|
|
118
126
|
/**
|
|
119
127
|
* Seal a person's decision in the transaction that settles it: read the approver's (and a person requester's) printed
|
|
@@ -147,6 +155,25 @@ export declare class ApprovalSealStore {
|
|
|
147
155
|
readonly step?: number;
|
|
148
156
|
readonly sequence?: number;
|
|
149
157
|
}, options?: RepositoryOptions): Promise<ApprovalSeal | null>;
|
|
158
|
+
/**
|
|
159
|
+
* The LATEST seal of another decision made through the tool `toolName` on the record `subject`, in the same source and
|
|
160
|
+
* tenant (#2914): what a decision that replaces it supersedes. A seal its approver's erasure retained counts, as in
|
|
161
|
+
* {@link readOfDecision}. The tool is read from the seal's own presentation (`toolName`), the one place a seal records
|
|
162
|
+
* it; a seal whose presentation is not inline (moved to a file, or removed by an erasure) cannot be attributed to a
|
|
163
|
+
* tool and is passed over rather than guessed. Reads the most recent {@link SUBJECT_SEAL_SCAN_LIMIT} seals of the record.
|
|
164
|
+
*/
|
|
165
|
+
readLatestOfSubject(identity: {
|
|
166
|
+
readonly source: ApprovalSource;
|
|
167
|
+
readonly subject: {
|
|
168
|
+
readonly resourceType: string;
|
|
169
|
+
readonly resourceId: string;
|
|
170
|
+
};
|
|
171
|
+
readonly toolName: string;
|
|
172
|
+
readonly exceptDecisionRef: string;
|
|
173
|
+
readonly organizationId?: string;
|
|
174
|
+
}, options?: RepositoryOptions): Promise<ApprovalSeal | null>;
|
|
150
175
|
}
|
|
176
|
+
/** How many of a record's most recent seals {@link ApprovalSealStore.readLatestOfSubject} reads to find a tool's latest. */
|
|
177
|
+
export declare const SUBJECT_SEAL_SCAN_LIMIT = 50;
|
|
151
178
|
export {};
|
|
152
179
|
//# sourceMappingURL=approval-seal-store.backend.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-seal-store.backend.d.ts","sourceRoot":"","sources":["../../../../src/compliance/approval-seals/approval-seal-store.backend.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"approval-seal-store.backend.d.ts","sourceRoot":"","sources":["../../../../src/compliance/approval-seals/approval-seal-store.backend.ts"],"names":[],"mappings":"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"}
|
|
@@ -200,10 +200,20 @@ export function deciderRecordOfSeal(seal) {
|
|
|
200
200
|
* back leaves no seal and one that commits has exactly one.
|
|
201
201
|
*/
|
|
202
202
|
export async function sealDecisionInTransaction(services, facts, options) {
|
|
203
|
-
const { approverUserId, requester, ...decision } = facts;
|
|
203
|
+
const { approverUserId, requester, replacesEarlierApprovalOfSubject, ...decision } = facts;
|
|
204
204
|
const store = new ApprovalSealStore(services.repositoriesRegistry);
|
|
205
205
|
// A step answered before (its answer put back on the question, then answered again) is superseded, never collided with.
|
|
206
|
-
const
|
|
206
|
+
const latestOfDecision = await store.readOfDecision({ source: decision.source, decisionRef: decision.decisionRef, step: decision.step ?? 0 }, options);
|
|
207
|
+
// #2914: a decision that replaces an earlier one on the same record (another decision of the same tool) supersedes its
|
|
208
|
+
// latest seal. The same supersession, one level up: the new seal names it, and the trail records it SUPERSEDED. Its own
|
|
209
|
+
// sequence stays 1, since it is the first answer of its own decision.
|
|
210
|
+
const replaced = !latestOfDecision && replacesEarlierApprovalOfSubject
|
|
211
|
+
? await store.readLatestOfSubject({
|
|
212
|
+
source: decision.source, subject: decision.subject, toolName: replacesEarlierApprovalOfSubject.toolName,
|
|
213
|
+
exceptDecisionRef: decision.decisionRef, ...(decision.organizationId ? { organizationId: decision.organizationId } : {}),
|
|
214
|
+
}, options)
|
|
215
|
+
: null;
|
|
216
|
+
const latest = latestOfDecision ?? replaced;
|
|
207
217
|
const requesterIsPerson = requester !== undefined && requester.kind !== HumanDecision_RequesterKind.MACHINE;
|
|
208
218
|
const [applicationId, approverName, requesterName] = await Promise.all([
|
|
209
219
|
services.applicationIdentity.getCanonicalApplicationId(),
|
|
@@ -212,7 +222,8 @@ export async function sealDecisionInTransaction(services, facts, options) {
|
|
|
212
222
|
]);
|
|
213
223
|
const prepared = prepareApprovalSeal({
|
|
214
224
|
...decision,
|
|
215
|
-
...(
|
|
225
|
+
...(latestOfDecision ? { sequence: latestOfDecision.sequence + 1 } : {}),
|
|
226
|
+
...(latest ? { supersedes: { sealId: latest._id, jti: String(latest.claims.jti) } } : {}),
|
|
216
227
|
applicationId,
|
|
217
228
|
approver: { userId: approverUserId, ...(approverName ? { name: approverName } : {}) },
|
|
218
229
|
...(requester ? {
|
|
@@ -279,5 +290,33 @@ export class ApprovalSealStore {
|
|
|
279
290
|
return live ?? retained ?? null;
|
|
280
291
|
return live.sequence >= retained.sequence ? live : retained;
|
|
281
292
|
}
|
|
293
|
+
/**
|
|
294
|
+
* The LATEST seal of another decision made through the tool `toolName` on the record `subject`, in the same source and
|
|
295
|
+
* tenant (#2914): what a decision that replaces it supersedes. A seal its approver's erasure retained counts, as in
|
|
296
|
+
* {@link readOfDecision}. The tool is read from the seal's own presentation (`toolName`), the one place a seal records
|
|
297
|
+
* it; a seal whose presentation is not inline (moved to a file, or removed by an erasure) cannot be attributed to a
|
|
298
|
+
* tool and is passed over rather than guessed. Reads the most recent {@link SUBJECT_SEAL_SCAN_LIMIT} seals of the record.
|
|
299
|
+
*/
|
|
300
|
+
async readLatestOfSubject(identity, options) {
|
|
301
|
+
const filter = { source: identity.source, linkedResourceType: identity.subject.resourceType, linkedResourceId: identity.subject.resourceId };
|
|
302
|
+
const bounds = { sort: [{ field: 'decidedAt', order: SortOrder.DESC }], limit: SUBJECT_SEAL_SCAN_LIMIT };
|
|
303
|
+
// Sequential, like `readOfDecision`: both run in the decision's transaction.
|
|
304
|
+
const live = await this.repositoriesRegistry.findManyForInfrastructure(SEALS, filter, undefined, options, bounds);
|
|
305
|
+
const retained = await this.repositoriesRegistry.findRetainedForCompletionForInfrastructure(SEALS, filter, undefined, options, bounds);
|
|
306
|
+
const candidates = [...live, ...retained]
|
|
307
|
+
.filter((seal) => seal.decisionRef !== identity.exceptDecisionRef
|
|
308
|
+
&& (seal.organizationId ?? undefined) === identity.organizationId
|
|
309
|
+
&& approvalSealToolNameOf(seal) === identity.toolName)
|
|
310
|
+
.sort((first, second) => new Date(second.decidedAt).getTime() - new Date(first.decidedAt).getTime() || second.sequence - first.sequence);
|
|
311
|
+
return candidates[0] ?? null;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/** How many of a record's most recent seals {@link ApprovalSealStore.readLatestOfSubject} reads to find a tool's latest. */
|
|
315
|
+
export const SUBJECT_SEAL_SCAN_LIMIT = 50;
|
|
316
|
+
/** The tool a seal's inline presentation names, when it names one (a tool approval's card). */
|
|
317
|
+
function approvalSealToolNameOf(seal) {
|
|
318
|
+
const content = seal.presentation?.content;
|
|
319
|
+
const toolName = content !== null && typeof content === 'object' ? content.toolName : undefined;
|
|
320
|
+
return typeof toolName === 'string' ? toolName : undefined;
|
|
282
321
|
}
|
|
283
322
|
//# sourceMappingURL=approval-seal-store.backend.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-seal-store.backend.js","sourceRoot":"","sources":["../../../../src/compliance/approval-seals/approval-seal-store.backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EACL,sBAAsB,EACtB,2BAA2B,EAC3B,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,SAAS,EACT,2BAA2B,EAC3B,kBAAkB,EAClB,+BAA+B,GAQhC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,4BAA4B,EAC5B,0BAA0B,EAC1B,+BAA+B,EAC/B,2BAA2B,EAC3B,8BAA8B,EAC9B,uBAAuB,EACvB,6BAA6B,EAC7B,kBAAkB,GAGnB,MAAM,+BAA+B,CAAC;AAOvC,OAAO,EAAE,mCAAmC,EAAE,MAAM,mDAAmD,CAAC;AACxG,OAAO,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AAGvG,MAAM,KAAK,GAAG,gBAAgB,CAAC,cAA8B,CAAC;AAoD9D;;;;GAIG;AACH,SAAS,iBAAiB;IACxB,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC;AAED,4HAA4H;AAC5H,SAAS,WAAW,CAAC,KAA8B;IACjD,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC;AAChG,CAAC;AAED,SAAS,YAAY,CAAC,SAAsC,EAAE,KAA8B;IAC1F,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,6BAA6B,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;AACzF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAA+B,EAAE,MAAY,IAAI,IAAI,EAAE;IACzF,IAAI,CAAE,sBAA4C,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,KAAK,CAAC,mEAAmE,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC;IACvG,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;IAC7B,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,kBAAkB,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC9G,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IAE1B,MAAM,QAAQ,GAAG,YAAY,CAAC,2BAA2B,CAAC,QAAQ,EAAE;QAClE,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM;QAC7B,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,IAAI;QACzB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,qHAAqH;QACrH,0GAA0G;QAC1G,eAAe,EAAE,OAAO,CAAC,eAAe;QACxC,kBAAkB,EAAE,OAAO,CAAC,kBAAkB;QAC9C,iBAAiB,EAAE,OAAO,CAAC,eAAe,EAAE,iBAAiB;KAC9D,CAAC,CAAC;IACH,MAAM,iBAAiB,GAAG,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,KAAK,2BAA2B,CAAC,OAAO,CAAC;IACxH,MAAM,SAAS,GAAG,iBAAiB;QACjC,CAAC,CAAC,YAAY,CAAC,2BAA2B,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,SAAU,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,SAAU,CAAC,IAAI,EAAE,CAAC;QACpH,CAAC,CAAC,SAAS,CAAC;IACd,mHAAmH;IACnH,MAAM,YAAY,GAAG,KAAK,CAAC,YAAY;QACrC,CAAC,CAAC,EAAE,SAAS,EAAE,2BAA2B,CAAC,YAAY,EAAE,IAAI,EAAE,6BAA6B,EAAE,EAAE,KAAK,EAAE,EAAE,GAAG,KAAK,CAAC,YAAY,CAAC,OAAO,EAA6B,EAAE;QACrK,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS;QAC/B,CAAC,CAAC,EAAE,SAAS,EAAE,2BAA2B,CAAC,SAAS,EAAE,IAAI,EAAE,6BAA6B,EAAE,EAAE,KAAK,EAAE,EAAE,GAAG,KAAK,CAAC,SAAS,EAA6B,EAAE;QACvJ,CAAC,CAAC,SAAS,CAAC;IACd,qGAAqG;IACrG,MAAM,eAAe,GAAG,KAAK,CAAC,eAAe,IAAI,+BAA+B,CAAC,KAAK,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC;QACzI,CAAC,CAAC,KAAK,CAAC,eAAe;QACvB,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,MAAM,GAAG,0BAA0B,CAAC,KAAK,CAAC;QAC9C,CAAC,EAAE,4BAA4B;QAC/B,GAAG,EAAE,kBAAkB,EAAE;QACzB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,IAAI;QACJ,QAAQ;QACR,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,MAAM,EAAE,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,aAAa;QACnD,OAAO,EAAE;YACP,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,YAAY;YACxC,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU;YACpC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,yBAAyB,EAAE,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACvG;QACD,GAAG,CAAC,KAAK,CAAC,YAAY,IAAI,YAAY,CAAC,CAAC,CAAC;YACvC,YAAY,EAAE;gBACZ,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC/D,UAAU,EAAE,KAAK,CAAC,YAAY,CAAC,UAAU;gBACzC,MAAM,EAAE,8BAA8B,CAAC,YAAY,CAAC;aACrD;SACF,CAAC,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,8BAA8B,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpF,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC;QACvD,OAAO,EAAE,WAAW,CAAC;YACnB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,kBAAkB,EAAE,OAAO,CAAC,kBAAkB;YAC9C,gBAAgB,EAAE,OAAO,CAAC,eAAe,EAAE,gBAAgB;SAC5D,CAAC;QACF,GAAG,CAAC,KAAK,CAAC,SAAS;YACjB,CAAC,CAAC;gBACE,SAAS,EAAE,WAAW,CAAC;oBACrB,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,IAAI;oBAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,QAAQ;oBAClC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,8BAA8B,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS;iBAC9E,CAAC;aACH;YACH,CAAC,CAAC,EAAE,CAAC;QACP,QAAQ,EAAE,8BAA8B,CAAC,QAAQ,CAAC;KACnD,CAAC,CAAC;IACH,MAAM,qBAAqB,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAE9D,MAAM,GAAG,GAAG,kBAAkB,CAAC,KAAK,CAAC;QACnC,GAAG,EAAE,iBAAiB,EAAE;QACxB,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,IAAI;QACJ,QAAQ;QACR,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1E,QAAQ;QACR,kBAAkB,EAAE,KAAK,CAAC,OAAO,CAAC,YAAY;QAC9C,gBAAgB,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU;QAC1C,cAAc,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM;QACrC,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,mBAAmB,EAAE,2BAA2B,CAAC,QAAQ;QACzD,MAAM;QACN,qBAAqB;QACrB,WAAW,EAAE,CAAC,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,EAAE,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC;QAC5D,mGAAmG;QACnG,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,KAAK,CAAC,SAAU,CAAC,GAAG,EAAE,mBAAmB,EAAE,EAAE,GAAG,SAAS,EAAE,KAAK,EAAE,EAAE,GAAG,SAAS,CAAC,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrI,GAAG,CAAC,KAAK,CAAC,YAAY,IAAI,YAAY,CAAC,CAAC,CAAC;YACvC,YAAY,EAAE;gBACZ,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC/D,UAAU,EAAE,KAAK,CAAC,YAAY,CAAC,UAAU;gBACzC,aAAa,EAAE,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,aAAa;gBACvD,IAAI,EAAE,YAAY,CAAC,IAAI;gBACvB,OAAO,EAAE,YAAY,CAAC,KAAK;aAC5B;SACF,CAAC,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvF,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,eAAe,CAAC,MAAM,EAAE,mBAAmB,EAAE,eAAe,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpH,MAAM,EAAE,kBAAkB,CAAC,OAAO;QAClC,YAAY,EAAE,CAAC;QACf,aAAa,EAAE,GAAG;QAClB,SAAS,EAAE,GAAG;QACd,SAAS,EAAE,GAAG;KACf,CAAC,CAAC;IACH,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC;AAChD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,YAA8D,EAAE,MAAc;IAC3H,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,YAAY,CAC1C,gBAAgB,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,mBAAmB,EAAE,IAAI,EAAW,CAChF,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACpB,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvH,OAAO,IAAI,CAAC,WAAW,IAAI,MAAM,IAAI,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC;AAC/D,CAAC;AAID;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAkC;IACpE,MAAM,MAAM,GAAG,+BAA+B,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9E,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IACtC,MAAM,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,GAAG,OAAO,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC;IACxE,OAAO,OAAO,CAAC;AACjB,CAAC;AA+BD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,QAA8B,EAAE,KAAwB,EAAE,OAA0B;IAClI,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,CAAC;IACzD,MAAM,KAAK,GAAG,IAAI,iBAAiB,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;IACnE,wHAAwH;IACxH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,cAAc,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IAC7I,MAAM,iBAAiB,GAAG,SAAS,KAAK,SAAS,IAAI,SAAS,CAAC,IAAI,KAAK,2BAA2B,CAAC,OAAO,CAAC;IAC5G,MAAM,CAAC,aAAa,EAAE,YAAY,EAAE,aAAa,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACrE,QAAQ,CAAC,mBAAmB,CAAC,yBAAyB,EAAE;QACxD,wBAAwB,CAAC,QAAQ,CAAC,YAAY,EAAE,cAAc,CAAC;QAC/D,iBAAiB,CAAC,CAAC,CAAC,wBAAwB,CAAC,QAAQ,CAAC,YAAY,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;KAC/F,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,mBAAmB,CAAC;QACnC,GAAG,QAAQ;QACX,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,GAAG,CAAC,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxH,aAAa;QACb,QAAQ,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;QACrF,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;YACd,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;SAC5K,CAAC,CAAC,CAAC,EAAE,CAAC;KACR,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IACvB,MAAM,KAAK,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC7C,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC,WAAW,IAAI,EAAE,CAAC;IACxD,IAAI,OAAO,CAAC,WAAW,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,EAAE,CAAC;QAChD,mCAAmC,CAAC,OAAO,CAAC,WAAW,EAAE;YACvD,GAAG,EAAE,yBAAyB,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE;YAChD,OAAO,EAAE,KAAK,IAAI,EAAE;gBAClB,MAAM,OAAO,CAAC,GAAG,CAAC;oBAChB,SAAS,EAAE,oBAAoB,CAAC,wBAAwB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;oBACvE,MAAM,CAAC,CAAC,CAAC,SAAS,EAAE,oBAAoB,CAAC,2BAA2B,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;iBACxG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;gBAC1B,kHAAkH;gBAClH,6GAA6G;gBAC7G,KAAK,KAAK,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3C,CAAC;SACF,CAAC,CAAC;IACL,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,+GAA+G;AAC/G,MAAM,OAAO,iBAAiB;IACC;IAA7B,YAA6B,oBAA8B;QAA9B,yBAAoB,GAApB,oBAAoB,CAAU;IAAG,CAAC;IAE/D;;;;OAIG;IACH,KAAK,CAAC,aAAa,CAAC,QAA8B,EAAE,OAA0B;QAC5E,IAAI,CAAC,OAAO,EAAE,WAAW;YAAE,MAAM,IAAI,KAAK,CAAC,+EAA+E,CAAC,CAAC;QAC5H,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,KAAK,kBAAkB,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QACjI,MAAM,IAAI,CAAC,oBAAoB,CAAC,+BAA+B,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QACzG,OAAO,QAAQ,CAAC,GAAG,CAAC;IACtB,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,cAAc,CAClB,QAA+H,EAC/H,OAA2B;QAE3B,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAC;QAChC,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,KAAK,SAAS;YAC5C,CAAC,CAAC,EAAE,QAAQ,EAAE,kBAAkB,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE;YACrI,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC;QACzE,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAClF,mGAAmG;QACnG,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,yBAAyB,CAAe,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAClI,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,0CAA0C,CAAe,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACvJ,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,IAAI,QAAQ,IAAI,IAAI,CAAC;QACxD,OAAO,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC9D,CAAC;CACF","sourcesContent":["/**\n * # Approval seals: the PENDING row a decision writes (#2903)\n *\n * A decision that a person answered (approved, approved with modifications, rejected) writes ONE `approvalSeals` row in\n * the transaction that settles it. That row is its own outbox: the relay signs it later through the platform custodian\n * (#2891), so signing never blocks, slows or fails the decision, and a crash between the commit and the signing leaves\n * one PENDING row, sealed once.\n *\n * {@link prepareApprovalSeal} builds the row from what the decision door verified; it is pure, so each plane prepares it\n * where it holds the facts and writes it where it holds the transaction. {@link ApprovalSealStore.insertPending} is the\n * one write, and it requires that transaction: a seal written beside a decision rather than with it could exist for a\n * decision that rolled back, or be missing for one that committed.\n *\n * ## What the payload says, and what only the row knows\n *\n * The claims ({@link ApprovalSealClaimsV1}) name no person and carry no stable pseudonym of one. The approver, and a\n * requester who is a person, are each ONE salted disclosure: the payload carries its digest, the row its salt and clear\n * value. So a seal shared alone confirms nothing about who decided, and the approver's erasure removes the disclosures\n * and leaves a seal that still verifies, with that content reported as erased.\n *\n * The decider's session id and chat identity link stay inside the approver's disclosure, never in the payload: each is\n * a handle on the person (#2905).\n */\nimport { randomBytes } from 'node:crypto';\nimport {\n APPROVAL_SEAL_OUTCOMES,\n ApprovalPresentationCapture,\n ApprovalSealSchema,\n ApprovalSealStatus,\n CoreResourceType,\n SortOrder,\n HumanDecision_RequesterKind,\n approvalSealSlotOf,\n humanDecisionBoundDeliverableOf,\n type ApprovalSeal,\n type ApprovalSealMeaning,\n type ApprovalSealOutcome,\n type ApprovalSource,\n type HumanDecision_DeciderRecord,\n type HumanDecision_Requester,\n type ResourceType,\n} from '@wildo-ai/saas-models';\nimport {\n APPROVAL_SEAL_CLAIMS_VERSION,\n ApprovalSealClaimsV1Schema,\n ApprovalSealDeciderClaimsSchema,\n ApprovalSealDisclosureClaim,\n approvalSealDisclosureDigestOf,\n decisionPayloadDigestOf,\n newApprovalSealDisclosureSalt,\n newApprovalSealJti,\n type ApprovalSealClaimsV1,\n type ApprovalSealDisclosureValue,\n} from '@wildo-ai/platform-config-lib';\nimport type { RepositoriesRegistryHandlerBackendService } from '../../base-classes/services/repositories/repositories-registry-handler.backend.service';\nimport type { RepositoryOptions } from '../../base-classes/models/repositories.backend.schemas';\nimport type { SystemAccessBackendService } from '../../base-classes/services/services/system-access.backend.service';\nimport type { ApplicationIdentityBackendService } from '../../applications/services/application-identity.backend.service';\nimport type { AuditLogsBackendService } from '../audit-trails/services/audit-logs.backend.service';\nimport type { ApprovalSealRelayBackendService } from './approval-seal-relay.backend.service';\nimport { registerTransactionPostCommitEffect } from '../../databases/models/transaction.shared.schemas';\nimport { approvalSealPendingEvent, approvalSealSupersededEvent } from './approval-seal-events.backend';\nimport type { DecisionStatement, SealedDecisionPresentation } from './decision-presentation.backend';\n\nconst SEALS = CoreResourceType.APPROVAL_SEALS as ResourceType;\n\n/** What a decision door knows when a person's answer settles: everything the seal says, nothing it computes. */\nexport interface PendingApprovalSealInput {\n readonly applicationId: string;\n /** The organization the decision belongs to; absent when it belongs to none (the tenant is then the application). */\n readonly organizationId?: string;\n readonly source: ApprovalSource;\n /** The decision's own id on its source. */\n readonly decisionRef: string;\n /** Which approver of several, from 0. Defaults to 0. */\n readonly step?: number;\n /**\n * From 1, incremented by a reopen of the same decision. Defaults to 1 here; {@link sealDecisionInTransaction} sets it\n * one past the step's latest seal, which it then supersedes (an answer put back on its question and answered again).\n */\n readonly sequence?: number;\n /** The seal this one supersedes, when a later decision on the same subject replaces it. */\n readonly supersedes?: { readonly sealId: string; readonly jti: string };\n /** The record decided about. */\n readonly subject: { readonly resourceType: string; readonly resourceId: string };\n readonly outcome: ApprovalSealOutcome;\n readonly meaning: ApprovalSealMeaning;\n /** When the person answered. */\n readonly decidedAt: Date;\n /** How the person who answered was authenticated, as the door verified it (#2905). */\n readonly decider: HumanDecision_DeciderRecord;\n readonly approver: { readonly userId: string; readonly name?: string };\n /** Who asked. A person's name joins their disclosure; a machine is named by kind only. */\n readonly requester?: Pick<HumanDecision_Requester, 'kind' | 'ref' | 'clientId'> & { readonly name?: string };\n /**\n * What the person was shown (#2903 S6), checked against the decision's row by the door that took the answer\n * (`acknowledgeDecisionPresentation`). Absent only for a plane that builds no presentation.\n */\n readonly presentation?: SealedDecisionPresentation;\n /** What the person answered (`decisionStatementOf`). */\n readonly statement?: DecisionStatement;\n /**\n * The file deliverable the presentation binds (#2904), with the salt its commitment was made with\n * (`resolveDecisionDeliverables`). Written onto the row only when `presentation` binds that file (a BOUND deliverable):\n * a card that did not show the file (a chat card without the call's arguments) seals no file.\n */\n readonly deliverableFile?: { readonly fileId: string; readonly salt: string };\n}\n\n/** A seal ready to write: the row, the claims it commits to, and the digest the decision's own event carries. */\nexport interface PreparedApprovalSeal {\n readonly row: ApprovalSeal;\n readonly claims: ApprovalSealClaimsV1;\n readonly decisionPayloadDigest: string;\n}\n\n/**\n * A new seal row id: 96 random bits, 24 hex characters, the width every adapter stores as an id. Not derived from the\n * slot: the slot's uniqueness is the unique index's, which an erased (retained) seal leaves (its index is partial), and a\n * derived id would make the next seal of that slot collide with a row nobody can see.\n */\nfunction newApprovalSealId(): string {\n return randomBytes(12).toString('hex');\n}\n\n/** A disclosure's value without absent members: the canonical form refuses `undefined`, and absence must not be a value. */\nfunction presentOnly(value: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(Object.entries(value).filter(([, member]) => member !== undefined));\n}\n\nfunction disclosureOf(claimName: ApprovalSealDisclosureClaim, value: Record<string, unknown>): ApprovalSealDisclosureValue {\n return { claimName, salt: newApprovalSealDisclosureSalt(), value: presentOnly(value) };\n}\n\n/**\n * Build a PENDING seal. Pure: the caller writes it with {@link ApprovalSealStore.insertPending} in the transaction that\n * settles the decision. Refuses an outcome no person decided, so a lapse or a withdrawal can never be sealed as one.\n */\nexport function prepareApprovalSeal(input: PendingApprovalSealInput, now: Date = new Date()): PreparedApprovalSeal {\n if (!(APPROVAL_SEAL_OUTCOMES as readonly string[]).includes(input.outcome)) {\n throw new Error(`An approval seal records only an outcome a person decided, not \"${input.outcome}\"`);\n }\n const step = input.step ?? 0;\n const sequence = input.sequence ?? 1;\n const sealSlot = approvalSealSlotOf({ source: input.source, decisionRef: input.decisionRef, step, sequence });\n const { decider } = input;\n\n const approver = disclosureOf(ApprovalSealDisclosureClaim.APPROVER, {\n userId: input.approver.userId,\n name: input.approver.name,\n authTime: decider.authTime,\n sessionId: decider.sessionId,\n // #2923: a passkey assertion that signed a challenge naming this decision. Salted with the rest of the approver: its\n // credential id links the person across decisions, so it is never a claim in clear (WebAuthn L3 §14.6.3).\n stepUpAssertion: decider.stepUpAssertion,\n chatIdentityLinkId: decider.chatIdentityLinkId,\n inboundDeliveryId: decider.answeredThrough?.inboundDeliveryId,\n });\n const requesterIsPerson = input.requester !== undefined && input.requester.kind !== HumanDecision_RequesterKind.MACHINE;\n const requester = requesterIsPerson\n ? disclosureOf(ApprovalSealDisclosureClaim.REQUESTER, { userId: input.requester!.ref, name: input.requester!.name })\n : undefined;\n // #2903 S6: what was shown and what was answered, each committed to by a salted digest like a person's disclosure.\n const presentation = input.presentation\n ? { claimName: ApprovalSealDisclosureClaim.PRESENTATION, salt: newApprovalSealDisclosureSalt(), value: { ...input.presentation.content } as Record<string, unknown> }\n : undefined;\n const statement = input.statement\n ? { claimName: ApprovalSealDisclosureClaim.STATEMENT, salt: newApprovalSealDisclosureSalt(), value: { ...input.statement } as Record<string, unknown> }\n : undefined;\n // #2904: the file the person approved, attested only when what they were shown commits to its bytes.\n const deliverableFile = input.deliverableFile && humanDecisionBoundDeliverableOf(input.presentation?.content, input.deliverableFile.fileId)\n ? input.deliverableFile\n : undefined;\n\n const claims = ApprovalSealClaimsV1Schema.parse({\n v: APPROVAL_SEAL_CLAIMS_VERSION,\n jti: newApprovalSealJti(),\n source: input.source,\n decisionRef: input.decisionRef,\n step,\n sequence,\n ...(input.supersedes ? { supersedes: input.supersedes.jti } : {}),\n tenant: input.organizationId ?? input.applicationId,\n subject: {\n resourceType: input.subject.resourceType,\n resourceId: input.subject.resourceId,\n ...(input.presentation ? { presentationSchemaVersion: input.presentation.content.schemaVersion } : {}),\n },\n ...(input.presentation && presentation ? {\n presentation: {\n ...(input.presentation.id ? { id: input.presentation.id } : {}),\n provenance: input.presentation.provenance,\n digest: approvalSealDisclosureDigestOf(presentation),\n },\n } : {}),\n ...(statement ? { statementDigest: approvalSealDisclosureDigestOf(statement) } : {}),\n meaning: input.meaning,\n outcome: input.outcome,\n decidedAt: Math.floor(input.decidedAt.getTime() / 1000),\n decider: presentOnly({\n kind: decider.kind,\n channel: decider.channel,\n act: decider.act,\n authTime: decider.authTime,\n amr: decider.amr,\n stepUpMethod: decider.stepUpMethod,\n stepUpAt: decider.stepUpAt,\n stepUpUserVerified: decider.stepUpUserVerified,\n inboundSourceKey: decider.answeredThrough?.inboundSourceKey,\n }),\n ...(input.requester\n ? {\n requester: presentOnly({\n kind: input.requester.kind,\n clientId: input.requester.clientId,\n disclosure: requester ? approvalSealDisclosureDigestOf(requester) : undefined,\n }),\n }\n : {}),\n approver: approvalSealDisclosureDigestOf(approver),\n });\n const decisionPayloadDigest = decisionPayloadDigestOf(claims);\n\n const row = ApprovalSealSchema.parse({\n _id: newApprovalSealId(),\n applicationId: input.applicationId,\n ...(input.organizationId ? { organizationId: input.organizationId } : {}),\n source: input.source,\n decisionRef: input.decisionRef,\n step,\n sequence,\n ...(input.supersedes ? { supersedesSealId: input.supersedes.sealId } : {}),\n sealSlot,\n linkedResourceType: input.subject.resourceType,\n linkedResourceId: input.subject.resourceId,\n approverUserId: input.approver.userId,\n outcome: input.outcome,\n meaning: input.meaning,\n decidedAt: input.decidedAt,\n presentationCapture: ApprovalPresentationCapture.CAPTURED,\n claims,\n decisionPayloadDigest,\n disclosures: [{ ...approver, value: { ...approver.value } }],\n // The requester's id beside their disclosure (#3001): the column their erasure finds this seal by.\n ...(requester ? { requesterUserId: input.requester!.ref, requesterDisclosure: { ...requester, value: { ...requester.value } } } : {}),\n ...(input.presentation && presentation ? {\n presentation: {\n ...(input.presentation.id ? { id: input.presentation.id } : {}),\n provenance: input.presentation.provenance,\n schemaVersion: input.presentation.content.schemaVersion,\n salt: presentation.salt,\n content: presentation.value,\n },\n } : {}),\n ...(statement ? { statement: { salt: statement.salt, content: statement.value } } : {}),\n ...(deliverableFile ? { deliverableFileId: deliverableFile.fileId, deliverableFileSalt: deliverableFile.salt } : {}),\n status: ApprovalSealStatus.PENDING,\n attemptCount: 0,\n nextAttemptAt: now,\n createdAt: now,\n updatedAt: now,\n });\n return { row, claims, decisionPayloadDigest };\n}\n\n/**\n * A person's printed name, for their disclosure: the display name, else first and last name, else the email. Read as the\n * system, unaudited like any read of a decision's own parties; undefined when the person cannot be read, so a seal is\n * never refused for a name (the disclosure still carries their reference).\n */\nexport async function approvalSealPersonNameOf(systemAccess: Pick<SystemAccessBackendService, 'readAsSystem'>, userId: string): Promise<string | undefined> {\n const user = await systemAccess.readAsSystem<{ displayName?: string; firstName?: string; lastName?: string; email?: string }>(\n CoreResourceType.USERS, { _id: userId }, { suppressSystemAudit: true } as never,\n ).catch(() => null);\n if (!user) return undefined;\n const joined = [user.firstName, user.lastName].filter((part) => typeof part === 'string' && part.length > 0).join(' ');\n return user.displayName || joined || user.email || undefined;\n}\n\ntype Registry = Pick<RepositoriesRegistryHandlerBackendService, 'insertDocumentForInfrastructure' | 'findManyForInfrastructure' | 'findRetainedForCompletionForInfrastructure'>;\n\n/**\n * How a sealed decision's decider was authenticated, read back from the seal's own claims: what an ending recorded after\n * the fact (a repair, whose writer lost the record) states beside its decider. The session is not in the claims, and an\n * answer's inbound delivery stays in the approver's disclosure, so neither is returned. Undefined for claims this version\n * cannot read.\n */\nexport function deciderRecordOfSeal(seal: Pick<ApprovalSeal, 'claims'>): HumanDecision_DeciderRecord | undefined {\n const parsed = ApprovalSealDeciderClaimsSchema.safeParse(seal.claims.decider);\n if (!parsed.success) return undefined;\n const { inboundSourceKey: _inboundSourceKey, ...decider } = parsed.data;\n return decider;\n}\n\n/** What sealing a decision inside its transaction reads: the seal rows, the people's names, and the application. */\nexport interface DecisionSealServices {\n readonly repositoriesRegistry: Registry;\n readonly systemAccess: Pick<SystemAccessBackendService, 'readAsSystem'>;\n /**\n * The APPLICATION record's id, which the seal's `applicationId` column holds and the application scope keys on. Never\n * the platform's id for the process (`AppConfigurationService.applicationId`): the two differ, and a row stamped with\n * the platform's matches no scope predicate.\n */\n readonly applicationIdentity: Pick<ApplicationIdentityBackendService, 'getCanonicalApplicationId'>;\n /**\n * What runs once the decision's transaction COMMITS: the seal's PENDING row on the trail (and the SUPERSEDED row of the\n * seal it replaces), and the relay's best-effort signing, so a seal is usually signed within seconds. Neither may fail\n * the decision: the seal row is durable and the batch signs what the fast path did not. A trail row that cannot be\n * written is dropped, not retried (review F6): the PENDING seal row, committed with the decision, is the record it\n * mirrors, and the relay's settlement writes its own rows.\n */\n readonly afterCommit?: {\n readonly auditLogs?: Pick<AuditLogsBackendService, 'logApprovalSealEvent'>;\n readonly relay?: Pick<ApprovalSealRelayBackendService, 'sealSoon'>;\n };\n}\n\n/** A decision's facts as a plane holds them; the people are named by reference, and their names are read here. */\nexport type DecisionSealFacts = Omit<PendingApprovalSealInput, 'applicationId' | 'approver' | 'requester'> & {\n readonly approverUserId: string;\n readonly requester?: Pick<HumanDecision_Requester, 'kind' | 'ref' | 'clientId'>;\n};\n\n/**\n * Seal a person's decision in the transaction that settles it: read the approver's (and a person requester's) printed\n * name, prepare the seal and write it PENDING. Every plane calls this from inside its settle, so a decision that rolls\n * back leaves no seal and one that commits has exactly one.\n */\nexport async function sealDecisionInTransaction(services: DecisionSealServices, facts: DecisionSealFacts, options: RepositoryOptions): Promise<PreparedApprovalSeal> {\n const { approverUserId, requester, ...decision } = facts;\n const store = new ApprovalSealStore(services.repositoriesRegistry);\n // A step answered before (its answer put back on the question, then answered again) is superseded, never collided with.\n const latest = await store.readOfDecision({ source: decision.source, decisionRef: decision.decisionRef, step: decision.step ?? 0 }, options);\n const requesterIsPerson = requester !== undefined && requester.kind !== HumanDecision_RequesterKind.MACHINE;\n const [applicationId, approverName, requesterName] = await Promise.all([\n services.applicationIdentity.getCanonicalApplicationId(),\n approvalSealPersonNameOf(services.systemAccess, approverUserId),\n requesterIsPerson ? approvalSealPersonNameOf(services.systemAccess, requester.ref) : undefined,\n ]);\n const prepared = prepareApprovalSeal({\n ...decision,\n ...(latest ? { sequence: latest.sequence + 1, supersedes: { sealId: latest._id, jti: String(latest.claims.jti) } } : {}),\n applicationId,\n approver: { userId: approverUserId, ...(approverName ? { name: approverName } : {}) },\n ...(requester ? {\n requester: { kind: requester.kind, ref: requester.ref, ...(requester.clientId ? { clientId: requester.clientId } : {}), ...(requesterName ? { name: requesterName } : {}) },\n } : {}),\n }, decision.decidedAt);\n await store.insertPending(prepared, options);\n const { auditLogs, relay } = services.afterCommit ?? {};\n if (options.transaction && (auditLogs || relay)) {\n registerTransactionPostCommitEffect(options.transaction, {\n key: `approval-seal:pending:${prepared.row._id}`,\n execute: async () => {\n await Promise.all([\n auditLogs?.logApprovalSealEvent(approvalSealPendingEvent(prepared.row)),\n latest ? auditLogs?.logApprovalSealEvent(approvalSealSupersededEvent(latest, prepared.row)) : undefined,\n ]).catch(() => undefined);\n // Not awaited: the adapters await the post-commit drain before the decision's caller is answered, so awaiting the\n // custodian's round trip here would hold every decision for it (up to its timeout). `sealSoon` never throws.\n void relay?.sealSoon([prepared.row._id]);\n },\n });\n }\n return prepared;\n}\n\n/** The `approvalSeals` rows: the PENDING write a decision makes, and the reads that find a decision's seal. */\nexport class ApprovalSealStore {\n constructor(private readonly repositoriesRegistry: Registry) {}\n\n /**\n * Write a PENDING seal in the decision's transaction. Requires the transaction: a seal written outside it could name\n * a decision that rolled back. A second write of the same slot collides on the unique slot and throws, which\n * rolls the decision back with it: one decision step has one seal per sequence.\n */\n async insertPending(prepared: PreparedApprovalSeal, options: RepositoryOptions): Promise<ApprovalSeal> {\n if (!options?.transaction) throw new Error('An approval seal is written only in the transaction that settles its decision');\n if (prepared.row.status !== ApprovalSealStatus.PENDING) throw new Error('Only a PENDING approval seal is written by a decision');\n await this.repositoriesRegistry.insertDocumentForInfrastructure(SEALS, prepared.row, undefined, options);\n return prepared.row;\n }\n\n /**\n * The LATEST seal of one decision step (the highest sequence), or the one of a given sequence; null when it has none (a\n * decision older than seals, a lapse, a withdrawal). A seal its approver's erasure retained counts (#3000, review L5):\n * a step answered again after that erasure is sequenced after it and supersedes it, so a verifier never sees two seals\n * of one sequence. Three callers (#3000 review N1): the settle's sequencing, which uses the seal's sequence, id and\n * `claims.jti`; and the two ending records (`operation-approval-records.backend.utils.ts`, the representative-admission\n * plane), which copy its `claims.decider` (through `deciderRecordOfSeal`) and `decisionPayloadDigest` onto the\n * decision's RESOLVED audit row. None of those is personal data: the claims name no person, and the decider record\n * carries how the person authenticated, never who they are.\n */\n async readOfDecision(\n identity: { readonly source: ApprovalSource; readonly decisionRef: string; readonly step?: number; readonly sequence?: number },\n options?: RepositoryOptions,\n ): Promise<ApprovalSeal | null> {\n const step = identity.step ?? 0;\n const filter = identity.sequence !== undefined\n ? { sealSlot: approvalSealSlotOf({ source: identity.source, decisionRef: identity.decisionRef, step, sequence: identity.sequence }) }\n : { source: identity.source, decisionRef: identity.decisionRef, step };\n const bounds = { sort: [{ field: 'sequence', order: SortOrder.DESC }], limit: 1 };\n // Sequential: both run in the decision's transaction, and a session takes one operation at a time.\n const [live] = await this.repositoriesRegistry.findManyForInfrastructure<ApprovalSeal>(SEALS, filter, undefined, options, bounds);\n const [retained] = await this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<ApprovalSeal>(SEALS, filter, undefined, options, bounds);\n if (!live || !retained) return live ?? retained ?? null;\n return live.sequence >= retained.sequence ? live : retained;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"approval-seal-store.backend.js","sourceRoot":"","sources":["../../../../src/compliance/approval-seals/approval-seal-store.backend.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * # Approval seals: the PENDING row a decision writes (#2903)\n *\n * A decision that a person answered (approved, approved with modifications, rejected) writes ONE `approvalSeals` row in\n * the transaction that settles it. That row is its own outbox: the relay signs it later through the platform custodian\n * (#2891), so signing never blocks, slows or fails the decision, and a crash between the commit and the signing leaves\n * one PENDING row, sealed once.\n *\n * {@link prepareApprovalSeal} builds the row from what the decision door verified; it is pure, so each plane prepares it\n * where it holds the facts and writes it where it holds the transaction. {@link ApprovalSealStore.insertPending} is the\n * one write, and it requires that transaction: a seal written beside a decision rather than with it could exist for a\n * decision that rolled back, or be missing for one that committed.\n *\n * ## What the payload says, and what only the row knows\n *\n * The claims ({@link ApprovalSealClaimsV1}) name no person and carry no stable pseudonym of one. The approver, and a\n * requester who is a person, are each ONE salted disclosure: the payload carries its digest, the row its salt and clear\n * value. So a seal shared alone confirms nothing about who decided, and the approver's erasure removes the disclosures\n * and leaves a seal that still verifies, with that content reported as erased.\n *\n * The decider's session id and chat identity link stay inside the approver's disclosure, never in the payload: each is\n * a handle on the person (#2905).\n */\nimport { randomBytes } from 'node:crypto';\nimport {\n APPROVAL_SEAL_OUTCOMES,\n ApprovalPresentationCapture,\n ApprovalSealSchema,\n ApprovalSealStatus,\n CoreResourceType,\n SortOrder,\n HumanDecision_RequesterKind,\n approvalSealSlotOf,\n humanDecisionBoundDeliverableOf,\n type ApprovalSeal,\n type ApprovalSealMeaning,\n type ApprovalSealOutcome,\n type ApprovalSource,\n type HumanDecision_DeciderRecord,\n type HumanDecision_Requester,\n type ResourceType,\n} from '@wildo-ai/saas-models';\nimport {\n APPROVAL_SEAL_CLAIMS_VERSION,\n ApprovalSealClaimsV1Schema,\n ApprovalSealDeciderClaimsSchema,\n ApprovalSealDisclosureClaim,\n approvalSealDisclosureDigestOf,\n decisionPayloadDigestOf,\n newApprovalSealDisclosureSalt,\n newApprovalSealJti,\n type ApprovalSealClaimsV1,\n type ApprovalSealDisclosureValue,\n} from '@wildo-ai/platform-config-lib';\nimport type { RepositoriesRegistryHandlerBackendService } from '../../base-classes/services/repositories/repositories-registry-handler.backend.service';\nimport type { RepositoryOptions } from '../../base-classes/models/repositories.backend.schemas';\nimport type { SystemAccessBackendService } from '../../base-classes/services/services/system-access.backend.service';\nimport type { ApplicationIdentityBackendService } from '../../applications/services/application-identity.backend.service';\nimport type { AuditLogsBackendService } from '../audit-trails/services/audit-logs.backend.service';\nimport type { ApprovalSealRelayBackendService } from './approval-seal-relay.backend.service';\nimport { registerTransactionPostCommitEffect } from '../../databases/models/transaction.shared.schemas';\nimport { approvalSealPendingEvent, approvalSealSupersededEvent } from './approval-seal-events.backend';\nimport type { DecisionStatement, SealedDecisionPresentation } from './decision-presentation.backend';\n\nconst SEALS = CoreResourceType.APPROVAL_SEALS as ResourceType;\n\n/** What a decision door knows when a person's answer settles: everything the seal says, nothing it computes. */\nexport interface PendingApprovalSealInput {\n readonly applicationId: string;\n /** The organization the decision belongs to; absent when it belongs to none (the tenant is then the application). */\n readonly organizationId?: string;\n readonly source: ApprovalSource;\n /** The decision's own id on its source. */\n readonly decisionRef: string;\n /** Which approver of several, from 0. Defaults to 0. */\n readonly step?: number;\n /**\n * From 1, incremented by a reopen of the same decision. Defaults to 1 here; {@link sealDecisionInTransaction} sets it\n * one past the step's latest seal, which it then supersedes (an answer put back on its question and answered again).\n */\n readonly sequence?: number;\n /** The seal this one supersedes, when a later decision on the same subject replaces it. */\n readonly supersedes?: { readonly sealId: string; readonly jti: string };\n /** The record decided about. */\n readonly subject: { readonly resourceType: string; readonly resourceId: string };\n readonly outcome: ApprovalSealOutcome;\n readonly meaning: ApprovalSealMeaning;\n /** When the person answered. */\n readonly decidedAt: Date;\n /** How the person who answered was authenticated, as the door verified it (#2905). */\n readonly decider: HumanDecision_DeciderRecord;\n readonly approver: { readonly userId: string; readonly name?: string };\n /** Who asked. A person's name joins their disclosure; a machine is named by kind only. */\n readonly requester?: Pick<HumanDecision_Requester, 'kind' | 'ref' | 'clientId'> & { readonly name?: string };\n /**\n * What the person was shown (#2903 S6), checked against the decision's row by the door that took the answer\n * (`acknowledgeDecisionPresentation`). Absent only for a plane that builds no presentation.\n */\n readonly presentation?: SealedDecisionPresentation;\n /** What the person answered (`decisionStatementOf`). */\n readonly statement?: DecisionStatement;\n /**\n * The file deliverable the presentation binds (#2904), with the salt its commitment was made with\n * (`resolveDecisionDeliverables`). Written onto the row only when `presentation` binds that file (a BOUND deliverable):\n * a card that did not show the file (a chat card without the call's arguments) seals no file.\n */\n readonly deliverableFile?: { readonly fileId: string; readonly salt: string };\n}\n\n/** A seal ready to write: the row, the claims it commits to, and the digest the decision's own event carries. */\nexport interface PreparedApprovalSeal {\n readonly row: ApprovalSeal;\n readonly claims: ApprovalSealClaimsV1;\n readonly decisionPayloadDigest: string;\n}\n\n/**\n * A new seal row id: 96 random bits, 24 hex characters, the width every adapter stores as an id. Not derived from the\n * slot: the slot's uniqueness is the unique index's, which an erased (retained) seal leaves (its index is partial), and a\n * derived id would make the next seal of that slot collide with a row nobody can see.\n */\nfunction newApprovalSealId(): string {\n return randomBytes(12).toString('hex');\n}\n\n/** A disclosure's value without absent members: the canonical form refuses `undefined`, and absence must not be a value. */\nfunction presentOnly(value: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(Object.entries(value).filter(([, member]) => member !== undefined));\n}\n\nfunction disclosureOf(claimName: ApprovalSealDisclosureClaim, value: Record<string, unknown>): ApprovalSealDisclosureValue {\n return { claimName, salt: newApprovalSealDisclosureSalt(), value: presentOnly(value) };\n}\n\n/**\n * Build a PENDING seal. Pure: the caller writes it with {@link ApprovalSealStore.insertPending} in the transaction that\n * settles the decision. Refuses an outcome no person decided, so a lapse or a withdrawal can never be sealed as one.\n */\nexport function prepareApprovalSeal(input: PendingApprovalSealInput, now: Date = new Date()): PreparedApprovalSeal {\n if (!(APPROVAL_SEAL_OUTCOMES as readonly string[]).includes(input.outcome)) {\n throw new Error(`An approval seal records only an outcome a person decided, not \"${input.outcome}\"`);\n }\n const step = input.step ?? 0;\n const sequence = input.sequence ?? 1;\n const sealSlot = approvalSealSlotOf({ source: input.source, decisionRef: input.decisionRef, step, sequence });\n const { decider } = input;\n\n const approver = disclosureOf(ApprovalSealDisclosureClaim.APPROVER, {\n userId: input.approver.userId,\n name: input.approver.name,\n authTime: decider.authTime,\n sessionId: decider.sessionId,\n // #2923: a passkey assertion that signed a challenge naming this decision. Salted with the rest of the approver: its\n // credential id links the person across decisions, so it is never a claim in clear (WebAuthn L3 §14.6.3).\n stepUpAssertion: decider.stepUpAssertion,\n chatIdentityLinkId: decider.chatIdentityLinkId,\n inboundDeliveryId: decider.answeredThrough?.inboundDeliveryId,\n });\n const requesterIsPerson = input.requester !== undefined && input.requester.kind !== HumanDecision_RequesterKind.MACHINE;\n const requester = requesterIsPerson\n ? disclosureOf(ApprovalSealDisclosureClaim.REQUESTER, { userId: input.requester!.ref, name: input.requester!.name })\n : undefined;\n // #2903 S6: what was shown and what was answered, each committed to by a salted digest like a person's disclosure.\n const presentation = input.presentation\n ? { claimName: ApprovalSealDisclosureClaim.PRESENTATION, salt: newApprovalSealDisclosureSalt(), value: { ...input.presentation.content } as Record<string, unknown> }\n : undefined;\n const statement = input.statement\n ? { claimName: ApprovalSealDisclosureClaim.STATEMENT, salt: newApprovalSealDisclosureSalt(), value: { ...input.statement } as Record<string, unknown> }\n : undefined;\n // #2904: the file the person approved, attested only when what they were shown commits to its bytes.\n const deliverableFile = input.deliverableFile && humanDecisionBoundDeliverableOf(input.presentation?.content, input.deliverableFile.fileId)\n ? input.deliverableFile\n : undefined;\n\n const claims = ApprovalSealClaimsV1Schema.parse({\n v: APPROVAL_SEAL_CLAIMS_VERSION,\n jti: newApprovalSealJti(),\n source: input.source,\n decisionRef: input.decisionRef,\n step,\n sequence,\n ...(input.supersedes ? { supersedes: input.supersedes.jti } : {}),\n tenant: input.organizationId ?? input.applicationId,\n subject: {\n resourceType: input.subject.resourceType,\n resourceId: input.subject.resourceId,\n ...(input.presentation ? { presentationSchemaVersion: input.presentation.content.schemaVersion } : {}),\n },\n ...(input.presentation && presentation ? {\n presentation: {\n ...(input.presentation.id ? { id: input.presentation.id } : {}),\n provenance: input.presentation.provenance,\n digest: approvalSealDisclosureDigestOf(presentation),\n },\n } : {}),\n ...(statement ? { statementDigest: approvalSealDisclosureDigestOf(statement) } : {}),\n meaning: input.meaning,\n outcome: input.outcome,\n decidedAt: Math.floor(input.decidedAt.getTime() / 1000),\n decider: presentOnly({\n kind: decider.kind,\n channel: decider.channel,\n act: decider.act,\n authTime: decider.authTime,\n amr: decider.amr,\n stepUpMethod: decider.stepUpMethod,\n stepUpAt: decider.stepUpAt,\n stepUpUserVerified: decider.stepUpUserVerified,\n inboundSourceKey: decider.answeredThrough?.inboundSourceKey,\n }),\n ...(input.requester\n ? {\n requester: presentOnly({\n kind: input.requester.kind,\n clientId: input.requester.clientId,\n disclosure: requester ? approvalSealDisclosureDigestOf(requester) : undefined,\n }),\n }\n : {}),\n approver: approvalSealDisclosureDigestOf(approver),\n });\n const decisionPayloadDigest = decisionPayloadDigestOf(claims);\n\n const row = ApprovalSealSchema.parse({\n _id: newApprovalSealId(),\n applicationId: input.applicationId,\n ...(input.organizationId ? { organizationId: input.organizationId } : {}),\n source: input.source,\n decisionRef: input.decisionRef,\n step,\n sequence,\n ...(input.supersedes ? { supersedesSealId: input.supersedes.sealId } : {}),\n sealSlot,\n linkedResourceType: input.subject.resourceType,\n linkedResourceId: input.subject.resourceId,\n approverUserId: input.approver.userId,\n outcome: input.outcome,\n meaning: input.meaning,\n decidedAt: input.decidedAt,\n presentationCapture: ApprovalPresentationCapture.CAPTURED,\n claims,\n decisionPayloadDigest,\n disclosures: [{ ...approver, value: { ...approver.value } }],\n // The requester's id beside their disclosure (#3001): the column their erasure finds this seal by.\n ...(requester ? { requesterUserId: input.requester!.ref, requesterDisclosure: { ...requester, value: { ...requester.value } } } : {}),\n ...(input.presentation && presentation ? {\n presentation: {\n ...(input.presentation.id ? { id: input.presentation.id } : {}),\n provenance: input.presentation.provenance,\n schemaVersion: input.presentation.content.schemaVersion,\n salt: presentation.salt,\n content: presentation.value,\n },\n } : {}),\n ...(statement ? { statement: { salt: statement.salt, content: statement.value } } : {}),\n ...(deliverableFile ? { deliverableFileId: deliverableFile.fileId, deliverableFileSalt: deliverableFile.salt } : {}),\n status: ApprovalSealStatus.PENDING,\n attemptCount: 0,\n nextAttemptAt: now,\n createdAt: now,\n updatedAt: now,\n });\n return { row, claims, decisionPayloadDigest };\n}\n\n/**\n * A person's printed name, for their disclosure: the display name, else first and last name, else the email. Read as the\n * system, unaudited like any read of a decision's own parties; undefined when the person cannot be read, so a seal is\n * never refused for a name (the disclosure still carries their reference).\n */\nexport async function approvalSealPersonNameOf(systemAccess: Pick<SystemAccessBackendService, 'readAsSystem'>, userId: string): Promise<string | undefined> {\n const user = await systemAccess.readAsSystem<{ displayName?: string; firstName?: string; lastName?: string; email?: string }>(\n CoreResourceType.USERS, { _id: userId }, { suppressSystemAudit: true } as never,\n ).catch(() => null);\n if (!user) return undefined;\n const joined = [user.firstName, user.lastName].filter((part) => typeof part === 'string' && part.length > 0).join(' ');\n return user.displayName || joined || user.email || undefined;\n}\n\ntype Registry = Pick<RepositoriesRegistryHandlerBackendService, 'insertDocumentForInfrastructure' | 'findManyForInfrastructure' | 'findRetainedForCompletionForInfrastructure'>;\n\n/**\n * How a sealed decision's decider was authenticated, read back from the seal's own claims: what an ending recorded after\n * the fact (a repair, whose writer lost the record) states beside its decider. The session is not in the claims, and an\n * answer's inbound delivery stays in the approver's disclosure, so neither is returned. Undefined for claims this version\n * cannot read.\n */\nexport function deciderRecordOfSeal(seal: Pick<ApprovalSeal, 'claims'>): HumanDecision_DeciderRecord | undefined {\n const parsed = ApprovalSealDeciderClaimsSchema.safeParse(seal.claims.decider);\n if (!parsed.success) return undefined;\n const { inboundSourceKey: _inboundSourceKey, ...decider } = parsed.data;\n return decider;\n}\n\n/** What sealing a decision inside its transaction reads: the seal rows, the people's names, and the application. */\nexport interface DecisionSealServices {\n readonly repositoriesRegistry: Registry;\n readonly systemAccess: Pick<SystemAccessBackendService, 'readAsSystem'>;\n /**\n * The APPLICATION record's id, which the seal's `applicationId` column holds and the application scope keys on. Never\n * the platform's id for the process (`AppConfigurationService.applicationId`): the two differ, and a row stamped with\n * the platform's matches no scope predicate.\n */\n readonly applicationIdentity: Pick<ApplicationIdentityBackendService, 'getCanonicalApplicationId'>;\n /**\n * What runs once the decision's transaction COMMITS: the seal's PENDING row on the trail (and the SUPERSEDED row of the\n * seal it replaces), and the relay's best-effort signing, so a seal is usually signed within seconds. Neither may fail\n * the decision: the seal row is durable and the batch signs what the fast path did not. A trail row that cannot be\n * written is dropped, not retried (review F6): the PENDING seal row, committed with the decision, is the record it\n * mirrors, and the relay's settlement writes its own rows.\n */\n readonly afterCommit?: {\n readonly auditLogs?: Pick<AuditLogsBackendService, 'logApprovalSealEvent'>;\n readonly relay?: Pick<ApprovalSealRelayBackendService, 'sealSoon'>;\n };\n}\n\n/** A decision's facts as a plane holds them; the people are named by reference, and their names are read here. */\nexport type DecisionSealFacts = Omit<PendingApprovalSealInput, 'applicationId' | 'approver' | 'requester'> & {\n readonly approverUserId: string;\n readonly requester?: Pick<HumanDecision_Requester, 'kind' | 'ref' | 'clientId'>;\n /**\n * #2914: this decision REPLACES the latest earlier approval made through the same tool on the same record (its tool\n * declares `approvalReplacesEarlierApprovalOfRow`): a month signed off again after a reopen is a new decision, and its\n * seal must still name the sign-off it replaces. Honoured only when the decision supersedes none of its own seals.\n */\n readonly replacesEarlierApprovalOfSubject?: { readonly toolName: string };\n};\n\n/**\n * Seal a person's decision in the transaction that settles it: read the approver's (and a person requester's) printed\n * name, prepare the seal and write it PENDING. Every plane calls this from inside its settle, so a decision that rolls\n * back leaves no seal and one that commits has exactly one.\n */\nexport async function sealDecisionInTransaction(services: DecisionSealServices, facts: DecisionSealFacts, options: RepositoryOptions): Promise<PreparedApprovalSeal> {\n const { approverUserId, requester, replacesEarlierApprovalOfSubject, ...decision } = facts;\n const store = new ApprovalSealStore(services.repositoriesRegistry);\n // A step answered before (its answer put back on the question, then answered again) is superseded, never collided with.\n const latestOfDecision = await store.readOfDecision({ source: decision.source, decisionRef: decision.decisionRef, step: decision.step ?? 0 }, options);\n // #2914: a decision that replaces an earlier one on the same record (another decision of the same tool) supersedes its\n // latest seal. The same supersession, one level up: the new seal names it, and the trail records it SUPERSEDED. Its own\n // sequence stays 1, since it is the first answer of its own decision.\n const replaced = !latestOfDecision && replacesEarlierApprovalOfSubject\n ? await store.readLatestOfSubject({\n source: decision.source, subject: decision.subject, toolName: replacesEarlierApprovalOfSubject.toolName,\n exceptDecisionRef: decision.decisionRef, ...(decision.organizationId ? { organizationId: decision.organizationId } : {}),\n }, options)\n : null;\n const latest = latestOfDecision ?? replaced;\n const requesterIsPerson = requester !== undefined && requester.kind !== HumanDecision_RequesterKind.MACHINE;\n const [applicationId, approverName, requesterName] = await Promise.all([\n services.applicationIdentity.getCanonicalApplicationId(),\n approvalSealPersonNameOf(services.systemAccess, approverUserId),\n requesterIsPerson ? approvalSealPersonNameOf(services.systemAccess, requester.ref) : undefined,\n ]);\n const prepared = prepareApprovalSeal({\n ...decision,\n ...(latestOfDecision ? { sequence: latestOfDecision.sequence + 1 } : {}),\n ...(latest ? { supersedes: { sealId: latest._id, jti: String(latest.claims.jti) } } : {}),\n applicationId,\n approver: { userId: approverUserId, ...(approverName ? { name: approverName } : {}) },\n ...(requester ? {\n requester: { kind: requester.kind, ref: requester.ref, ...(requester.clientId ? { clientId: requester.clientId } : {}), ...(requesterName ? { name: requesterName } : {}) },\n } : {}),\n }, decision.decidedAt);\n await store.insertPending(prepared, options);\n const { auditLogs, relay } = services.afterCommit ?? {};\n if (options.transaction && (auditLogs || relay)) {\n registerTransactionPostCommitEffect(options.transaction, {\n key: `approval-seal:pending:${prepared.row._id}`,\n execute: async () => {\n await Promise.all([\n auditLogs?.logApprovalSealEvent(approvalSealPendingEvent(prepared.row)),\n latest ? auditLogs?.logApprovalSealEvent(approvalSealSupersededEvent(latest, prepared.row)) : undefined,\n ]).catch(() => undefined);\n // Not awaited: the adapters await the post-commit drain before the decision's caller is answered, so awaiting the\n // custodian's round trip here would hold every decision for it (up to its timeout). `sealSoon` never throws.\n void relay?.sealSoon([prepared.row._id]);\n },\n });\n }\n return prepared;\n}\n\n/** The `approvalSeals` rows: the PENDING write a decision makes, and the reads that find a decision's seal. */\nexport class ApprovalSealStore {\n constructor(private readonly repositoriesRegistry: Registry) {}\n\n /**\n * Write a PENDING seal in the decision's transaction. Requires the transaction: a seal written outside it could name\n * a decision that rolled back. A second write of the same slot collides on the unique slot and throws, which\n * rolls the decision back with it: one decision step has one seal per sequence.\n */\n async insertPending(prepared: PreparedApprovalSeal, options: RepositoryOptions): Promise<ApprovalSeal> {\n if (!options?.transaction) throw new Error('An approval seal is written only in the transaction that settles its decision');\n if (prepared.row.status !== ApprovalSealStatus.PENDING) throw new Error('Only a PENDING approval seal is written by a decision');\n await this.repositoriesRegistry.insertDocumentForInfrastructure(SEALS, prepared.row, undefined, options);\n return prepared.row;\n }\n\n /**\n * The LATEST seal of one decision step (the highest sequence), or the one of a given sequence; null when it has none (a\n * decision older than seals, a lapse, a withdrawal). A seal its approver's erasure retained counts (#3000, review L5):\n * a step answered again after that erasure is sequenced after it and supersedes it, so a verifier never sees two seals\n * of one sequence. Three callers (#3000 review N1): the settle's sequencing, which uses the seal's sequence, id and\n * `claims.jti`; and the two ending records (`operation-approval-records.backend.utils.ts`, the representative-admission\n * plane), which copy its `claims.decider` (through `deciderRecordOfSeal`) and `decisionPayloadDigest` onto the\n * decision's RESOLVED audit row. None of those is personal data: the claims name no person, and the decider record\n * carries how the person authenticated, never who they are.\n */\n async readOfDecision(\n identity: { readonly source: ApprovalSource; readonly decisionRef: string; readonly step?: number; readonly sequence?: number },\n options?: RepositoryOptions,\n ): Promise<ApprovalSeal | null> {\n const step = identity.step ?? 0;\n const filter = identity.sequence !== undefined\n ? { sealSlot: approvalSealSlotOf({ source: identity.source, decisionRef: identity.decisionRef, step, sequence: identity.sequence }) }\n : { source: identity.source, decisionRef: identity.decisionRef, step };\n const bounds = { sort: [{ field: 'sequence', order: SortOrder.DESC }], limit: 1 };\n // Sequential: both run in the decision's transaction, and a session takes one operation at a time.\n const [live] = await this.repositoriesRegistry.findManyForInfrastructure<ApprovalSeal>(SEALS, filter, undefined, options, bounds);\n const [retained] = await this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<ApprovalSeal>(SEALS, filter, undefined, options, bounds);\n if (!live || !retained) return live ?? retained ?? null;\n return live.sequence >= retained.sequence ? live : retained;\n }\n\n /**\n * The LATEST seal of another decision made through the tool `toolName` on the record `subject`, in the same source and\n * tenant (#2914): what a decision that replaces it supersedes. A seal its approver's erasure retained counts, as in\n * {@link readOfDecision}. The tool is read from the seal's own presentation (`toolName`), the one place a seal records\n * it; a seal whose presentation is not inline (moved to a file, or removed by an erasure) cannot be attributed to a\n * tool and is passed over rather than guessed. Reads the most recent {@link SUBJECT_SEAL_SCAN_LIMIT} seals of the record.\n */\n async readLatestOfSubject(\n identity: {\n readonly source: ApprovalSource;\n readonly subject: { readonly resourceType: string; readonly resourceId: string };\n readonly toolName: string;\n readonly exceptDecisionRef: string;\n readonly organizationId?: string;\n },\n options?: RepositoryOptions,\n ): Promise<ApprovalSeal | null> {\n const filter = { source: identity.source, linkedResourceType: identity.subject.resourceType, linkedResourceId: identity.subject.resourceId };\n const bounds = { sort: [{ field: 'decidedAt', order: SortOrder.DESC }], limit: SUBJECT_SEAL_SCAN_LIMIT };\n // Sequential, like `readOfDecision`: both run in the decision's transaction.\n const live = await this.repositoriesRegistry.findManyForInfrastructure<ApprovalSeal>(SEALS, filter, undefined, options, bounds);\n const retained = await this.repositoriesRegistry.findRetainedForCompletionForInfrastructure<ApprovalSeal>(SEALS, filter, undefined, options, bounds);\n const candidates = [...live, ...retained]\n .filter((seal) => seal.decisionRef !== identity.exceptDecisionRef\n && (seal.organizationId ?? undefined) === identity.organizationId\n && approvalSealToolNameOf(seal) === identity.toolName)\n .sort((first, second) => new Date(second.decidedAt).getTime() - new Date(first.decidedAt).getTime() || second.sequence - first.sequence);\n return candidates[0] ?? null;\n }\n}\n\n/** How many of a record's most recent seals {@link ApprovalSealStore.readLatestOfSubject} reads to find a tool's latest. */\nexport const SUBJECT_SEAL_SCAN_LIMIT = 50;\n\n/** The tool a seal's inline presentation names, when it names one (a tool approval's card). */\nfunction approvalSealToolNameOf(seal: Pick<ApprovalSeal, 'presentation'>): string | undefined {\n const content = (seal.presentation as { content?: unknown } | undefined)?.content;\n const toolName = content !== null && typeof content === 'object' ? (content as { toolName?: unknown }).toolName : undefined;\n return typeof toolName === 'string' ? toolName : undefined;\n}\n"]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Public contracts of the approval-seals operator door (#2903): literals and types only, so the CLI, tests and scripts
|
|
3
3
|
* use the paths without the DI container (the split the data-seeding and external-data admin surfaces use).
|
|
4
4
|
*/
|
|
5
|
-
import type { ApprovalSealStatus, ApprovalSource, CryptoKey_SignatureRefusal } from '@wildo-ai/saas-models';
|
|
5
|
+
import type { ApprovalSealStatus, ApprovalSealSubjectCurrency, ApprovalSource, CryptoKey_SignatureRefusal, HumanDecision_PresentedFieldCurrency } from '@wildo-ai/saas-models';
|
|
6
6
|
import type { SigningLogExportFile } from '@wildo-ai/platform-config-lib';
|
|
7
7
|
/** @wildo_source:part:start saas.approval-seals.admin-endpoints facet:kind:framework-api facet:audience:operator */
|
|
8
8
|
/**
|
|
@@ -55,6 +55,16 @@ export declare const ApprovalSealsAdminEndpointPath: {
|
|
|
55
55
|
* which no copy can be made (`reason` names why, `detail` says more).
|
|
56
56
|
*/
|
|
57
57
|
readonly MANIFESTED_COPY_REBUILD: "/manifested-copy/rebuild";
|
|
58
|
+
/**
|
|
59
|
+
* POST — whether ONE seal's approval is still CURRENT over the record it is about (#2914): `{ "sealId": "…" }` →
|
|
60
|
+
* {@link ApprovalSealCurrencyResult}. The seal's presentation carries the values of the fields its tool declared the
|
|
61
|
+
* approval covers (`sealedRecordFields`); they are compared with the record as it is now. CURRENT right after the
|
|
62
|
+
* approval, NO_LONGER_CURRENT once one of them changed, SUBJECT_GONE when the record is gone, NO_SEALED_FIELD_SET when
|
|
63
|
+
* the seal covers no record field. Names which fields moved, never a value, so it is not recorded on the trail. 404 for
|
|
64
|
+
* an unknown seal (a seal its approver's erasure retained is not read here); 409 for one whose presentation file is
|
|
65
|
+
* unreadable or not the one its row recorded.
|
|
66
|
+
*/
|
|
67
|
+
readonly CURRENCY: "/currency";
|
|
58
68
|
};
|
|
59
69
|
/**
|
|
60
70
|
* What became of one seal signature the signing log records, against the application's stored seals (#2932). A
|
|
@@ -133,6 +143,21 @@ export interface ApprovalSealRetryResult {
|
|
|
133
143
|
/** True when the relay's immediate attempt signed it; false when the batch will. */
|
|
134
144
|
readonly sealed: boolean;
|
|
135
145
|
}
|
|
146
|
+
/** `POST /currency`'s answer (#2914). Names no person and no value. */
|
|
147
|
+
export interface ApprovalSealCurrencyResult {
|
|
148
|
+
readonly sealId: string;
|
|
149
|
+
readonly standing: ApprovalSealSubjectCurrency;
|
|
150
|
+
/** The record compared, as the seal names it; absent for NO_SEALED_FIELD_SET. */
|
|
151
|
+
readonly subject?: {
|
|
152
|
+
readonly resourceType: string;
|
|
153
|
+
readonly resourceId: string;
|
|
154
|
+
};
|
|
155
|
+
/** Each sealed field's currency (CURRENT / CHANGED / ABSENT); absent unless compared. */
|
|
156
|
+
readonly fields?: readonly {
|
|
157
|
+
readonly key: string;
|
|
158
|
+
readonly currency: HumanDecision_PresentedFieldCurrency;
|
|
159
|
+
}[];
|
|
160
|
+
}
|
|
136
161
|
/** `POST /manifested-copy/rebuild`'s answer. */
|
|
137
162
|
export interface ApprovalSealManifestedCopyRebuildResult {
|
|
138
163
|
readonly sealId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-seals-admin.backend.contracts.d.ts","sourceRoot":"","sources":["../../../../src/compliance/approval-seals/approval-seals-admin.backend.contracts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"approval-seals-admin.backend.contracts.d.ts","sourceRoot":"","sources":["../../../../src/compliance/approval-seals/approval-seals-admin.backend.contracts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,2BAA2B,EAAE,cAAc,EAAE,0BAA0B,EAAE,oCAAoC,EAAE,MAAM,uBAAuB,CAAC;AAC/K,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAE1E,oHAAoH;AACpH;;;GAGG;AACH,eAAO,MAAM,gCAAgC,EAAG,0BAAmC,CAAC;AAEpF,kCAAkC;AAClC,eAAO,MAAM,mCAAmC,EAAG,gBAAyB,CAAC;AAE7E,2DAA2D;AAC3D,eAAO,MAAM,uCAAuC,EAAG,gCAAyC,CAAC;AAEjG,8EAA8E;AAC9E,eAAO,MAAM,8BAA8B;IACzC,uGAAuG;;IAEvG;;;;;OAKG;;IAEH;;;;;;;;OAQG;;IAEH;;;;;;;;OAQG;;IAEH;;;;;;;;OAQG;;IAEH;;;;;;;;OAQG;;CAEK,CAAC;AAEX;;;;GAIG;AACH,oBAAY,sBAAsB;IAChC,4EAA4E;IAC5E,MAAM,WAAW;IACjB;;;;;OAKG;IACH,QAAQ,aAAa;IACrB;;;OAGG;IACH,WAAW,gBAAgB;IAC3B;;;;OAIG;IACH,SAAS,cAAc;CACxB;AAED,4FAA4F;AAC5F,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,6GAA6G;AAC7G,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sFAAsF;IACtF,QAAQ,CAAC,QAAQ,EAAE,SAAS,yBAAyB,EAAE,CAAC;IACxD,iEAAiE;IACjE,QAAQ,CAAC,WAAW,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAC3D,2HAA2H;IAC3H,QAAQ,CAAC,SAAS,EAAE,SAAS,yBAAyB,EAAE,CAAC;CAC1D;AAED,uIAAuI;AACvI,MAAM,WAAW,kCAAmC,SAAQ,oBAAoB;IAC9E,iDAAiD;IACjD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,6EAA6E;IAC7E,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,cAAc,EAAE,wBAAwB,CAAC;CACnD;AAED,8GAA8G;AAC9G,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,0BAA0B,GAAG,IAAI,CAAC;CACzD;AAED,8BAA8B;AAC9B,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,oFAAoF;IACpF,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,uEAAuE;AACvE,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,2BAA2B,CAAC;IAC/C,iFAAiF;IACjF,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAClF,yFAAyF;IACzF,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,oCAAoC,CAAA;KAAE,EAAE,CAAC;CAChH;AAED,gDAAgD;AAChD,MAAM,WAAW,uCAAuC;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,2BAA2B;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AACD,iEAAiE"}
|