@wildo-ai/saas-models 1.1.7 → 1.1.9
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/_inspect.d.ts.map +1 -1
- package/dist/esm/_inspect.js.map +1 -1
- package/dist/esm/applications/application-metadata.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/applications/application-metadata.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/applications/application-subject.shared.schemas.d.ts.map +1 -1
- package/dist/esm/applications/application-subject.shared.schemas.js.map +1 -1
- package/dist/esm/applications/application-versions.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/applications/application-versions.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/applications/applications-context.schemas.d.ts.map +1 -1
- package/dist/esm/applications/applications-context.schemas.js.map +1 -1
- package/dist/esm/applications/applications.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/applications/applications.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/applications/applications.shared.schemas.d.ts.map +1 -1
- package/dist/esm/applications/applications.shared.schemas.js.map +1 -1
- package/dist/esm/billing/billing-account.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/billing/billing-account.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/billing/billing-account.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/billing-account.shared.schemas.js.map +1 -1
- package/dist/esm/billing/billing-configuration.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/billing-configuration.shared.schemas.js.map +1 -1
- package/dist/esm/billing/billing-enums.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/billing-enums.shared.schemas.js.map +1 -1
- package/dist/esm/billing/billing-types.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/billing-types.shared.schemas.js.map +1 -1
- package/dist/esm/billing/credit-pool.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/billing/credit-pool.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/billing/credit-pool.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/credit-pool.shared.schemas.js.map +1 -1
- package/dist/esm/billing/invoice-ref.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/billing/invoice-ref.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/billing/invoice-ref.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/invoice-ref.shared.schemas.js.map +1 -1
- package/dist/esm/billing/price.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/billing/price.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/billing/price.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/price.shared.schemas.js.map +1 -1
- package/dist/esm/billing/product-behavior-policy.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/product-behavior-policy.shared.schemas.js.map +1 -1
- package/dist/esm/billing/product-definition.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/product-definition.shared.schemas.js.map +1 -1
- package/dist/esm/billing/product.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/billing/product.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/billing/product.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/product.shared.schemas.js.map +1 -1
- package/dist/esm/billing/promotions.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/billing/promotions.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/billing/promotions.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/promotions.shared.schemas.js.map +1 -1
- package/dist/esm/billing/public-pricing-catalog.shared.atoms.d.ts.map +1 -1
- package/dist/esm/billing/public-pricing-catalog.shared.atoms.js.map +1 -1
- package/dist/esm/billing/public-pricing-catalog.shared.d.ts.map +1 -1
- package/dist/esm/billing/public-pricing-catalog.shared.js.map +1 -1
- package/dist/esm/billing/referral-reward.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/referral-reward.shared.schemas.js.map +1 -1
- package/dist/esm/billing/referral.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/billing/referral.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/billing/referral.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/referral.shared.schemas.js.map +1 -1
- package/dist/esm/billing/subscription.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/billing/subscription.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/billing/subscription.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/subscription.shared.schemas.js.map +1 -1
- package/dist/esm/billing/usage-flush-evidence.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/usage-flush-evidence.shared.schemas.js.map +1 -1
- package/dist/esm/billing/usage-record.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/billing/usage-record.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/billing/usage-record.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/usage-record.shared.schemas.js.map +1 -1
- package/dist/esm/charts/aggregation-query.shared.schemas.d.ts.map +1 -1
- package/dist/esm/charts/aggregation-query.shared.schemas.js.map +1 -1
- package/dist/esm/charts/aggregation.shared.definitions.d.ts.map +1 -1
- package/dist/esm/charts/aggregation.shared.definitions.js.map +1 -1
- package/dist/esm/charts/chart-definition-builder.shared.d.ts.map +1 -1
- package/dist/esm/charts/chart-definition-builder.shared.js.map +1 -1
- package/dist/esm/companion/artifact-placement.shared.definitions.d.ts.map +1 -1
- package/dist/esm/companion/artifact-placement.shared.definitions.js.map +1 -1
- package/dist/esm/companion/provider-discovery.shared.schemas.d.ts +13 -0
- package/dist/esm/companion/provider-discovery.shared.schemas.d.ts.map +1 -1
- package/dist/esm/companion/provider-discovery.shared.schemas.js +13 -0
- package/dist/esm/companion/provider-discovery.shared.schemas.js.map +1 -1
- package/dist/esm/companion/shared-library-companion.shared.definitions.d.ts.map +1 -1
- package/dist/esm/companion/shared-library-companion.shared.definitions.js.map +1 -1
- package/dist/esm/companion-exports.d.ts.map +1 -1
- package/dist/esm/companion-exports.js.map +1 -1
- package/dist/esm/compliance/audit-trails/application-audit-logs.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/application-audit-logs.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/compliance/audit-trails/audit-actor.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/audit-actor.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/audit-trails/audit-export-projection.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/audit-export-projection.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/audit-trails/audit-log-sink.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/audit-log-sink.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/audit-trails/audit-logs.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/audit-logs.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/compliance/audit-trails/audit-trail-config.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/audit-trail-config.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/audit-trails/auditable-events.shared.schema.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/auditable-events.shared.schema.js.map +1 -1
- package/dist/esm/compliance/audit-trails/security-audit-event-envelope.shared.schema.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/security-audit-event-envelope.shared.schema.js.map +1 -1
- package/dist/esm/compliance/data-classification/data-classification.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/data-classification/data-classification.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/documents/governed-document-interactions.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/documents/governed-document-interactions.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/documents/governed-documents.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/documents/governed-documents.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/documents/user-governed-document-acceptances.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/documents/user-governed-document-acceptances.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/compliance/documents/user-governed-document-acceptances.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/documents/user-governed-document-acceptances.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/ai-use-posture.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/ai-use-posture.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/capability-consent-purposes.shared.utils.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/capability-consent-purposes.shared.utils.js.map +1 -1
- package/dist/esm/compliance/privacy/client-storage.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/client-storage.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/consent-gate-vocabulary.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/consent-gate-vocabulary.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/consent-purposes.shared.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/consent-purposes.shared.js.map +1 -1
- package/dist/esm/compliance/privacy/data-subject-rights.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/data-subject-rights.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/impersonalization-scrub.shared.utils.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/impersonalization-scrub.shared.utils.js.map +1 -1
- package/dist/esm/compliance/privacy/impersonalization.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/impersonalization.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/legal-hold-subject-attribution.shared.utils.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/legal-hold-subject-attribution.shared.utils.js.map +1 -1
- package/dist/esm/compliance/privacy/legal-holds.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/legal-holds.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/legal-holds.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/legal-holds.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/operating-jurisdictions.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/operating-jurisdictions.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/operator-compliance-identity.shared.schemas.d.ts +32 -1
- package/dist/esm/compliance/privacy/operator-compliance-identity.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/operator-compliance-identity.shared.schemas.js +32 -0
- package/dist/esm/compliance/privacy/operator-compliance-identity.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/personal-data-category.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/personal-data-category.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/personal-data-declaration.shared.utils.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/personal-data-declaration.shared.utils.js.map +1 -1
- package/dist/esm/compliance/privacy/privacy.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/privacy.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/provider-capability-disclosure.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/provider-capability-disclosure.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/purpose-ref.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/purpose-ref.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/redaction.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/redaction.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/retention-binding.shared.utils.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/retention-binding.shared.utils.js.map +1 -1
- package/dist/esm/compliance/privacy/retention-enforcement-records.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/retention-enforcement-records.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/retention-enforcement-records.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/retention-enforcement-records.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/retention-schedule.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/retention-schedule.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/retention-scope-deleted.shared.utils.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/retention-scope-deleted.shared.utils.js.map +1 -1
- package/dist/esm/compliance/privacy/sharing.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/sharing.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/subject-data-recipients.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/subject-data-recipients.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/subject-erasure-lane-evidence.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/subject-erasure-lane-evidence.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/subject-erasure.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/subject-erasure.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/subject-export-render.shared.utils.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/subject-export-render.shared.utils.js.map +1 -1
- package/dist/esm/compliance/privacy/subject-export.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/subject-export.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/review-cadence.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/review-cadence.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/risk-posture.shared.schemas.d.ts +15 -3
- package/dist/esm/compliance/risk-posture.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/risk-posture.shared.schemas.js +14 -2
- package/dist/esm/compliance/risk-posture.shared.schemas.js.map +1 -1
- package/dist/esm/config/analytics-value-moments.shared.schemas.d.ts.map +1 -1
- package/dist/esm/config/analytics-value-moments.shared.schemas.js.map +1 -1
- package/dist/esm/config/app-configuration-shared.shared.schemas.d.ts.map +1 -1
- package/dist/esm/config/app-configuration-shared.shared.schemas.js.map +1 -1
- package/dist/esm/config/app-frontend-type.shared.schemas.d.ts.map +1 -1
- package/dist/esm/config/app-frontend-type.shared.schemas.js.map +1 -1
- package/dist/esm/config/auth-config-resolution.shared.utils.d.ts.map +1 -1
- package/dist/esm/config/auth-config-resolution.shared.utils.js.map +1 -1
- package/dist/esm/config/brand-assets.shared.schemas.d.ts.map +1 -1
- package/dist/esm/config/brand-assets.shared.schemas.js.map +1 -1
- package/dist/esm/config/configuration-validation.shared.schemas.d.ts.map +1 -1
- package/dist/esm/config/configuration-validation.shared.schemas.js.map +1 -1
- package/dist/esm/config/entity-identity-config.shared.schemas.d.ts.map +1 -1
- package/dist/esm/config/entity-identity-config.shared.schemas.js.map +1 -1
- package/dist/esm/config/frontend/chart-definition.shared.schemas.d.ts.map +1 -1
- package/dist/esm/config/frontend/chart-definition.shared.schemas.js.map +1 -1
- package/dist/esm/config/frontend/chart-registration-alignment.shared.d.ts.map +1 -1
- package/dist/esm/config/frontend/chart-registration-alignment.shared.js.map +1 -1
- package/dist/esm/config/frontend/navigation.shared.schemas.d.ts.map +1 -1
- package/dist/esm/config/frontend/navigation.shared.schemas.js.map +1 -1
- package/dist/esm/config/frontend/onboarding.shared.schemas.d.ts.map +1 -1
- package/dist/esm/config/frontend/onboarding.shared.schemas.js.map +1 -1
- package/dist/esm/config/postgresql.shared.schemas.d.ts.map +1 -1
- package/dist/esm/config/postgresql.shared.schemas.js.map +1 -1
- package/dist/esm/config/registration-acquisition-policy.shared.utils.d.ts.map +1 -1
- package/dist/esm/config/registration-acquisition-policy.shared.utils.js.map +1 -1
- package/dist/esm/config-authoring.entry.d.ts.map +1 -1
- package/dist/esm/config-authoring.entry.js.map +1 -1
- package/dist/esm/crdt/crdt-merge.shared.utils.d.ts.map +1 -1
- package/dist/esm/crdt/crdt-merge.shared.utils.js.map +1 -1
- package/dist/esm/data-seeding/data-seeding-config.shared.schemas.d.ts.map +1 -1
- package/dist/esm/data-seeding/data-seeding-config.shared.schemas.js.map +1 -1
- package/dist/esm/errors/caught-error-description.shared.utils.d.ts.map +1 -1
- package/dist/esm/errors/caught-error-description.shared.utils.js.map +1 -1
- package/dist/esm/errors/errors.custom-message-ref.shared.definitions.d.ts.map +1 -1
- package/dist/esm/errors/errors.custom-message-ref.shared.definitions.js.map +1 -1
- package/dist/esm/errors/errors.shared.definitions.d.ts.map +1 -1
- package/dist/esm/errors/errors.shared.definitions.js.map +1 -1
- package/dist/esm/errors/errors.shared.schemas.d.ts.map +1 -1
- package/dist/esm/errors/errors.shared.schemas.js.map +1 -1
- package/dist/esm/errors/errors.shared.utils.d.ts.map +1 -1
- package/dist/esm/errors/errors.shared.utils.js.map +1 -1
- package/dist/esm/errors/resource-access-forbidden.shared.error.d.ts.map +1 -1
- package/dist/esm/errors/resource-access-forbidden.shared.error.js.map +1 -1
- package/dist/esm/errors/thrown-value-description.shared.utils.d.ts.map +1 -1
- package/dist/esm/errors/thrown-value-description.shared.utils.js.map +1 -1
- package/dist/esm/errors/zod-issue-formatting.shared.utils.d.ts.map +1 -1
- package/dist/esm/errors/zod-issue-formatting.shared.utils.js.map +1 -1
- package/dist/esm/exports/tabular-csv.shared.utils.d.ts.map +1 -1
- package/dist/esm/exports/tabular-csv.shared.utils.js.map +1 -1
- package/dist/esm/external-data/external-data-pipeline-description.shared.d.ts.map +1 -1
- package/dist/esm/external-data/external-data-pipeline-description.shared.js.map +1 -1
- package/dist/esm/external-data/external-data-pipeline-pass-mode.shared.d.ts.map +1 -1
- package/dist/esm/external-data/external-data-pipeline-pass-mode.shared.js.map +1 -1
- package/dist/esm/external-data/external-data-pipeline.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-data/external-data-pipeline.shared.schemas.js.map +1 -1
- package/dist/esm/external-data/external-data-provenance.shared.d.ts.map +1 -1
- package/dist/esm/external-data/external-data-provenance.shared.js.map +1 -1
- package/dist/esm/external-data.exports.d.ts.map +1 -1
- package/dist/esm/external-data.exports.js.map +1 -1
- package/dist/esm/external-providers/compose-provider-registry.shared.d.ts.map +1 -1
- package/dist/esm/external-providers/compose-provider-registry.shared.js.map +1 -1
- package/dist/esm/external-providers/engine-capabilities.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/engine-capabilities.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/engine-capability-resolution-mode.shared.d.ts.map +1 -1
- package/dist/esm/external-providers/engine-capability-resolution-mode.shared.js.map +1 -1
- package/dist/esm/external-providers/engine-capability-surface.shared.d.ts.map +1 -1
- package/dist/esm/external-providers/engine-capability-surface.shared.js.map +1 -1
- package/dist/esm/external-providers/external-providers.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/external-providers.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/frontend-bootstrap.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/frontend-bootstrap.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/frontend-capability-public-config.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/frontend-capability-public-config.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/frontend-capability-runtime.shared.types.d.ts.map +1 -1
- package/dist/esm/external-providers/frontend-capability-runtime.shared.types.js.map +1 -1
- package/dist/esm/external-providers/frontend-provider-entry.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/frontend-provider-entry.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/frontend-provider-public-config.shared.d.ts.map +1 -1
- package/dist/esm/external-providers/frontend-provider-public-config.shared.js.map +1 -1
- package/dist/esm/external-providers/model-cost-accounting-config.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/model-cost-accounting-config.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/provider-address-lookup-contract.shared.types.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-address-lookup-contract.shared.types.js.map +1 -1
- package/dist/esm/external-providers/provider-augmentation-opt-ins.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-augmentation-opt-ins.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/provider-authentication-assurance.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-authentication-assurance.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/provider-browser-operations.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-browser-operations.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/provider-capability.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-capability.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/provider-compliance-profile.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-compliance-profile.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/provider-frontend-component-contract.shared.types.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-frontend-component-contract.shared.types.js.map +1 -1
- package/dist/esm/external-providers/provider-frontend-surface.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-frontend-surface.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/provider-metadata.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-metadata.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/provider-package-allow-list.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-package-allow-list.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/provider-protocol.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-protocol.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/provider-scope-reauthorization.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-scope-reauthorization.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/provider-shared-connections.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-shared-connections.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/provider-tier-rule.shared.utils.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-tier-rule.shared.utils.js.map +1 -1
- package/dist/esm/external-providers/provider-usage-cost.shared.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-usage-cost.shared.js.map +1 -1
- package/dist/esm/external-providers/provider-usage-pricing.example.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-usage-pricing.example.js.map +1 -1
- package/dist/esm/external-providers/provider-usage-pricing.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-usage-pricing.shared.schemas.js.map +1 -1
- package/dist/esm/features/application-features.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/features/application-features.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/features/connected-feature.example.d.ts.map +1 -1
- package/dist/esm/features/connected-feature.example.js.map +1 -1
- package/dist/esm/features/core-feature-definitions.shared.d.ts.map +1 -1
- package/dist/esm/features/core-feature-definitions.shared.js.map +1 -1
- package/dist/esm/features/feature-builders.shared.d.ts.map +1 -1
- package/dist/esm/features/feature-builders.shared.js.map +1 -1
- package/dist/esm/features/feature-definition.shared.schemas.d.ts.map +1 -1
- package/dist/esm/features/feature-definition.shared.schemas.js.map +1 -1
- package/dist/esm/features/feature-registry.shared.d.ts.map +1 -1
- package/dist/esm/features/feature-registry.shared.js.map +1 -1
- package/dist/esm/features/feature-resolution.shared.schemas.d.ts.map +1 -1
- package/dist/esm/features/feature-resolution.shared.schemas.js.map +1 -1
- package/dist/esm/features/scope-features.shared.schemas.d.ts.map +1 -1
- package/dist/esm/features/scope-features.shared.schemas.js.map +1 -1
- package/dist/esm/features/user-features.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/features/user-features.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/files/file-remote-reference-link.shared.schemas.d.ts.map +1 -1
- package/dist/esm/files/file-remote-reference-link.shared.schemas.js.map +1 -1
- package/dist/esm/files/file-upload-grant.shared.schemas.d.ts.map +1 -1
- package/dist/esm/files/file-upload-grant.shared.schemas.js.map +1 -1
- package/dist/esm/files/files.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/files/files.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/files/files.shared.schemas.d.ts.map +1 -1
- package/dist/esm/files/files.shared.schemas.js.map +1 -1
- package/dist/esm/files/files.shared.utils.d.ts.map +1 -1
- package/dist/esm/files/files.shared.utils.js.map +1 -1
- package/dist/esm/flows-actors/a2a-push-delivery-log.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a-push-delivery-log.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/flows-actors/a2a-push-delivery-log.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a-push-delivery-log.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/a2a-token-budget-state.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a-token-budget-state.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/flows-actors/a2a-token-budget-state.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a-token-budget-state.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/actors.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/actors.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/agent-traceability.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/agent-traceability.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/agent-work-decisions.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/agent-work-decisions.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/flows-actors/agent-work-decisions.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/agent-work-decisions.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/agents.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/agents.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/autonomous-agents.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/autonomous-agents.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/deliberation.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/deliberation.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/execution-plan-readiness.shared.utils.d.ts.map +1 -1
- package/dist/esm/flows-actors/execution-plan-readiness.shared.utils.js.map +1 -1
- package/dist/esm/flows-actors/flows-actors-execution.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/flows-actors-execution.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/flows-actors/flows-actors-execution.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/flows-actors-execution.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/flows-actors-task.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/flows-actors-task.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/flows-actors/flows-actors-task.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/flows-actors-task.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/flows-actors.commons.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/flows-actors.commons.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/flows-actors.configuration.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/flows-actors.configuration.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/flows-actors.frontend.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/flows-actors.frontend.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/flows-actors.io.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/flows-actors.io.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/flows-actors.system.shared.definitions.d.ts.map +1 -1
- package/dist/esm/flows-actors/flows-actors.system.shared.definitions.js.map +1 -1
- package/dist/esm/flows-actors/flows-actors.system.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/flows-actors.system.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/flows.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/flows.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/human-decision.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/human-decision.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/mcp-servers.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/mcp-servers.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/model-call-attributions.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/model-call-attributions.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/flows-actors/model-call-attributions.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/model-call-attributions.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/model-cost-period-aggregates.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/model-cost-period-aggregates.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/flows-actors/model-cost-period-aggregates.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/model-cost-period-aggregates.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/model-cost-summary.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/model-cost-summary.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/prompt-ir.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/prompt-ir.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/provider-call-records.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/provider-call-records.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/flows-actors/provider-call-records.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/provider-call-records.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/review-deadlines.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/review-deadlines.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/tasks.actors.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/tasks.actors.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/work-attribution.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/work-attribution.shared.schemas.js.map +1 -1
- package/dist/esm/frontend-definitions/frontend-notification-custom-message-ref.definitions.d.ts.map +1 -1
- package/dist/esm/frontend-definitions/frontend-notification-custom-message-ref.definitions.js.map +1 -1
- package/dist/esm/frontend-definitions/settings-destination-ref.definitions.d.ts.map +1 -1
- package/dist/esm/frontend-definitions/settings-destination-ref.definitions.js.map +1 -1
- package/dist/esm/guidance/guidance-flow.shared.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/guidance-flow.shared.schemas.js.map +1 -1
- package/dist/esm/guidance/guidance-state.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/guidance-state.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/guidance/guidance-state.shared.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/guidance-state.shared.schemas.js.map +1 -1
- package/dist/esm/guidance/guidance-state.shared.utils.d.ts.map +1 -1
- package/dist/esm/guidance/guidance-state.shared.utils.js.map +1 -1
- package/dist/esm/guidance/lifecycle-config.shared.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/lifecycle-config.shared.schemas.js.map +1 -1
- package/dist/esm/guidance/lifecycle-state.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/lifecycle-state.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/guidance/lifecycle-state.shared.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/lifecycle-state.shared.schemas.js.map +1 -1
- package/dist/esm/guidance/milestone-builders.shared.d.ts.map +1 -1
- package/dist/esm/guidance/milestone-builders.shared.js.map +1 -1
- package/dist/esm/guidance/milestone-definition.shared.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/milestone-definition.shared.schemas.js.map +1 -1
- package/dist/esm/guidance/progression-presentation.shared.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/progression-presentation.shared.schemas.js.map +1 -1
- package/dist/esm/guidance/progression-state.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/progression-state.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/guidance/progression-state.shared.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/progression-state.shared.schemas.js.map +1 -1
- package/dist/esm/http-api-binding/http-api-binding-id.shared.utils.d.ts.map +1 -1
- package/dist/esm/http-api-binding/http-api-binding-id.shared.utils.js.map +1 -1
- package/dist/esm/http-api-binding/http-api-binding.shared.schemas.d.ts.map +1 -1
- package/dist/esm/http-api-binding/http-api-binding.shared.schemas.js.map +1 -1
- package/dist/esm/http-api-binding/http-api-erasure-stance.shared.d.ts.map +1 -1
- package/dist/esm/http-api-binding/http-api-erasure-stance.shared.js.map +1 -1
- package/dist/esm/http-api-binding/http-api-rest-write-operations.shared.schemas.d.ts.map +1 -1
- package/dist/esm/http-api-binding/http-api-rest-write-operations.shared.schemas.js.map +1 -1
- package/dist/esm/http-api-binding/http-api-transport-dialect.shared.d.ts.map +1 -1
- package/dist/esm/http-api-binding/http-api-transport-dialect.shared.js.map +1 -1
- package/dist/esm/http-api-binding/read-through-engine-anchors.shared.d.ts.map +1 -1
- package/dist/esm/http-api-binding/read-through-engine-anchors.shared.js.map +1 -1
- package/dist/esm/i18n/application-config-vocabulary.shared.d.ts.map +1 -1
- package/dist/esm/i18n/application-config-vocabulary.shared.js.map +1 -1
- package/dist/esm/i18n/engine-open-vocabulary-values.shared.d.ts.map +1 -1
- package/dist/esm/i18n/engine-open-vocabulary-values.shared.js.map +1 -1
- package/dist/esm/i18n/engine-open-vocabulary.shared.d.ts.map +1 -1
- package/dist/esm/i18n/engine-open-vocabulary.shared.js.map +1 -1
- package/dist/esm/i18n/interpolate-label-params.shared.utils.d.ts.map +1 -1
- package/dist/esm/i18n/interpolate-label-params.shared.utils.js.map +1 -1
- package/dist/esm/i18n/labelling.dto.shared.schemas.d.ts.map +1 -1
- package/dist/esm/i18n/labelling.dto.shared.schemas.js.map +1 -1
- package/dist/esm/inbound/conversation-threads.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/inbound/conversation-threads.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/inbound/conversation-threads.shared.schemas.d.ts.map +1 -1
- package/dist/esm/inbound/conversation-threads.shared.schemas.js.map +1 -1
- package/dist/esm/inbound/inbound-channels.shared.schemas.d.ts.map +1 -1
- package/dist/esm/inbound/inbound-channels.shared.schemas.js.map +1 -1
- package/dist/esm/inbound/inbound-delivery.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/inbound/inbound-delivery.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/inbound/inbound-delivery.shared.schemas.d.ts.map +1 -1
- package/dist/esm/inbound/inbound-delivery.shared.schemas.js.map +1 -1
- package/dist/esm/inbound/inbound-endpoint-env.shared.d.ts.map +1 -1
- package/dist/esm/inbound/inbound-endpoint-env.shared.js.map +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/meta-workflows/actions.meta-workflows.shared.schemas.d.ts.map +1 -1
- package/dist/esm/meta-workflows/actions.meta-workflows.shared.schemas.js.map +1 -1
- package/dist/esm/meta-workflows/catalog.meta-workflows.shared.schemas.d.ts.map +1 -1
- package/dist/esm/meta-workflows/catalog.meta-workflows.shared.schemas.js.map +1 -1
- package/dist/esm/meta-workflows/coding-tasks.meta-workflows.shared.schemas.d.ts.map +1 -1
- package/dist/esm/meta-workflows/coding-tasks.meta-workflows.shared.schemas.js.map +1 -1
- package/dist/esm/meta-workflows/context-selection.meta-workflows.shared.schemas.d.ts.map +1 -1
- package/dist/esm/meta-workflows/context-selection.meta-workflows.shared.schemas.js.map +1 -1
- package/dist/esm/meta-workflows/decisions.meta-workflows.shared.schemas.d.ts.map +1 -1
- package/dist/esm/meta-workflows/decisions.meta-workflows.shared.schemas.js.map +1 -1
- package/dist/esm/meta-workflows/elicitation-depth.meta-workflows.shared.schemas.d.ts +128 -0
- package/dist/esm/meta-workflows/elicitation-depth.meta-workflows.shared.schemas.d.ts.map +1 -0
- package/dist/esm/meta-workflows/elicitation-depth.meta-workflows.shared.schemas.js +136 -0
- package/dist/esm/meta-workflows/elicitation-depth.meta-workflows.shared.schemas.js.map +1 -0
- package/dist/esm/meta-workflows/orchestration.meta-workflows.shared.schemas.d.ts +32 -0
- package/dist/esm/meta-workflows/orchestration.meta-workflows.shared.schemas.d.ts.map +1 -1
- package/dist/esm/meta-workflows/orchestration.meta-workflows.shared.schemas.js +66 -1
- package/dist/esm/meta-workflows/orchestration.meta-workflows.shared.schemas.js.map +1 -1
- package/dist/esm/meta-workflows/portable-primitives.meta-workflows.shared.schemas.d.ts.map +1 -1
- package/dist/esm/meta-workflows/portable-primitives.meta-workflows.shared.schemas.js.map +1 -1
- package/dist/esm/meta-workflows.exports.d.ts +1 -0
- package/dist/esm/meta-workflows.exports.d.ts.map +1 -1
- package/dist/esm/meta-workflows.exports.js +1 -0
- package/dist/esm/meta-workflows.exports.js.map +1 -1
- package/dist/esm/monitoring/monitoring.shared.schemas.d.ts.map +1 -1
- package/dist/esm/monitoring/monitoring.shared.schemas.js.map +1 -1
- package/dist/esm/notifications/email/email-context.shared.schemas.d.ts.map +1 -1
- package/dist/esm/notifications/email/email-context.shared.schemas.js.map +1 -1
- package/dist/esm/notifications/email/email-submission.shared.enums.d.ts.map +1 -1
- package/dist/esm/notifications/email/email-submission.shared.enums.js.map +1 -1
- package/dist/esm/notifications/email/email-template-registry.shared.schemas.d.ts.map +1 -1
- package/dist/esm/notifications/email/email-template-registry.shared.schemas.js.map +1 -1
- package/dist/esm/notifications/email/email-template.shared.enums.d.ts.map +1 -1
- package/dist/esm/notifications/email/email-template.shared.enums.js.map +1 -1
- package/dist/esm/notifications/inbound-email/inbound-email.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/notifications/inbound-email/inbound-email.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/notifications/inbound-email/inbound-email.shared.schemas.d.ts.map +1 -1
- package/dist/esm/notifications/inbound-email/inbound-email.shared.schemas.js.map +1 -1
- package/dist/esm/notifications/m2m/m2m-webhook-delivery-contract.shared.d.ts.map +1 -1
- package/dist/esm/notifications/m2m/m2m-webhook-delivery-contract.shared.js.map +1 -1
- package/dist/esm/notifications/m2m/m2m-webhook-delivery-log.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/notifications/m2m/m2m-webhook-delivery-log.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/notifications/m2m/m2m-webhook-delivery-log.shared.schemas.d.ts.map +1 -1
- package/dist/esm/notifications/m2m/m2m-webhook-delivery-log.shared.schemas.js.map +1 -1
- package/dist/esm/notifications/m2m/webhook-config.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/notifications/m2m/webhook-config.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/notifications/m2m/webhook-config.shared.schemas.d.ts.map +1 -1
- package/dist/esm/notifications/m2m/webhook-config.shared.schemas.js.map +1 -1
- package/dist/esm/notifications/notification-badges.core.definitions.d.ts.map +1 -1
- package/dist/esm/notifications/notification-badges.core.definitions.js.map +1 -1
- package/dist/esm/notifications/notification-badges.schemas.d.ts.map +1 -1
- package/dist/esm/notifications/notification-badges.schemas.js.map +1 -1
- package/dist/esm/notifications/notification-badges.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/notifications/notification-badges.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/notifications/notifications.shared.schemas.d.ts.map +1 -1
- package/dist/esm/notifications/notifications.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/application-owner-organization.shared.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/application-owner-organization.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-features.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-features.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-features.shared.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-features.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-members.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-members.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-members.shared.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-members.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-notifications.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-notifications.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-notifications.shared.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-notifications.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-preferences.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-preferences.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-preferences.shared.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-preferences.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-profile.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-profile.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-profile.shared.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-profile.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-unit-inheritance.shared.d.ts.map +1 -1
- package/dist/esm/organizations/organization-unit-inheritance.shared.js.map +1 -1
- package/dist/esm/organizations/organization-unit-members.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-unit-members.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-unit-members.shared.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-unit-members.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-unit-narrowing-decision.shared.d.ts.map +1 -1
- package/dist/esm/organizations/organization-unit-narrowing-decision.shared.js.map +1 -1
- package/dist/esm/organizations/organization-unit-narrowing.example.d.ts.map +1 -1
- package/dist/esm/organizations/organization-unit-narrowing.example.js.map +1 -1
- package/dist/esm/organizations/organization-unit-narrowing.shared.d.ts.map +1 -1
- package/dist/esm/organizations/organization-unit-narrowing.shared.js.map +1 -1
- package/dist/esm/organizations/organization-units.shared.path.d.ts.map +1 -1
- package/dist/esm/organizations/organization-units.shared.path.js.map +1 -1
- package/dist/esm/organizations/organization-units.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-units.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-units.shared.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-units.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/organizations.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organizations.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/organizations/organizations.shared.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organizations.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/service-provider-activity-feed.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/service-provider-activity-feed.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/organizations/service-provider-activity-feed.shared.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/service-provider-activity-feed.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/service-provider-capability-grants.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/service-provider-capability-grants.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/organizations/service-provider-capability-grants.shared.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/service-provider-capability-grants.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/service-provider-client-controls.shared.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/service-provider-client-controls.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/service-provider-relationships.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/service-provider-relationships.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/organizations/service-provider-relationships.shared.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/service-provider-relationships.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/tenant-teardown-config.shared.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/tenant-teardown-config.shared.schemas.js.map +1 -1
- package/dist/esm/provider-registration-runtime.exports.d.ts.map +1 -1
- package/dist/esm/provider-registration-runtime.exports.js.map +1 -1
- package/dist/esm/public-runtime/index.d.ts.map +1 -1
- package/dist/esm/public-runtime/index.js.map +1 -1
- package/dist/esm/queue/jobs.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/queue/jobs.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/queue/jobs.shared.schemas.d.ts +70 -1
- package/dist/esm/queue/jobs.shared.schemas.d.ts.map +1 -1
- package/dist/esm/queue/jobs.shared.schemas.js +85 -2
- package/dist/esm/queue/jobs.shared.schemas.js.map +1 -1
- package/dist/esm/queue/jobs.shared.utils.d.ts.map +1 -1
- package/dist/esm/queue/jobs.shared.utils.js.map +1 -1
- package/dist/esm/queue/queues.shared.schemas.d.ts.map +1 -1
- package/dist/esm/queue/queues.shared.schemas.js.map +1 -1
- package/dist/esm/queue/queues.shared.utils.d.ts.map +1 -1
- package/dist/esm/queue/queues.shared.utils.js.map +1 -1
- package/dist/esm/queue/rabbitmq-queue-args.shared.d.ts.map +1 -1
- package/dist/esm/queue/rabbitmq-queue-args.shared.js.map +1 -1
- package/dist/esm/rag/rag-retrieval-health.shared.d.ts.map +1 -1
- package/dist/esm/rag/rag-retrieval-health.shared.js.map +1 -1
- package/dist/esm/requests/header-keys.shared.d.ts.map +1 -1
- package/dist/esm/requests/header-keys.shared.js.map +1 -1
- package/dist/esm/requests/http-requests.shared.d.ts.map +1 -1
- package/dist/esm/requests/http-requests.shared.js.map +1 -1
- package/dist/esm/requests/idempotency-key.shared.d.ts.map +1 -1
- package/dist/esm/requests/idempotency-key.shared.js.map +1 -1
- package/dist/esm/requests/manual-controllers-routes-documentation.d.ts.map +1 -1
- package/dist/esm/requests/manual-controllers-routes-documentation.js.map +1 -1
- package/dist/esm/requests/manual-controllers-routes-urls.d.ts.map +1 -1
- package/dist/esm/requests/manual-controllers-routes-urls.js.map +1 -1
- package/dist/esm/requests/rate-limits.shared.schemas.d.ts.map +1 -1
- package/dist/esm/requests/rate-limits.shared.schemas.js.map +1 -1
- package/dist/esm/requests/websocket.shared.schemas.d.ts.map +1 -1
- package/dist/esm/requests/websocket.shared.schemas.js.map +1 -1
- package/dist/esm/resources/child-operations.shared.schemas.d.ts.map +1 -1
- package/dist/esm/resources/child-operations.shared.schemas.js.map +1 -1
- package/dist/esm/resources/collection-query-parameters.shared.d.ts.map +1 -1
- package/dist/esm/resources/collection-query-parameters.shared.js.map +1 -1
- package/dist/esm/resources/context-policy.shared.schemas.d.ts.map +1 -1
- package/dist/esm/resources/context-policy.shared.schemas.js.map +1 -1
- package/dist/esm/resources/embedded-resource-mark.shared.utils.d.ts.map +1 -1
- package/dist/esm/resources/embedded-resource-mark.shared.utils.js.map +1 -1
- package/dist/esm/resources/relationship-display.shared.schemas.d.ts.map +1 -1
- package/dist/esm/resources/relationship-display.shared.schemas.js.map +1 -1
- package/dist/esm/resources/resources-config.shared.factory.d.ts.map +1 -1
- package/dist/esm/resources/resources-config.shared.factory.js.map +1 -1
- package/dist/esm/resources/resources-config.shared.schemas.d.ts.map +1 -1
- package/dist/esm/resources/resources-config.shared.schemas.js.map +1 -1
- package/dist/esm/resources/resources-registry.shared.core.definitions.d.ts.map +1 -1
- package/dist/esm/resources/resources-registry.shared.core.definitions.js.map +1 -1
- package/dist/esm/resources/resources-relationships.shared.factory.d.ts.map +1 -1
- package/dist/esm/resources/resources-relationships.shared.factory.js.map +1 -1
- package/dist/esm/resources/resources-serialization.shared.schemas.d.ts.map +1 -1
- package/dist/esm/resources/resources-serialization.shared.schemas.js.map +1 -1
- package/dist/esm/resources/resources.shared.core.definitions.d.ts.map +1 -1
- package/dist/esm/resources/resources.shared.core.definitions.js.map +1 -1
- package/dist/esm/resources/resources.shared.schemas.d.ts.map +1 -1
- package/dist/esm/resources/resources.shared.schemas.js.map +1 -1
- package/dist/esm/resources/resources.shared.utils.d.ts.map +1 -1
- package/dist/esm/resources/resources.shared.utils.js.map +1 -1
- package/dist/esm/resources/utils/collection-export.shared.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/collection-export.shared.utils.js.map +1 -1
- package/dist/esm/resources/utils/composition-cascade-deletability.validation.d.ts.map +1 -1
- package/dist/esm/resources/utils/composition-cascade-deletability.validation.js.map +1 -1
- package/dist/esm/resources/utils/composition-seedability.validation.d.ts.map +1 -1
- package/dist/esm/resources/utils/composition-seedability.validation.js.map +1 -1
- package/dist/esm/resources/utils/context-addressed-composition-singleton.shared.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/context-addressed-composition-singleton.shared.utils.js.map +1 -1
- package/dist/esm/resources/utils/dependent-lifecycle-classification.validation.d.ts.map +1 -1
- package/dist/esm/resources/utils/dependent-lifecycle-classification.validation.js.map +1 -1
- package/dist/esm/resources/utils/duplicate-relationship-registration.validation.d.ts.map +1 -1
- package/dist/esm/resources/utils/duplicate-relationship-registration.validation.js.map +1 -1
- package/dist/esm/resources/utils/field-value-disclosure.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/field-value-disclosure.utils.js.map +1 -1
- package/dist/esm/resources/utils/http-api-write-declaration.shared.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/http-api-write-declaration.shared.utils.js.map +1 -1
- package/dist/esm/resources/utils/initiator-stamped-field-satisfiability.validation.d.ts.map +1 -1
- package/dist/esm/resources/utils/initiator-stamped-field-satisfiability.validation.js.map +1 -1
- package/dist/esm/resources/utils/no-subject-data-stance-coherence.shared.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/no-subject-data-stance-coherence.shared.utils.js.map +1 -1
- package/dist/esm/resources/utils/persistence-adapter-discrimination.shared.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/persistence-adapter-discrimination.shared.utils.js.map +1 -1
- package/dist/esm/resources/utils/populated-file-fields.shared.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/populated-file-fields.shared.utils.js.map +1 -1
- package/dist/esm/resources/utils/repository-dto-builder.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/repository-dto-builder.utils.js.map +1 -1
- package/dist/esm/resources/utils/request-schema-field-carriage.shared.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/request-schema-field-carriage.shared.utils.js.map +1 -1
- package/dist/esm/resources/utils/required-fk-fillability.validation.d.ts.map +1 -1
- package/dist/esm/resources/utils/required-fk-fillability.validation.js.map +1 -1
- package/dist/esm/resources/utils/resource-operation-type-guards.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/resource-operation-type-guards.utils.js.map +1 -1
- package/dist/esm/resources/utils/resource-polymorphism.factory.d.ts.map +1 -1
- package/dist/esm/resources/utils/resource-polymorphism.factory.js.map +1 -1
- package/dist/esm/resources/utils/resource-polymorphism.relationships.d.ts.map +1 -1
- package/dist/esm/resources/utils/resource-polymorphism.relationships.js.map +1 -1
- package/dist/esm/resources/utils/resource-polymorphism.schemas.d.ts.map +1 -1
- package/dist/esm/resources/utils/resource-polymorphism.schemas.js.map +1 -1
- package/dist/esm/resources/utils/resource-polymorphism.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/resource-polymorphism.utils.js.map +1 -1
- package/dist/esm/resources/utils/resource-subtree.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/resource-subtree.utils.js.map +1 -1
- package/dist/esm/resources/utils/resources-config-context-needs.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/resources-config-context-needs.utils.js.map +1 -1
- package/dist/esm/resources/utils/resources-config-naming.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/resources-config-naming.utils.js.map +1 -1
- package/dist/esm/resources/utils/resources-config-operations.dtos-builder.utils.d.ts +25 -0
- package/dist/esm/resources/utils/resources-config-operations.dtos-builder.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/resources-config-operations.dtos-builder.utils.js +47 -19
- package/dist/esm/resources/utils/resources-config-operations.dtos-builder.utils.js.map +1 -1
- package/dist/esm/resources/utils/resources-config-operations.path.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/resources-config-operations.path.utils.js.map +1 -1
- package/dist/esm/resources/utils/resources-config-operations.urls-builder.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/resources-config-operations.urls-builder.utils.js.map +1 -1
- package/dist/esm/resources/utils/resources-config-operations.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/resources-config-operations.utils.js.map +1 -1
- package/dist/esm/resources/utils/resources-serialization.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/resources-serialization.utils.js.map +1 -1
- package/dist/esm/resources/utils/resources-summary.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/resources-summary.utils.js.map +1 -1
- package/dist/esm/resources/utils/schema-family-builder.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/schema-family-builder.utils.js.map +1 -1
- package/dist/esm/resources/utils/schema-type-inference.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/schema-type-inference.utils.js.map +1 -1
- package/dist/esm/resources/utils/schema-type-utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/schema-type-utils.js.map +1 -1
- package/dist/esm/resources/utils/schema-variant-resolver.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/schema-variant-resolver.utils.js.map +1 -1
- package/dist/esm/resources/utils/shared-persistence-collection.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/shared-persistence-collection.utils.js.map +1 -1
- package/dist/esm/resources/utils/templatable-file-fields.shared.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/templatable-file-fields.shared.utils.js.map +1 -1
- package/dist/esm/resources/work-unit.shared.schemas.d.ts.map +1 -1
- package/dist/esm/resources/work-unit.shared.schemas.js.map +1 -1
- package/dist/esm/runtime/domain-module.shared.definitions.d.ts.map +1 -1
- package/dist/esm/runtime/domain-module.shared.definitions.js.map +1 -1
- package/dist/esm/runtime/execution-context.shared.schemas.d.ts.map +1 -1
- package/dist/esm/runtime/execution-context.shared.schemas.js.map +1 -1
- package/dist/esm/runtime/runtime.shared.schemas.d.ts.map +1 -1
- package/dist/esm/runtime/runtime.shared.schemas.js.map +1 -1
- package/dist/esm/security/api-keys/api-keys-application.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/api-keys/api-keys-application.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/api-keys/api-keys-organization.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/api-keys/api-keys-organization.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/api-keys/api-keys.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/api-keys/api-keys.shared.schemas.js.map +1 -1
- package/dist/esm/security/authentications/anonymous-session/anonymous-session.shared.contract.d.ts.map +1 -1
- package/dist/esm/security/authentications/anonymous-session/anonymous-session.shared.contract.js.map +1 -1
- package/dist/esm/security/authentications/authentication.shared.dto.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/authentication.shared.dto.schemas.js.map +1 -1
- package/dist/esm/security/authentications/authentication.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/authentication.shared.schemas.js.map +1 -1
- package/dist/esm/security/authentications/authentication.shared.utils.d.ts.map +1 -1
- package/dist/esm/security/authentications/authentication.shared.utils.js.map +1 -1
- package/dist/esm/security/authentications/consumable-token.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/consumable-token.shared.schemas.js.map +1 -1
- package/dist/esm/security/authentications/cross-frontend-handoff.shared.dto.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/cross-frontend-handoff.shared.dto.schemas.js.map +1 -1
- package/dist/esm/security/authentications/mfa-backup-code-contract.shared.d.ts.map +1 -1
- package/dist/esm/security/authentications/mfa-backup-code-contract.shared.js.map +1 -1
- package/dist/esm/security/authentications/password-blocklist.shared.utils.d.ts.map +1 -1
- package/dist/esm/security/authentications/password-blocklist.shared.utils.js.map +1 -1
- package/dist/esm/security/authentications/password-reset.shared.dto.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/password-reset.shared.dto.schemas.js.map +1 -1
- package/dist/esm/security/authentications/registration.shared.dto.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/registration.shared.dto.schemas.js.map +1 -1
- package/dist/esm/security/authentications/same-origin-redirect-path.shared.d.ts.map +1 -1
- package/dist/esm/security/authentications/same-origin-redirect-path.shared.js.map +1 -1
- package/dist/esm/security/authentications/scim/scim-organization-unit-mapping.shared.d.ts.map +1 -1
- package/dist/esm/security/authentications/scim/scim-organization-unit-mapping.shared.js.map +1 -1
- package/dist/esm/security/authentications/scim/scim-provisioning-config.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/scim/scim-provisioning-config.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/authentications/scim/scim-provisioning-config.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/scim/scim-provisioning-config.shared.schemas.js.map +1 -1
- package/dist/esm/security/authentications/scim/scim-tokens.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/scim/scim-tokens.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/authentications/scim/scim-tokens.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/scim/scim-tokens.shared.schemas.js.map +1 -1
- package/dist/esm/security/authentications/service-provider-client-authentication.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/service-provider-client-authentication.shared.schemas.js.map +1 -1
- package/dist/esm/security/authentications/siem/siem-delivery-dlq.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/siem/siem-delivery-dlq.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/authentications/siem/siem-delivery-dlq.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/siem/siem-delivery-dlq.shared.schemas.js.map +1 -1
- package/dist/esm/security/authentications/siem/siem-delivery-outbox.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/siem/siem-delivery-outbox.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/authentications/siem/siem-delivery-outbox.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/siem/siem-delivery-outbox.shared.schemas.js.map +1 -1
- package/dist/esm/security/authentications/siem/siem-delivery-reliability-contract.shared.d.ts.map +1 -1
- package/dist/esm/security/authentications/siem/siem-delivery-reliability-contract.shared.js.map +1 -1
- package/dist/esm/security/authentications/siem/siem-export-config.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/siem/siem-export-config.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/authentications/siem/siem-export-config.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/siem/siem-export-config.shared.schemas.js.map +1 -1
- package/dist/esm/security/authentications/sso/sso-config.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/sso/sso-config.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/authentications/sso/sso-config.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/sso/sso-config.shared.schemas.js.map +1 -1
- package/dist/esm/security/authentications/sso/sso-connection.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/sso/sso-connection.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/authentications/sso/sso-connection.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/sso/sso-connection.shared.schemas.js.map +1 -1
- package/dist/esm/security/authorizations/administrative-continuity.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authorizations/administrative-continuity.shared.schemas.js.map +1 -1
- package/dist/esm/security/authorizations/application-access-grants.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/authorizations/application-access-grants.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/authorizations/application-access-grants.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authorizations/application-access-grants.shared.schemas.js.map +1 -1
- package/dist/esm/security/authorizations/platform-access-grants.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/authorizations/platform-access-grants.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/authorizations/platform-access-grants.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authorizations/platform-access-grants.shared.schemas.js.map +1 -1
- package/dist/esm/security/authorizations/roles.shared.defaults.d.ts.map +1 -1
- package/dist/esm/security/authorizations/roles.shared.defaults.js.map +1 -1
- package/dist/esm/security/authorizations/roles.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authorizations/roles.shared.schemas.js.map +1 -1
- package/dist/esm/security/authorizations/roles.shared.utils.d.ts.map +1 -1
- package/dist/esm/security/authorizations/roles.shared.utils.js.map +1 -1
- package/dist/esm/security/connected-accounts/provider-connection-listing.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/provider-connection-listing.shared.schemas.js.map +1 -1
- package/dist/esm/security/connected-accounts/provider-credentials-organization.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/provider-credentials-organization.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/connected-accounts/provider-credentials-user.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/provider-credentials-user.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/connected-accounts/provider-credentials.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/connected-accounts/provider-credentials.shared.schemas.js.map +1 -1
- package/dist/esm/security/credential-rotation-grace.shared.utils.d.ts.map +1 -1
- package/dist/esm/security/credential-rotation-grace.shared.utils.js.map +1 -1
- package/dist/esm/security/crypto-keys/crypto-keys.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/crypto-keys/crypto-keys.shared.schemas.js.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-clients-application.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-clients-application.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-clients-organization.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-clients-organization.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-clients.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-clients.shared.schemas.js.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-consent-grants.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-consent-grants.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-consent-grants.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-consent-grants.shared.schemas.js.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-resource-server.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-resource-server.shared.schemas.js.map +1 -1
- package/dist/esm/security/outbound-target-control.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/outbound-target-control.shared.schemas.js.map +1 -1
- package/dist/esm/security/submission-challenge/submission-challenge.shared.d.ts.map +1 -1
- package/dist/esm/security/submission-challenge/submission-challenge.shared.js.map +1 -1
- package/dist/esm/systems-of-record/system-of-record-actions.shared.schemas.d.ts.map +1 -1
- package/dist/esm/systems-of-record/system-of-record-actions.shared.schemas.js.map +1 -1
- package/dist/esm/systems-of-record/system-of-record-credential-kind.shared.d.ts.map +1 -1
- package/dist/esm/systems-of-record/system-of-record-credential-kind.shared.js.map +1 -1
- package/dist/esm/systems-of-record/system-of-record-declaration.shared.schemas.d.ts.map +1 -1
- package/dist/esm/systems-of-record/system-of-record-declaration.shared.schemas.js.map +1 -1
- package/dist/esm/systems-of-record/system-of-record-env.shared.d.ts.map +1 -1
- package/dist/esm/systems-of-record/system-of-record-env.shared.js.map +1 -1
- package/dist/esm/systems-of-record/system-of-record-error-codes.shared.d.ts.map +1 -1
- package/dist/esm/systems-of-record/system-of-record-error-codes.shared.js.map +1 -1
- package/dist/esm/systems-of-record/system-of-record-facet.shared.schemas.d.ts.map +1 -1
- package/dist/esm/systems-of-record/system-of-record-facet.shared.schemas.js.map +1 -1
- package/dist/esm/systems-of-record/system-of-record-partition-assignments.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/systems-of-record/system-of-record-partition-assignments.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/systems-of-record/system-of-record-partition-assignments.shared.schemas.d.ts.map +1 -1
- package/dist/esm/systems-of-record/system-of-record-partition-assignments.shared.schemas.js.map +1 -1
- package/dist/esm/testing/resource-config-builders.d.ts.map +1 -1
- package/dist/esm/testing/resource-config-builders.js.map +1 -1
- package/dist/esm/testing.d.ts.map +1 -1
- package/dist/esm/testing.js.map +1 -1
- package/dist/esm/users/anonymous-user-marketing-metadata.shared.schemas.d.ts.map +1 -1
- package/dist/esm/users/anonymous-user-marketing-metadata.shared.schemas.js.map +1 -1
- package/dist/esm/users/anonymous-users.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/users/anonymous-users.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/anonymous-users.shared.schema.d.ts.map +1 -1
- package/dist/esm/users/anonymous-users.shared.schema.js.map +1 -1
- package/dist/esm/users/inbound-contacts.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/users/inbound-contacts.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/inbound-contacts.shared.schemas.d.ts.map +1 -1
- package/dist/esm/users/inbound-contacts.shared.schemas.js.map +1 -1
- package/dist/esm/users/user-consent-decision.shared.utils.d.ts.map +1 -1
- package/dist/esm/users/user-consent-decision.shared.utils.js.map +1 -1
- package/dist/esm/users/user-credentials.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/users/user-credentials.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/user-credentials.shared.schemas.d.ts.map +1 -1
- package/dist/esm/users/user-credentials.shared.schemas.js.map +1 -1
- package/dist/esm/users/user-identity-links.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/users/user-identity-links.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/user-identity-links.shared.schemas.d.ts.map +1 -1
- package/dist/esm/users/user-identity-links.shared.schemas.js.map +1 -1
- package/dist/esm/users/user-preferences-reset.shared.utils.d.ts.map +1 -1
- package/dist/esm/users/user-preferences-reset.shared.utils.js.map +1 -1
- package/dist/esm/users/user-preferences.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/users/user-preferences.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/user-profiles.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/users/user-profiles.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/user-self-preferences.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/users/user-self-preferences.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/user-self-profiles.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/users/user-self-profiles.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/user-self.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/users/user-self.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/users.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/users/users.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/users.shared.schemas.d.ts.map +1 -1
- package/dist/esm/users/users.shared.schemas.js.map +1 -1
- package/package.json +4 -4
- package/dist/esm/__tests__/setup.d.ts +0 -2
- package/dist/esm/__tests__/setup.d.ts.map +0 -1
- package/dist/esm/__tests__/setup.js +0 -19
- package/dist/esm/__tests__/setup.js.map +0 -1
- package/dist/tsconfig.build.tsbuildinfo +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-storage.shared.schemas.js","sourceRoot":"","sources":["../../../../src/compliance/privacy/client-storage.shared.schemas.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\n\nimport { WEBSITE_VISITOR_CONSENT_STORAGE_KEY } from \"./consent-purposes.shared\";\n\n/**\n * **What the application stores in a visitor's browser, and what gates it.**\n *\n * ## What a cookie notice actually is\n *\n * An itemised table: which cookies and client-side storage keys are set, what each is for, how long it\n * persists, and which are strictly necessary versus consent-gated. Nothing in the framework declared\n * any of it (issue #91).\n *\n * The consent POSTURE was already real and enforced — `consentedPurposes` plus the capability\n * flags make `ConsentPurpose.ANALYTICS` a boundary the runtime honours rather than a stated intention, which is a\n * stronger position than most cookie notices, which describe consent they do not enforce. What could\n * not be produced was the table.\n *\n * ## The engine sets cookies of its own, and that is why this has an ORIGIN split\n *\n * Every generated application sets at least one cookie it never declared, because the framework sets\n * it: {@link ENGINE_CLIENT_STORAGE_ENTRIES}. Asking only the application would produce a cookie table\n * that omits the session cookie — the same shape as the engine-versus-application finding in the\n * resource declarations, and the same remedy: report the two origins separately, and let the framework\n * answer for its own.\n *\n * ## Lifetimes the framework will not invent\n *\n * The engine's cookies take their `maxAge` from the application's session configuration, so the\n * framework declares the NAME, the purpose and the necessity, and describes the lifetime by where it\n * comes from. A fixed number here would be a published commitment nothing enforces — the same rule\n * that governs the retention schedule.\n */\n\n/** Where a value is stored in the browser. Cookies and web storage carry different expectations and different law. */\nexport enum ClientStorageMechanism {\n COOKIE = \"COOKIE\",\n LOCAL_STORAGE = \"LOCAL_STORAGE\",\n SESSION_STORAGE = \"SESSION_STORAGE\",\n}\n\n/**\n * Whether the entry may be set before consent.\n *\n * The distinction a cookie banner exists to implement, and the one a notice is read for. Two values on\n * purpose: an entry is either required for a service the visitor asked for, or it is not and needs\n * consent. A middle category would be a place to put everything nobody wanted to decide.\n */\nexport enum ClientStorageNecessity {\n /** Required to deliver a service the visitor explicitly requested — signing in, keeping a session. */\n STRICTLY_NECESSARY = \"STRICTLY_NECESSARY\",\n /** Set only after the visitor consents. Analytics, personalisation, anything measuring behaviour. */\n CONSENT_GATED = \"CONSENT_GATED\",\n}\n\n/** One cookie or storage key, as a notice's table would print it. */\nexport const ClientStorageEntrySchema = z.strictObject({\n /** The exact key or cookie name a visitor would see in their browser. Not a description of it. */\n name: z.string().trim().min(1),\n mechanism: z.enum(ClientStorageMechanism),\n /** What it is FOR, in a sentence a visitor can read. \"Session management\", not \"auth token v2\". */\n purpose: z.string().trim().min(1),\n necessity: z.enum(ClientStorageNecessity),\n /**\n * How long it persists, as a notice would state it — \"the browser session\", \"30 days\", or where the\n * value comes from when the application configures it.\n *\n * Free text rather than a duration, because the honest answer is often a reference rather than a\n * number, and a number the application does not actually enforce is worse than a description of the\n * mechanism that does.\n */\n lifetime: z.string().trim().min(1),\n /**\n * WHEN it is set, for an entry that is not set on every visit — `null` when it always is.\n *\n * Required-and-nullable rather than optional: \"set on every visit\" and \"nobody recorded when\" are\n * different answers, and a cookie table that implies the first while meaning the second overstates\n * what a visitor's browser holds.\n */\n setWhen: z.string().trim().min(1).nullable(),\n});\nexport type ClientStorageEntry = z.infer<typeof ClientStorageEntrySchema>;\n\n/**\n * The client storage the FRAMEWORK sets, which no application authored and every application inherits.\n *\n * All are `STRICTLY_NECESSARY`. The two cookies carry session state for a service the visitor asked for\n * and are `httpOnly`, so no script can read them. The website consent record (#534) is web storage and\n * is necessary for a different reason: remembering a refusal is what makes the refusal hold, and a\n * consent record that itself needed consent could never be kept.\n *\n * Their lifetimes are the application's to configure, so they are described by their SOURCE. Their\n * `setWhen` is stated because neither is unconditional: an application whose visitors never sign in\n * sets no refresh cookie, and one that does not use anonymous sessions sets no anonymous cookie. A\n * table claiming both are always present would overstate what a visitor's browser holds.\n */\nexport const ENGINE_CLIENT_STORAGE_ENTRIES: readonly ClientStorageEntry[] = Object.freeze([\n Object.freeze({\n name: \"__wildo_refresh\",\n mechanism: ClientStorageMechanism.COOKIE,\n purpose: \"Keeps a signed-in session alive so a visitor is not asked to authenticate on every request.\",\n necessity: ClientStorageNecessity.STRICTLY_NECESSARY,\n lifetime: \"The application's configured refresh-token expiry.\",\n setWhen: \"Set when a visitor signs in, and cleared when they sign out.\",\n }),\n Object.freeze({\n name: \"__wildo_anon_session\",\n mechanism: ClientStorageMechanism.COOKIE,\n purpose: \"Gives a visitor who has not signed in a continuous session, so work in progress survives a page load.\",\n necessity: ClientStorageNecessity.STRICTLY_NECESSARY,\n lifetime: \"The application's configured anonymous-session lifetime.\",\n setWhen: \"Set only where the application admits anonymous visitors.\",\n }),\n Object.freeze({\n name: WEBSITE_VISITOR_CONSENT_STORAGE_KEY,\n mechanism: ClientStorageMechanism.LOCAL_STORAGE,\n purpose: \"Remembers which optional purposes a website visitor agreed to, so they are not asked on every page and nothing optional starts without it.\",\n necessity: ClientStorageNecessity.STRICTLY_NECESSARY,\n lifetime: \"Until the visitor changes their choice or clears the site's storage.\",\n setWhen: \"Set on the marketing website when a visitor makes a consent choice, and only where the site runs a consent-based provider.\",\n }),\n]);\n\n/**\n * The application's own client storage, per FRONTEND SURFACE.\n *\n * Per surface rather than application-wide, and that is the issue's own point: a public marketing site\n * and the authenticated application set different things, and one merged list would be wrong for both —\n * it would show a visitor to the marketing site cookies only the app sets.\n *\n * Partial: a surface with no entry has not been inventoried, which the derivation reports. An empty\n * ARRAY is the different, positive answer — this surface sets nothing of its own beyond the engine's.\n */\nexport const ApplicationClientStorageInventorySchema = z.record(\n z.string().trim().min(1),\n z.array(ClientStorageEntrySchema),\n);\nexport type ApplicationClientStorageInventory = z.infer<typeof ApplicationClientStorageInventorySchema>;\n\n/**\n * Frontend surfaces with no inventory at all — the gap, per surface.\n *\n * Takes the surface list as an argument so the same function serves the companion (which reads the\n * declared services) and a test. Order follows the surfaces given, so the answer reads like the\n * application it describes.\n */\nexport function uninventoriedClientStorageSurfaces(\n frontendSurfaceKeys: readonly string[],\n inventory: ApplicationClientStorageInventory | undefined,\n): readonly string[] {\n return frontendSurfaceKeys.filter((surfaceKey) => inventory?.[surfaceKey] === undefined);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"client-storage.shared.schemas.js","sourceRoot":"","sources":["../../../../../src/compliance/privacy/client-storage.shared.schemas.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\n\nimport { WEBSITE_VISITOR_CONSENT_STORAGE_KEY } from \"./consent-purposes.shared\";\n\n/**\n * **What the application stores in a visitor's browser, and what gates it.**\n *\n * ## What a cookie notice actually is\n *\n * An itemised table: which cookies and client-side storage keys are set, what each is for, how long it\n * persists, and which are strictly necessary versus consent-gated. Nothing in the framework declared\n * any of it (issue #91).\n *\n * The consent POSTURE was already real and enforced — `consentedPurposes` plus the capability\n * flags make `ConsentPurpose.ANALYTICS` a boundary the runtime honours rather than a stated intention, which is a\n * stronger position than most cookie notices, which describe consent they do not enforce. What could\n * not be produced was the table.\n *\n * ## The engine sets cookies of its own, and that is why this has an ORIGIN split\n *\n * Every generated application sets at least one cookie it never declared, because the framework sets\n * it: {@link ENGINE_CLIENT_STORAGE_ENTRIES}. Asking only the application would produce a cookie table\n * that omits the session cookie — the same shape as the engine-versus-application finding in the\n * resource declarations, and the same remedy: report the two origins separately, and let the framework\n * answer for its own.\n *\n * ## Lifetimes the framework will not invent\n *\n * The engine's cookies take their `maxAge` from the application's session configuration, so the\n * framework declares the NAME, the purpose and the necessity, and describes the lifetime by where it\n * comes from. A fixed number here would be a published commitment nothing enforces — the same rule\n * that governs the retention schedule.\n */\n\n/** Where a value is stored in the browser. Cookies and web storage carry different expectations and different law. */\nexport enum ClientStorageMechanism {\n COOKIE = \"COOKIE\",\n LOCAL_STORAGE = \"LOCAL_STORAGE\",\n SESSION_STORAGE = \"SESSION_STORAGE\",\n}\n\n/**\n * Whether the entry may be set before consent.\n *\n * The distinction a cookie banner exists to implement, and the one a notice is read for. Two values on\n * purpose: an entry is either required for a service the visitor asked for, or it is not and needs\n * consent. A middle category would be a place to put everything nobody wanted to decide.\n */\nexport enum ClientStorageNecessity {\n /** Required to deliver a service the visitor explicitly requested — signing in, keeping a session. */\n STRICTLY_NECESSARY = \"STRICTLY_NECESSARY\",\n /** Set only after the visitor consents. Analytics, personalisation, anything measuring behaviour. */\n CONSENT_GATED = \"CONSENT_GATED\",\n}\n\n/** One cookie or storage key, as a notice's table would print it. */\nexport const ClientStorageEntrySchema = z.strictObject({\n /** The exact key or cookie name a visitor would see in their browser. Not a description of it. */\n name: z.string().trim().min(1),\n mechanism: z.enum(ClientStorageMechanism),\n /** What it is FOR, in a sentence a visitor can read. \"Session management\", not \"auth token v2\". */\n purpose: z.string().trim().min(1),\n necessity: z.enum(ClientStorageNecessity),\n /**\n * How long it persists, as a notice would state it — \"the browser session\", \"30 days\", or where the\n * value comes from when the application configures it.\n *\n * Free text rather than a duration, because the honest answer is often a reference rather than a\n * number, and a number the application does not actually enforce is worse than a description of the\n * mechanism that does.\n */\n lifetime: z.string().trim().min(1),\n /**\n * WHEN it is set, for an entry that is not set on every visit — `null` when it always is.\n *\n * Required-and-nullable rather than optional: \"set on every visit\" and \"nobody recorded when\" are\n * different answers, and a cookie table that implies the first while meaning the second overstates\n * what a visitor's browser holds.\n */\n setWhen: z.string().trim().min(1).nullable(),\n});\nexport type ClientStorageEntry = z.infer<typeof ClientStorageEntrySchema>;\n\n/**\n * The client storage the FRAMEWORK sets, which no application authored and every application inherits.\n *\n * All are `STRICTLY_NECESSARY`. The two cookies carry session state for a service the visitor asked for\n * and are `httpOnly`, so no script can read them. The website consent record (#534) is web storage and\n * is necessary for a different reason: remembering a refusal is what makes the refusal hold, and a\n * consent record that itself needed consent could never be kept.\n *\n * Their lifetimes are the application's to configure, so they are described by their SOURCE. Their\n * `setWhen` is stated because neither is unconditional: an application whose visitors never sign in\n * sets no refresh cookie, and one that does not use anonymous sessions sets no anonymous cookie. A\n * table claiming both are always present would overstate what a visitor's browser holds.\n */\nexport const ENGINE_CLIENT_STORAGE_ENTRIES: readonly ClientStorageEntry[] = Object.freeze([\n Object.freeze({\n name: \"__wildo_refresh\",\n mechanism: ClientStorageMechanism.COOKIE,\n purpose: \"Keeps a signed-in session alive so a visitor is not asked to authenticate on every request.\",\n necessity: ClientStorageNecessity.STRICTLY_NECESSARY,\n lifetime: \"The application's configured refresh-token expiry.\",\n setWhen: \"Set when a visitor signs in, and cleared when they sign out.\",\n }),\n Object.freeze({\n name: \"__wildo_anon_session\",\n mechanism: ClientStorageMechanism.COOKIE,\n purpose: \"Gives a visitor who has not signed in a continuous session, so work in progress survives a page load.\",\n necessity: ClientStorageNecessity.STRICTLY_NECESSARY,\n lifetime: \"The application's configured anonymous-session lifetime.\",\n setWhen: \"Set only where the application admits anonymous visitors.\",\n }),\n Object.freeze({\n name: WEBSITE_VISITOR_CONSENT_STORAGE_KEY,\n mechanism: ClientStorageMechanism.LOCAL_STORAGE,\n purpose: \"Remembers which optional purposes a website visitor agreed to, so they are not asked on every page and nothing optional starts without it.\",\n necessity: ClientStorageNecessity.STRICTLY_NECESSARY,\n lifetime: \"Until the visitor changes their choice or clears the site's storage.\",\n setWhen: \"Set on the marketing website when a visitor makes a consent choice, and only where the site runs a consent-based provider.\",\n }),\n]);\n\n/**\n * The application's own client storage, per FRONTEND SURFACE.\n *\n * Per surface rather than application-wide, and that is the issue's own point: a public marketing site\n * and the authenticated application set different things, and one merged list would be wrong for both —\n * it would show a visitor to the marketing site cookies only the app sets.\n *\n * Partial: a surface with no entry has not been inventoried, which the derivation reports. An empty\n * ARRAY is the different, positive answer — this surface sets nothing of its own beyond the engine's.\n */\nexport const ApplicationClientStorageInventorySchema = z.record(\n z.string().trim().min(1),\n z.array(ClientStorageEntrySchema),\n);\nexport type ApplicationClientStorageInventory = z.infer<typeof ApplicationClientStorageInventorySchema>;\n\n/**\n * Frontend surfaces with no inventory at all — the gap, per surface.\n *\n * Takes the surface list as an argument so the same function serves the companion (which reads the\n * declared services) and a test. Order follows the surfaces given, so the answer reads like the\n * application it describes.\n */\nexport function uninventoriedClientStorageSurfaces(\n frontendSurfaceKeys: readonly string[],\n inventory: ApplicationClientStorageInventory | undefined,\n): readonly string[] {\n return frontendSurfaceKeys.filter((surfaceKey) => inventory?.[surfaceKey] === undefined);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consent-gate-vocabulary.shared.schemas.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"consent-gate-vocabulary.shared.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/compliance/privacy/consent-gate-vocabulary.shared.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D;;;;;;;;;;;GAWG;AACH,oBAAY,iBAAiB;IAC3B,kIAAkI;IAClI,OAAO,YAAY;IACnB,sFAAsF;IACtF,MAAM,WAAW;IACjB,+JAA+J;IAC/J,aAAa,iBAAiB;IAC9B,wHAAwH;IACxH,MAAM,UAAU;IAChB,wKAAwK;IACxK,SAAS,aAAa;IACtB,sKAAsK;IACtK,MAAM,WAAW;CAClB;AAED;;;;;;;GAOG;AACH,oBAAY,kBAAkB;IAC5B,qHAAqH;IACrH,MAAM,WAAW;IACjB;;;;OAIG;IACH,mBAAmB,uBAAuB;IAC1C;;;;;;OAMG;IACH,gBAAgB,oBAAoB;CACrC;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kCAAkC,2BAA2B,CAAC;AAC3E,eAAO,MAAM,mCAAmC,sCAAsC,CAAC;AAEvF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,uCAAuC;IACtD,wDAAwD;IACxD,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,mGAAmG;IACnG,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,gBAAgB,CAAC,CAAC;IACpF,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC;CACrC;AAED,0GAA0G;AAC1G,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;CACtC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,QAAQ,CAAC,OAAO,EAAE,SAAS,cAAc,EAAE,CAAC;IAC5C,QAAQ,CAAC,WAAW,EAAE,uCAAuC,GAAG,SAAS,CAAC;IAC1E,QAAQ,CAAC,uBAAuB,EAAE,SAAS,cAAc,EAAE,CAAC;CAC7D,GAAG,yBAAyB,GAAG,SAAS,CAMxC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consent-gate-vocabulary.shared.schemas.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"consent-gate-vocabulary.shared.schemas.js","sourceRoot":"","sources":["../../../../../src/compliance/privacy/consent-gate-vocabulary.shared.schemas.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,MAAM,CAAN,IAAY,iBAaX;AAbD,WAAY,iBAAiB;IAC3B,kIAAkI;IAClI,wCAAmB,CAAA;IACnB,sFAAsF;IACtF,sCAAiB,CAAA;IACjB,+JAA+J;IAC/J,mDAA8B,CAAA;IAC9B,wHAAwH;IACxH,qCAAgB,CAAA;IAChB,wKAAwK;IACxK,2CAAsB,CAAA;IACtB,sKAAsK;IACtK,sCAAiB,CAAA;AACnB,CAAC,EAbW,iBAAiB,KAAjB,iBAAiB,QAa5B;AAED;;;;;;;GAOG;AACH,MAAM,CAAN,IAAY,kBAiBX;AAjBD,WAAY,kBAAkB;IAC5B,qHAAqH;IACrH,uCAAiB,CAAA;IACjB;;;;OAIG;IACH,gEAA0C,CAAA;IAC1C;;;;;;OAMG;IACH,0DAAoC,CAAA;AACtC,CAAC,EAjBW,kBAAkB,KAAlB,kBAAkB,QAiB7B;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,kCAAkC,GAAG,iBAAiB,CAAC,MAAM,CAAC;AAC3E,MAAM,CAAC,MAAM,mCAAmC,GAAG,kBAAkB,CAAC,gBAAgB,CAAC;AA2CvF;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,yBAAyB,CAAC,KAIzC;IACC,MAAM,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC;IAC9B,IAAI,CAAC,WAAW;QAAE,OAAO,SAAS,CAAC;IACnC,IAAI,KAAK,CAAC,uBAAuB,CAAC,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IAClF,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IAClE,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,OAAO,IAAI,kBAAkB,CAAC,mBAAmB,EAAE,CAAC;AAClH,CAAC","sourcesContent":["import { ConsentPurpose } from './consent-purposes.shared';\n\n/**\n * WHEN a person is put the question of a consent-gated purpose (#1258 Step 3).\n *\n * `compliance.serviceConsentRequirement` collapsed this axis to one member — the check runs on\n * every user-initiated operation, forever — and that is correct for exactly the case it exists for\n * (the whole application rests on the purpose). Most declared purposes do not: an operation that\n * merely USES a purpose when it is granted needs to ask once, not on every call.\n *\n * A closed vocabulary rather than a boolean or a duration, because each member is a different KIND\n * of trigger — some are moments in a lifecycle, one is a standing check — and a single \"how often\"\n * field could not tell a reader which.\n */\nexport enum ConsentGateTiming {\n /** Before there is an account — the marketing website's own visitor prompt. Not backend-enforced: no request exists to refuse. */\n VISITOR = 'visitor',\n /** At the moment an account is created, alongside document acceptance. Asked once. */\n SIGNUP = 'signup',\n /** The first time a signed-in person's session reaches the application, via the guidance/onboarding engine (D7). Asked once per person, not per capability. */\n FIRST_SESSION = 'firstSession',\n /** The first time THIS capability is reached, by the surface that declares it. Asked once per person per capability. */\n ON_USE = 'onUse',\n /** Re-asked when the declaration this purpose rests on changes materially — mirrors governed-document re-acceptance (Step 2), never a silent re-prompt of everybody. */\n ON_CHANGE = 'onChange',\n /** Checked on every user-initiated operation, application-wide. The ONLY member `serviceConsentRequirement` uses — see {@link SERVICE_CONSENT_REQUIREMENT_TIMING}. */\n ALWAYS = 'always',\n}\n\n/**\n * WHAT a missing consent-gated purpose costs the person right now (#1258 Step 3).\n *\n * A closed vocabulary rather than a boolean \"blocking\", because a missing purpose has three\n * genuinely different consequences and conflating any two of them either over-blocks (today's\n * `serviceConsentRequirement`, applied per capability, would lock a person out of a to-do list over\n * analytics) or under-informs (silently disabling a feature with no explanation).\n */\nexport enum ConsentGateRefusal {\n /** Nothing is withheld. The purpose is surfaced to the person as a decision they have not made, and nothing more. */\n INFORM = 'inform',\n /**\n * The DECLARING operation refuses, with a typed error the caller can branch on, and nothing else.\n * The default when a declaration names a purpose and no refusal (D2) — a declaration that only\n * says WHAT is asked must not silently become a claim about the whole product.\n */\n WITHHOLD_CAPABILITY = 'withholdCapability',\n /**\n * The whole application is withheld until the purpose is granted. Reserved for the application-wide\n * requirement (`serviceConsentRequirement`) — see {@link SERVICE_CONSENT_REQUIREMENT_REFUSAL}. An\n * operation-level declaration may not choose this member (its type excludes it): a single capability\n * asking for the whole product to be withheld is exactly the collapse D2 exists to prevent, and the\n * one place that genuinely means it already has its own field.\n */\n WITHHOLD_SERVICE = 'withholdService',\n}\n\n/**\n * `compliance.serviceConsentRequirement` is the ONE cell of the ⟨timing, refusal⟩ grid this framework\n * enforces unconditionally (D1): {@link ConsentGateTiming.ALWAYS} × {@link ConsentGateRefusal.WITHHOLD_SERVICE},\n * applied to the whole application rather than to one capability.\n *\n * It needs no `timing` / `refusal` field of its own — the cell is fixed by what the field IS — and\n * these two constants exist only so the mapping is STATED rather than merely true: a reader who has\n * just read {@link ConsentGateTiming} and {@link ConsentGateRefusal} can find, in one place, which\n * cell the field they already know about occupies. The runtime behaviour is unchanged; see\n * `assertServiceConsentRequirementMet` in `@wildo-ai/saas-backend-lib`, which evaluates BOTH this\n * cell and any operation's own {@link ResourceOperationConsentGateDeclaration} through the same\n * chokepoint, so the two axes cannot disagree about a purpose both name.\n */\nexport const SERVICE_CONSENT_REQUIREMENT_TIMING = ConsentGateTiming.ALWAYS;\nexport const SERVICE_CONSENT_REQUIREMENT_REFUSAL = ConsentGateRefusal.WITHHOLD_SERVICE;\n\n/**\n * What a resource OPERATION declares about the purpose its processing rests on (#1258 Step 3).\n *\n * \"A capability declares the purpose it rests on — on the resource operation first\": this is that\n * declaration. It lives beside `recordsUsage` and `userNotifications` on the operation config — an\n * authored consequence of the operation, expressed where the operation is expressed — and is read by\n * the SAME evaluator `serviceConsentRequirement` goes through, so a purpose required at BOTH levels is\n * governed once rather than twice (`consentGateCapabilityOwed`).\n *\n * `refusal` excludes {@link ConsentGateRefusal.WITHHOLD_SERVICE} by TYPE, not by convention — see that\n * member's own doc for why. `timing` is advisory to the backend (which enforces regardless of when a\n * frontend surface asked) and load-bearing for the frontend surface that decides WHEN to ask.\n *\n * **The prompt surface reads this field (#1462).** `applicationAskedConsentPurposes` unions\n * `requiredPurposes`, `analytics.*` and `compliance.capabilityDeclaredConsentPurposes` — the set the\n * engine derives, once at boot, from every operation's own `consentGate` across the whole registry\n * (`collectCapabilityDeclaredConsentPurposes`, called by `ResourcesRegistryBackendService.initialize()`\n * the moment the registry is built). So declaring one here is enough: no second declaration site, and\n * the application-tier gate offers it the same way it already offers ANALYTICS.\n *\n * What this does NOT yet do: distinguish `timing`. `ON_USE` / `FIRST_SESSION` are declared members of\n * {@link ConsentGateTiming} with no dedicated prompt surface to honour them — every declared purpose\n * is offered by the one generic prompt that exists today, regardless of which timing member it names.\n * That is a real, tracked gap (`#1462`'s two folded-in follow-ups), and it is strictly better than the\n * alternative it replaced: refusing a capability with nowhere at all to grant what it asks for.\n */\nexport interface ResourceOperationConsentGateDeclaration {\n /** The purpose this operation's processing rests on. */\n readonly purpose: ConsentPurpose;\n /** What a missing grant costs. Defaults to {@link ConsentGateRefusal.WITHHOLD_CAPABILITY} (D2). */\n readonly refusal?: Exclude<ConsentGateRefusal, ConsentGateRefusal.WITHHOLD_SERVICE>;\n /** When the person is asked. Defaults to {@link ConsentGateTiming.ON_USE}. */\n readonly timing?: ConsentGateTiming;\n}\n\n/** One purpose this principal owes, and what it currently costs them, for ONE operation's declaration. */\nexport interface ConsentGateCapabilityOwed {\n readonly purpose: ConsentPurpose;\n readonly refusal: ConsentGateRefusal;\n}\n\n/**\n * What an operation's OWN {@link ResourceOperationConsentGateDeclaration} still owes, given what the\n * person has granted and what the application already requires application-wide.\n *\n * Pure, so the merge rule between the two independent sources of a required purpose — the\n * application-wide requirement and a capability's own declaration — is written once and pinned\n * without a running backend. `undefined` in every case where nothing is owed:\n *\n * - the operation declares nothing;\n * - the declared purpose is already granted;\n * - the declared purpose is ALSO in the application-wide required set — that purpose is already\n * governed by `serviceConsentRequirement`'s WITHHOLD_SERVICE cell, so re-declaring it here would\n * evaluate the same fact twice and could, on a future edit, disagree with itself.\n */\nexport function consentGateCapabilityOwed(input: {\n readonly granted: readonly ConsentPurpose[];\n readonly declaration: ResourceOperationConsentGateDeclaration | undefined;\n readonly serviceRequiredPurposes: readonly ConsentPurpose[];\n}): ConsentGateCapabilityOwed | undefined {\n const { declaration } = input;\n if (!declaration) return undefined;\n if (input.serviceRequiredPurposes.includes(declaration.purpose)) return undefined;\n if (input.granted.includes(declaration.purpose)) return undefined;\n return { purpose: declaration.purpose, refusal: declaration.refusal ?? ConsentGateRefusal.WITHHOLD_CAPABILITY };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consent-purposes.shared.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"consent-purposes.shared.d.ts","sourceRoot":"","sources":["../../../../../src/compliance/privacy/consent-purposes.shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,oBAAY,cAAc;IACxB,6EAA6E;IAC7E,SAAS,cAAc;IACvB,mFAAmF;IACnF,SAAS,cAAc;CACxB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,mCAAmC,4BAA4B,CAAC;AAE7E;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,6BAA6B,oCAAoC,CAAC;AAE/E;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,+BAA+B,QAAQ,CAAC;AAErD,uFAAuF;AACvF,eAAO,MAAM,gBAAgB,EAAE,SAAS,cAAc,EAAiD,CAAC;AAExG;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,SAAS,cAAc,EAAE,GAAG,SAAS,EAC9C,QAAQ,EAAE,SAAS,cAAc,EAAE,GAClC,cAAc,EAAE,CAGlB;AAED,uDAAuD;AACvD,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,SAAS,cAAc,EAAE,GAAG,SAAS,EAC9C,QAAQ,EAAE,SAAS,cAAc,EAAE,GAClC,OAAO,CAET;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE;IACrD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9C,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,wBAAwB,EAAE,OAAO,CAAC;IAC3C,0IAA0I;IAC1I,QAAQ,CAAC,0BAA0B,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACzD,GAAG,cAAc,EAAE,CAQnB;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAAG,cAAc,EAAE,CAGlG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consent-purposes.shared.js","sourceRoot":"","sources":["../../../../src/compliance/privacy/consent-purposes.shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAN,IAAY,cAKX;AALD,WAAY,cAAc;IACxB,6EAA6E;IAC7E,yCAAuB,CAAA;IACvB,mFAAmF;IACnF,yCAAuB,CAAA;AACzB,CAAC,EALW,cAAc,KAAd,cAAc,QAKzB;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,mCAAmC,GAAG,yBAAyB,CAAC;AAE7E;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,iCAAiC,CAAC;AAE/E;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,KAAK,CAAC;AAErD,uFAAuF;AACvF,MAAM,CAAC,MAAM,gBAAgB,GAA8B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;AAExG;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAA8C,EAC9C,QAAmC;IAEnC,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IAC1C,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;AACtG,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,yBAAyB,CACvC,OAA8C,EAC9C,QAAmC;IAEnC,OAAO,sBAAsB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,+BAA+B,CAAC,KAM/C;IACC,MAAM,QAAQ,GAAG,wBAAwB,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAClE,MAAM,kBAAkB,GAAG,wBAAwB,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACtF,MAAM,KAAK,GAAG,IAAI,GAAG,CAAiB,CAAC,GAAG,QAAQ,EAAE,GAAG,kBAAkB,CAAC,CAAC,CAAC;IAC5E,IAAI,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,wBAAwB,EAAE,CAAC;QAC7D,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;AAClE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CAAC,QAAuC;IAC9E,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IACtC,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;AAClE,CAAC","sourcesContent":["/**\n * Consent purposes — the optional processing a person may independently agree to.\n *\n * ## A SET, not a ladder (decided by Paul, 2026-09-09 — #534 / #453)\n *\n * This replaces `DataProcessingConsent` (`NONE · BASIC · ANALYTICS · MARKETING · FULL`), which was an\n * ORDERED level. The order was a claim nobody decided and the law does not make: agreeing to\n * marketing is not \"more than\" agreeing to analytics, and a ladder made consenting to one imply\n * consenting to the ones \"below\" it. The only thing that ever enforced the order was a module-private\n * `CONSENT_ORDER` inside the frontend analytics provider.\n *\n * So each member is a PURPOSE, granted or not on its own, and a person's consent is the set of\n * purposes they granted. The old members map without loss of meaning:\n *\n * - `NONE` → the empty set.\n * - `BASIC` → not a purpose at all. It stood for processing the service needs in order to exist,\n * which is never consent-based (it rests on contract or legitimate interest), so it has no member.\n * - `FULL` → every member.\n *\n * ## Why this file imports nothing\n *\n * It is carved onto `@wildo-ai/saas-models/public-runtime` (K-2), because the visitor-tier\n * `WebsiteConsentGate` in the browser bundle reads the same vocabulary the application stores. One\n * vocabulary, one file: the original privacy schema imports it from here.\n *\n * Adding a member is a product decision with legal weight — every surface that asks a person for\n * consent renders the whole set, and every application's consent-gated processing must name which\n * member it rests on.\n */\nexport enum ConsentPurpose {\n /** Measuring how the service is used — product analytics, usage tracking. */\n ANALYTICS = 'analytics',\n /** Contacting the person or tailoring outreach to them for promotional reasons. */\n MARKETING = 'marketing',\n}\n\n/**\n * The browser storage key under which a Wildo marketing website keeps a VISITOR's consent decision.\n *\n * The visitor tier has no account to store a decision on, so it lives in the visitor's own browser, on\n * the website's origin — which is also why it does not follow them into the signed-in application, whose\n * decision is `privacy.consentedPurposes` on the person's preferences. Named once here so the website's\n * storage adapter and the cookie table (`ENGINE_CLIENT_STORAGE_ENTRIES`) cannot name different keys.\n */\nexport const WEBSITE_VISITOR_CONSENT_STORAGE_KEY = '__wildo_website_consent';\n\n/**\n * The route a VISITOR's consent decision is recorded through — `ANONYMOUS_USERS.record_consent`.\n *\n * Named here for the same reason as the storage key above: the marketing website must not depend on\n * `saas-models`' resource layer (bundle discipline keeps it to `public-runtime` atoms), so without a\n * shared constant the website would hard-code a path string and the engine would build one, with\n * nothing joining them. `/inbound-contacts` is hard-coded that way today, which is the drift this\n * avoids.\n *\n * It is not asserted by hand: `consent-purposes.shared.test.ts` derives it from the operation's own\n * identifier through `ResourcesConfigNamingUtils.toKebabCase` — the same transform the URL builder\n * uses — so renaming the resource or the operation reddens rather than 404s at runtime.\n */\nexport const ANONYMOUS_CONSENT_RECORD_PATH = '/anonymous-users/record-consent';\n\n/**\n * The HTTP METHOD that route answers — `PUT`, not `POST`.\n *\n * ## Why this constant had to exist\n *\n * The sibling above named the PATH and stopped there, and its own note predicted the consequence of a\n * drift precisely: *\"the failure is a 404 at runtime, on a public path nobody monitors.\"* That is what\n * happened, to the half it did not cover. `RECORD_CONSENT` declares\n * `resourceOperationLike: UPDATE_MANY`, and `getDefaultHttpVerbForOperation` maps every UPDATE verb to\n * `PUT` — but nothing said so where a client could read it, so two independent clients assumed POST and\n * both 404'd: the marketing website's recorder, whose failure is deliberately (and correctly) silent,\n * and the application's pre-auth recorder written against it.\n *\n * A path without its method is half an address. Naming both here is what lets a client be right by\n * reading rather than by guessing, and `consent-purposes.shared.test.ts` derives this from the built\n * operation's own `httpVerb` — the value the router registers — so changing the operation's shape\n * reddens instead of silently moving the door.\n */\nexport const ANONYMOUS_CONSENT_RECORD_METHOD = 'PUT';\n\n/** Every purpose, in declaration order — the order a consent surface lists them in. */\nexport const CONSENT_PURPOSES: readonly ConsentPurpose[] = Object.freeze(Object.values(ConsentPurpose));\n\n/**\n * The purposes in `required` that `granted` does not contain. Empty when every required purpose was\n * granted — including when nothing is required.\n *\n * Membership, never rank: there is no purpose whose grant satisfies another.\n */\nexport function missingConsentPurposes(\n granted: readonly ConsentPurpose[] | undefined,\n required: readonly ConsentPurpose[],\n): ConsentPurpose[] {\n const grantedSet = new Set(granted ?? []);\n return CONSENT_PURPOSES.filter((purpose) => required.includes(purpose) && !grantedSet.has(purpose));\n}\n\n/** Whether every purpose in `required` was granted. */\nexport function hasGrantedConsentPurposes(\n granted: readonly ConsentPurpose[] | undefined,\n required: readonly ConsentPurpose[],\n): boolean {\n return missingConsentPurposes(granted, required).length === 0;\n}\n\n/**\n * Every purpose THIS APPLICATION would put to a person — what its own consent surface asks.\n *\n * Two readers needed this and would otherwise have derived it twice: the application's consent gate,\n * deciding what to render, and the anonymous-consent carry, deciding whether a visitor was shown\n * enough for their decision to count as complete. Two derivations of \"what do we ask\" drift, and the\n * drift is invisible — the gate would prompt for a purpose the carry had already recorded as\n * decided, or the reverse.\n *\n * Takes PRIMITIVES rather than the config objects, so this file keeps the import-free property that\n * lets it be carved onto `public-runtime` for the website bundle.\n *\n * Total over what the configuration STATES A USE FOR, never over the enum: asking for a purpose\n * nothing processes collects a consent that means nothing. A required purpose is asked by\n * definition; ANALYTICS is asked when analytics runs and rests on consent; and — since #1462 — a\n * purpose at least one resource operation's `consentGate` names is asked too, because a capability\n * that may refuse over a purpose is a capability that must have somewhere to grant it. This function\n * does not, and cannot, distinguish WHEN each purpose should be asked (a required purpose, ANALYTICS\n * and a `consentGate` purpose may each want different `ConsentGateTiming`); it only says WHETHER the\n * one generic prompt surface that exists today should offer it.\n */\nexport function applicationAskedConsentPurposes(input: {\n readonly requiredPurposes?: readonly string[];\n readonly analyticsEnabled: boolean;\n readonly analyticsRequiresConsent: boolean;\n /** Every purpose declared by at least one resource operation's `consentGate` (#1462) — `compliance.capabilityDeclaredConsentPurposes`. */\n readonly capabilityDeclaredPurposes?: readonly string[];\n}): ConsentPurpose[] {\n const required = normalizeConsentPurposes(input.requiredPurposes);\n const capabilityDeclared = normalizeConsentPurposes(input.capabilityDeclaredPurposes);\n const asked = new Set<ConsentPurpose>([...required, ...capabilityDeclared]);\n if (input.analyticsEnabled && input.analyticsRequiresConsent) {\n asked.add(ConsentPurpose.ANALYTICS);\n }\n return CONSENT_PURPOSES.filter((purpose) => asked.has(purpose));\n}\n\n/**\n * A purpose list in its canonical form: de-duplicated, restricted to known members, in declaration\n * order.\n *\n * Stored consent is compared by the audit trail's before/after evidence, so two lists naming the same\n * purposes in a different order must not read as a change of decision.\n */\nexport function normalizeConsentPurposes(purposes: readonly string[] | undefined): ConsentPurpose[] {\n const given = new Set(purposes ?? []);\n return CONSENT_PURPOSES.filter((purpose) => given.has(purpose));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"consent-purposes.shared.js","sourceRoot":"","sources":["../../../../../src/compliance/privacy/consent-purposes.shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAN,IAAY,cAKX;AALD,WAAY,cAAc;IACxB,6EAA6E;IAC7E,yCAAuB,CAAA;IACvB,mFAAmF;IACnF,yCAAuB,CAAA;AACzB,CAAC,EALW,cAAc,KAAd,cAAc,QAKzB;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,mCAAmC,GAAG,yBAAyB,CAAC;AAE7E;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,iCAAiC,CAAC;AAE/E;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,KAAK,CAAC;AAErD,uFAAuF;AACvF,MAAM,CAAC,MAAM,gBAAgB,GAA8B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;AAExG;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAA8C,EAC9C,QAAmC;IAEnC,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IAC1C,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;AACtG,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,yBAAyB,CACvC,OAA8C,EAC9C,QAAmC;IAEnC,OAAO,sBAAsB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,+BAA+B,CAAC,KAM/C;IACC,MAAM,QAAQ,GAAG,wBAAwB,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAClE,MAAM,kBAAkB,GAAG,wBAAwB,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACtF,MAAM,KAAK,GAAG,IAAI,GAAG,CAAiB,CAAC,GAAG,QAAQ,EAAE,GAAG,kBAAkB,CAAC,CAAC,CAAC;IAC5E,IAAI,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,wBAAwB,EAAE,CAAC;QAC7D,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;AAClE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CAAC,QAAuC;IAC9E,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IACtC,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;AAClE,CAAC","sourcesContent":["/**\n * Consent purposes — the optional processing a person may independently agree to.\n *\n * ## A SET, not a ladder (decided by Paul, 2026-09-09 — #534 / #453)\n *\n * This replaces `DataProcessingConsent` (`NONE · BASIC · ANALYTICS · MARKETING · FULL`), which was an\n * ORDERED level. The order was a claim nobody decided and the law does not make: agreeing to\n * marketing is not \"more than\" agreeing to analytics, and a ladder made consenting to one imply\n * consenting to the ones \"below\" it. The only thing that ever enforced the order was a module-private\n * `CONSENT_ORDER` inside the frontend analytics provider.\n *\n * So each member is a PURPOSE, granted or not on its own, and a person's consent is the set of\n * purposes they granted. The old members map without loss of meaning:\n *\n * - `NONE` → the empty set.\n * - `BASIC` → not a purpose at all. It stood for processing the service needs in order to exist,\n * which is never consent-based (it rests on contract or legitimate interest), so it has no member.\n * - `FULL` → every member.\n *\n * ## Why this file imports nothing\n *\n * It is carved onto `@wildo-ai/saas-models/public-runtime` (K-2), because the visitor-tier\n * `WebsiteConsentGate` in the browser bundle reads the same vocabulary the application stores. One\n * vocabulary, one file: the original privacy schema imports it from here.\n *\n * Adding a member is a product decision with legal weight — every surface that asks a person for\n * consent renders the whole set, and every application's consent-gated processing must name which\n * member it rests on.\n */\nexport enum ConsentPurpose {\n /** Measuring how the service is used — product analytics, usage tracking. */\n ANALYTICS = 'analytics',\n /** Contacting the person or tailoring outreach to them for promotional reasons. */\n MARKETING = 'marketing',\n}\n\n/**\n * The browser storage key under which a Wildo marketing website keeps a VISITOR's consent decision.\n *\n * The visitor tier has no account to store a decision on, so it lives in the visitor's own browser, on\n * the website's origin — which is also why it does not follow them into the signed-in application, whose\n * decision is `privacy.consentedPurposes` on the person's preferences. Named once here so the website's\n * storage adapter and the cookie table (`ENGINE_CLIENT_STORAGE_ENTRIES`) cannot name different keys.\n */\nexport const WEBSITE_VISITOR_CONSENT_STORAGE_KEY = '__wildo_website_consent';\n\n/**\n * The route a VISITOR's consent decision is recorded through — `ANONYMOUS_USERS.record_consent`.\n *\n * Named here for the same reason as the storage key above: the marketing website must not depend on\n * `saas-models`' resource layer (bundle discipline keeps it to `public-runtime` atoms), so without a\n * shared constant the website would hard-code a path string and the engine would build one, with\n * nothing joining them. `/inbound-contacts` is hard-coded that way today, which is the drift this\n * avoids.\n *\n * It is not asserted by hand: `consent-purposes.shared.test.ts` derives it from the operation's own\n * identifier through `ResourcesConfigNamingUtils.toKebabCase` — the same transform the URL builder\n * uses — so renaming the resource or the operation reddens rather than 404s at runtime.\n */\nexport const ANONYMOUS_CONSENT_RECORD_PATH = '/anonymous-users/record-consent';\n\n/**\n * The HTTP METHOD that route answers — `PUT`, not `POST`.\n *\n * ## Why this constant had to exist\n *\n * The sibling above named the PATH and stopped there, and its own note predicted the consequence of a\n * drift precisely: *\"the failure is a 404 at runtime, on a public path nobody monitors.\"* That is what\n * happened, to the half it did not cover. `RECORD_CONSENT` declares\n * `resourceOperationLike: UPDATE_MANY`, and `getDefaultHttpVerbForOperation` maps every UPDATE verb to\n * `PUT` — but nothing said so where a client could read it, so two independent clients assumed POST and\n * both 404'd: the marketing website's recorder, whose failure is deliberately (and correctly) silent,\n * and the application's pre-auth recorder written against it.\n *\n * A path without its method is half an address. Naming both here is what lets a client be right by\n * reading rather than by guessing, and `consent-purposes.shared.test.ts` derives this from the built\n * operation's own `httpVerb` — the value the router registers — so changing the operation's shape\n * reddens instead of silently moving the door.\n */\nexport const ANONYMOUS_CONSENT_RECORD_METHOD = 'PUT';\n\n/** Every purpose, in declaration order — the order a consent surface lists them in. */\nexport const CONSENT_PURPOSES: readonly ConsentPurpose[] = Object.freeze(Object.values(ConsentPurpose));\n\n/**\n * The purposes in `required` that `granted` does not contain. Empty when every required purpose was\n * granted — including when nothing is required.\n *\n * Membership, never rank: there is no purpose whose grant satisfies another.\n */\nexport function missingConsentPurposes(\n granted: readonly ConsentPurpose[] | undefined,\n required: readonly ConsentPurpose[],\n): ConsentPurpose[] {\n const grantedSet = new Set(granted ?? []);\n return CONSENT_PURPOSES.filter((purpose) => required.includes(purpose) && !grantedSet.has(purpose));\n}\n\n/** Whether every purpose in `required` was granted. */\nexport function hasGrantedConsentPurposes(\n granted: readonly ConsentPurpose[] | undefined,\n required: readonly ConsentPurpose[],\n): boolean {\n return missingConsentPurposes(granted, required).length === 0;\n}\n\n/**\n * Every purpose THIS APPLICATION would put to a person — what its own consent surface asks.\n *\n * Two readers needed this and would otherwise have derived it twice: the application's consent gate,\n * deciding what to render, and the anonymous-consent carry, deciding whether a visitor was shown\n * enough for their decision to count as complete. Two derivations of \"what do we ask\" drift, and the\n * drift is invisible — the gate would prompt for a purpose the carry had already recorded as\n * decided, or the reverse.\n *\n * Takes PRIMITIVES rather than the config objects, so this file keeps the import-free property that\n * lets it be carved onto `public-runtime` for the website bundle.\n *\n * Total over what the configuration STATES A USE FOR, never over the enum: asking for a purpose\n * nothing processes collects a consent that means nothing. A required purpose is asked by\n * definition; ANALYTICS is asked when analytics runs and rests on consent; and — since #1462 — a\n * purpose at least one resource operation's `consentGate` names is asked too, because a capability\n * that may refuse over a purpose is a capability that must have somewhere to grant it. This function\n * does not, and cannot, distinguish WHEN each purpose should be asked (a required purpose, ANALYTICS\n * and a `consentGate` purpose may each want different `ConsentGateTiming`); it only says WHETHER the\n * one generic prompt surface that exists today should offer it.\n */\nexport function applicationAskedConsentPurposes(input: {\n readonly requiredPurposes?: readonly string[];\n readonly analyticsEnabled: boolean;\n readonly analyticsRequiresConsent: boolean;\n /** Every purpose declared by at least one resource operation's `consentGate` (#1462) — `compliance.capabilityDeclaredConsentPurposes`. */\n readonly capabilityDeclaredPurposes?: readonly string[];\n}): ConsentPurpose[] {\n const required = normalizeConsentPurposes(input.requiredPurposes);\n const capabilityDeclared = normalizeConsentPurposes(input.capabilityDeclaredPurposes);\n const asked = new Set<ConsentPurpose>([...required, ...capabilityDeclared]);\n if (input.analyticsEnabled && input.analyticsRequiresConsent) {\n asked.add(ConsentPurpose.ANALYTICS);\n }\n return CONSENT_PURPOSES.filter((purpose) => asked.has(purpose));\n}\n\n/**\n * A purpose list in its canonical form: de-duplicated, restricted to known members, in declaration\n * order.\n *\n * Stored consent is compared by the audit trail's before/after evidence, so two lists naming the same\n * purposes in a different order must not read as a change of decision.\n */\nexport function normalizeConsentPurposes(purposes: readonly string[] | undefined): ConsentPurpose[] {\n const given = new Set(purposes ?? []);\n return CONSENT_PURPOSES.filter((purpose) => given.has(purpose));\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-subject-rights.shared.schemas.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"data-subject-rights.shared.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/compliance/privacy/data-subject-rights.shared.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,+CAA+C,CAAC;AAGpG;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,mEAAmE;AACnE,oBAAY,oBAAoB;IAC9B,2DAA2D;IAC3D,OAAO,YAAY;IACnB,uGAAuG;IACvG,OAAO,YAAY;CACpB;AAQD,yDAAyD;AACzD,oBAAY,gBAAgB;IAC1B,2EAA2E;IAC3E,MAAM,WAAW;IACjB,kDAAkD;IAClD,aAAa,kBAAkB;IAC/B,+DAA+D;IAC/D,OAAO,YAAY;IACnB,2CAA2C;IAC3C,WAAW,gBAAgB;IAC3B,0HAA0H;IAC1H,WAAW,gBAAgB;IAC3B,2FAA2F;IAC3F,SAAS,cAAc;IACvB,wFAAwF;IACxF,gBAAgB,qBAAqB;IACrC,+HAA+H;IAC/H,eAAe,oBAAoB;IACnC,kHAAkH;IAClH,sBAAsB,2BAA2B;CAClD;AAED,uGAAuG;AACvG,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,wGAAwG;IACxG,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,sGAAsG;AACtG,wBAAgB,sBAAsB,CAAC,gBAAgB,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAEjG;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,oBAAoB,EAC5B,WAAW,EAAE,SAAS;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;CAAE,EAAE,GAChF,SAAS,0BAA0B,EAAE,CAiBvC;AAeD;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAO9E;AAED,uEAAuE;AACvE,oBAAY,uBAAuB;IACjC,kFAAkF;IAClF,QAAQ,aAAa;IACrB;;;;OAIG;IACH,mBAAmB,wBAAwB;CAC5C;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,sBAAsB,GAAG,uBAAuB,GAAG,SAAS,CAS5G"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-subject-rights.shared.schemas.js","sourceRoot":"","sources":["../../../../src/compliance/privacy/data-subject-rights.shared.schemas.ts"],"names":[],"mappings":"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","sourcesContent":["import { LawfulBasis, OperatorProcessingRole } from './operator-compliance-identity.shared.schemas';\nimport { jurisdictionReachCovers } from './operating-jurisdictions.shared.schemas';\n\n/**\n * **Which data-subject rights a privacy notice must state, derived from where the application operates and\n * the lawful bases it declares.**\n *\n * A notice must tell a person which rights they have (GDPR Art. 13(2)(b)–(d)). Which ones apply is not the\n * operator's choice: the law attaches them, several of them conditionally on the lawful basis of the\n * processing. So nobody is asked to type this list. It is a function of two declarations the application\n * already makes — `operatingJurisdictions` and `operatorComplianceIdentity.lawfulBases` — and of the law\n * of the regime a jurisdiction falls under, which is written down here once.\n *\n * spec-cite: GDPR Art. 13(2)(b)–(d), Art. 15–18, Art. 20(1), Art. 21(1), Art. 7(3), Art. 77(1).\n * spec-cite: UK GDPR Art. 7(3), 15–18, 20, 21 (legislation.gov.uk, read 2026-09-25); Data Protection Act 2018\n * s.164A and s.165(2) as amended by the Data (Use and Access) Act 2025 s.103, in force 19 June 2026.\n *\n * ## Only the regimes written here are known, and an unknown one is named rather than guessed\n *\n * Two regimes: the EU GDPR, reaching every EU member state through {@link jurisdictionReachCovers}, and the\n * United Kingdom's. They are written separately although the rights match article for article, because the\n * complaint route does not: from 19 June 2026 UK GDPR Art. 77 is omitted, a person may complain to the\n * controller itself (DPA 2018 s.164A — acknowledged within 30 days) and to the Information Commissioner\n * (s.165(2)). A notice that borrowed the EU wording would name a route UK law no longer has. A declared\n * jurisdiction outside every known regime gets NO rights list and the caller names it as owed. Adding a\n * regime is a deliberate edit to {@link DATA_PROTECTION_REGIME_REACH}, {@link rightsUnderRegime} and\n * {@link complaintRouteUnderRegime}, with its own citations.\n */\n\n/** A data-protection regime whose rights this module can state. */\nexport enum DataProtectionRegime {\n /** Regulation (EU) 2016/679, for every EU member state. */\n EU_GDPR = 'EU_GDPR',\n /** The UK GDPR with the Data Protection Act 2018, as amended by the Data (Use and Access) Act 2025. */\n UK_GDPR = 'UK_GDPR',\n}\n\n/** The jurisdiction each regime reaches, in the `operatingJurisdictions` slug vocabulary. */\nconst DATA_PROTECTION_REGIME_REACH: Readonly<Record<DataProtectionRegime, string>> = {\n [DataProtectionRegime.EU_GDPR]: 'eu',\n [DataProtectionRegime.UK_GDPR]: 'gb',\n};\n\n/** A right a data subject holds against a controller. */\nexport enum DataSubjectRight {\n /** Art. 15 — access to their data and information about its processing. */\n ACCESS = 'ACCESS',\n /** Art. 16 — rectification of inaccurate data. */\n RECTIFICATION = 'RECTIFICATION',\n /** Art. 17 — erasure, subject to the Art. 17(3) exceptions. */\n ERASURE = 'ERASURE',\n /** Art. 18 — restriction of processing. */\n RESTRICTION = 'RESTRICTION',\n /** Art. 20 — portability of data the subject provided, where processing rests on consent or contract and is automated. */\n PORTABILITY = 'PORTABILITY',\n /** Art. 21(1) — objection to processing resting on public task or legitimate interests. */\n OBJECTION = 'OBJECTION',\n /** Art. 7(3) — withdrawal of consent at any time, where processing rests on consent. */\n WITHDRAW_CONSENT = 'WITHDRAW_CONSENT',\n /** A complaint to the supervisory authority — GDPR Art. 77(1); in the UK, the Information Commissioner (DPA 2018 s.165(2)). */\n LODGE_COMPLAINT = 'LODGE_COMPLAINT',\n /** UK only — a complaint to the controller itself, which must acknowledge it within 30 days (DPA 2018 s.164A). */\n COMPLAIN_TO_CONTROLLER = 'COMPLAIN_TO_CONTROLLER',\n}\n\n/** One right as it applies to this application: the provision, and the declared purposes it covers. */\nexport interface ApplicableDataSubjectRight {\n readonly right: DataSubjectRight;\n readonly provision: string;\n /** The declared processing purposes the right attaches to. Every purpose for an unconditional right. */\n readonly purposes: readonly string[];\n}\n\n/** The regime a declared jurisdiction falls under, or `undefined` when no known regime reaches it. */\nexport function dataProtectionRegimeOf(jurisdictionSlug: string): DataProtectionRegime | undefined {\n return Object.values(DataProtectionRegime).find((regime) => jurisdictionReachCovers(DATA_PROTECTION_REGIME_REACH[regime], jurisdictionSlug));\n}\n\n/**\n * The rights a regime grants for the declared purposes and their bases.\n *\n * A conditional right is listed only when at least one declared purpose meets its condition, and then only\n * for those purposes: stating a right to object to processing that rests on contract would tell a person\n * they may stop the service they signed up for. The complaint route is always listed — Art. 13(2)(d) requires\n * it whatever the basis.\n */\nexport function rightsUnderRegime(\n regime: DataProtectionRegime,\n lawfulBases: readonly { readonly purpose: string; readonly basis: LawfulBasis }[],\n): readonly ApplicableDataSubjectRight[] {\n const every = lawfulBases.map((entry) => entry.purpose);\n const where = (bases: readonly LawfulBasis[]): string[] => lawfulBases.filter((entry) => bases.includes(entry.basis)).map((entry) => entry.purpose);\n // The UK kept the GDPR's rights articles, so one table serves both regimes; only the statute's name and the\n // complaint provisions differ.\n const law = regime === DataProtectionRegime.EU_GDPR ? 'GDPR' : 'UK GDPR';\n const rights: ApplicableDataSubjectRight[] = [\n { right: DataSubjectRight.ACCESS, provision: `${law} Art. 15`, purposes: every },\n { right: DataSubjectRight.RECTIFICATION, provision: `${law} Art. 16`, purposes: every },\n { right: DataSubjectRight.ERASURE, provision: `${law} Art. 17`, purposes: every },\n { right: DataSubjectRight.RESTRICTION, provision: `${law} Art. 18`, purposes: every },\n { right: DataSubjectRight.PORTABILITY, provision: `${law} Art. 20(1)`, purposes: where([LawfulBasis.CONSENT, LawfulBasis.CONTRACT]) },\n { right: DataSubjectRight.OBJECTION, provision: `${law} Art. 21(1)`, purposes: where([LawfulBasis.PUBLIC_TASK, LawfulBasis.LEGITIMATE_INTERESTS]) },\n { right: DataSubjectRight.WITHDRAW_CONSENT, provision: `${law} Art. 7(3)`, purposes: where([LawfulBasis.CONSENT]) },\n ...complaintRights(regime, every),\n ];\n return rights.filter((entry) => entry.purposes.length > 0);\n}\n\n/** The complaint rights a regime grants — where it differs from its neighbour, which is why it is its own switch. */\nfunction complaintRights(regime: DataProtectionRegime, every: string[]): ApplicableDataSubjectRight[] {\n switch (regime) {\n case DataProtectionRegime.EU_GDPR:\n return [{ right: DataSubjectRight.LODGE_COMPLAINT, provision: 'GDPR Art. 77(1)', purposes: every }];\n case DataProtectionRegime.UK_GDPR:\n return [\n { right: DataSubjectRight.COMPLAIN_TO_CONTROLLER, provision: 'Data Protection Act 2018 s.164A', purposes: every },\n { right: DataSubjectRight.LODGE_COMPLAINT, provision: 'Data Protection Act 2018 s.165(2)', purposes: every },\n ];\n }\n}\n\n/**\n * Where a person may complain under a regime, as a notice states it.\n *\n * The regime fixes the route; the operator chooses nothing here, which is why no authority is NAMED. Under\n * the GDPR a person may complain to the authority of their own member state (Art. 77(1)) whichever authority\n * leads for the operator, so naming only the operator's lead authority would understate the route.\n */\nexport function complaintRouteUnderRegime(regime: DataProtectionRegime): string {\n switch (regime) {\n case DataProtectionRegime.EU_GDPR:\n return 'a supervisory authority, in particular in the member state of habitual residence, place of work or place of the alleged infringement (GDPR Art. 77(1))';\n case DataProtectionRegime.UK_GDPR:\n return 'the operator itself, which must acknowledge the complaint within 30 days and tell you its outcome (Data Protection Act 2018 s.164A), and the Information Commissioner (s.165(2))';\n }\n}\n\n/** Who answers a data-subject request about one population of data. */\nexport enum SubjectRequestResponder {\n /** The operator is the controller of this data and answers the request itself. */\n OPERATOR = 'OPERATOR',\n /**\n * The operator is a PROCESSOR here: the customer that controls the data answers, and the operator forwards the\n * request and assists (GDPR Art. 28(3)(e)). A notice saying the operator will answer would promise a decision\n * the operator has no authority to make over its customer's records.\n */\n CUSTOMER_CONTROLLER = 'CUSTOMER_CONTROLLER',\n}\n\n/**\n * Who answers, for a role the operator holds over a population. `undefined` for a joint controllership, whose\n * arrangement decides it and is not declared anywhere a function can read.\n */\nexport function subjectRequestResponderFor(role: OperatorProcessingRole): SubjectRequestResponder | undefined {\n switch (role) {\n case OperatorProcessingRole.CONTROLLER:\n return SubjectRequestResponder.OPERATOR;\n case OperatorProcessingRole.PROCESSOR:\n return SubjectRequestResponder.CUSTOMER_CONTROLLER;\n case OperatorProcessingRole.JOINT_CONTROLLER:\n return undefined;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"data-subject-rights.shared.schemas.js","sourceRoot":"","sources":["../../../../../src/compliance/privacy/data-subject-rights.shared.schemas.ts"],"names":[],"mappings":"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","sourcesContent":["import { LawfulBasis, OperatorProcessingRole } from './operator-compliance-identity.shared.schemas';\nimport { jurisdictionReachCovers } from './operating-jurisdictions.shared.schemas';\n\n/**\n * **Which data-subject rights a privacy notice must state, derived from where the application operates and\n * the lawful bases it declares.**\n *\n * A notice must tell a person which rights they have (GDPR Art. 13(2)(b)–(d)). Which ones apply is not the\n * operator's choice: the law attaches them, several of them conditionally on the lawful basis of the\n * processing. So nobody is asked to type this list. It is a function of two declarations the application\n * already makes — `operatingJurisdictions` and `operatorComplianceIdentity.lawfulBases` — and of the law\n * of the regime a jurisdiction falls under, which is written down here once.\n *\n * spec-cite: GDPR Art. 13(2)(b)–(d), Art. 15–18, Art. 20(1), Art. 21(1), Art. 7(3), Art. 77(1).\n * spec-cite: UK GDPR Art. 7(3), 15–18, 20, 21 (legislation.gov.uk, read 2026-09-25); Data Protection Act 2018\n * s.164A and s.165(2) as amended by the Data (Use and Access) Act 2025 s.103, in force 19 June 2026.\n *\n * ## Only the regimes written here are known, and an unknown one is named rather than guessed\n *\n * Two regimes: the EU GDPR, reaching every EU member state through {@link jurisdictionReachCovers}, and the\n * United Kingdom's. They are written separately although the rights match article for article, because the\n * complaint route does not: from 19 June 2026 UK GDPR Art. 77 is omitted, a person may complain to the\n * controller itself (DPA 2018 s.164A — acknowledged within 30 days) and to the Information Commissioner\n * (s.165(2)). A notice that borrowed the EU wording would name a route UK law no longer has. A declared\n * jurisdiction outside every known regime gets NO rights list and the caller names it as owed. Adding a\n * regime is a deliberate edit to {@link DATA_PROTECTION_REGIME_REACH}, {@link rightsUnderRegime} and\n * {@link complaintRouteUnderRegime}, with its own citations.\n */\n\n/** A data-protection regime whose rights this module can state. */\nexport enum DataProtectionRegime {\n /** Regulation (EU) 2016/679, for every EU member state. */\n EU_GDPR = 'EU_GDPR',\n /** The UK GDPR with the Data Protection Act 2018, as amended by the Data (Use and Access) Act 2025. */\n UK_GDPR = 'UK_GDPR',\n}\n\n/** The jurisdiction each regime reaches, in the `operatingJurisdictions` slug vocabulary. */\nconst DATA_PROTECTION_REGIME_REACH: Readonly<Record<DataProtectionRegime, string>> = {\n [DataProtectionRegime.EU_GDPR]: 'eu',\n [DataProtectionRegime.UK_GDPR]: 'gb',\n};\n\n/** A right a data subject holds against a controller. */\nexport enum DataSubjectRight {\n /** Art. 15 — access to their data and information about its processing. */\n ACCESS = 'ACCESS',\n /** Art. 16 — rectification of inaccurate data. */\n RECTIFICATION = 'RECTIFICATION',\n /** Art. 17 — erasure, subject to the Art. 17(3) exceptions. */\n ERASURE = 'ERASURE',\n /** Art. 18 — restriction of processing. */\n RESTRICTION = 'RESTRICTION',\n /** Art. 20 — portability of data the subject provided, where processing rests on consent or contract and is automated. */\n PORTABILITY = 'PORTABILITY',\n /** Art. 21(1) — objection to processing resting on public task or legitimate interests. */\n OBJECTION = 'OBJECTION',\n /** Art. 7(3) — withdrawal of consent at any time, where processing rests on consent. */\n WITHDRAW_CONSENT = 'WITHDRAW_CONSENT',\n /** A complaint to the supervisory authority — GDPR Art. 77(1); in the UK, the Information Commissioner (DPA 2018 s.165(2)). */\n LODGE_COMPLAINT = 'LODGE_COMPLAINT',\n /** UK only — a complaint to the controller itself, which must acknowledge it within 30 days (DPA 2018 s.164A). */\n COMPLAIN_TO_CONTROLLER = 'COMPLAIN_TO_CONTROLLER',\n}\n\n/** One right as it applies to this application: the provision, and the declared purposes it covers. */\nexport interface ApplicableDataSubjectRight {\n readonly right: DataSubjectRight;\n readonly provision: string;\n /** The declared processing purposes the right attaches to. Every purpose for an unconditional right. */\n readonly purposes: readonly string[];\n}\n\n/** The regime a declared jurisdiction falls under, or `undefined` when no known regime reaches it. */\nexport function dataProtectionRegimeOf(jurisdictionSlug: string): DataProtectionRegime | undefined {\n return Object.values(DataProtectionRegime).find((regime) => jurisdictionReachCovers(DATA_PROTECTION_REGIME_REACH[regime], jurisdictionSlug));\n}\n\n/**\n * The rights a regime grants for the declared purposes and their bases.\n *\n * A conditional right is listed only when at least one declared purpose meets its condition, and then only\n * for those purposes: stating a right to object to processing that rests on contract would tell a person\n * they may stop the service they signed up for. The complaint route is always listed — Art. 13(2)(d) requires\n * it whatever the basis.\n */\nexport function rightsUnderRegime(\n regime: DataProtectionRegime,\n lawfulBases: readonly { readonly purpose: string; readonly basis: LawfulBasis }[],\n): readonly ApplicableDataSubjectRight[] {\n const every = lawfulBases.map((entry) => entry.purpose);\n const where = (bases: readonly LawfulBasis[]): string[] => lawfulBases.filter((entry) => bases.includes(entry.basis)).map((entry) => entry.purpose);\n // The UK kept the GDPR's rights articles, so one table serves both regimes; only the statute's name and the\n // complaint provisions differ.\n const law = regime === DataProtectionRegime.EU_GDPR ? 'GDPR' : 'UK GDPR';\n const rights: ApplicableDataSubjectRight[] = [\n { right: DataSubjectRight.ACCESS, provision: `${law} Art. 15`, purposes: every },\n { right: DataSubjectRight.RECTIFICATION, provision: `${law} Art. 16`, purposes: every },\n { right: DataSubjectRight.ERASURE, provision: `${law} Art. 17`, purposes: every },\n { right: DataSubjectRight.RESTRICTION, provision: `${law} Art. 18`, purposes: every },\n { right: DataSubjectRight.PORTABILITY, provision: `${law} Art. 20(1)`, purposes: where([LawfulBasis.CONSENT, LawfulBasis.CONTRACT]) },\n { right: DataSubjectRight.OBJECTION, provision: `${law} Art. 21(1)`, purposes: where([LawfulBasis.PUBLIC_TASK, LawfulBasis.LEGITIMATE_INTERESTS]) },\n { right: DataSubjectRight.WITHDRAW_CONSENT, provision: `${law} Art. 7(3)`, purposes: where([LawfulBasis.CONSENT]) },\n ...complaintRights(regime, every),\n ];\n return rights.filter((entry) => entry.purposes.length > 0);\n}\n\n/** The complaint rights a regime grants — where it differs from its neighbour, which is why it is its own switch. */\nfunction complaintRights(regime: DataProtectionRegime, every: string[]): ApplicableDataSubjectRight[] {\n switch (regime) {\n case DataProtectionRegime.EU_GDPR:\n return [{ right: DataSubjectRight.LODGE_COMPLAINT, provision: 'GDPR Art. 77(1)', purposes: every }];\n case DataProtectionRegime.UK_GDPR:\n return [\n { right: DataSubjectRight.COMPLAIN_TO_CONTROLLER, provision: 'Data Protection Act 2018 s.164A', purposes: every },\n { right: DataSubjectRight.LODGE_COMPLAINT, provision: 'Data Protection Act 2018 s.165(2)', purposes: every },\n ];\n }\n}\n\n/**\n * Where a person may complain under a regime, as a notice states it.\n *\n * The regime fixes the route; the operator chooses nothing here, which is why no authority is NAMED. Under\n * the GDPR a person may complain to the authority of their own member state (Art. 77(1)) whichever authority\n * leads for the operator, so naming only the operator's lead authority would understate the route.\n */\nexport function complaintRouteUnderRegime(regime: DataProtectionRegime): string {\n switch (regime) {\n case DataProtectionRegime.EU_GDPR:\n return 'a supervisory authority, in particular in the member state of habitual residence, place of work or place of the alleged infringement (GDPR Art. 77(1))';\n case DataProtectionRegime.UK_GDPR:\n return 'the operator itself, which must acknowledge the complaint within 30 days and tell you its outcome (Data Protection Act 2018 s.164A), and the Information Commissioner (s.165(2))';\n }\n}\n\n/** Who answers a data-subject request about one population of data. */\nexport enum SubjectRequestResponder {\n /** The operator is the controller of this data and answers the request itself. */\n OPERATOR = 'OPERATOR',\n /**\n * The operator is a PROCESSOR here: the customer that controls the data answers, and the operator forwards the\n * request and assists (GDPR Art. 28(3)(e)). A notice saying the operator will answer would promise a decision\n * the operator has no authority to make over its customer's records.\n */\n CUSTOMER_CONTROLLER = 'CUSTOMER_CONTROLLER',\n}\n\n/**\n * Who answers, for a role the operator holds over a population. `undefined` for a joint controllership, whose\n * arrangement decides it and is not declared anywhere a function can read.\n */\nexport function subjectRequestResponderFor(role: OperatorProcessingRole): SubjectRequestResponder | undefined {\n switch (role) {\n case OperatorProcessingRole.CONTROLLER:\n return SubjectRequestResponder.OPERATOR;\n case OperatorProcessingRole.PROCESSOR:\n return SubjectRequestResponder.CUSTOMER_CONTROLLER;\n case OperatorProcessingRole.JOINT_CONTROLLER:\n return undefined;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impersonalization-scrub.shared.utils.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"impersonalization-scrub.shared.utils.d.ts","sourceRoot":"","sources":["../../../../../src/compliance/privacy/impersonalization-scrub.shared.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,qDAAa,CAAC;AAEtD;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,WAAW,EAAE,CAAC,CAAC,UAAU,GAAG,MAAM,CAE/E;AAED;;;;;;;;;;GAUG;AACH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,8BAA8B,CAAC,WAAW,EAAE,CAAC,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAoEpG;AAED,wBAAgB,mCAAmC,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAM9E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,iCAAiC,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,GAAG,SAAS,MAAM,EAAE,CAS7F;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA8C9F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impersonalization-scrub.shared.utils.js","sourceRoot":"","sources":["../../../../src/compliance/privacy/impersonalization-scrub.shared.utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod';\nimport { getDataCategories, getImpersonalizeMaskValue, getImpersonalizeTreatment, getMergedObjectOrUnionShape } from '@wildo-ai/zod-decorators';\nimport { RedactionType } from './redaction.shared.schemas';\nimport { FIELD_IDENTIFIER_TO_PRIMARY_SCOPE, ResourcePrimaryScope } from '../../resources/resources.shared.schemas';\n\n/**\n * The DEFAULT mask applied for `RedactionType.MASK`.\n *\n * It is an UNCONSTRAINED string, so a field whose schema constrains its shape — `z.email()`,\n * `z.uuid()`, `.min(n)` — cannot hold it. Such a field declares its own value via\n * `.impersonalizeWith(MASK, { maskValue })`; see {@link resolveImpersonalizeMaskValue}.\n */\nexport const IMPERSONALIZE_MASK_CONSTANT = '••••••••';\n\n/**\n * The value a `MASK` treatment actually writes for one field: the field's own override when it\n * declares one, the framework constant otherwise.\n *\n * ONE authority, deliberately. The boot guard `safeParse`s exactly this value against the field's\n * schema and the scrub writer `$set`s exactly this value — so a guard that passes at boot cannot be\n * followed by a write the update DTO rejects inside the erasure transaction. Splitting the two\n * would reintroduce precisely the failure mode the boot guard exists to eliminate.\n */\nexport function resolveImpersonalizeMaskValue(fieldSchema: z.ZodTypeAny): string {\n return getImpersonalizeMaskValue(fieldSchema) ?? IMPERSONALIZE_MASK_CONSTANT;\n}\n\n/**\n * The impersonalization NEVER-SCRUB FLOOR: the org/app SCOPE FKs + `createdByUserId`. Nulling these\n * would orphan the retained row from its tenant (a cross-tenant / security regression) or lose its\n * audit provenance, so they stay protected even if an author accidentally puts a treatment on them.\n *\n * The PERSON-LINK (`userId` / `anonymousUserId` — the USER_SELF / ANONYMOUS scopes) is DELIBERATELY NOT\n * floor-protected: D1 allows SEVERING the person-link while keeping org/app scope (the mirror, opposite\n * direction, of the anon→user transposition). So a `userId` that carries an explicit\n * `.impersonalizeWith('remove')` IS severable — this is how \"erase the subject's link, keep the scoped\n * record\" is expressed.\n */\n/**\n * The value a `RESET` field becomes: its OWN schema default.\n *\n * Resolved by asking the schema, never by an authored constant. `parse(undefined)` is exactly the\n * question \"what is this field when nobody has set it\", answered by Zod's own semantics — so the\n * default lives in ONE place and a later change to it moves the scrub with it. An authored copy would\n * drift, and a scrub writing a stale default is a row that looks reset and is not.\n *\n * Refuses a field with NO default rather than inventing one. `RESET` on such a field is an authoring\n * error — `undefined` would either fail the re-parse or leave the value untouched depending on the\n * writer, and both are worse than a loud refusal at config time. REMOVE is what that field wants.\n *\n * The result must still SATISFY the schema, which is the whole failure this treatment exists to\n * prevent: a patch writing a value the schema rejects surfaces as a read error long after the erasure\n * reported success. `parse` gives that for free — a default that does not validate cannot be returned.\n */\nexport function resolveImpersonalizeResetValue(fieldSchema: z.ZodTypeAny, fieldName: string): unknown {\n const parsed = fieldSchema.safeParse(undefined);\n if (!parsed.success) {\n throw new Error(\n `[impersonalize] RESET treatment on '${fieldName}' requires the field to declare a .default(), and it does not. ` +\n `RESET means \"return this field to what it is when nobody has set it\", which has no answer here. ` +\n `Use REMOVE for a field that may be absent, or add the default the treatment is asking for.`,\n );\n }\n\n /*\n * A CLOCK-READ default is refused, and this is the sharp edge of the whole treatment.\n *\n * `.default(() => new Date())` means \"compute a fresh value at write time\". Applied to\n * `lastActiveAt` — a real field, declared USAGE personal data — RESET wrote the ERASURE's own\n * timestamp, recording an erased person as last active at the moment they were erased. Measured\n * before this guard: the value landed within a millisecond of `now`. That is worse than leaving the\n * field alone. It does not fail to remove information, it FABRICATES it, and the fabricated value is\n * exactly the kind a reader would trust.\n *\n * ## Why this is a heuristic, and why the obvious checks do not work\n *\n * Zod 4 exposes `defaultValue` as a GETTER returning the resolved value, so a literal and a thunk are\n * statically indistinguishable — measured, both report `typeof object`. And resolving twice does not\n * separate them either: two `new Date()` reads microseconds apart stringify identically, so a\n * difference-based check silently passes the exact case it exists for. That version was written,\n * tested, and failed to fire.\n *\n * What IS distinguishable is the value's relationship to the clock. A default resolving to a Date\n * near `now` can only have come from reading the clock — whether from a thunk, or from a literal\n * `.default(new Date())` evaluated at module load, which is equally wrong and equally invisible.\n *\n * A deliberate sentinel is never \"recently\". `new Date(0)` is 1970; an explicit epoch or a fixed\n * historical date is years away. So the bound below admits every deliberate choice and refuses every\n * clock read, and it is stated as a bound rather than pretending to be exact.\n */\n /*\n * `.optional()` PARSES `undefined` successfully, so the check above passes it and the resolver would\n * return `undefined` — which is not a scrub. The patch would `$set` an undefined, which either\n * no-ops or is rejected downstream by the canonicalizer, and either way the personal data survives\n * an erasure that reported success.\n *\n * The distinction the two checks draw together: \"has no default at all\" and \"is optional so its\n * default IS undefined\" are different authoring mistakes, and both mean RESET has no value to write.\n * REMOVE is what an optional field wants — it writes an explicit null, which is a scrub.\n */\n if (parsed.data === undefined) {\n throw new Error(\n `[impersonalize] RESET treatment on '${fieldName}' resolves to \\`undefined\\` — the field is optional rather ` +\n `than defaulted, so \"what it is when nobody has set it\" is nothing at all. Writing that is not a scrub: the ` +\n `patch would set undefined and the personal data would survive. Use REMOVE, which writes an explicit null, ` +\n `or give the field the .default() RESET is asking for.`,\n );\n }\n\n const RESET_CLOCK_READ_WINDOW_MS = 24 * 60 * 60 * 1000;\n if (parsed.data instanceof Date && Math.abs(Date.now() - parsed.data.getTime()) < RESET_CLOCK_READ_WINDOW_MS) {\n throw new Error(\n `[impersonalize] RESET treatment on '${fieldName}' resolves to a timestamp within a day of NOW, which means ` +\n `the default reads the clock (typically \\`.default(() => new Date())\\`, or a literal \\`new Date()\\` evaluated ` +\n `at module load). Erasure would then write a value generated BY the erasure — a field like 'lastActiveAt' ` +\n `would record the erased person as active at the moment they were erased, fabricating information rather ` +\n `than removing it. Give the field a STATIC neutral default such as new Date(0), which asserts \"no recorded ` +\n `value\", or make it nullable and use REMOVE, which asserts \"unknown\". Those are different claims about an ` +\n `erased person, so choose deliberately.`,\n );\n }\n return parsed.data;\n}\n\nexport function isImpersonalizeNeverScrubFloorField(fieldName: string): boolean {\n if (fieldName === 'createdByUserId') return true;\n const scope = FIELD_IDENTIFIER_TO_PRIMARY_SCOPE[fieldName];\n return scope === ResourcePrimaryScope.ORGANIZATIONS\n || scope === ResourcePrimaryScope.APPLICATION;\n // USER_SELF / ANONYMOUS (person-link) fall through → severable per D1.\n}\n\n/**\n * The fields whose declarations say this resource holds personal data — the evidence against a\n * `RETAIN_ONLY` claim.\n *\n * ## Why this exists\n *\n * `RETAIN_ONLY` asserts a resource holds NO personal data of its own, and the factory could check that\n * in only one direction: it refuses the mode when a field carries an impersonalize TREATMENT. It could\n * not see personal data that nobody had given a treatment to. So the cheap answer for most resources\n * was also the one that failed silently when wrong — a governed document stating that erasure leaves\n * nothing behind, about rows holding a person's data. The opposite mode never had this hole:\n * `RETAIN_AND_IMPERSONALIZE` is refused when nothing would be scrubbed.\n *\n * `.dataCategories()` is the declaration this reads, so the check catches a CONTRADICTION — a resource\n * that says both \"this field is personal data\" and \"this resource holds none\". It cannot catch an\n * OMISSION, where nothing was ever classified; that is a coverage question and belongs to the category\n * inventory, not here. Saying so matters: a clean result is not a proof that a resource holds nothing.\n *\n * ## Read the RESOLVED shape, never the source text\n *\n * `getMergedObjectOrUnionShape` is used deliberately, for the same reason the scrub builder below uses\n * it. A text-shaped read of a named schema misses both shapes that occur here in practice: a schema\n * that `.extend()`s a base carries its categories on the BASE, and one file commonly declares several\n * schemas so a range scan closes on a nested object. A census built that way reported `users` as\n * holding no personal data, while `users.email` carries `CONTACT_DETAILS` — understating personal data,\n * which is the dangerous direction for a check whose whole job is to refuse a false negative claim.\n *\n * The never-scrub floor is excluded on the same terms as the scrub patch: a scope FK or\n * `createdByUserId` links a row to a person without being personal data the row holds, and every mode\n * preserves it — so its presence is no evidence against `RETAIN_ONLY`.\n */\nexport function collectDeclaredPersonalDataFields(mainSchema: z.ZodTypeAny): readonly string[] {\n const shape = getMergedObjectOrUnionShape(mainSchema);\n const declared: string[] = [];\n for (const [fieldName, fieldSchema] of Object.entries(shape)) {\n if (isImpersonalizeNeverScrubFloorField(fieldName)) continue;\n const categories = getDataCategories(fieldSchema as z.ZodTypeAny);\n if (categories !== undefined && categories.length > 0) declared.push(fieldName);\n }\n return declared;\n}\n\n/**\n * Synthesize the field-scrub `$set` patch for an impersonalize-in-place write, from a resource's\n * per-field `.impersonalizeWith()` treatments. Returns ONLY the scrubbed FIELDS — the impersonalize\n * writer appends the `retentionStatus` / `impersonalizedAt` markers.\n *\n * M4 is the FIRST + ONLY exhaustive consumer of `RedactionType` (zero appliers existed before), so the\n * `default` arm is load-bearing: it keeps the enum ADDITIVELY safe — a future member (e.g. a reserved\n * `TOKENIZE`) fails LOUD here rather than being silently skipped.\n *\n * v1 scope: KEEP / REMOVE / MASK are expressible in a single STATIC `$set` (batch `updateManyAsSystem`).\n * A per-field `maskValue` stays inside that scope — it changes WHICH constant a field is set to, not\n * that the write is one static `$set` shared by every row in the batch.\n * - `HASH` is value-dependent (each row hashes its own value) → NOT expressible in a static `$set`; it\n * THROWS in v1 (add a per-doc / aggregation-pipeline scrub path later — additive).\n * - `ENCRYPT` is reversible → forbidden for impersonalization (D6: v1 impersonalization is IRREVERSIBLE);\n * `ENCRYPT` remains a flow-actors-only redaction option.\n */\nexport function buildImpersonalizeScrubPatch(mainSchema: z.ZodTypeAny): Record<string, unknown> {\n // UNION-AWARE on purpose. `getZodObjectShape` returns `{}` for a discriminated union, which would\n // make the scrub a SILENT NO-OP the day polymorphic resources become retention-governed (rows would\n // flip to RETAINED with every personal field intact). This mirrors the union-aware shape read used\n // by `deriveTrustedSystemWritePreservedFields`, so the two never disagree about what a resource's\n // fields are.\n const shape = getMergedObjectOrUnionShape(mainSchema);\n const patch: Record<string, unknown> = {};\n\n for (const [fieldName, fieldSchema] of Object.entries(shape)) {\n const treatment = getImpersonalizeTreatment(fieldSchema as z.ZodTypeAny);\n if (treatment === undefined) continue; // no `.impersonalizeWith()` → leave the field untouched\n\n // Never-scrub floor: even an explicit treatment cannot null a scope FK / createdByUserId.\n if (isImpersonalizeNeverScrubFloorField(fieldName)) continue;\n\n switch (treatment as RedactionType) {\n case RedactionType.KEEP:\n continue; // explicit never-scrub\n case RedactionType.REMOVE:\n patch[fieldName] = null;\n break;\n case RedactionType.MASK:\n patch[fieldName] = resolveImpersonalizeMaskValue(fieldSchema as z.ZodTypeAny);\n break;\n case RedactionType.RESET:\n patch[fieldName] = resolveImpersonalizeResetValue(fieldSchema as z.ZodTypeAny, fieldName);\n break;\n case RedactionType.HASH:\n throw new Error(\n `[impersonalize] HASH treatment on '${fieldName}' is value-dependent and not supported in v1 ` +\n `(a static $set cannot hash per-row) — use REMOVE/MASK/KEEP, or add the per-doc/pipeline scrub path.`,\n );\n case RedactionType.ENCRYPT:\n throw new Error(\n `[impersonalize] ENCRYPT treatment on '${fieldName}' is reversible — forbidden for impersonalization ` +\n `(D6: v1 impersonalization is irreversible). ENCRYPT stays a flow-actors-only redaction option.`,\n );\n default:\n // Exhaustive guard: an unknown / future RedactionType member MUST fail LOUD, never be silently\n // skipped — this is exactly what keeps RedactionType additively safe (deep-review B-F2).\n throw new Error(`[impersonalize] unsupported impersonalize treatment '${treatment}' on '${fieldName}'.`);\n }\n }\n\n return patch;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"impersonalization-scrub.shared.utils.js","sourceRoot":"","sources":["../../../../../src/compliance/privacy/impersonalization-scrub.shared.utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod';\nimport { getDataCategories, getImpersonalizeMaskValue, getImpersonalizeTreatment, getMergedObjectOrUnionShape } from '@wildo-ai/zod-decorators';\nimport { RedactionType } from './redaction.shared.schemas';\nimport { FIELD_IDENTIFIER_TO_PRIMARY_SCOPE, ResourcePrimaryScope } from '../../resources/resources.shared.schemas';\n\n/**\n * The DEFAULT mask applied for `RedactionType.MASK`.\n *\n * It is an UNCONSTRAINED string, so a field whose schema constrains its shape — `z.email()`,\n * `z.uuid()`, `.min(n)` — cannot hold it. Such a field declares its own value via\n * `.impersonalizeWith(MASK, { maskValue })`; see {@link resolveImpersonalizeMaskValue}.\n */\nexport const IMPERSONALIZE_MASK_CONSTANT = '••••••••';\n\n/**\n * The value a `MASK` treatment actually writes for one field: the field's own override when it\n * declares one, the framework constant otherwise.\n *\n * ONE authority, deliberately. The boot guard `safeParse`s exactly this value against the field's\n * schema and the scrub writer `$set`s exactly this value — so a guard that passes at boot cannot be\n * followed by a write the update DTO rejects inside the erasure transaction. Splitting the two\n * would reintroduce precisely the failure mode the boot guard exists to eliminate.\n */\nexport function resolveImpersonalizeMaskValue(fieldSchema: z.ZodTypeAny): string {\n return getImpersonalizeMaskValue(fieldSchema) ?? IMPERSONALIZE_MASK_CONSTANT;\n}\n\n/**\n * The impersonalization NEVER-SCRUB FLOOR: the org/app SCOPE FKs + `createdByUserId`. Nulling these\n * would orphan the retained row from its tenant (a cross-tenant / security regression) or lose its\n * audit provenance, so they stay protected even if an author accidentally puts a treatment on them.\n *\n * The PERSON-LINK (`userId` / `anonymousUserId` — the USER_SELF / ANONYMOUS scopes) is DELIBERATELY NOT\n * floor-protected: D1 allows SEVERING the person-link while keeping org/app scope (the mirror, opposite\n * direction, of the anon→user transposition). So a `userId` that carries an explicit\n * `.impersonalizeWith('remove')` IS severable — this is how \"erase the subject's link, keep the scoped\n * record\" is expressed.\n */\n/**\n * The value a `RESET` field becomes: its OWN schema default.\n *\n * Resolved by asking the schema, never by an authored constant. `parse(undefined)` is exactly the\n * question \"what is this field when nobody has set it\", answered by Zod's own semantics — so the\n * default lives in ONE place and a later change to it moves the scrub with it. An authored copy would\n * drift, and a scrub writing a stale default is a row that looks reset and is not.\n *\n * Refuses a field with NO default rather than inventing one. `RESET` on such a field is an authoring\n * error — `undefined` would either fail the re-parse or leave the value untouched depending on the\n * writer, and both are worse than a loud refusal at config time. REMOVE is what that field wants.\n *\n * The result must still SATISFY the schema, which is the whole failure this treatment exists to\n * prevent: a patch writing a value the schema rejects surfaces as a read error long after the erasure\n * reported success. `parse` gives that for free — a default that does not validate cannot be returned.\n */\nexport function resolveImpersonalizeResetValue(fieldSchema: z.ZodTypeAny, fieldName: string): unknown {\n const parsed = fieldSchema.safeParse(undefined);\n if (!parsed.success) {\n throw new Error(\n `[impersonalize] RESET treatment on '${fieldName}' requires the field to declare a .default(), and it does not. ` +\n `RESET means \"return this field to what it is when nobody has set it\", which has no answer here. ` +\n `Use REMOVE for a field that may be absent, or add the default the treatment is asking for.`,\n );\n }\n\n /*\n * A CLOCK-READ default is refused, and this is the sharp edge of the whole treatment.\n *\n * `.default(() => new Date())` means \"compute a fresh value at write time\". Applied to\n * `lastActiveAt` — a real field, declared USAGE personal data — RESET wrote the ERASURE's own\n * timestamp, recording an erased person as last active at the moment they were erased. Measured\n * before this guard: the value landed within a millisecond of `now`. That is worse than leaving the\n * field alone. It does not fail to remove information, it FABRICATES it, and the fabricated value is\n * exactly the kind a reader would trust.\n *\n * ## Why this is a heuristic, and why the obvious checks do not work\n *\n * Zod 4 exposes `defaultValue` as a GETTER returning the resolved value, so a literal and a thunk are\n * statically indistinguishable — measured, both report `typeof object`. And resolving twice does not\n * separate them either: two `new Date()` reads microseconds apart stringify identically, so a\n * difference-based check silently passes the exact case it exists for. That version was written,\n * tested, and failed to fire.\n *\n * What IS distinguishable is the value's relationship to the clock. A default resolving to a Date\n * near `now` can only have come from reading the clock — whether from a thunk, or from a literal\n * `.default(new Date())` evaluated at module load, which is equally wrong and equally invisible.\n *\n * A deliberate sentinel is never \"recently\". `new Date(0)` is 1970; an explicit epoch or a fixed\n * historical date is years away. So the bound below admits every deliberate choice and refuses every\n * clock read, and it is stated as a bound rather than pretending to be exact.\n */\n /*\n * `.optional()` PARSES `undefined` successfully, so the check above passes it and the resolver would\n * return `undefined` — which is not a scrub. The patch would `$set` an undefined, which either\n * no-ops or is rejected downstream by the canonicalizer, and either way the personal data survives\n * an erasure that reported success.\n *\n * The distinction the two checks draw together: \"has no default at all\" and \"is optional so its\n * default IS undefined\" are different authoring mistakes, and both mean RESET has no value to write.\n * REMOVE is what an optional field wants — it writes an explicit null, which is a scrub.\n */\n if (parsed.data === undefined) {\n throw new Error(\n `[impersonalize] RESET treatment on '${fieldName}' resolves to \\`undefined\\` — the field is optional rather ` +\n `than defaulted, so \"what it is when nobody has set it\" is nothing at all. Writing that is not a scrub: the ` +\n `patch would set undefined and the personal data would survive. Use REMOVE, which writes an explicit null, ` +\n `or give the field the .default() RESET is asking for.`,\n );\n }\n\n const RESET_CLOCK_READ_WINDOW_MS = 24 * 60 * 60 * 1000;\n if (parsed.data instanceof Date && Math.abs(Date.now() - parsed.data.getTime()) < RESET_CLOCK_READ_WINDOW_MS) {\n throw new Error(\n `[impersonalize] RESET treatment on '${fieldName}' resolves to a timestamp within a day of NOW, which means ` +\n `the default reads the clock (typically \\`.default(() => new Date())\\`, or a literal \\`new Date()\\` evaluated ` +\n `at module load). Erasure would then write a value generated BY the erasure — a field like 'lastActiveAt' ` +\n `would record the erased person as active at the moment they were erased, fabricating information rather ` +\n `than removing it. Give the field a STATIC neutral default such as new Date(0), which asserts \"no recorded ` +\n `value\", or make it nullable and use REMOVE, which asserts \"unknown\". Those are different claims about an ` +\n `erased person, so choose deliberately.`,\n );\n }\n return parsed.data;\n}\n\nexport function isImpersonalizeNeverScrubFloorField(fieldName: string): boolean {\n if (fieldName === 'createdByUserId') return true;\n const scope = FIELD_IDENTIFIER_TO_PRIMARY_SCOPE[fieldName];\n return scope === ResourcePrimaryScope.ORGANIZATIONS\n || scope === ResourcePrimaryScope.APPLICATION;\n // USER_SELF / ANONYMOUS (person-link) fall through → severable per D1.\n}\n\n/**\n * The fields whose declarations say this resource holds personal data — the evidence against a\n * `RETAIN_ONLY` claim.\n *\n * ## Why this exists\n *\n * `RETAIN_ONLY` asserts a resource holds NO personal data of its own, and the factory could check that\n * in only one direction: it refuses the mode when a field carries an impersonalize TREATMENT. It could\n * not see personal data that nobody had given a treatment to. So the cheap answer for most resources\n * was also the one that failed silently when wrong — a governed document stating that erasure leaves\n * nothing behind, about rows holding a person's data. The opposite mode never had this hole:\n * `RETAIN_AND_IMPERSONALIZE` is refused when nothing would be scrubbed.\n *\n * `.dataCategories()` is the declaration this reads, so the check catches a CONTRADICTION — a resource\n * that says both \"this field is personal data\" and \"this resource holds none\". It cannot catch an\n * OMISSION, where nothing was ever classified; that is a coverage question and belongs to the category\n * inventory, not here. Saying so matters: a clean result is not a proof that a resource holds nothing.\n *\n * ## Read the RESOLVED shape, never the source text\n *\n * `getMergedObjectOrUnionShape` is used deliberately, for the same reason the scrub builder below uses\n * it. A text-shaped read of a named schema misses both shapes that occur here in practice: a schema\n * that `.extend()`s a base carries its categories on the BASE, and one file commonly declares several\n * schemas so a range scan closes on a nested object. A census built that way reported `users` as\n * holding no personal data, while `users.email` carries `CONTACT_DETAILS` — understating personal data,\n * which is the dangerous direction for a check whose whole job is to refuse a false negative claim.\n *\n * The never-scrub floor is excluded on the same terms as the scrub patch: a scope FK or\n * `createdByUserId` links a row to a person without being personal data the row holds, and every mode\n * preserves it — so its presence is no evidence against `RETAIN_ONLY`.\n */\nexport function collectDeclaredPersonalDataFields(mainSchema: z.ZodTypeAny): readonly string[] {\n const shape = getMergedObjectOrUnionShape(mainSchema);\n const declared: string[] = [];\n for (const [fieldName, fieldSchema] of Object.entries(shape)) {\n if (isImpersonalizeNeverScrubFloorField(fieldName)) continue;\n const categories = getDataCategories(fieldSchema as z.ZodTypeAny);\n if (categories !== undefined && categories.length > 0) declared.push(fieldName);\n }\n return declared;\n}\n\n/**\n * Synthesize the field-scrub `$set` patch for an impersonalize-in-place write, from a resource's\n * per-field `.impersonalizeWith()` treatments. Returns ONLY the scrubbed FIELDS — the impersonalize\n * writer appends the `retentionStatus` / `impersonalizedAt` markers.\n *\n * M4 is the FIRST + ONLY exhaustive consumer of `RedactionType` (zero appliers existed before), so the\n * `default` arm is load-bearing: it keeps the enum ADDITIVELY safe — a future member (e.g. a reserved\n * `TOKENIZE`) fails LOUD here rather than being silently skipped.\n *\n * v1 scope: KEEP / REMOVE / MASK are expressible in a single STATIC `$set` (batch `updateManyAsSystem`).\n * A per-field `maskValue` stays inside that scope — it changes WHICH constant a field is set to, not\n * that the write is one static `$set` shared by every row in the batch.\n * - `HASH` is value-dependent (each row hashes its own value) → NOT expressible in a static `$set`; it\n * THROWS in v1 (add a per-doc / aggregation-pipeline scrub path later — additive).\n * - `ENCRYPT` is reversible → forbidden for impersonalization (D6: v1 impersonalization is IRREVERSIBLE);\n * `ENCRYPT` remains a flow-actors-only redaction option.\n */\nexport function buildImpersonalizeScrubPatch(mainSchema: z.ZodTypeAny): Record<string, unknown> {\n // UNION-AWARE on purpose. `getZodObjectShape` returns `{}` for a discriminated union, which would\n // make the scrub a SILENT NO-OP the day polymorphic resources become retention-governed (rows would\n // flip to RETAINED with every personal field intact). This mirrors the union-aware shape read used\n // by `deriveTrustedSystemWritePreservedFields`, so the two never disagree about what a resource's\n // fields are.\n const shape = getMergedObjectOrUnionShape(mainSchema);\n const patch: Record<string, unknown> = {};\n\n for (const [fieldName, fieldSchema] of Object.entries(shape)) {\n const treatment = getImpersonalizeTreatment(fieldSchema as z.ZodTypeAny);\n if (treatment === undefined) continue; // no `.impersonalizeWith()` → leave the field untouched\n\n // Never-scrub floor: even an explicit treatment cannot null a scope FK / createdByUserId.\n if (isImpersonalizeNeverScrubFloorField(fieldName)) continue;\n\n switch (treatment as RedactionType) {\n case RedactionType.KEEP:\n continue; // explicit never-scrub\n case RedactionType.REMOVE:\n patch[fieldName] = null;\n break;\n case RedactionType.MASK:\n patch[fieldName] = resolveImpersonalizeMaskValue(fieldSchema as z.ZodTypeAny);\n break;\n case RedactionType.RESET:\n patch[fieldName] = resolveImpersonalizeResetValue(fieldSchema as z.ZodTypeAny, fieldName);\n break;\n case RedactionType.HASH:\n throw new Error(\n `[impersonalize] HASH treatment on '${fieldName}' is value-dependent and not supported in v1 ` +\n `(a static $set cannot hash per-row) — use REMOVE/MASK/KEEP, or add the per-doc/pipeline scrub path.`,\n );\n case RedactionType.ENCRYPT:\n throw new Error(\n `[impersonalize] ENCRYPT treatment on '${fieldName}' is reversible — forbidden for impersonalization ` +\n `(D6: v1 impersonalization is irreversible). ENCRYPT stays a flow-actors-only redaction option.`,\n );\n default:\n // Exhaustive guard: an unknown / future RedactionType member MUST fail LOUD, never be silently\n // skipped — this is exactly what keeps RedactionType additively safe (deep-review B-F2).\n throw new Error(`[impersonalize] unsupported impersonalize treatment '${treatment}' on '${fieldName}'.`);\n }\n }\n\n return patch;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impersonalization.shared.schemas.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"impersonalization.shared.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/compliance/privacy/impersonalization.shared.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,oBAAY,eAAe;IACzB,sDAAsD;IACtD,MAAM,WAAW;IACjB;;;;;;;;;;;;;OAaG;IACH,QAAQ,aAAa;CACtB;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,eAAe,CAC3C,CAAC;AAE1B;;;;;;;;;;;;;;GAcG;AACH,oBAAY,oBAAoB;IAC9B;;;;;;OAMG;IACH,WAAW,gBAAgB;IAC3B;;;;;;OAMG;IACH,wBAAwB,6BAA6B;CACtD;AAED;;;GAGG;AACH,eAAO,MAAM,0BAA0B,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,oBAAoB,CAChD,CAAC;AAE/B,8HAA8H;AAC9H;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,oBAAY,wBAAwB;IAClC,oGAAoG;IACpG,gBAAgB,qBAAqB;CACtC;AAED;;;GAGG;AACH,eAAO,MAAM,8BAA8B,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,wBAAwB,CACpD,CAAC;AACnC,4EAA4E;AAE5E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,oBAAY,uBAAuB;IACjC;;;;;;;;;;;;;;;;;;OAkBG;IACH,YAAY,iBAAiB;IAC7B;;;;;;;;;OASG;IACH,cAAc,mBAAmB;IACjC;;;;;;;;;;OAUG;IACH,gBAAgB,qBAAqB;CACtC;AAED;;;GAGG;AACH,eAAO,MAAM,6BAA6B,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,uBAAuB,CACnD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impersonalization.shared.schemas.js","sourceRoot":"","sources":["../../../../src/compliance/privacy/impersonalization.shared.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAN,IAAY,eAkBX;AAlBD,WAAY,eAAe;IACzB,sDAAsD;IACtD,oCAAiB,CAAA;IACjB;;;;;;;;;;;;;OAaG;IACH,wCAAqB,CAAA;AACvB,CAAC,EAlBW,eAAe,KAAf,eAAe,QAkB1B;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAChC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;AAE1B;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAN,IAAY,oBAiBX;AAjBD,WAAY,oBAAoB;IAC9B;;;;;;OAMG;IACH,mDAA2B,CAAA;IAC3B;;;;;;OAMG;IACH,6EAAqD,CAAA;AACvD,CAAC,EAjBW,oBAAoB,KAApB,oBAAoB,QAiB/B;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,0BAA0B,GACrC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;AAE/B,8HAA8H;AAC9H;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAN,IAAY,wBAGX;AAHD,WAAY,wBAAwB;IAClC,oGAAoG;IACpG,iEAAqC,CAAA;AACvC,CAAC,EAHW,wBAAwB,KAAxB,wBAAwB,QAGnC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,8BAA8B,GACzC,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;AACnC,4EAA4E;AAE5E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,MAAM,CAAN,IAAY,uBA4CX;AA5CD,WAAY,uBAAuB;IACjC;;;;;;;;;;;;;;;;;;OAkBG;IACH,wDAA6B,CAAA;IAC7B;;;;;;;;;OASG;IACH,4DAAiC,CAAA;IACjC;;;;;;;;;;OAUG;IACH,gEAAqC,CAAA;AACvC,CAAC,EA5CW,uBAAuB,KAAvB,uBAAuB,QA4ClC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,6BAA6B,GACxC,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC","sourcesContent":["import { z } from 'zod';\n\n/**\n * # Impersonalization — per-record retention lifecycle state\n *\n * `impersonalization` = scrubbing the personal data OUT of a stored record while\n * KEEPING the row, so it can be retained for a legal/audit obligation (GDPR\n * Art. 17(3)(b) legal-obligation carve-out; tax/SOX retention). This is the third\n * erasure outcome alongside hard-delete and leave-as-is.\n *\n * ⚠️ **Not** the anonymous-user concept. `isAnonymizable` / `anonymousUserId` /\n * anonymous-session ownership transposition is an unrelated, opposite-direction\n * mechanism (carrying a pre-auth anonymous session's rows forward to a real user).\n * Never conflate the two. See `.claude/plans/retention-impersonalization-architecture.md`.\n *\n * `RetentionStatus` is the per-record marker the resource factory injects (as the\n * `retentionStatus` field) onto any resource that opts into `retentionPolicy`. The\n * INTENDED contract for a `RETAINED` record is **hidden and immutable by default**\n * (behave-as-deleted), reachable only through the audited `seeRetained` see-through path.\n *\n * **LIVE.** The factory injects the marker (defaulting to `ACTIVE`), the visibility/immutability\n * enforcement and the audited see-through read primitive are all wired and runtime-proven. A\n * `RETAINED` record is hidden from every ordinary read, list, count and chart aggregate, and is\n * immutable to ordinary writes. (This block previously said the enforcement was \"wired in a later\n * phase\"; that became false without being revisited.)\n */\nexport enum RetentionStatus {\n /** Live record — normal visibility and mutability. */\n ACTIVE = 'active',\n /**\n * Impersonalized-and-retained — personal fields scrubbed in place, the row kept for a\n * retention obligation: hidden and immutable to normal callers, readable only via the audited\n * `seeRetained` see-through path, disposable only by a privileged system op.\n *\n * ENFORCED, not intended. This said \"enforcement wired in a later phase\" long after the phase\n * landed, which is worth correcting rather than deleting: a reader deciding whether to trust the\n * marker would have concluded the row was still visible. The rule has one semantic authority —\n * `compliance/privacy/retention-hide-predicate.backend` — consumed by both persistence adapters,\n * the aggregation/charts surface and RAG retrieval, and a guard test fails the suite if any site\n * hand-writes the predicate again. That single-authority shape exists because the duplicated\n * version produced two recovered defects: retained rows still counted in every chart, and the\n * Mongo/Postgres compilers silently disagreed about which rows a NULL marker selected.\n */\n RETAINED = 'retained',\n}\n\n/**\n * Zod schema for {@link RetentionStatus}. Explicitly annotated for the\n * `isolatedDeclarations` emit constraint.\n */\nexport const RetentionStatusSchema: z.ZodEnum<typeof RetentionStatus> =\n z.enum(RetentionStatus);\n\n/**\n * # What erasure DOES to a retention-governed row\n *\n * Retention (the row survives, is marked `RETAINED`, becomes hidden + immutable) and\n * impersonalization (its personal FIELDS are scrubbed) are ORTHOGONAL. A record can be legally\n * retainable while holding no personal data of its own — a financial row that merely POINTS at a\n * person is the canonical case: erasing the subject must not destroy the invoice, but there is\n * nothing on the invoice to scrub, because the name and address live on the linked user.\n *\n * Fusing the two axes forced such a resource to either declare a fake scrub (shipping a record\n * stamped \"impersonalized\" that never was) or forgo retention entirely (letting the cascade destroy a\n * legally-required record). Naming the two outcomes separately removes that false choice AND makes\n * the author's claim auditable: \"this resource holds no personal data\" becomes an explicit, reviewable\n * declaration rather than something a compliance reviewer must infer from an absence of treatments.\n */\nexport enum ErasureRetentionMode {\n /**\n * Keep and FREEZE the row; scrub nothing — this resource holds no personal data of its own.\n *\n * Declaring a `.impersonalizeWith()` treatment under this mode is a contradiction and fails at\n * config build: if a field does hold personal data, the resource wants\n * {@link ErasureRetentionMode.RETAIN_AND_IMPERSONALIZE} instead.\n */\n RETAIN_ONLY = 'retain_only',\n /**\n * Keep and freeze the row AND scrub the fields marked with `.impersonalizeWith()`.\n *\n * Requires at least one field that the writer would ACTUALLY scrub (a `KEEP` treatment, or one on a\n * never-scrub floor field such as a scope FK, does not count) — otherwise the row would flip to\n * `RETAINED` with every field intact while claiming to have been impersonalized.\n */\n RETAIN_AND_IMPERSONALIZE = 'retain_and_impersonalize',\n}\n\n/**\n * Zod schema for {@link ErasureRetentionMode}. Explicitly annotated for the\n * `isolatedDeclarations` emit constraint.\n */\nexport const ErasureRetentionModeSchema: z.ZodEnum<typeof ErasureRetentionMode> =\n z.enum(ErasureRetentionMode);\n\n/** @wildo_source:part:start saas.models.privacy.statutory-retention-ground facet:layer:shared facet:audience:app-developer */\n/**\n * **WHY the law lets a row survive an erasure** — the exemption a `retentionPolicy.statutoryRetention`\n * declaration names (#1635).\n *\n * A data subject's right to erasure (GDPR Art. 17(1)) does not apply \"to the extent that processing is\n * necessary … for compliance with a legal obligation which requires processing by Union or Member State\n * law to which the controller is subject\" (Art. 17(3)(b)). Business correspondence and accounting source\n * documents carry exactly such an obligation — HGB §257 and AO §147 in Germany, Code de commerce L123-22 in\n * France — so a subject erasure keeps those rows until the statutory period ends, and RESTRICTS them in the\n * meantime: stored, and processed for nothing else (the Art. 18(2) effect, which BDSG §35(1)/(3) states\n * explicitly as the substitute for erasure).\n *\n * spec-cite: Regulation (EU) 2016/679, Art. 17(3) introductory sentence, (b) and (e), fetched from\n * gdpr-info.eu/art-17-gdpr 2026-09-27; Art. 18(2) and BDSG §35(1)/(3) as fetched and quoted in #1635.\n *\n * ## One member, on purpose\n *\n * Art. 17(3)(e) — \"for the establishment, exercise or defence of legal claims\" — is the other ground an\n * operator reaches for, and it is deliberately NOT a member. It is a property of a CASE, decided when a claim\n * arises and lifted when it ends: that is a legal hold (#1634), not a property of every row of a class. A\n * member here would let a resource declare every row permanently \"needed for legal claims\", which is the\n * standing retention the storage-limitation principle forbids. The remaining grounds of Art. 17(3) (freedom\n * of expression, public health, archiving in the public interest) have no Wildo mechanism behind them; a\n * member without one would be a claim nothing enforces.\n *\n * `z.enum` rather than a literal so a member added later reaches every consumer through this one source.\n */\nexport enum StatutoryRetentionGround {\n /** GDPR Art. 17(3)(b): the rows are kept because a statute requires the controller to keep them. */\n LEGAL_OBLIGATION = 'legal_obligation',\n}\n\n/**\n * Zod schema for {@link StatutoryRetentionGround}. Explicitly annotated for the `isolatedDeclarations`\n * emit constraint.\n */\nexport const StatutoryRetentionGroundSchema: z.ZodEnum<typeof StatutoryRetentionGround> =\n z.enum(StatutoryRetentionGround);\n/** @wildo_source:part:end saas.models.privacy.statutory-retention-ground */\n\n/**\n * **WHOSE SESSION ENDS** when a row of this resource is erased. The second axis of the erasure\n * contract, beside {@link ErasureRetentionMode} (which says what happens to the row).\n *\n * ## This axis is NOT \"is this row about a person?\" — read this before adding a member\n *\n * The two questions look like one and are not, and conflating them cost this vocabulary a member name\n * for months (see the rename note below). Wildo answers them on SEPARATE axes:\n *\n * | question | the axis that answers it |\n * |---|---|\n * | Does this resource hold personal data? | {@link ErasureRetentionMode} — `RETAIN_AND_IMPERSONALIZE` requires at least one field that would actually be scrubbed; `RETAIN_ONLY` means *\"holds no personal data of its own\"*, and a scrub treatment under it fails at config build |\n * | Can a subject-access or portability export answer for it? | `systemAccessPolicy.exportSubject` |\n * | **Whose login session must be revoked?** | **this enum** |\n *\n * A CRM contact, a sales lead, a newsletter subscriber and a patient with no portal account are all\n * **data subjects with no session**. They declare `RETAIN_AND_IMPERSONALIZE` (they hold personal data)\n * and {@link ResourceDataSubjectKind.NO_PRINCIPAL} (there is no session to end) — two independent,\n * truthful answers. Adding a fourth member here for them would make this enum a cross-product of two\n * axes, which is two fields wearing one name.\n *\n * ## Why the third member is `NO_PRINCIPAL` and not `NOT_A_DATA_SUBJECT`\n *\n * It was `NOT_A_DATA_SUBJECT` until 2026-08-28, and the name was the defect. Operationally it always\n * meant *\"revoke nobody\"* — which is exactly right for a CRM contact — while its NAME claimed the row\n * was not about a person, which is false for one. Nothing misbehaved at runtime (the single consumer,\n * `resolveScrubSessionPrincipals`, only ever asked the session question), so the cost landed entirely\n * on readers: a human, and a compliance-document generator, both read the name and would have stated\n * in a published privacy notice that the application holds no personal data in precisely the resource\n * its customers care most about.\n *\n * The industry model this now matches is unambiguous — Intercom deletes \"a user **or lead**\", HubSpot\n * GDPR-deletes a Contact by id or by email, Zendesk \"forgets\" an end-user: an account and a data\n * subject are different objects, and the erasure verb applies to both. Wildo's `eraseSubjectAsSystem`\n * already takes `(resourceType, rowIds)` with no principal, so the capability was never missing.\n *\n * ## Why this must be DECLARED and can never be inferred\n *\n * An erasure of a person must also end that person's session, or a \"deleted\" person keeps browsing on\n * a live token until it expires. The tempting shortcut is to look for a `userId`-shaped foreign key on\n * the erased row and revoke it. **That shortcut is a defect, not an optimisation.** On almost every\n * resource a user foreign key names the OWNER or the ACTOR, not the subject: Wonder Todos' `TODOS` is\n * retention-governed and carries `createdByUserId`, `assignedToUserId` and `escalationContactUserId`,\n * so an inferring implementation would log out the author, the assignee and the escalation contact —\n * three people, none of them the data subject — every time a todo was erased.\n *\n * So the linkage is authored, never guessed, and a resource that can be an erasure subject (i.e. one\n * declaring a `retentionPolicy`) must say which of these it is. Undeclared is refused at config build:\n * nobody has decided yet, and refusing is what forces the decision — the same doctrine the subject\n * EXPORT model applies to an undeclared resource.\n */\nexport enum ResourceDataSubjectKind {\n /**\n * Erasing a row of this resource revokes **no session**, because no login is reachable from it.\n *\n * Two very different populations share this answer, and the enum is deliberately silent about which\n * one a given resource is — {@link ErasureRetentionMode} says that:\n *\n * - **Not a person at all.** A todo, an invoice, a log line. Any user foreign keys it carries name\n * ACTORS — an author, an assignee, an owner, an escalation contact — and revoking their sessions\n * because a record was erased would log out three uninvolved people. Such a resource pairs this\n * with `RETAIN_ONLY`.\n * - **A person with no account.** A CRM contact, a sales lead, a subscriber, a patient with no\n * portal login. Their rows ARE personal data and carry the full weight of Arts 15–17 and 20 —\n * there is simply no session to end. Such a resource pairs this with `RETAIN_AND_IMPERSONALIZE`\n * and per-field `.impersonalizeWith()` treatments, and its subject-rights path is the ordinary\n * administrative one: `eraseSubjectAsSystem(resourceType, rowIds)` and a subject export.\n *\n * The second population is the majority of what a B2B SaaS customer stores about third parties, and\n * it is what most of a privacy notice describes. Do not read this member as \"nothing to disclose\".\n */\n NO_PRINCIPAL = 'no_principal',\n /**\n * Rows of this resource ARE the person, and the row's own id IS the session principal: erasing row\n * `X` ends the session of user `X`. This is `USERS` / `USER_SELF`.\n *\n * Note this makes EXPLICIT a revocation that is otherwise only incidental. Erasing a `USERS` row\n * already logs the user out today — but only as a side effect of the retention row-hide (the auth\n * fronts re-read the user, find the row hidden, and 401) plus the scrub write bumping\n * `authorizationVersion`. Nothing on the erasure path ever WROTE a revocation, so the guarantee\n * lived entirely in the behaviour of two unrelated mechanisms.\n */\n SELF_PRINCIPAL = 'self_principal',\n /**\n * Rows of this resource are a person whose login lives in a DIFFERENT `USERS` row — a Patient, an\n * Employee, a Member record that a human signs in as. `sessionPrincipalField` names the field\n * holding that user's id.\n *\n * The named field must carry no `.impersonalizeWith()` treatment. Not because the revocation would\n * break — the principal is resolved BEFORE the scrub, so a scrubbed field is still readable when it\n * matters — but because declaring one field to be BOTH the link to a person and personal data to\n * destroy is self-contradictory, and it leaves the retained row with no way to say whose session was\n * ended. Enforced at config build.\n */\n LINKED_PRINCIPAL = 'linked_principal',\n}\n\n/**\n * Zod schema for {@link ResourceDataSubjectKind}. Explicitly annotated for the\n * `isolatedDeclarations` emit constraint.\n */\nexport const ResourceDataSubjectKindSchema: z.ZodEnum<typeof ResourceDataSubjectKind> =\n z.enum(ResourceDataSubjectKind);\n"]}
|
|
1
|
+
{"version":3,"file":"impersonalization.shared.schemas.js","sourceRoot":"","sources":["../../../../../src/compliance/privacy/impersonalization.shared.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAN,IAAY,eAkBX;AAlBD,WAAY,eAAe;IACzB,sDAAsD;IACtD,oCAAiB,CAAA;IACjB;;;;;;;;;;;;;OAaG;IACH,wCAAqB,CAAA;AACvB,CAAC,EAlBW,eAAe,KAAf,eAAe,QAkB1B;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAChC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;AAE1B;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAN,IAAY,oBAiBX;AAjBD,WAAY,oBAAoB;IAC9B;;;;;;OAMG;IACH,mDAA2B,CAAA;IAC3B;;;;;;OAMG;IACH,6EAAqD,CAAA;AACvD,CAAC,EAjBW,oBAAoB,KAApB,oBAAoB,QAiB/B;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,0BAA0B,GACrC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;AAE/B,8HAA8H;AAC9H;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAN,IAAY,wBAGX;AAHD,WAAY,wBAAwB;IAClC,oGAAoG;IACpG,iEAAqC,CAAA;AACvC,CAAC,EAHW,wBAAwB,KAAxB,wBAAwB,QAGnC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,8BAA8B,GACzC,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;AACnC,4EAA4E;AAE5E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,MAAM,CAAN,IAAY,uBA4CX;AA5CD,WAAY,uBAAuB;IACjC;;;;;;;;;;;;;;;;;;OAkBG;IACH,wDAA6B,CAAA;IAC7B;;;;;;;;;OASG;IACH,4DAAiC,CAAA;IACjC;;;;;;;;;;OAUG;IACH,gEAAqC,CAAA;AACvC,CAAC,EA5CW,uBAAuB,KAAvB,uBAAuB,QA4ClC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,6BAA6B,GACxC,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC","sourcesContent":["import { z } from 'zod';\n\n/**\n * # Impersonalization — per-record retention lifecycle state\n *\n * `impersonalization` = scrubbing the personal data OUT of a stored record while\n * KEEPING the row, so it can be retained for a legal/audit obligation (GDPR\n * Art. 17(3)(b) legal-obligation carve-out; tax/SOX retention). This is the third\n * erasure outcome alongside hard-delete and leave-as-is.\n *\n * ⚠️ **Not** the anonymous-user concept. `isAnonymizable` / `anonymousUserId` /\n * anonymous-session ownership transposition is an unrelated, opposite-direction\n * mechanism (carrying a pre-auth anonymous session's rows forward to a real user).\n * Never conflate the two. See `.claude/plans/retention-impersonalization-architecture.md`.\n *\n * `RetentionStatus` is the per-record marker the resource factory injects (as the\n * `retentionStatus` field) onto any resource that opts into `retentionPolicy`. The\n * INTENDED contract for a `RETAINED` record is **hidden and immutable by default**\n * (behave-as-deleted), reachable only through the audited `seeRetained` see-through path.\n *\n * **LIVE.** The factory injects the marker (defaulting to `ACTIVE`), the visibility/immutability\n * enforcement and the audited see-through read primitive are all wired and runtime-proven. A\n * `RETAINED` record is hidden from every ordinary read, list, count and chart aggregate, and is\n * immutable to ordinary writes. (This block previously said the enforcement was \"wired in a later\n * phase\"; that became false without being revisited.)\n */\nexport enum RetentionStatus {\n /** Live record — normal visibility and mutability. */\n ACTIVE = 'active',\n /**\n * Impersonalized-and-retained — personal fields scrubbed in place, the row kept for a\n * retention obligation: hidden and immutable to normal callers, readable only via the audited\n * `seeRetained` see-through path, disposable only by a privileged system op.\n *\n * ENFORCED, not intended. This said \"enforcement wired in a later phase\" long after the phase\n * landed, which is worth correcting rather than deleting: a reader deciding whether to trust the\n * marker would have concluded the row was still visible. The rule has one semantic authority —\n * `compliance/privacy/retention-hide-predicate.backend` — consumed by both persistence adapters,\n * the aggregation/charts surface and RAG retrieval, and a guard test fails the suite if any site\n * hand-writes the predicate again. That single-authority shape exists because the duplicated\n * version produced two recovered defects: retained rows still counted in every chart, and the\n * Mongo/Postgres compilers silently disagreed about which rows a NULL marker selected.\n */\n RETAINED = 'retained',\n}\n\n/**\n * Zod schema for {@link RetentionStatus}. Explicitly annotated for the\n * `isolatedDeclarations` emit constraint.\n */\nexport const RetentionStatusSchema: z.ZodEnum<typeof RetentionStatus> =\n z.enum(RetentionStatus);\n\n/**\n * # What erasure DOES to a retention-governed row\n *\n * Retention (the row survives, is marked `RETAINED`, becomes hidden + immutable) and\n * impersonalization (its personal FIELDS are scrubbed) are ORTHOGONAL. A record can be legally\n * retainable while holding no personal data of its own — a financial row that merely POINTS at a\n * person is the canonical case: erasing the subject must not destroy the invoice, but there is\n * nothing on the invoice to scrub, because the name and address live on the linked user.\n *\n * Fusing the two axes forced such a resource to either declare a fake scrub (shipping a record\n * stamped \"impersonalized\" that never was) or forgo retention entirely (letting the cascade destroy a\n * legally-required record). Naming the two outcomes separately removes that false choice AND makes\n * the author's claim auditable: \"this resource holds no personal data\" becomes an explicit, reviewable\n * declaration rather than something a compliance reviewer must infer from an absence of treatments.\n */\nexport enum ErasureRetentionMode {\n /**\n * Keep and FREEZE the row; scrub nothing — this resource holds no personal data of its own.\n *\n * Declaring a `.impersonalizeWith()` treatment under this mode is a contradiction and fails at\n * config build: if a field does hold personal data, the resource wants\n * {@link ErasureRetentionMode.RETAIN_AND_IMPERSONALIZE} instead.\n */\n RETAIN_ONLY = 'retain_only',\n /**\n * Keep and freeze the row AND scrub the fields marked with `.impersonalizeWith()`.\n *\n * Requires at least one field that the writer would ACTUALLY scrub (a `KEEP` treatment, or one on a\n * never-scrub floor field such as a scope FK, does not count) — otherwise the row would flip to\n * `RETAINED` with every field intact while claiming to have been impersonalized.\n */\n RETAIN_AND_IMPERSONALIZE = 'retain_and_impersonalize',\n}\n\n/**\n * Zod schema for {@link ErasureRetentionMode}. Explicitly annotated for the\n * `isolatedDeclarations` emit constraint.\n */\nexport const ErasureRetentionModeSchema: z.ZodEnum<typeof ErasureRetentionMode> =\n z.enum(ErasureRetentionMode);\n\n/** @wildo_source:part:start saas.models.privacy.statutory-retention-ground facet:layer:shared facet:audience:app-developer */\n/**\n * **WHY the law lets a row survive an erasure** — the exemption a `retentionPolicy.statutoryRetention`\n * declaration names (#1635).\n *\n * A data subject's right to erasure (GDPR Art. 17(1)) does not apply \"to the extent that processing is\n * necessary … for compliance with a legal obligation which requires processing by Union or Member State\n * law to which the controller is subject\" (Art. 17(3)(b)). Business correspondence and accounting source\n * documents carry exactly such an obligation — HGB §257 and AO §147 in Germany, Code de commerce L123-22 in\n * France — so a subject erasure keeps those rows until the statutory period ends, and RESTRICTS them in the\n * meantime: stored, and processed for nothing else (the Art. 18(2) effect, which BDSG §35(1)/(3) states\n * explicitly as the substitute for erasure).\n *\n * spec-cite: Regulation (EU) 2016/679, Art. 17(3) introductory sentence, (b) and (e), fetched from\n * gdpr-info.eu/art-17-gdpr 2026-09-27; Art. 18(2) and BDSG §35(1)/(3) as fetched and quoted in #1635.\n *\n * ## One member, on purpose\n *\n * Art. 17(3)(e) — \"for the establishment, exercise or defence of legal claims\" — is the other ground an\n * operator reaches for, and it is deliberately NOT a member. It is a property of a CASE, decided when a claim\n * arises and lifted when it ends: that is a legal hold (#1634), not a property of every row of a class. A\n * member here would let a resource declare every row permanently \"needed for legal claims\", which is the\n * standing retention the storage-limitation principle forbids. The remaining grounds of Art. 17(3) (freedom\n * of expression, public health, archiving in the public interest) have no Wildo mechanism behind them; a\n * member without one would be a claim nothing enforces.\n *\n * `z.enum` rather than a literal so a member added later reaches every consumer through this one source.\n */\nexport enum StatutoryRetentionGround {\n /** GDPR Art. 17(3)(b): the rows are kept because a statute requires the controller to keep them. */\n LEGAL_OBLIGATION = 'legal_obligation',\n}\n\n/**\n * Zod schema for {@link StatutoryRetentionGround}. Explicitly annotated for the `isolatedDeclarations`\n * emit constraint.\n */\nexport const StatutoryRetentionGroundSchema: z.ZodEnum<typeof StatutoryRetentionGround> =\n z.enum(StatutoryRetentionGround);\n/** @wildo_source:part:end saas.models.privacy.statutory-retention-ground */\n\n/**\n * **WHOSE SESSION ENDS** when a row of this resource is erased. The second axis of the erasure\n * contract, beside {@link ErasureRetentionMode} (which says what happens to the row).\n *\n * ## This axis is NOT \"is this row about a person?\" — read this before adding a member\n *\n * The two questions look like one and are not, and conflating them cost this vocabulary a member name\n * for months (see the rename note below). Wildo answers them on SEPARATE axes:\n *\n * | question | the axis that answers it |\n * |---|---|\n * | Does this resource hold personal data? | {@link ErasureRetentionMode} — `RETAIN_AND_IMPERSONALIZE` requires at least one field that would actually be scrubbed; `RETAIN_ONLY` means *\"holds no personal data of its own\"*, and a scrub treatment under it fails at config build |\n * | Can a subject-access or portability export answer for it? | `systemAccessPolicy.exportSubject` |\n * | **Whose login session must be revoked?** | **this enum** |\n *\n * A CRM contact, a sales lead, a newsletter subscriber and a patient with no portal account are all\n * **data subjects with no session**. They declare `RETAIN_AND_IMPERSONALIZE` (they hold personal data)\n * and {@link ResourceDataSubjectKind.NO_PRINCIPAL} (there is no session to end) — two independent,\n * truthful answers. Adding a fourth member here for them would make this enum a cross-product of two\n * axes, which is two fields wearing one name.\n *\n * ## Why the third member is `NO_PRINCIPAL` and not `NOT_A_DATA_SUBJECT`\n *\n * It was `NOT_A_DATA_SUBJECT` until 2026-08-28, and the name was the defect. Operationally it always\n * meant *\"revoke nobody\"* — which is exactly right for a CRM contact — while its NAME claimed the row\n * was not about a person, which is false for one. Nothing misbehaved at runtime (the single consumer,\n * `resolveScrubSessionPrincipals`, only ever asked the session question), so the cost landed entirely\n * on readers: a human, and a compliance-document generator, both read the name and would have stated\n * in a published privacy notice that the application holds no personal data in precisely the resource\n * its customers care most about.\n *\n * The industry model this now matches is unambiguous — Intercom deletes \"a user **or lead**\", HubSpot\n * GDPR-deletes a Contact by id or by email, Zendesk \"forgets\" an end-user: an account and a data\n * subject are different objects, and the erasure verb applies to both. Wildo's `eraseSubjectAsSystem`\n * already takes `(resourceType, rowIds)` with no principal, so the capability was never missing.\n *\n * ## Why this must be DECLARED and can never be inferred\n *\n * An erasure of a person must also end that person's session, or a \"deleted\" person keeps browsing on\n * a live token until it expires. The tempting shortcut is to look for a `userId`-shaped foreign key on\n * the erased row and revoke it. **That shortcut is a defect, not an optimisation.** On almost every\n * resource a user foreign key names the OWNER or the ACTOR, not the subject: Wonder Todos' `TODOS` is\n * retention-governed and carries `createdByUserId`, `assignedToUserId` and `escalationContactUserId`,\n * so an inferring implementation would log out the author, the assignee and the escalation contact —\n * three people, none of them the data subject — every time a todo was erased.\n *\n * So the linkage is authored, never guessed, and a resource that can be an erasure subject (i.e. one\n * declaring a `retentionPolicy`) must say which of these it is. Undeclared is refused at config build:\n * nobody has decided yet, and refusing is what forces the decision — the same doctrine the subject\n * EXPORT model applies to an undeclared resource.\n */\nexport enum ResourceDataSubjectKind {\n /**\n * Erasing a row of this resource revokes **no session**, because no login is reachable from it.\n *\n * Two very different populations share this answer, and the enum is deliberately silent about which\n * one a given resource is — {@link ErasureRetentionMode} says that:\n *\n * - **Not a person at all.** A todo, an invoice, a log line. Any user foreign keys it carries name\n * ACTORS — an author, an assignee, an owner, an escalation contact — and revoking their sessions\n * because a record was erased would log out three uninvolved people. Such a resource pairs this\n * with `RETAIN_ONLY`.\n * - **A person with no account.** A CRM contact, a sales lead, a subscriber, a patient with no\n * portal login. Their rows ARE personal data and carry the full weight of Arts 15–17 and 20 —\n * there is simply no session to end. Such a resource pairs this with `RETAIN_AND_IMPERSONALIZE`\n * and per-field `.impersonalizeWith()` treatments, and its subject-rights path is the ordinary\n * administrative one: `eraseSubjectAsSystem(resourceType, rowIds)` and a subject export.\n *\n * The second population is the majority of what a B2B SaaS customer stores about third parties, and\n * it is what most of a privacy notice describes. Do not read this member as \"nothing to disclose\".\n */\n NO_PRINCIPAL = 'no_principal',\n /**\n * Rows of this resource ARE the person, and the row's own id IS the session principal: erasing row\n * `X` ends the session of user `X`. This is `USERS` / `USER_SELF`.\n *\n * Note this makes EXPLICIT a revocation that is otherwise only incidental. Erasing a `USERS` row\n * already logs the user out today — but only as a side effect of the retention row-hide (the auth\n * fronts re-read the user, find the row hidden, and 401) plus the scrub write bumping\n * `authorizationVersion`. Nothing on the erasure path ever WROTE a revocation, so the guarantee\n * lived entirely in the behaviour of two unrelated mechanisms.\n */\n SELF_PRINCIPAL = 'self_principal',\n /**\n * Rows of this resource are a person whose login lives in a DIFFERENT `USERS` row — a Patient, an\n * Employee, a Member record that a human signs in as. `sessionPrincipalField` names the field\n * holding that user's id.\n *\n * The named field must carry no `.impersonalizeWith()` treatment. Not because the revocation would\n * break — the principal is resolved BEFORE the scrub, so a scrubbed field is still readable when it\n * matters — but because declaring one field to be BOTH the link to a person and personal data to\n * destroy is self-contradictory, and it leaves the retained row with no way to say whose session was\n * ended. Enforced at config build.\n */\n LINKED_PRINCIPAL = 'linked_principal',\n}\n\n/**\n * Zod schema for {@link ResourceDataSubjectKind}. Explicitly annotated for the\n * `isolatedDeclarations` emit constraint.\n */\nexport const ResourceDataSubjectKindSchema: z.ZodEnum<typeof ResourceDataSubjectKind> =\n z.enum(ResourceDataSubjectKind);\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"legal-hold-subject-attribution.shared.utils.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"legal-hold-subject-attribution.shared.utils.d.ts","sourceRoot":"","sources":["../../../../../src/compliance/privacy/legal-hold-subject-attribution.shared.utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,0CAA0C,CAAC;AAElD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mDAAmD,CAAC;AACtF,OAAO,EAKL,KAAK,gCAAgC,EACtC,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAEL,KAAK,2BAA2B,EACjC,MAAM,8BAA8B,CAAC;AAEtC;;;;;;;;;;;;GAYG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE;IACrD,QAAQ,CAAC,iBAAiB,EAAE,YAAY,CAAC;IACzC,QAAQ,CAAC,kBAAkB,EAAE,YAAY,CAAC;IAC1C,QAAQ,CAAC,kBAAkB,EAAE,gCAAgC,CAAC;IAC9D,QAAQ,CAAC,iBAAiB,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,OAAO,CAAC;IACpE,+FAA+F;IAC/F,QAAQ,CAAC,oBAAoB,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,SAAS,oBAAoB,EAAE,CAAC;IAC/F,6FAA6F;IAC7F,QAAQ,CAAC,sBAAsB,EAAE,CAAC,YAAY,EAAE,oBAAoB,KAAK,MAAM,CAAC;CACjF,GAAG,2BAA2B,CAyD9B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"legal-hold-subject-attribution.shared.utils.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"legal-hold-subject-attribution.shared.utils.js","sourceRoot":"","sources":["../../../../../src/compliance/privacy/legal-hold-subject-attribution.shared.utils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Which rows of a resource type a `DATA_SUBJECT` legal hold covers (#1634) — derived from the SAME\n * subject-export classification an Art. 15 access request uses, so the rows a hold on a person preserves\n * and the rows an access request about that person discloses cannot drift apart.\n *\n * Pure over configuration; the backend computes it once per resource type and caches it.\n */\n\nimport {\n RelationshipLifecycleModel,\n type ResourceRelationship,\n} from '../../resources/resources.shared.schemas';\nimport { Resources_SharedUtils } from '../../resources/resources.shared.utils';\nimport type { ResourceType } from '../../resources/resources.shared.core.definitions';\nimport {\n SubjectExportEdgeDisposition,\n SubjectExportPurpose,\n enumerateSubjectExportRelationshipTraversals,\n isIncludedSubjectExportEdgeDisposition,\n type SubjectExportRelationshipBuckets,\n} from './subject-export.shared.schemas';\nimport {\n LegalHoldSubjectAttributionKind,\n type LegalHoldSubjectAttribution,\n} from './legal-holds.shared.schemas';\n\n/**\n * Plan the attribution of `targetResourceType`'s rows to a person.\n *\n * 1. `USERS` itself → the row IS the person.\n * 2. A resource declared `exportSubject: FORBIDDEN` is outside the export graph → never attributed. Its rows\n * (credentials, sessions) are the ones an access request withholds, so a hold on the person does not\n * preserve them either.\n * 3. A resource on an included `USERS` export edge whose rows hold the foreign key → attributed by that field.\n * 4. A resource the export reaches only through another row — a key held on the `USERS` side, or an owned\n * descendant of an included owned edge — cannot be attributed from its own fields → UNRESOLVABLE, and the\n * hold covers every row of it in the held tenant. That is the conservative direction on purpose.\n * 5. Anything else is not the person's data → not attributed.\n */\nexport function planLegalHoldSubjectAttribution(input: {\n readonly usersResourceType: ResourceType;\n readonly targetResourceType: ResourceType;\n readonly usersRelationships: SubjectExportRelationshipBuckets;\n readonly isExportForbidden: (resourceType: ResourceType) => boolean;\n /** The child-direction relationships of a resource type (for the owned-descendant closure). */\n readonly childRelationshipsOf: (resourceType: ResourceType) => readonly ResourceRelationship[];\n /** The FK field of a relationship normalized with the referenced side as `resourceType1`. */\n readonly resolveForeignKeyField: (relationship: ResourceRelationship) => string;\n}): LegalHoldSubjectAttribution {\n const { usersResourceType, targetResourceType } = input;\n if (targetResourceType === usersResourceType) return { kind: LegalHoldSubjectAttributionKind.SUBJECT_ROW };\n if (input.isExportForbidden(targetResourceType)) return { kind: LegalHoldSubjectAttributionKind.NOT_ATTRIBUTED };\n\n const included = enumerateSubjectExportRelationshipTraversals(\n usersResourceType,\n input.usersRelationships,\n SubjectExportPurpose.ACCESS_ART_15,\n ).filter((traversal) => isIncludedSubjectExportEdgeDisposition(traversal.classification.disposition));\n\n const foreignKeyFields = new Set<string>();\n let unresolvable = false;\n for (const traversal of included) {\n if (traversal.classification.relatedResourceType !== targetResourceType) continue;\n const holder = Resources_SharedUtils.resolveForeignKeyHolderResourceType(traversal.normalizedRelationship);\n if (holder === targetResourceType) {\n foreignKeyFields.add(input.resolveForeignKeyField(traversal.normalizedRelationship));\n } else {\n unresolvable = true;\n }\n }\n\n if (!unresolvable) {\n // The owned-descendant closure: rows below a row the person owns are the person's data too, and their\n // own fields do not say whose ancestor they hang from.\n const pending = included\n .filter((traversal) => traversal.classification.disposition === SubjectExportEdgeDisposition.INCLUDED_OWNED)\n .map((traversal) => traversal.classification.relatedResourceType);\n const walked = new Set<string>([String(usersResourceType)]);\n while (pending.length > 0 && !unresolvable) {\n const current = pending.shift()!;\n if (walked.has(String(current))) continue;\n walked.add(String(current));\n for (const relationship of input.childRelationshipsOf(current)) {\n if (relationship.isDisabled === true) continue;\n const semantics = Resources_SharedUtils.requireResolvedRelationshipSemantics(relationship);\n if (semantics.handling.lifecycleModelMode !== RelationshipLifecycleModel.DEPENDENT) continue;\n const child = relationship.resourceType2 as ResourceType;\n if (child === targetResourceType) {\n unresolvable = true;\n break;\n }\n pending.push(child);\n }\n }\n }\n\n if (unresolvable) {\n return foreignKeyFields.size > 0\n ? { kind: LegalHoldSubjectAttributionKind.UNRESOLVABLE, foreignKeyFields: [...foreignKeyFields].sort() }\n : { kind: LegalHoldSubjectAttributionKind.UNRESOLVABLE };\n }\n if (foreignKeyFields.size > 0) {\n return { kind: LegalHoldSubjectAttributionKind.FOREIGN_KEY, foreignKeyFields: [...foreignKeyFields].sort() };\n }\n return { kind: LegalHoldSubjectAttributionKind.NOT_ATTRIBUTED };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"legal-holds.shared.resources-config.schemas.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"legal-holds.shared.resources-config.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/compliance/privacy/legal-holds.shared.resources-config.schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,sBAAsB,EAItB,eAAe,EACf,qBAAqB,EACtB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,qBAAqB,EAAwD,MAAM,mDAAmD,CAAC;AAChJ,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,0CAA0C,CAAC;AAMlD,KAAK,wBAAwB,GACzB,qBAAqB,CAAC,IAAI,GAC1B,qBAAqB,CAAC,IAAI,GAC1B,qBAAqB,CAAC,KAAK,GAC3B,qBAAqB,CAAC,MAAM,CAAC;AAGjC,eAAO,MAAM,qDAAqD,GAAI,wBAAwB,oBAAoB,EAAE;;;;;;;;;;;;;;;;;;iCAsNhH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"legal-holds.shared.resources-config.schemas.js","sourceRoot":"","sources":["../../../../src/compliance/privacy/legal-holds.shared.resources-config.schemas.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Legal holds — resource configuration (#1634).\n *\n * Two verbs and two tiers:\n *\n * place — the tenant's owner (default variant), or an application super-administrator crossing into the\n * tenant through the declared door (`admin` variant, requires a usable platform access grant)\n * release — the SAME tier that placed the hold, and only that tier (see {@link LegalHoldPlacementTier})\n *\n * No client can create, update or delete a hold any other way. The one DELETE is route-less and exists so\n * the retention-class sweep can dispose of a RELEASED hold once its `AUDIT_LOGS` period has passed.\n */\n\nimport {\n LegalHoldPlacementTier,\n LegalHoldPlaceRequestSchema,\n LegalHoldReleaseRequestSchema,\n LegalHoldSchema,\n LegalHoldStatus,\n LegalHolds_Operations,\n} from './legal-holds.shared.schemas';\nimport { CoreResourceOperation, CoreResourceType, coreResourceShared_FieldIdentifier } from '../../resources/resources.shared.core.definitions';\nimport {\n ResourceOperationRiskLevel,\n ResourceOperationVariantType,\n type ResourceRelationship,\n} from '../../resources/resources.shared.schemas';\nimport { createResourceConfiguration_Initialization } from '../../resources/resources-config.shared.factory';\nimport { ResourceSystemAccessMode } from '../../resources/resources-config.shared.schemas';\nimport { CORE_APP_ROLES, CORE_ORG_ROLES } from '../../security/authorizations/roles.shared.schemas';\nimport { DataRetentionClass, RetentionStartPoint } from './retention-schedule.shared.schemas';\n\ntype LegalHoldsCoreOperations =\n | CoreResourceOperation.READ\n | CoreResourceOperation.LIST\n | CoreResourceOperation.COUNT\n | CoreResourceOperation.DELETE;\n\n\nexport const legalHoldsResourceConfiguration_InitializationFactory = (resourcesRelationships: ResourceRelationship[]) =>\n createResourceConfiguration_Initialization<\n typeof LegalHolds_Operations,\n LegalHoldsCoreOperations,\n typeof LegalHoldSchema\n >({\n mainSchema: LegalHoldSchema,\n resourceIdentifier: CoreResourceType.LEGAL_HOLDS,\n resourceFieldIdentifier: coreResourceShared_FieldIdentifier[CoreResourceType.LEGAL_HOLDS],\n resourceRelationships: resourcesRelationships,\n isSystemResource: true,\n\n /**\n * No trusted door of any kind. Every deletion path reads the ACTIVE holds through the infrastructure\n * tier (one indexed query), and every write is a custom verb. A system `create`/`update` would be a\n * second, unaudited way to place or lift a preservation duty.\n *\n * `exportSubject: FORBIDDEN`: `placedByUserId`, `releasedByUserId` and `subjectUserId` put these rows on\n * a user's access graph, and an included resource with no declaration refuses the whole export. A hold is\n * the operator's litigation record; disclosing it to the person it concerns can prejudice the very claim\n * it preserves, and it names the placer and the matter. Left OUT of the bundle and recorded, never\n * silently dropped.\n */\n systemAccessPolicy: {\n exportSubject: ResourceSystemAccessMode.FORBIDDEN,\n },\n\n /**\n * A released hold is kept as defence evidence for the `AUDIT_LOGS` period, counted from its release.\n * An ACTIVE hold has no `releasedAt`, so it never expires — a hold that lapsed on its own would be the\n * failure it exists to prevent. The organization edge disables the teardown cascade, so the record also\n * outlives a purged tenant until its period ends.\n *\n * Deliberately NOT retention-governed (`retentionPolicy`): a scrubbed-and-hidden hold would be invisible\n * to the infrastructure read every deletion path consults, which would lift the hold silently.\n */\n retentionBinding: {\n retentionClass: DataRetentionClass.AUDIT_LOGS,\n startPoint: RetentionStartPoint.CLOSURE_EVENT,\n closureFieldName: 'releasedAt',\n },\n\n coreOperations: [\n CoreResourceOperation.READ,\n CoreResourceOperation.LIST,\n CoreResourceOperation.COUNT,\n // Route-less, for the retention-class sweep only.\n CoreResourceOperation.DELETE,\n ],\n\n operationsConfiguration: {\n [CoreResourceOperation.READ]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_OWNER],\n riskLevel: ResourceOperationRiskLevel.LOW,\n },\n {\n // The same read an operator makes into a tenant, through the declared door and a usable grant.\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: false,\n variantKey: 'admin',\n roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN],\n riskLevel: ResourceOperationRiskLevel.LOW,\n // assurance-control: WILDO.ACCESS.CROSS_TENANT_ADMINISTRATION — an operator reads a tenant's holds only through a usable grant.\n admitsCrossTenantPlatformAdministration: true,\n },\n ],\n },\n [CoreResourceOperation.LIST]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_OWNER],\n riskLevel: ResourceOperationRiskLevel.LOW,\n },\n {\n // The same read an operator makes into a tenant, through the declared door and a usable grant.\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: false,\n variantKey: 'admin',\n roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN],\n riskLevel: ResourceOperationRiskLevel.LOW,\n // assurance-control: WILDO.ACCESS.CROSS_TENANT_ADMINISTRATION — an operator reads a tenant's holds only through a usable grant.\n admitsCrossTenantPlatformAdministration: true,\n },\n ],\n },\n [CoreResourceOperation.COUNT]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_OWNER],\n riskLevel: ResourceOperationRiskLevel.LOW,\n },\n {\n // The same read an operator makes into a tenant, through the declared door and a usable grant.\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: false,\n variantKey: 'admin',\n roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN],\n riskLevel: ResourceOperationRiskLevel.LOW,\n // assurance-control: WILDO.ACCESS.CROSS_TENANT_ADMINISTRATION — an operator reads a tenant's holds only through a usable grant.\n admitsCrossTenantPlatformAdministration: true,\n },\n ],\n },\n\n /**\n * SWEEP ONLY — no client can delete a hold. `INTERNAL_CALL` registers no route; the retention-class\n * sweep disposes of a released hold at the end of its period, and the delete chokepoint itself never\n * holds a hold.\n */\n [CoreResourceOperation.DELETE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.INTERNAL_CALL,\n isDefault: true,\n roles: [],\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n },\n ],\n },\n\n /**\n * Placing a hold suspends every deletion path for its scope until it is released.\n *\n * HIGH with step-up: a hold stops a tenant's retention schedule and its data subjects' erasures, and a\n * hijacked session must not be able to do that on an old login.\n *\n * assurance-control: WILDO.PRIVACY.STORAGE_LIMITATION — deletion suspended under a recorded legal hold.\n */\n [LegalHolds_Operations.PLACE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_OWNER],\n riskLevel: ResourceOperationRiskLevel.HIGH,\n resourceOperationLike: CoreResourceOperation.CREATE,\n requestDto: LegalHoldPlaceRequestSchema,\n // No `auditableEvent.reasonField`: the justification names the matter, and the generic operation row\n // it would ride is exported to every SIEM route. The hold keeps it; LEGAL_HOLD_PLACED carries the scope.\n // assurance-control: WILDO.IDENTITY.STEP_UP_AUTHENTICATION — re-authentication before a high-impact action.\n requiresStepUpAuthentication: true,\n },\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: false,\n variantKey: 'admin',\n roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN],\n riskLevel: ResourceOperationRiskLevel.HIGH,\n resourceOperationLike: CoreResourceOperation.CREATE,\n requestDto: LegalHoldPlaceRequestSchema,\n // No `auditableEvent.reasonField`: the justification names the matter, and the generic operation row\n // it would ride is exported to every SIEM route. The hold keeps it; LEGAL_HOLD_PLACED carries the scope.\n // Preservation is monotonic — it only ever stops a destruction — so crossing to place it passes\n // the reversibility test (`administrative-continuity-floors.md`). Still never ambient: the\n // admission requires a usable platform access grant for the tenant.\n // assurance-control: WILDO.ACCESS.CROSS_TENANT_ADMINISTRATION — declared crossing, grant required.\n admitsCrossTenantPlatformAdministration: true,\n // assurance-control: WILDO.IDENTITY.STEP_UP_AUTHENTICATION — re-authentication before a high-impact action.\n requiresStepUpAuthentication: true,\n },\n ],\n },\n\n /**\n * Releasing a hold lets the next sweep, purge or erasure proceed. Only an ACTIVE hold, and only by the\n * tier that placed it — the enabled condition mirrors the server-side refusal in the paired implementation.\n *\n * assurance-control: WILDO.PRIVACY.STORAGE_LIMITATION — deletion resumes only on a recorded release.\n */\n [LegalHolds_Operations.RELEASE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_OWNER],\n riskLevel: ResourceOperationRiskLevel.HIGH,\n resourceOperationLike: CoreResourceOperation.UPDATE,\n requestDto: LegalHoldReleaseRequestSchema,\n // No `auditableEvent.reasonField`, for the same reason as `place`: the release reason stays on the hold.\n enabledCondition: ({ currentObject }) => currentObject.status === LegalHoldStatus.ACTIVE\n && currentObject.placementTier === LegalHoldPlacementTier.ORGANIZATION,\n // assurance-control: WILDO.IDENTITY.STEP_UP_AUTHENTICATION — re-authentication before a high-impact action.\n requiresStepUpAuthentication: true,\n },\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: false,\n variantKey: 'admin',\n roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN],\n riskLevel: ResourceOperationRiskLevel.HIGH,\n resourceOperationLike: CoreResourceOperation.UPDATE,\n requestDto: LegalHoldReleaseRequestSchema,\n // No `auditableEvent.reasonField`, for the same reason as `place`: the release reason stays on the hold.\n // assurance-control: WILDO.ACCESS.CROSS_TENANT_ADMINISTRATION — declared crossing, grant required.\n admitsCrossTenantPlatformAdministration: true,\n // Any ACTIVE hold: the platform's own, or a tenant's own once that tenant is marked for deletion (its\n // owners then hold no authority to release it). The tenant's status is not on the hold, so the server\n // decides the second case and refuses a live tenant's hold.\n enabledCondition: ({ currentObject }) => currentObject.status === LegalHoldStatus.ACTIVE,\n // assurance-control: WILDO.IDENTITY.STEP_UP_AUTHENTICATION — re-authentication before a high-impact action.\n requiresStepUpAuthentication: true,\n },\n ],\n },\n },\n // The ORGANIZATIONS primary scope is declared on the registry relationship (ORGANIZATIONS → LEGAL_HOLDS).\n });\n"]}
|
|
1
|
+
{"version":3,"file":"legal-holds.shared.resources-config.schemas.js","sourceRoot":"","sources":["../../../../../src/compliance/privacy/legal-holds.shared.resources-config.schemas.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Legal holds — resource configuration (#1634).\n *\n * Two verbs and two tiers:\n *\n * place — the tenant's owner (default variant), or an application super-administrator crossing into the\n * tenant through the declared door (`admin` variant, requires a usable platform access grant)\n * release — the SAME tier that placed the hold, and only that tier (see {@link LegalHoldPlacementTier})\n *\n * No client can create, update or delete a hold any other way. The one DELETE is route-less and exists so\n * the retention-class sweep can dispose of a RELEASED hold once its `AUDIT_LOGS` period has passed.\n */\n\nimport {\n LegalHoldPlacementTier,\n LegalHoldPlaceRequestSchema,\n LegalHoldReleaseRequestSchema,\n LegalHoldSchema,\n LegalHoldStatus,\n LegalHolds_Operations,\n} from './legal-holds.shared.schemas';\nimport { CoreResourceOperation, CoreResourceType, coreResourceShared_FieldIdentifier } from '../../resources/resources.shared.core.definitions';\nimport {\n ResourceOperationRiskLevel,\n ResourceOperationVariantType,\n type ResourceRelationship,\n} from '../../resources/resources.shared.schemas';\nimport { createResourceConfiguration_Initialization } from '../../resources/resources-config.shared.factory';\nimport { ResourceSystemAccessMode } from '../../resources/resources-config.shared.schemas';\nimport { CORE_APP_ROLES, CORE_ORG_ROLES } from '../../security/authorizations/roles.shared.schemas';\nimport { DataRetentionClass, RetentionStartPoint } from './retention-schedule.shared.schemas';\n\ntype LegalHoldsCoreOperations =\n | CoreResourceOperation.READ\n | CoreResourceOperation.LIST\n | CoreResourceOperation.COUNT\n | CoreResourceOperation.DELETE;\n\n\nexport const legalHoldsResourceConfiguration_InitializationFactory = (resourcesRelationships: ResourceRelationship[]) =>\n createResourceConfiguration_Initialization<\n typeof LegalHolds_Operations,\n LegalHoldsCoreOperations,\n typeof LegalHoldSchema\n >({\n mainSchema: LegalHoldSchema,\n resourceIdentifier: CoreResourceType.LEGAL_HOLDS,\n resourceFieldIdentifier: coreResourceShared_FieldIdentifier[CoreResourceType.LEGAL_HOLDS],\n resourceRelationships: resourcesRelationships,\n isSystemResource: true,\n\n /**\n * No trusted door of any kind. Every deletion path reads the ACTIVE holds through the infrastructure\n * tier (one indexed query), and every write is a custom verb. A system `create`/`update` would be a\n * second, unaudited way to place or lift a preservation duty.\n *\n * `exportSubject: FORBIDDEN`: `placedByUserId`, `releasedByUserId` and `subjectUserId` put these rows on\n * a user's access graph, and an included resource with no declaration refuses the whole export. A hold is\n * the operator's litigation record; disclosing it to the person it concerns can prejudice the very claim\n * it preserves, and it names the placer and the matter. Left OUT of the bundle and recorded, never\n * silently dropped.\n */\n systemAccessPolicy: {\n exportSubject: ResourceSystemAccessMode.FORBIDDEN,\n },\n\n /**\n * A released hold is kept as defence evidence for the `AUDIT_LOGS` period, counted from its release.\n * An ACTIVE hold has no `releasedAt`, so it never expires — a hold that lapsed on its own would be the\n * failure it exists to prevent. The organization edge disables the teardown cascade, so the record also\n * outlives a purged tenant until its period ends.\n *\n * Deliberately NOT retention-governed (`retentionPolicy`): a scrubbed-and-hidden hold would be invisible\n * to the infrastructure read every deletion path consults, which would lift the hold silently.\n */\n retentionBinding: {\n retentionClass: DataRetentionClass.AUDIT_LOGS,\n startPoint: RetentionStartPoint.CLOSURE_EVENT,\n closureFieldName: 'releasedAt',\n },\n\n coreOperations: [\n CoreResourceOperation.READ,\n CoreResourceOperation.LIST,\n CoreResourceOperation.COUNT,\n // Route-less, for the retention-class sweep only.\n CoreResourceOperation.DELETE,\n ],\n\n operationsConfiguration: {\n [CoreResourceOperation.READ]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_OWNER],\n riskLevel: ResourceOperationRiskLevel.LOW,\n },\n {\n // The same read an operator makes into a tenant, through the declared door and a usable grant.\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: false,\n variantKey: 'admin',\n roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN],\n riskLevel: ResourceOperationRiskLevel.LOW,\n // assurance-control: WILDO.ACCESS.CROSS_TENANT_ADMINISTRATION — an operator reads a tenant's holds only through a usable grant.\n admitsCrossTenantPlatformAdministration: true,\n },\n ],\n },\n [CoreResourceOperation.LIST]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_OWNER],\n riskLevel: ResourceOperationRiskLevel.LOW,\n },\n {\n // The same read an operator makes into a tenant, through the declared door and a usable grant.\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: false,\n variantKey: 'admin',\n roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN],\n riskLevel: ResourceOperationRiskLevel.LOW,\n // assurance-control: WILDO.ACCESS.CROSS_TENANT_ADMINISTRATION — an operator reads a tenant's holds only through a usable grant.\n admitsCrossTenantPlatformAdministration: true,\n },\n ],\n },\n [CoreResourceOperation.COUNT]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_OWNER],\n riskLevel: ResourceOperationRiskLevel.LOW,\n },\n {\n // The same read an operator makes into a tenant, through the declared door and a usable grant.\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: false,\n variantKey: 'admin',\n roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN],\n riskLevel: ResourceOperationRiskLevel.LOW,\n // assurance-control: WILDO.ACCESS.CROSS_TENANT_ADMINISTRATION — an operator reads a tenant's holds only through a usable grant.\n admitsCrossTenantPlatformAdministration: true,\n },\n ],\n },\n\n /**\n * SWEEP ONLY — no client can delete a hold. `INTERNAL_CALL` registers no route; the retention-class\n * sweep disposes of a released hold at the end of its period, and the delete chokepoint itself never\n * holds a hold.\n */\n [CoreResourceOperation.DELETE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.INTERNAL_CALL,\n isDefault: true,\n roles: [],\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n },\n ],\n },\n\n /**\n * Placing a hold suspends every deletion path for its scope until it is released.\n *\n * HIGH with step-up: a hold stops a tenant's retention schedule and its data subjects' erasures, and a\n * hijacked session must not be able to do that on an old login.\n *\n * assurance-control: WILDO.PRIVACY.STORAGE_LIMITATION — deletion suspended under a recorded legal hold.\n */\n [LegalHolds_Operations.PLACE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_OWNER],\n riskLevel: ResourceOperationRiskLevel.HIGH,\n resourceOperationLike: CoreResourceOperation.CREATE,\n requestDto: LegalHoldPlaceRequestSchema,\n // No `auditableEvent.reasonField`: the justification names the matter, and the generic operation row\n // it would ride is exported to every SIEM route. The hold keeps it; LEGAL_HOLD_PLACED carries the scope.\n // assurance-control: WILDO.IDENTITY.STEP_UP_AUTHENTICATION — re-authentication before a high-impact action.\n requiresStepUpAuthentication: true,\n },\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: false,\n variantKey: 'admin',\n roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN],\n riskLevel: ResourceOperationRiskLevel.HIGH,\n resourceOperationLike: CoreResourceOperation.CREATE,\n requestDto: LegalHoldPlaceRequestSchema,\n // No `auditableEvent.reasonField`: the justification names the matter, and the generic operation row\n // it would ride is exported to every SIEM route. The hold keeps it; LEGAL_HOLD_PLACED carries the scope.\n // Preservation is monotonic — it only ever stops a destruction — so crossing to place it passes\n // the reversibility test (`administrative-continuity-floors.md`). Still never ambient: the\n // admission requires a usable platform access grant for the tenant.\n // assurance-control: WILDO.ACCESS.CROSS_TENANT_ADMINISTRATION — declared crossing, grant required.\n admitsCrossTenantPlatformAdministration: true,\n // assurance-control: WILDO.IDENTITY.STEP_UP_AUTHENTICATION — re-authentication before a high-impact action.\n requiresStepUpAuthentication: true,\n },\n ],\n },\n\n /**\n * Releasing a hold lets the next sweep, purge or erasure proceed. Only an ACTIVE hold, and only by the\n * tier that placed it — the enabled condition mirrors the server-side refusal in the paired implementation.\n *\n * assurance-control: WILDO.PRIVACY.STORAGE_LIMITATION — deletion resumes only on a recorded release.\n */\n [LegalHolds_Operations.RELEASE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_OWNER],\n riskLevel: ResourceOperationRiskLevel.HIGH,\n resourceOperationLike: CoreResourceOperation.UPDATE,\n requestDto: LegalHoldReleaseRequestSchema,\n // No `auditableEvent.reasonField`, for the same reason as `place`: the release reason stays on the hold.\n enabledCondition: ({ currentObject }) => currentObject.status === LegalHoldStatus.ACTIVE\n && currentObject.placementTier === LegalHoldPlacementTier.ORGANIZATION,\n // assurance-control: WILDO.IDENTITY.STEP_UP_AUTHENTICATION — re-authentication before a high-impact action.\n requiresStepUpAuthentication: true,\n },\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: false,\n variantKey: 'admin',\n roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN],\n riskLevel: ResourceOperationRiskLevel.HIGH,\n resourceOperationLike: CoreResourceOperation.UPDATE,\n requestDto: LegalHoldReleaseRequestSchema,\n // No `auditableEvent.reasonField`, for the same reason as `place`: the release reason stays on the hold.\n // assurance-control: WILDO.ACCESS.CROSS_TENANT_ADMINISTRATION — declared crossing, grant required.\n admitsCrossTenantPlatformAdministration: true,\n // Any ACTIVE hold: the platform's own, or a tenant's own once that tenant is marked for deletion (its\n // owners then hold no authority to release it). The tenant's status is not on the hold, so the server\n // decides the second case and refuses a live tenant's hold.\n enabledCondition: ({ currentObject }) => currentObject.status === LegalHoldStatus.ACTIVE,\n // assurance-control: WILDO.IDENTITY.STEP_UP_AUTHENTICATION — re-authentication before a high-impact action.\n requiresStepUpAuthentication: true,\n },\n ],\n },\n },\n // The ORGANIZATIONS primary scope is declared on the registry relationship (ORGANIZATIONS → LEGAL_HOLDS).\n });\n"]}
|