@wildo-ai/saas-models 1.1.9 → 1.1.10
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 +68 -2
- 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.map +1 -1
- 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 +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 +5 -2
- 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-event-classification.shared.d.ts +28 -0
- package/dist/esm/compliance/audit-trails/audit-event-classification.shared.d.ts.map +1 -0
- package/dist/esm/compliance/audit-trails/audit-event-classification.shared.js +30 -0
- package/dist/esm/compliance/audit-trails/audit-event-classification.shared.js.map +1 -0
- 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 +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 +2 -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 +20 -0
- 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 +40 -0
- 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 +1 -14
- 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 +1 -16
- 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 +17 -4
- 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 +25 -5
- 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 +0 -50
- package/dist/esm/compliance/documents/governed-documents.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/documents/governed-documents.shared.schemas.js +4 -51
- package/dist/esm/compliance/documents/governed-documents.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/documents/public-governed-documents.shared.d.ts +67 -0
- package/dist/esm/compliance/documents/public-governed-documents.shared.d.ts.map +1 -0
- package/dist/esm/compliance/documents/public-governed-documents.shared.js +69 -0
- package/dist/esm/compliance/documents/public-governed-documents.shared.js.map +1 -0
- 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 +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/jurisdiction-containment.shared.d.ts +32 -0
- package/dist/esm/compliance/privacy/jurisdiction-containment.shared.d.ts.map +1 -0
- package/dist/esm/compliance/privacy/jurisdiction-containment.shared.js +46 -0
- package/dist/esm/compliance/privacy/jurisdiction-containment.shared.js.map +1 -0
- 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/legal-notice-obligation.shared.d.ts +47 -0
- package/dist/esm/compliance/privacy/legal-notice-obligation.shared.d.ts.map +1 -0
- package/dist/esm/compliance/privacy/legal-notice-obligation.shared.js +54 -0
- package/dist/esm/compliance/privacy/legal-notice-obligation.shared.js.map +1 -0
- package/dist/esm/compliance/privacy/legal-notice.shared.d.ts +105 -0
- package/dist/esm/compliance/privacy/legal-notice.shared.d.ts.map +1 -0
- package/dist/esm/compliance/privacy/legal-notice.shared.js +112 -0
- package/dist/esm/compliance/privacy/legal-notice.shared.js.map +1 -0
- package/dist/esm/compliance/privacy/operating-jurisdictions.shared.schemas.d.ts +1 -27
- package/dist/esm/compliance/privacy/operating-jurisdictions.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/operating-jurisdictions.shared.schemas.js +2 -41
- 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 +51 -0
- 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 +65 -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 +8 -8
- 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.map +1 -1
- 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 +63 -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 +11 -0
- 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 +16 -16
- 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 +5 -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 +48 -4
- 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 +34 -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 +2 -1
- package/dist/esm/flows-actors/deliberation.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/deliberation.shared.schemas.js +2 -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 +2 -2
- 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 +5 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +5 -0
- 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.map +1 -1
- package/dist/esm/meta-workflows/elicitation-depth.meta-workflows.shared.schemas.js.map +1 -1
- package/dist/esm/meta-workflows/orchestration.meta-workflows.shared.schemas.d.ts +13 -1
- 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 +21 -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.map +1 -1
- 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 +5 -3
- package/dist/esm/notifications/notifications.shared.schemas.d.ts.map +1 -1
- package/dist/esm/notifications/notifications.shared.schemas.js +5 -3
- 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 +13 -0
- package/dist/esm/public-runtime/index.d.ts.map +1 -1
- package/dist/esm/public-runtime/index.js +13 -0
- 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 +1 -1
- package/dist/esm/queue/jobs.shared.schemas.d.ts.map +1 -1
- 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 +2 -2
- 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/resource-status-lifecycle.example.d.ts +100 -0
- package/dist/esm/resources/resource-status-lifecycle.example.d.ts.map +1 -0
- package/dist/esm/resources/resource-status-lifecycle.example.js +156 -0
- package/dist/esm/resources/resource-status-lifecycle.example.js.map +1 -0
- package/dist/esm/resources/resources-config.shared.factory.d.ts +25 -1
- package/dist/esm/resources/resources-config.shared.factory.d.ts.map +1 -1
- package/dist/esm/resources/resources-config.shared.factory.js +31 -8
- package/dist/esm/resources/resources-config.shared.factory.js.map +1 -1
- package/dist/esm/resources/resources-config.shared.schemas.d.ts +33 -0
- 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.map +1 -1
- 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.application-roles.example.d.ts +37 -0
- package/dist/esm/security/authorizations/roles.application-roles.example.d.ts.map +1 -0
- package/dist/esm/security/authorizations/roles.application-roles.example.js +50 -0
- package/dist/esm/security/authorizations/roles.application-roles.example.js.map +1 -0
- package/dist/esm/security/authorizations/roles.shared.defaults.d.ts +13 -0
- package/dist/esm/security/authorizations/roles.shared.defaults.d.ts.map +1 -1
- package/dist/esm/security/authorizations/roles.shared.defaults.js +13 -0
- package/dist/esm/security/authorizations/roles.shared.defaults.js.map +1 -1
- package/dist/esm/security/authorizations/roles.shared.schemas.d.ts +29 -0
- package/dist/esm/security/authorizations/roles.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authorizations/roles.shared.schemas.js +28 -0
- 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 +2 -0
- 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/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collection-export.shared.utils.js","sourceRoot":"","sources":["../../../../../src/resources/utils/collection-export.shared.utils.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getMergedObjectOrUnionShape,\n getZodDefSchemaProperty,\n getZodType,\n unwrapSchema,\n} from '@wildo-ai/zod-decorators';\nimport { z } from 'zod';\n\nimport type { ResourceCollectionExportConfig } from '../resources-config.shared.schemas';\nimport { ResourceCollectionExportFormat, ResourceCollectionExportRowScope } from '../resources-config.shared.schemas';\n\n/** IANA media types, one per format. */\nexport const COLLECTION_EXPORT_CONTENT_TYPES: Readonly<Record<ResourceCollectionExportFormat, string>> = {\n [ResourceCollectionExportFormat.CSV]: 'text/csv; charset=utf-8',\n [ResourceCollectionExportFormat.JSON]: 'application/json; charset=utf-8',\n [ResourceCollectionExportFormat.PDF]: 'application/pdf',\n};\n\n/** File extensions, one per format. */\nexport const COLLECTION_EXPORT_FILE_EXTENSIONS: Readonly<Record<ResourceCollectionExportFormat, string>> = {\n [ResourceCollectionExportFormat.CSV]: 'csv',\n [ResourceCollectionExportFormat.JSON]: 'json',\n [ResourceCollectionExportFormat.PDF]: 'pdf',\n};\n\n/** Query-parameter names the export route reads its two selectors from. */\nexport const COLLECTION_EXPORT_FORMAT_QUERY_PARAM = 'format';\nexport const COLLECTION_EXPORT_ROW_SCOPE_QUERY_PARAM = 'rowScope';\n\n/** Response header carrying the number of rows actually written. */\nexport const COLLECTION_EXPORT_ROW_COUNT_HEADER = 'X-Wildo-Export-Row-Count';\n\n/**\n * The CSV column set for an exported listing, resolved from the operation's DECLARED response shape\n * rather than from the rows.\n *\n * ## Why the schema and not the rows\n *\n * A whole-result-set export streams: the header record is written before the last page has been\n * read. Resolving columns from rows would therefore have to guess from the first page, and a column\n * that first appears on page 40 (an optional field absent from every earlier row) would be dropped\n * from a file that looks complete. Silent column loss inside a file the user then treats as\n * authoritative is exactly the failure this codebase refuses elsewhere.\n *\n * The declared shape has none of that problem: it is complete, ordered by the schema's own field\n * order (which reads far better than alphabetical), and identical across every export of the same\n * operation — so a downstream consumer can rely on the header.\n *\n * Returns `undefined` when the shape cannot be resolved, and callers must then REFUSE to render CSV\n * rather than fall back to a row-derived guess. JSON is unaffected: it carries whatever each row\n * carries, so it needs no column set at all.\n */\nexport function resolveCollectionExportCsvColumns(responseDto: z.ZodTypeAny | undefined): string[] | undefined {\n if (!responseDto) return undefined;\n\n // ⚠️ `getZodObjectShape` answers `{}` — NOT `undefined` — for anything that is not an object, and\n // `{}` is truthy. Every check here is therefore on the KEY COUNT. A truthiness check reads\n // correctly and is always satisfied, which is how the first implementation returned \"no columns\"\n // for a schema whose shape it had successfully read.\n const envelopeShape = getMergedObjectOrUnionShape(deepUnwrapSchema(responseDto));\n if (Object.keys(envelopeShape).length === 0) return undefined;\n\n // A paginated LIST/SEARCH response is `{ data: Row[], pagination: {...} }`.\n const dataSchema = envelopeShape.data ? deepUnwrapSchema(envelopeShape.data) : undefined;\n if (!dataSchema || getZodType(dataSchema) !== 'array') return undefined;\n\n const elementSchema = getZodDefSchemaProperty(dataSchema, 'element');\n if (!elementSchema) return undefined;\n\n // `getMergedObjectOrUnionShape` rather than `getZodObjectShape`: a resource declared through a\n // schema family (`createSchemaFamily`) has a DISCRIMINATED UNION as its row type, not an object —\n // Wonder Todos' `todos` is exactly that, discriminated on `recurringType`, with 24 fields on one\n // variant and 27 on the other. Reading the object shape off such an element yields nothing, which\n // would make CSV export impossible for every inheritance resource in the framework.\n //\n // The union is MERGED, not sampled: a recurring row carries fields a one-off row does not, and a\n // column set taken from one branch would drop the other's fields from a file that looks complete.\n const rowShape = getMergedObjectOrUnionShape(deepUnwrapSchema(elementSchema));\n const columns = Object.keys(rowShape);\n return columns.length > 0 ? columns : undefined;\n}\n\n/**\n * Peel every wrapper a response DTO may have acquired on its way here, until an inspectable schema\n * is reached.\n *\n * A LIST response DTO is not the plain object it was authored as: the DTO builder applies\n * network-boundary coercion (dates, money bigints), which produces `pipe`/effect wrappers around the\n * envelope AND around individual fields. A single `unwrapSchema` call stops at the first of those,\n * and the caller then reports \"no columns\" for a perfectly ordinary listing — a refusal that looks\n * like a configuration problem and is really a traversal that gave up one level early.\n *\n * `pipe` is walked OUTPUT-first: what a CSV column set describes is what the caller receives.\n */\nfunction deepUnwrapSchema(schema: z.ZodTypeAny, depth = 0): z.ZodTypeAny {\n // A cheap cycle/rabbit-hole guard: `z.lazy` chains are legal and a malformed one must not hang\n // resource configuration.\n if (depth > 12) return schema;\n\n const zodType = getZodType(schema);\n if (zodType === 'pipe') {\n const outSchema = getZodDefSchemaProperty(schema, 'out') ?? getZodDefSchemaProperty(schema, 'in');\n return outSchema ? deepUnwrapSchema(outSchema, depth + 1) : schema;\n }\n if (zodType === 'lazy') {\n const inner = getZodDefSchemaProperty(schema, 'getter');\n return inner ? deepUnwrapSchema(inner, depth + 1) : schema;\n }\n\n const innerType = getZodDefSchemaProperty(schema, 'innerType');\n if (innerType) return deepUnwrapSchema(innerType, depth + 1);\n\n const unwrapped = unwrapSchema(schema);\n return unwrapped !== schema ? deepUnwrapSchema(unwrapped, depth + 1) : schema;\n}\n\n/**\n * Resolve the caller's requested format against what the operation OFFERS.\n *\n * Absent ⇒ the operation's first declared format, which is the author's stated preference (the\n * declaration is an ordered list, not a set). Present but not offered ⇒ `undefined`, and the caller\n * refuses — never a silent fallback to something the author did not publish.\n */\nexport function resolveRequestedCollectionExportFormat(\n requested: unknown,\n offered: readonly ResourceCollectionExportFormat[],\n): ResourceCollectionExportFormat | undefined {\n if (requested === undefined || requested === null || requested === '') {\n return offered[0];\n }\n if (typeof requested !== 'string') return undefined;\n return offered.find((format) => format === requested);\n}\n\n/** The row-scope twin of {@link resolveRequestedCollectionExportFormat}, with the same rules. */\nexport function resolveRequestedCollectionExportRowScope(\n requested: unknown,\n offered: readonly ResourceCollectionExportRowScope[],\n): ResourceCollectionExportRowScope | undefined {\n if (requested === undefined || requested === null || requested === '') {\n return offered[0];\n }\n if (typeof requested !== 'string') return undefined;\n return offered.find((rowScope) => rowScope === requested);\n}\n\n/** One offered export: a format and a row scope the operation actually declared. */\nexport interface ResourceCollectionExportSelection {\n format: ResourceCollectionExportFormat;\n rowScope: ResourceCollectionExportRowScope;\n}\n\n/**\n * Every combination the operation offers, format-major, in the author's declared order.\n *\n * The declaration is two ORDERED lists, and the cross product is what a user should be able to\n * choose from — an action that silently picks one pair on their behalf is the surface answering a\n * question they were never asked. Format-major because format is the coarser choice: \"CSV, JSON or PDF\"\n * separates audiences (a spreadsheet, a system, a reader), while the row scope refines within each.\n */\nexport function listCollectionExportSelections(\n exportConfig: ResourceCollectionExportConfig,\n): ResourceCollectionExportSelection[] {\n const selections: ResourceCollectionExportSelection[] = [];\n for (const format of exportConfig.formats) {\n for (const rowScope of exportConfig.rowScopes) {\n selections.push({ format, rowScope });\n }\n }\n return selections;\n}\n\n/**\n * `<resourceType>-<ISO date>.<ext>` — stable, sortable, and free of any row content.\n *\n * The date rather than a timestamp: two exports on one day should not produce filenames a human\n * cannot tell apart at a glance, and the exact moment is in the audit trail where it belongs.\n */\nexport function buildCollectionExportFilename(\n resourceType: string,\n format: ResourceCollectionExportFormat,\n now: Date,\n): string {\n const datePart = now.toISOString().slice(0, 10);\n return `${resourceType}-${datePart}.${COLLECTION_EXPORT_FILE_EXTENSIONS[format]}`;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"collection-export.shared.utils.js","sourceRoot":"","sources":["../../../../src/resources/utils/collection-export.shared.utils.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getMergedObjectOrUnionShape,\n getZodDefSchemaProperty,\n getZodType,\n unwrapSchema,\n} from '@wildo-ai/zod-decorators';\nimport { z } from 'zod';\n\nimport type { ResourceCollectionExportConfig } from '../resources-config.shared.schemas';\nimport { ResourceCollectionExportFormat, ResourceCollectionExportRowScope } from '../resources-config.shared.schemas';\n\n/** IANA media types, one per format. */\nexport const COLLECTION_EXPORT_CONTENT_TYPES: Readonly<Record<ResourceCollectionExportFormat, string>> = {\n [ResourceCollectionExportFormat.CSV]: 'text/csv; charset=utf-8',\n [ResourceCollectionExportFormat.JSON]: 'application/json; charset=utf-8',\n [ResourceCollectionExportFormat.PDF]: 'application/pdf',\n};\n\n/** File extensions, one per format. */\nexport const COLLECTION_EXPORT_FILE_EXTENSIONS: Readonly<Record<ResourceCollectionExportFormat, string>> = {\n [ResourceCollectionExportFormat.CSV]: 'csv',\n [ResourceCollectionExportFormat.JSON]: 'json',\n [ResourceCollectionExportFormat.PDF]: 'pdf',\n};\n\n/** Query-parameter names the export route reads its two selectors from. */\nexport const COLLECTION_EXPORT_FORMAT_QUERY_PARAM = 'format';\nexport const COLLECTION_EXPORT_ROW_SCOPE_QUERY_PARAM = 'rowScope';\n\n/** Response header carrying the number of rows actually written. */\nexport const COLLECTION_EXPORT_ROW_COUNT_HEADER = 'X-Wildo-Export-Row-Count';\n\n/**\n * The CSV column set for an exported listing, resolved from the operation's DECLARED response shape\n * rather than from the rows.\n *\n * ## Why the schema and not the rows\n *\n * A whole-result-set export streams: the header record is written before the last page has been\n * read. Resolving columns from rows would therefore have to guess from the first page, and a column\n * that first appears on page 40 (an optional field absent from every earlier row) would be dropped\n * from a file that looks complete. Silent column loss inside a file the user then treats as\n * authoritative is exactly the failure this codebase refuses elsewhere.\n *\n * The declared shape has none of that problem: it is complete, ordered by the schema's own field\n * order (which reads far better than alphabetical), and identical across every export of the same\n * operation — so a downstream consumer can rely on the header.\n *\n * Returns `undefined` when the shape cannot be resolved, and callers must then REFUSE to render CSV\n * rather than fall back to a row-derived guess. JSON is unaffected: it carries whatever each row\n * carries, so it needs no column set at all.\n */\nexport function resolveCollectionExportCsvColumns(responseDto: z.ZodTypeAny | undefined): string[] | undefined {\n if (!responseDto) return undefined;\n\n // ⚠️ `getZodObjectShape` answers `{}` — NOT `undefined` — for anything that is not an object, and\n // `{}` is truthy. Every check here is therefore on the KEY COUNT. A truthiness check reads\n // correctly and is always satisfied, which is how the first implementation returned \"no columns\"\n // for a schema whose shape it had successfully read.\n const envelopeShape = getMergedObjectOrUnionShape(deepUnwrapSchema(responseDto));\n if (Object.keys(envelopeShape).length === 0) return undefined;\n\n // A paginated LIST/SEARCH response is `{ data: Row[], pagination: {...} }`.\n const dataSchema = envelopeShape.data ? deepUnwrapSchema(envelopeShape.data) : undefined;\n if (!dataSchema || getZodType(dataSchema) !== 'array') return undefined;\n\n const elementSchema = getZodDefSchemaProperty(dataSchema, 'element');\n if (!elementSchema) return undefined;\n\n // `getMergedObjectOrUnionShape` rather than `getZodObjectShape`: a resource declared through a\n // schema family (`createSchemaFamily`) has a DISCRIMINATED UNION as its row type, not an object —\n // Wonder Todos' `todos` is exactly that, discriminated on `recurringType`, with 24 fields on one\n // variant and 27 on the other. Reading the object shape off such an element yields nothing, which\n // would make CSV export impossible for every inheritance resource in the framework.\n //\n // The union is MERGED, not sampled: a recurring row carries fields a one-off row does not, and a\n // column set taken from one branch would drop the other's fields from a file that looks complete.\n const rowShape = getMergedObjectOrUnionShape(deepUnwrapSchema(elementSchema));\n const columns = Object.keys(rowShape);\n return columns.length > 0 ? columns : undefined;\n}\n\n/**\n * Peel every wrapper a response DTO may have acquired on its way here, until an inspectable schema\n * is reached.\n *\n * A LIST response DTO is not the plain object it was authored as: the DTO builder applies\n * network-boundary coercion (dates, money bigints), which produces `pipe`/effect wrappers around the\n * envelope AND around individual fields. A single `unwrapSchema` call stops at the first of those,\n * and the caller then reports \"no columns\" for a perfectly ordinary listing — a refusal that looks\n * like a configuration problem and is really a traversal that gave up one level early.\n *\n * `pipe` is walked OUTPUT-first: what a CSV column set describes is what the caller receives.\n */\nfunction deepUnwrapSchema(schema: z.ZodTypeAny, depth = 0): z.ZodTypeAny {\n // A cheap cycle/rabbit-hole guard: `z.lazy` chains are legal and a malformed one must not hang\n // resource configuration.\n if (depth > 12) return schema;\n\n const zodType = getZodType(schema);\n if (zodType === 'pipe') {\n const outSchema = getZodDefSchemaProperty(schema, 'out') ?? getZodDefSchemaProperty(schema, 'in');\n return outSchema ? deepUnwrapSchema(outSchema, depth + 1) : schema;\n }\n if (zodType === 'lazy') {\n const inner = getZodDefSchemaProperty(schema, 'getter');\n return inner ? deepUnwrapSchema(inner, depth + 1) : schema;\n }\n\n const innerType = getZodDefSchemaProperty(schema, 'innerType');\n if (innerType) return deepUnwrapSchema(innerType, depth + 1);\n\n const unwrapped = unwrapSchema(schema);\n return unwrapped !== schema ? deepUnwrapSchema(unwrapped, depth + 1) : schema;\n}\n\n/**\n * Resolve the caller's requested format against what the operation OFFERS.\n *\n * Absent ⇒ the operation's first declared format, which is the author's stated preference (the\n * declaration is an ordered list, not a set). Present but not offered ⇒ `undefined`, and the caller\n * refuses — never a silent fallback to something the author did not publish.\n */\nexport function resolveRequestedCollectionExportFormat(\n requested: unknown,\n offered: readonly ResourceCollectionExportFormat[],\n): ResourceCollectionExportFormat | undefined {\n if (requested === undefined || requested === null || requested === '') {\n return offered[0];\n }\n if (typeof requested !== 'string') return undefined;\n return offered.find((format) => format === requested);\n}\n\n/** The row-scope twin of {@link resolveRequestedCollectionExportFormat}, with the same rules. */\nexport function resolveRequestedCollectionExportRowScope(\n requested: unknown,\n offered: readonly ResourceCollectionExportRowScope[],\n): ResourceCollectionExportRowScope | undefined {\n if (requested === undefined || requested === null || requested === '') {\n return offered[0];\n }\n if (typeof requested !== 'string') return undefined;\n return offered.find((rowScope) => rowScope === requested);\n}\n\n/** One offered export: a format and a row scope the operation actually declared. */\nexport interface ResourceCollectionExportSelection {\n format: ResourceCollectionExportFormat;\n rowScope: ResourceCollectionExportRowScope;\n}\n\n/**\n * Every combination the operation offers, format-major, in the author's declared order.\n *\n * The declaration is two ORDERED lists, and the cross product is what a user should be able to\n * choose from — an action that silently picks one pair on their behalf is the surface answering a\n * question they were never asked. Format-major because format is the coarser choice: \"CSV, JSON or PDF\"\n * separates audiences (a spreadsheet, a system, a reader), while the row scope refines within each.\n */\nexport function listCollectionExportSelections(\n exportConfig: ResourceCollectionExportConfig,\n): ResourceCollectionExportSelection[] {\n const selections: ResourceCollectionExportSelection[] = [];\n for (const format of exportConfig.formats) {\n for (const rowScope of exportConfig.rowScopes) {\n selections.push({ format, rowScope });\n }\n }\n return selections;\n}\n\n/**\n * `<resourceType>-<ISO date>.<ext>` — stable, sortable, and free of any row content.\n *\n * The date rather than a timestamp: two exports on one day should not produce filenames a human\n * cannot tell apart at a glance, and the exact moment is in the audit trail where it belongs.\n */\nexport function buildCollectionExportFilename(\n resourceType: string,\n format: ResourceCollectionExportFormat,\n now: Date,\n): string {\n const datePart = now.toISOString().slice(0, 10);\n return `${resourceType}-${datePart}.${COLLECTION_EXPORT_FILE_EXTENSIONS[format]}`;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composition-cascade-deletability.validation.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"composition-cascade-deletability.validation.d.ts","sourceRoot":"","sources":["../../../../src/resources/utils/composition-cascade-deletability.validation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EAErB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAC3F,OAAO,EAAsB,sBAAsB,EAAyC,MAAM,oCAAoC,CAAC;AAGvI,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2DAA2D,CAAC;AAEtG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AAEH,gFAAgF;AAChF,MAAM,WAAW,2CAA2C;IAC1D,kBAAkB,EAAE,YAAY,CAAC;IACjC;;;;;;;;;;OAUG;IACH,UAAU,EAAE,aAAa,CAAC;QACxB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;KAC/C,CAAC,CAAC;IACH;;;;;;OAMG;IACH,eAAe,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,oBAAoB,CAAA;KAAE,CAAC;IAClD,qBAAqB,CAAC,EAAE;QACtB,mBAAmB,CAAC,EAAE,oBAAoB,EAAE,CAAC;QAC7C,iBAAiB,CAAC,EAAE,oBAAoB,EAAE,CAAC;KAC5C,CAAC;CACH;AAED,MAAM,WAAW,uCAAuC;IACtD,iBAAiB,EAAE,YAAY,CAAC;IAChC,kBAAkB,EAAE,YAAY,CAAC;IACjC,WAAW,EAAE,YAAY,GAAG,aAAa,CAAC;IAC1C,kIAAkI;IAClI,QAAQ,EAAE,sBAAsB,CAAC;IACjC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,qBAAqB,CAAC;IAC3C,yFAAyF;IACzF,iBAAiB,EAAE,OAAO,CAAC;IAC3B;;;;OAIG;IACH,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC;;;OAGG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC;CACjB;AAcD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,2CAA2C,GAAG,SAAS,GAChE,OAAO,CAaT;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sCAAsC,CACpD,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,2CAA2C,CAAC,GAClF,uCAAuC,EAAE,CAmJ3C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composition-cascade-deletability.validation.js","sourceRoot":"","sources":["../../../../../src/resources/utils/composition-cascade-deletability.validation.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ResourceRelationship,\n isOneToOneCardinality,\n} from '../resources.shared.schemas';\nimport { ResourceType, CoreResourceOperation } from '../resources.shared.core.definitions';\nimport { ChildLifecycleMode, ChildLifecycleStrategy, resolveChildLifecycleTeardownStrategy } from '../child-operations.shared.schemas';\nimport { Resources_SharedUtils } from '../resources.shared.utils';\nimport { getParentDirectionRelationships } from '../resources-config.shared.schemas';\nimport type { ErasureRetentionMode } from '../../compliance/privacy/impersonalization.shared.schemas';\n\n/**\n * Registry-level guardrail for the effective `onParentDelete` lifecycle — the\n * DELETE-side counterpart to `validateCompositionSeedability`.\n *\n * A relationship that OPTS IN to the delete cascade\n * (`childOperations.lifecycle.onParentDelete.enabled = true`) must actually be\n * cascade-deletable, or the runtime cascade throws `ErrorType.CONFIGURATION`\n * INSIDE the parent's delete transaction and ROLLS BACK the parent delete. Two\n * things must hold on the child, checked here with the exact predicate the\n * runtime uses (`supportsOperation`: the op has a default variant):\n *\n * 1. **Discovery** — `deleteChildrenImmediate` loads the children before\n * deleting them: a 1:1 child via READ, a 1:many child via LIST. Missing that\n * op → `CONFIGURATION` throw.\n * 2. **Teardown** — it then removes them via DELETE_MANY (preferred) or a\n * per-row DELETE loop. Missing BOTH → `CONFIGURATION` throw. (DELETE strategy.)\n *\n * ## Two teardown strategies (`onParentDelete.strategy`)\n *\n * DELETE (default) hard-deletes the child, so it needs the DELETE/DELETE_MANY\n * teardown op above. IMPERSONALIZE_AND_RETAIN instead scrubs the child's personal\n * fields IN PLACE and KEEPS the row (retain-for-audit, GDPR Art. 17(3)(b)), via the\n * trusted `updateManyAsSystem` writer — so it needs NO delete op. It instead needs\n * the child to be retention-governed (`retentionPolicy`,\n * which the resource factory guarantees also carries the UPDATE_MANY scrub grant +\n * the `retentionStatus` marker). Discovery (point 1) is shared by both strategies.\n *\n * REFUSE_WHILE_CHILDREN_EXIST tears nothing down and lists nothing. The parent's delete probes for one\n * remaining child with a repository READ on the edge's foreign key, whatever the cardinality, so READ\n * is its whole requirement. Without it every delete of the parent would be refused with CONFIGURATION.\n *\n * ## Why this is separate from (and dual to) seedability\n *\n * `onParentCreate` (seed) and `onParentDelete` (cascade) are orthogonal DDD axes\n * (created-with vs dies-with). The seed resolves the child's CREATE through the\n * SERVICE tier (rejects REPOSITORY_ONLY); the cascade deletes through the\n * REPOSITORY tier (variant-agnostic). So the two guards check different ops on\n * different resolution paths and neither implies the other — a child can be\n * seedable but not cascade-deletable (exactly the gap that shipped for the\n * lifecycle / guidance / progression / preferences / notifications adopters).\n *\n * ## Unreachable edges are NOT violations (parent-reachability skip)\n *\n * The cascade runs ONLY from the PARENT's DELETE / DELETE_MANY post-op logic. If\n * the parent can reach neither, the edge is structurally unreachable — dormant,\n * never fired — and is intentionally skipped (e.g. `USER_SELF` exposes only\n * READ/UPDATE, so `USER_SELF → USER_SELF_PREFERENCES/PROFILES` never cascades;\n * real user deletion runs through `USERS`, whose profile/preferences children DO\n * carry DELETE). This skip is self-correcting: the day the parent gains a delete\n * path, its dormant edges become reachable and this guard fires.\n *\n * \"Can reach\" means {@link canFireDeleteCascade}, not `supportsOperation` — a\n * CUSTOM operation borrowing the verb through `resourceOperationLike` fires the\n * cascade exactly as a core DELETE does. Reading only the core verb made this\n * skip unsound; `user_self | delete_account` (removed 2026-08-01) was the live\n * case, and its two edges reported clean here while throwing at runtime.\n *\n * ## Fail-closed, fail-open on ambiguity\n *\n * A retention violation is a boot-time throw; hard-delete prerequisite findings\n * are reported separately by the startup caller. When the edge cannot be classified (parent absent from the\n * map) the check skips (fail-open) so it never false-positives or blocks\n * startup. Pure and side-effect free.\n */\n\n/** Structural subset of a built resource configuration this validator needs. */\nexport interface CompositionCascadeDeletabilityResourceInput {\n resourceIdentifier: ResourceType;\n /**\n * Flattened per-variant operations. Parent reachability includes every callable\n * variant; child discovery/teardown follows runtime `supportsOperation`\n * (`op.operationIdentifier === verb && op.isOperationDefault`).\n *\n * `resourceOperationLike` is carried because a CUSTOM operation borrowing a core verb reaches the\n * same repository primitive as the core operation, and so fires the same cascade — see\n * {@link canFireDeleteCascade}. A child's teardown capability is still read through\n * {@link supportsOperation} (the runtime `supportsOperation` the cascade itself calls), so the\n * extra field matters only on the PARENT side.\n */\n operations: ReadonlyArray<{\n operationIdentifier: string;\n isOperationDefault?: boolean;\n resourceOperationLike?: CoreResourceOperation;\n }>;\n /**\n * Resolved retention policy, present (and normalized to opted-in) IFF this resource is\n * retention-governed (`retentionPolicy`). Only such resources carry the\n * factory-injected `retentionStatus` marker AND the derived UPDATE_MANY scrub grant, so only they\n * can be the CHILD of an `IMPERSONALIZE_AND_RETAIN` onParentDelete edge. Absent = not\n * retention-governed → an `IMPERSONALIZE_AND_RETAIN` edge toward it is a violation.\n */\n retentionPolicy?: { mode?: ErasureRetentionMode };\n resourceRelationships?: {\n parentRelationships?: ResourceRelationship[];\n selfRelationships?: ResourceRelationship[];\n };\n}\n\nexport interface CompositionCascadeDeletabilityViolation {\n childResourceType: ResourceType;\n parentResourceType: ResourceType;\n cardinality: 'one-to-one' | 'one-to-many';\n /** The strategy the edge declared: DELETE (hard-delete), IMPERSONALIZE_AND_RETAIN (scrub+keep) or REFUSE_WHILE_CHILDREN_EXIST. */\n strategy: ChildLifecycleStrategy;\n /**\n * The op the edge needs but the child lacks, if any: the cascade's discovery op (READ for 1:1, LIST for\n * 1:many, shared by DELETE and IMPERSONALIZE_AND_RETAIN), or READ, the existence probe, for REFUSE_WHILE_CHILDREN_EXIST.\n */\n missingDiscoveryOp?: CoreResourceOperation;\n /** DELETE strategy only: true when the child supports neither DELETE nor DELETE_MANY. */\n missingTeardownOp: boolean;\n /**\n * IMPERSONALIZE_AND_RETAIN strategy only: true when the child is NOT retention-governed\n * (no `retentionPolicy` → no `retentionStatus` marker + no derived\n * UPDATE_MANY scrub grant to flip it with).\n */\n missingRetentionGovernance?: boolean;\n /**\n * IMPERSONALIZE_AND_RETAIN strategy only: true when the edge declares `mode: LAZY`, which v1 cannot\n * execute (there is no async retain-and-scrub) and which would otherwise throw on the first erasure.\n */\n unsupportedLazyRetainMode?: boolean;\n message: string;\n}\n\n/** Runtime-truthful `supportsOperation`: a default variant for the verb exists. */\nfunction supportsOperation(\n resource: CompositionCascadeDeletabilityResourceInput | undefined,\n verb: CoreResourceOperation,\n): boolean {\n return (\n resource?.operations?.some(\n (op) => op.operationIdentifier === verb && op.isOperationDefault === true,\n ) ?? false\n );\n}\n\n/**\n * Whether this resource can reach the DELETE post-op logic that fires an `onParentDelete` cascade.\n *\n * NOT the same question as `supportsOperation(resource, DELETE)`. A CUSTOM operation declaring\n * `resourceOperationLike: DELETE` carries its own `operationIdentifier`, so `supportsOperation`\n * says no — yet it reaches `_doDelete` all the same: the service resolves the core verb through\n * `getCoreResourceOperationFromOperation` (which falls back to `resourceOperationLike`) and calls\n * the repository by OPERATION PATH, and the repository's operations map is built from EVERY\n * configured operation, custom ones included. The `coreOperations` gate on the public\n * `RepositoryResourceBackendService.delete()` convenience method is simply not on that path.\n *\n * Reading only the core verb made the parent-reachability skip below unsound, and it cost real\n * damage: `user_self | delete_account` (removed 2026-08-01) declared no core DELETE, so this guard\n * cleared its two `onParentDelete` edges as dormant — while at runtime the custom op fired the\n * cascade into `USER_SELF_PROFILES` / `USER_SELF_PREFERENCES`, neither of which declares a\n * teardown op. The cascade threw `ErrorType.CONFIGURATION` inside the delete transaction, so the\n * delete rolled back for any user who had one of those rows and committed for any user who had\n * neither. A boot guard that cannot see custom delete-like ops cannot protect that edge.\n *\n * `DELETE_MANY` is included for the same reason: `deleteMany` is the cascade's preferred teardown\n * path and a custom op may borrow it just as readily.\n */\nexport function canFireDeleteCascade(\n resource: CompositionCascadeDeletabilityResourceInput | undefined,\n): boolean {\n if (!resource?.operations) return false;\n return resource.operations.some((op) => {\n // A selected operation path can invoke any variant. Only child discovery/teardown\n // convenience calls require defaults; parent reachability must include keyed variants.\n // A core operation carries the verb as its own identifier; a custom one borrows it.\n const effectiveVerb = op.operationIdentifier === CoreResourceOperation.DELETE\n || op.operationIdentifier === CoreResourceOperation.DELETE_MANY\n ? (op.operationIdentifier as CoreResourceOperation)\n : op.resourceOperationLike;\n return effectiveVerb === CoreResourceOperation.DELETE\n || effectiveVerb === CoreResourceOperation.DELETE_MANY;\n });\n}\n\n/**\n * Validate that every effective relationship lifecycle which opted into\n * `onParentDelete.enabled` is actually cascade-deletable (its child has the\n * cardinality-appropriate discovery op + a DELETE/DELETE_MANY teardown op),\n * unless the edge is structurally unreachable because the parent cannot fire the\n * cascade. Returns the list of violations (empty when clean); startup rejects\n * retention violations and reports hard-delete prerequisites separately.\n *\n * @param resourceConfigurations - the registry's `resourceConfigurations` map\n * (`resourceType → built configuration`). Each entry is the CHILD in its\n * `parentRelationships` and `selfRelationships`; parents are looked up in the same map for the\n * reachability skip.\n */\nexport function validateCompositionCascadeDeletability(\n resourceConfigurations: Record<string, CompositionCascadeDeletabilityResourceInput>,\n): CompositionCascadeDeletabilityViolation[] {\n const violations: CompositionCascadeDeletabilityViolation[] = [];\n\n for (const child of Object.values(resourceConfigurations)) {\n const parentRelationships = getParentDirectionRelationships({\n parentRelationships: child.resourceRelationships?.parentRelationships ?? [],\n selfRelationships: child.resourceRelationships?.selfRelationships ?? [],\n childRelationships: [],\n });\n\n for (const relationship of parentRelationships) {\n // Use the same compiled lifecycle policy as execution. Authored nature alone\n // misses association-to-junction cascades; INDEPENDENT relationships are dormant.\n const onParentDelete = Resources_SharedUtils.resolveRelationshipLifecycleOnParentDeleteConfig(relationship);\n if (onParentDelete?.enabled !== true) {\n continue;\n }\n\n // Parent-reachability skip: the cascade fires from the parent's DELETE / DELETE_MANY post-op\n // logic. A parent that can reach neither can never trigger this edge → dormant, not a\n // violation. Self-correcting: the day the parent gains a delete path, this stops skipping and\n // the guard fires.\n //\n // Reachability is `canFireDeleteCascade`, NOT `supportsOperation` — a CUSTOM op borrowing the\n // verb via `resourceOperationLike` fires the cascade too, and reading only the core verb is\n // what let `user_self | delete_account` cascade into two teardown-less children while this\n // guard reported clean. See the function's JSDoc.\n const parent = resourceConfigurations[relationship.resourceType1];\n if (!parent) {\n continue; // fail-open: parent not in this map, cannot classify\n }\n if (!canFireDeleteCascade(parent)) {\n continue; // structurally unreachable edge — no core AND no delete-like custom op\n }\n\n // RESTRICT posture: no discovery list and no teardown. The refusal probes existence with ONE\n // repository READ on the edge's foreign key, whatever the cardinality, so READ is the whole requirement.\n if (onParentDelete.strategy === ChildLifecycleStrategy.REFUSE_WHILE_CHILDREN_EXIST) {\n if (supportsOperation(child, CoreResourceOperation.READ)) {\n continue;\n }\n violations.push({\n childResourceType: child.resourceIdentifier,\n parentResourceType: relationship.resourceType1,\n cardinality: isOneToOneCardinality(relationship.cardinality2) ? 'one-to-one' : 'one-to-many',\n strategy: ChildLifecycleStrategy.REFUSE_WHILE_CHILDREN_EXIST,\n missingDiscoveryOp: CoreResourceOperation.READ,\n missingTeardownOp: false,\n message:\n `Lifecycle child '${child.resourceIdentifier}' (parent '${relationship.resourceType1}') ` +\n `declares onParentDelete strategy REFUSE_WHILE_CHILDREN_EXIST but does not support READ. The ` +\n `parent's delete probes for a remaining child with a repository READ before it writes anything, ` +\n `so every delete of the parent would be refused with CONFIGURATION. Add a READ operation to the ` +\n `child (a REPOSITORY_ONLY variant is enough), or declare another strategy.`,\n });\n continue;\n }\n\n // Discovery op depends on cardinality: 1:1 discovered via READ, 1:many via LIST. SHARED by both\n // teardown strategies — impersonalizeChildrenImmediate reads the same way before scrubbing.\n const oneToOne = isOneToOneCardinality(relationship.cardinality2);\n const discoveryOp = oneToOne ? CoreResourceOperation.READ : CoreResourceOperation.LIST;\n const hasDiscovery = supportsOperation(child, discoveryOp);\n\n // The teardown STRATEGY decides what the child needs beyond discovery: DELETE (default) needs a\n // DELETE/DELETE_MANY op; IMPERSONALIZE_AND_RETAIN needs the child to be retention-governed.\n const strategy = resolveChildLifecycleTeardownStrategy(onParentDelete)!;\n\n if (strategy === ChildLifecycleStrategy.IMPERSONALIZE_AND_RETAIN) {\n // Retain-and-scrub teardown (via updateManyAsSystem), NOT a hard delete. The child must be\n // retention-governed: only `retentionPolicy` injects the retentionStatus\n // marker AND derives the UPDATE_MANY scrub grant. A non-retention child has nothing to flip →\n // impersonalizeChildrenImmediate throws CONFIGURATION and rolls back the parent delete.\n const isRetentionGoverned = child.retentionPolicy?.mode !== undefined;\n // v1 executes retain-and-scrub only in IMMEDIATE mode. Without this guard, a LAZY retain\n // edge could pass startup and throw on the first erasure — inside the parent transaction, so a\n // GDPR deletion request fails. Catch the unsupported combination here instead.\n const isUnsupportedLazyMode = onParentDelete.mode === ChildLifecycleMode.LAZY;\n if (hasDiscovery && isRetentionGoverned && !isUnsupportedLazyMode) {\n continue; // impersonalize-able\n }\n\n const missing: string[] = [];\n if (!hasDiscovery) {\n missing.push(`${discoveryOp} (to discover ${oneToOne ? '1:1' : '1:many'} dependents)`);\n }\n if (!isRetentionGoverned) {\n missing.push('retentionPolicy (either mode — to carry the retentionStatus marker + the UPDATE_MANY retain grant)');\n }\n if (isUnsupportedLazyMode) {\n missing.push('mode: IMMEDIATE (v1 has no async retain-and-scrub; LAZY would throw on the first erasure)');\n }\n\n violations.push({\n childResourceType: child.resourceIdentifier,\n parentResourceType: relationship.resourceType1,\n cardinality: oneToOne ? 'one-to-one' : 'one-to-many',\n strategy,\n missingDiscoveryOp: hasDiscovery ? undefined : discoveryOp,\n missingTeardownOp: false, // teardown is a scrub, not a delete op\n missingRetentionGovernance: !isRetentionGoverned,\n unsupportedLazyRetainMode: isUnsupportedLazyMode,\n message:\n `Lifecycle child '${child.resourceIdentifier}' (parent '${relationship.resourceType1}') ` +\n `enabled onParentDelete with strategy IMPERSONALIZE_AND_RETAIN but is NOT impersonalize-able: ` +\n `missing ${missing.join(' and ')}. The retain-and-scrub cascade (impersonalizeChildrenImmediate) ` +\n `would fail during parent deletion once a child row exists. ` +\n `Opt the child into retentionPolicy (RETAIN_ONLY or RETAIN_AND_IMPERSONALIZE), or use strategy DELETE.`,\n });\n continue;\n }\n\n // DELETE strategy (default): teardown op is DELETE_MANY (preferred by the cascade) or a per-row DELETE.\n const hasTeardown =\n supportsOperation(child, CoreResourceOperation.DELETE_MANY) ||\n supportsOperation(child, CoreResourceOperation.DELETE);\n\n if (hasDiscovery && hasTeardown) {\n continue; // cascade-deletable\n }\n\n const missing: string[] = [];\n if (!hasDiscovery) {\n missing.push(`${discoveryOp} (to discover ${oneToOne ? '1:1' : '1:many'} dependents)`);\n }\n if (!hasTeardown) {\n missing.push('DELETE or DELETE_MANY (to remove the row)');\n }\n\n violations.push({\n childResourceType: child.resourceIdentifier,\n parentResourceType: relationship.resourceType1,\n cardinality: oneToOne ? 'one-to-one' : 'one-to-many',\n strategy,\n missingDiscoveryOp: hasDiscovery ? undefined : discoveryOp,\n missingTeardownOp: !hasTeardown,\n message:\n `Lifecycle child '${child.resourceIdentifier}' (parent '${relationship.resourceType1}') ` +\n `enabled onParentDelete but is NOT cascade-deletable: missing ${missing.join(' and ')}. ` +\n `The delete cascade (deleteChildrenImmediate) would throw ErrorType.CONFIGURATION and roll ` +\n `back the parent delete once a child row exists. Add the missing op(s) (a REPOSITORY_ONLY ` +\n `DELETE is enough for teardown), or drop onParentDelete.enabled.`,\n });\n }\n }\n\n return violations;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"composition-cascade-deletability.validation.js","sourceRoot":"","sources":["../../../../src/resources/utils/composition-cascade-deletability.validation.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ResourceRelationship,\n isOneToOneCardinality,\n} from '../resources.shared.schemas';\nimport { ResourceType, CoreResourceOperation } from '../resources.shared.core.definitions';\nimport { ChildLifecycleMode, ChildLifecycleStrategy, resolveChildLifecycleTeardownStrategy } from '../child-operations.shared.schemas';\nimport { Resources_SharedUtils } from '../resources.shared.utils';\nimport { getParentDirectionRelationships } from '../resources-config.shared.schemas';\nimport type { ErasureRetentionMode } from '../../compliance/privacy/impersonalization.shared.schemas';\n\n/**\n * Registry-level guardrail for the effective `onParentDelete` lifecycle — the\n * DELETE-side counterpart to `validateCompositionSeedability`.\n *\n * A relationship that OPTS IN to the delete cascade\n * (`childOperations.lifecycle.onParentDelete.enabled = true`) must actually be\n * cascade-deletable, or the runtime cascade throws `ErrorType.CONFIGURATION`\n * INSIDE the parent's delete transaction and ROLLS BACK the parent delete. Two\n * things must hold on the child, checked here with the exact predicate the\n * runtime uses (`supportsOperation`: the op has a default variant):\n *\n * 1. **Discovery** — `deleteChildrenImmediate` loads the children before\n * deleting them: a 1:1 child via READ, a 1:many child via LIST. Missing that\n * op → `CONFIGURATION` throw.\n * 2. **Teardown** — it then removes them via DELETE_MANY (preferred) or a\n * per-row DELETE loop. Missing BOTH → `CONFIGURATION` throw. (DELETE strategy.)\n *\n * ## Two teardown strategies (`onParentDelete.strategy`)\n *\n * DELETE (default) hard-deletes the child, so it needs the DELETE/DELETE_MANY\n * teardown op above. IMPERSONALIZE_AND_RETAIN instead scrubs the child's personal\n * fields IN PLACE and KEEPS the row (retain-for-audit, GDPR Art. 17(3)(b)), via the\n * trusted `updateManyAsSystem` writer — so it needs NO delete op. It instead needs\n * the child to be retention-governed (`retentionPolicy`,\n * which the resource factory guarantees also carries the UPDATE_MANY scrub grant +\n * the `retentionStatus` marker). Discovery (point 1) is shared by both strategies.\n *\n * REFUSE_WHILE_CHILDREN_EXIST tears nothing down and lists nothing. The parent's delete probes for one\n * remaining child with a repository READ on the edge's foreign key, whatever the cardinality, so READ\n * is its whole requirement. Without it every delete of the parent would be refused with CONFIGURATION.\n *\n * ## Why this is separate from (and dual to) seedability\n *\n * `onParentCreate` (seed) and `onParentDelete` (cascade) are orthogonal DDD axes\n * (created-with vs dies-with). The seed resolves the child's CREATE through the\n * SERVICE tier (rejects REPOSITORY_ONLY); the cascade deletes through the\n * REPOSITORY tier (variant-agnostic). So the two guards check different ops on\n * different resolution paths and neither implies the other — a child can be\n * seedable but not cascade-deletable (exactly the gap that shipped for the\n * lifecycle / guidance / progression / preferences / notifications adopters).\n *\n * ## Unreachable edges are NOT violations (parent-reachability skip)\n *\n * The cascade runs ONLY from the PARENT's DELETE / DELETE_MANY post-op logic. If\n * the parent can reach neither, the edge is structurally unreachable — dormant,\n * never fired — and is intentionally skipped (e.g. `USER_SELF` exposes only\n * READ/UPDATE, so `USER_SELF → USER_SELF_PREFERENCES/PROFILES` never cascades;\n * real user deletion runs through `USERS`, whose profile/preferences children DO\n * carry DELETE). This skip is self-correcting: the day the parent gains a delete\n * path, its dormant edges become reachable and this guard fires.\n *\n * \"Can reach\" means {@link canFireDeleteCascade}, not `supportsOperation` — a\n * CUSTOM operation borrowing the verb through `resourceOperationLike` fires the\n * cascade exactly as a core DELETE does. Reading only the core verb made this\n * skip unsound; `user_self | delete_account` (removed 2026-08-01) was the live\n * case, and its two edges reported clean here while throwing at runtime.\n *\n * ## Fail-closed, fail-open on ambiguity\n *\n * A retention violation is a boot-time throw; hard-delete prerequisite findings\n * are reported separately by the startup caller. When the edge cannot be classified (parent absent from the\n * map) the check skips (fail-open) so it never false-positives or blocks\n * startup. Pure and side-effect free.\n */\n\n/** Structural subset of a built resource configuration this validator needs. */\nexport interface CompositionCascadeDeletabilityResourceInput {\n resourceIdentifier: ResourceType;\n /**\n * Flattened per-variant operations. Parent reachability includes every callable\n * variant; child discovery/teardown follows runtime `supportsOperation`\n * (`op.operationIdentifier === verb && op.isOperationDefault`).\n *\n * `resourceOperationLike` is carried because a CUSTOM operation borrowing a core verb reaches the\n * same repository primitive as the core operation, and so fires the same cascade — see\n * {@link canFireDeleteCascade}. A child's teardown capability is still read through\n * {@link supportsOperation} (the runtime `supportsOperation` the cascade itself calls), so the\n * extra field matters only on the PARENT side.\n */\n operations: ReadonlyArray<{\n operationIdentifier: string;\n isOperationDefault?: boolean;\n resourceOperationLike?: CoreResourceOperation;\n }>;\n /**\n * Resolved retention policy, present (and normalized to opted-in) IFF this resource is\n * retention-governed (`retentionPolicy`). Only such resources carry the\n * factory-injected `retentionStatus` marker AND the derived UPDATE_MANY scrub grant, so only they\n * can be the CHILD of an `IMPERSONALIZE_AND_RETAIN` onParentDelete edge. Absent = not\n * retention-governed → an `IMPERSONALIZE_AND_RETAIN` edge toward it is a violation.\n */\n retentionPolicy?: { mode?: ErasureRetentionMode };\n resourceRelationships?: {\n parentRelationships?: ResourceRelationship[];\n selfRelationships?: ResourceRelationship[];\n };\n}\n\nexport interface CompositionCascadeDeletabilityViolation {\n childResourceType: ResourceType;\n parentResourceType: ResourceType;\n cardinality: 'one-to-one' | 'one-to-many';\n /** The strategy the edge declared: DELETE (hard-delete), IMPERSONALIZE_AND_RETAIN (scrub+keep) or REFUSE_WHILE_CHILDREN_EXIST. */\n strategy: ChildLifecycleStrategy;\n /**\n * The op the edge needs but the child lacks, if any: the cascade's discovery op (READ for 1:1, LIST for\n * 1:many, shared by DELETE and IMPERSONALIZE_AND_RETAIN), or READ, the existence probe, for REFUSE_WHILE_CHILDREN_EXIST.\n */\n missingDiscoveryOp?: CoreResourceOperation;\n /** DELETE strategy only: true when the child supports neither DELETE nor DELETE_MANY. */\n missingTeardownOp: boolean;\n /**\n * IMPERSONALIZE_AND_RETAIN strategy only: true when the child is NOT retention-governed\n * (no `retentionPolicy` → no `retentionStatus` marker + no derived\n * UPDATE_MANY scrub grant to flip it with).\n */\n missingRetentionGovernance?: boolean;\n /**\n * IMPERSONALIZE_AND_RETAIN strategy only: true when the edge declares `mode: LAZY`, which v1 cannot\n * execute (there is no async retain-and-scrub) and which would otherwise throw on the first erasure.\n */\n unsupportedLazyRetainMode?: boolean;\n message: string;\n}\n\n/** Runtime-truthful `supportsOperation`: a default variant for the verb exists. */\nfunction supportsOperation(\n resource: CompositionCascadeDeletabilityResourceInput | undefined,\n verb: CoreResourceOperation,\n): boolean {\n return (\n resource?.operations?.some(\n (op) => op.operationIdentifier === verb && op.isOperationDefault === true,\n ) ?? false\n );\n}\n\n/**\n * Whether this resource can reach the DELETE post-op logic that fires an `onParentDelete` cascade.\n *\n * NOT the same question as `supportsOperation(resource, DELETE)`. A CUSTOM operation declaring\n * `resourceOperationLike: DELETE` carries its own `operationIdentifier`, so `supportsOperation`\n * says no — yet it reaches `_doDelete` all the same: the service resolves the core verb through\n * `getCoreResourceOperationFromOperation` (which falls back to `resourceOperationLike`) and calls\n * the repository by OPERATION PATH, and the repository's operations map is built from EVERY\n * configured operation, custom ones included. The `coreOperations` gate on the public\n * `RepositoryResourceBackendService.delete()` convenience method is simply not on that path.\n *\n * Reading only the core verb made the parent-reachability skip below unsound, and it cost real\n * damage: `user_self | delete_account` (removed 2026-08-01) declared no core DELETE, so this guard\n * cleared its two `onParentDelete` edges as dormant — while at runtime the custom op fired the\n * cascade into `USER_SELF_PROFILES` / `USER_SELF_PREFERENCES`, neither of which declares a\n * teardown op. The cascade threw `ErrorType.CONFIGURATION` inside the delete transaction, so the\n * delete rolled back for any user who had one of those rows and committed for any user who had\n * neither. A boot guard that cannot see custom delete-like ops cannot protect that edge.\n *\n * `DELETE_MANY` is included for the same reason: `deleteMany` is the cascade's preferred teardown\n * path and a custom op may borrow it just as readily.\n */\nexport function canFireDeleteCascade(\n resource: CompositionCascadeDeletabilityResourceInput | undefined,\n): boolean {\n if (!resource?.operations) return false;\n return resource.operations.some((op) => {\n // A selected operation path can invoke any variant. Only child discovery/teardown\n // convenience calls require defaults; parent reachability must include keyed variants.\n // A core operation carries the verb as its own identifier; a custom one borrows it.\n const effectiveVerb = op.operationIdentifier === CoreResourceOperation.DELETE\n || op.operationIdentifier === CoreResourceOperation.DELETE_MANY\n ? (op.operationIdentifier as CoreResourceOperation)\n : op.resourceOperationLike;\n return effectiveVerb === CoreResourceOperation.DELETE\n || effectiveVerb === CoreResourceOperation.DELETE_MANY;\n });\n}\n\n/**\n * Validate that every effective relationship lifecycle which opted into\n * `onParentDelete.enabled` is actually cascade-deletable (its child has the\n * cardinality-appropriate discovery op + a DELETE/DELETE_MANY teardown op),\n * unless the edge is structurally unreachable because the parent cannot fire the\n * cascade. Returns the list of violations (empty when clean); startup rejects\n * retention violations and reports hard-delete prerequisites separately.\n *\n * @param resourceConfigurations - the registry's `resourceConfigurations` map\n * (`resourceType → built configuration`). Each entry is the CHILD in its\n * `parentRelationships` and `selfRelationships`; parents are looked up in the same map for the\n * reachability skip.\n */\nexport function validateCompositionCascadeDeletability(\n resourceConfigurations: Record<string, CompositionCascadeDeletabilityResourceInput>,\n): CompositionCascadeDeletabilityViolation[] {\n const violations: CompositionCascadeDeletabilityViolation[] = [];\n\n for (const child of Object.values(resourceConfigurations)) {\n const parentRelationships = getParentDirectionRelationships({\n parentRelationships: child.resourceRelationships?.parentRelationships ?? [],\n selfRelationships: child.resourceRelationships?.selfRelationships ?? [],\n childRelationships: [],\n });\n\n for (const relationship of parentRelationships) {\n // Use the same compiled lifecycle policy as execution. Authored nature alone\n // misses association-to-junction cascades; INDEPENDENT relationships are dormant.\n const onParentDelete = Resources_SharedUtils.resolveRelationshipLifecycleOnParentDeleteConfig(relationship);\n if (onParentDelete?.enabled !== true) {\n continue;\n }\n\n // Parent-reachability skip: the cascade fires from the parent's DELETE / DELETE_MANY post-op\n // logic. A parent that can reach neither can never trigger this edge → dormant, not a\n // violation. Self-correcting: the day the parent gains a delete path, this stops skipping and\n // the guard fires.\n //\n // Reachability is `canFireDeleteCascade`, NOT `supportsOperation` — a CUSTOM op borrowing the\n // verb via `resourceOperationLike` fires the cascade too, and reading only the core verb is\n // what let `user_self | delete_account` cascade into two teardown-less children while this\n // guard reported clean. See the function's JSDoc.\n const parent = resourceConfigurations[relationship.resourceType1];\n if (!parent) {\n continue; // fail-open: parent not in this map, cannot classify\n }\n if (!canFireDeleteCascade(parent)) {\n continue; // structurally unreachable edge — no core AND no delete-like custom op\n }\n\n // RESTRICT posture: no discovery list and no teardown. The refusal probes existence with ONE\n // repository READ on the edge's foreign key, whatever the cardinality, so READ is the whole requirement.\n if (onParentDelete.strategy === ChildLifecycleStrategy.REFUSE_WHILE_CHILDREN_EXIST) {\n if (supportsOperation(child, CoreResourceOperation.READ)) {\n continue;\n }\n violations.push({\n childResourceType: child.resourceIdentifier,\n parentResourceType: relationship.resourceType1,\n cardinality: isOneToOneCardinality(relationship.cardinality2) ? 'one-to-one' : 'one-to-many',\n strategy: ChildLifecycleStrategy.REFUSE_WHILE_CHILDREN_EXIST,\n missingDiscoveryOp: CoreResourceOperation.READ,\n missingTeardownOp: false,\n message:\n `Lifecycle child '${child.resourceIdentifier}' (parent '${relationship.resourceType1}') ` +\n `declares onParentDelete strategy REFUSE_WHILE_CHILDREN_EXIST but does not support READ. The ` +\n `parent's delete probes for a remaining child with a repository READ before it writes anything, ` +\n `so every delete of the parent would be refused with CONFIGURATION. Add a READ operation to the ` +\n `child (a REPOSITORY_ONLY variant is enough), or declare another strategy.`,\n });\n continue;\n }\n\n // Discovery op depends on cardinality: 1:1 discovered via READ, 1:many via LIST. SHARED by both\n // teardown strategies — impersonalizeChildrenImmediate reads the same way before scrubbing.\n const oneToOne = isOneToOneCardinality(relationship.cardinality2);\n const discoveryOp = oneToOne ? CoreResourceOperation.READ : CoreResourceOperation.LIST;\n const hasDiscovery = supportsOperation(child, discoveryOp);\n\n // The teardown STRATEGY decides what the child needs beyond discovery: DELETE (default) needs a\n // DELETE/DELETE_MANY op; IMPERSONALIZE_AND_RETAIN needs the child to be retention-governed.\n const strategy = resolveChildLifecycleTeardownStrategy(onParentDelete)!;\n\n if (strategy === ChildLifecycleStrategy.IMPERSONALIZE_AND_RETAIN) {\n // Retain-and-scrub teardown (via updateManyAsSystem), NOT a hard delete. The child must be\n // retention-governed: only `retentionPolicy` injects the retentionStatus\n // marker AND derives the UPDATE_MANY scrub grant. A non-retention child has nothing to flip →\n // impersonalizeChildrenImmediate throws CONFIGURATION and rolls back the parent delete.\n const isRetentionGoverned = child.retentionPolicy?.mode !== undefined;\n // v1 executes retain-and-scrub only in IMMEDIATE mode. Without this guard, a LAZY retain\n // edge could pass startup and throw on the first erasure — inside the parent transaction, so a\n // GDPR deletion request fails. Catch the unsupported combination here instead.\n const isUnsupportedLazyMode = onParentDelete.mode === ChildLifecycleMode.LAZY;\n if (hasDiscovery && isRetentionGoverned && !isUnsupportedLazyMode) {\n continue; // impersonalize-able\n }\n\n const missing: string[] = [];\n if (!hasDiscovery) {\n missing.push(`${discoveryOp} (to discover ${oneToOne ? '1:1' : '1:many'} dependents)`);\n }\n if (!isRetentionGoverned) {\n missing.push('retentionPolicy (either mode — to carry the retentionStatus marker + the UPDATE_MANY retain grant)');\n }\n if (isUnsupportedLazyMode) {\n missing.push('mode: IMMEDIATE (v1 has no async retain-and-scrub; LAZY would throw on the first erasure)');\n }\n\n violations.push({\n childResourceType: child.resourceIdentifier,\n parentResourceType: relationship.resourceType1,\n cardinality: oneToOne ? 'one-to-one' : 'one-to-many',\n strategy,\n missingDiscoveryOp: hasDiscovery ? undefined : discoveryOp,\n missingTeardownOp: false, // teardown is a scrub, not a delete op\n missingRetentionGovernance: !isRetentionGoverned,\n unsupportedLazyRetainMode: isUnsupportedLazyMode,\n message:\n `Lifecycle child '${child.resourceIdentifier}' (parent '${relationship.resourceType1}') ` +\n `enabled onParentDelete with strategy IMPERSONALIZE_AND_RETAIN but is NOT impersonalize-able: ` +\n `missing ${missing.join(' and ')}. The retain-and-scrub cascade (impersonalizeChildrenImmediate) ` +\n `would fail during parent deletion once a child row exists. ` +\n `Opt the child into retentionPolicy (RETAIN_ONLY or RETAIN_AND_IMPERSONALIZE), or use strategy DELETE.`,\n });\n continue;\n }\n\n // DELETE strategy (default): teardown op is DELETE_MANY (preferred by the cascade) or a per-row DELETE.\n const hasTeardown =\n supportsOperation(child, CoreResourceOperation.DELETE_MANY) ||\n supportsOperation(child, CoreResourceOperation.DELETE);\n\n if (hasDiscovery && hasTeardown) {\n continue; // cascade-deletable\n }\n\n const missing: string[] = [];\n if (!hasDiscovery) {\n missing.push(`${discoveryOp} (to discover ${oneToOne ? '1:1' : '1:many'} dependents)`);\n }\n if (!hasTeardown) {\n missing.push('DELETE or DELETE_MANY (to remove the row)');\n }\n\n violations.push({\n childResourceType: child.resourceIdentifier,\n parentResourceType: relationship.resourceType1,\n cardinality: oneToOne ? 'one-to-one' : 'one-to-many',\n strategy,\n missingDiscoveryOp: hasDiscovery ? undefined : discoveryOp,\n missingTeardownOp: !hasTeardown,\n message:\n `Lifecycle child '${child.resourceIdentifier}' (parent '${relationship.resourceType1}') ` +\n `enabled onParentDelete but is NOT cascade-deletable: missing ${missing.join(' and ')}. ` +\n `The delete cascade (deleteChildrenImmediate) would throw ErrorType.CONFIGURATION and roll ` +\n `back the parent delete once a child row exists. Add the missing op(s) (a REPOSITORY_ONLY ` +\n `DELETE is enough for teardown), or drop onParentDelete.enabled.`,\n });\n }\n }\n\n return violations;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composition-seedability.validation.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"composition-seedability.validation.d.ts","sourceRoot":"","sources":["../../../../src/resources/utils/composition-seedability.validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,oBAAoB,EAErB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAGpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,0EAA0E;AAC1E,MAAM,WAAW,mCAAmC;IAClD,kBAAkB,EAAE,YAAY,CAAC;IACjC,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC;IACzB,qBAAqB,EAAE;QACrB,mBAAmB,EAAE,oBAAoB,EAAE,CAAC;KAC7C,CAAC;CACH;AAED,MAAM,WAAW,+BAA+B;IAC9C,iBAAiB,EAAE,YAAY,CAAC;IAChC,kBAAkB,EAAE,YAAY,CAAC;IACjC,eAAe,EAAE,MAAM,CAAC;IACxB,gFAAgF;IAChF,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAC5C,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,mCAAmC,CAAC,GAC1E,+BAA+B,EAAE,CAoEnC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composition-seedability.validation.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"composition-seedability.validation.js","sourceRoot":"","sources":["../../../../src/resources/utils/composition-seedability.validation.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,kBAAkB,GACnB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAqD3E,8EAA8E;AAC9E,2BAA2B;AAC3B,MAAM,0BAA0B,GAAG,0BAA0B,CAAC;AAE9D;;;;;;;;;GASG;AACH,MAAM,UAAU,8BAA8B,CAC5C,sBAA2E;IAE3E,MAAM,UAAU,GAAsC,EAAE,CAAC;IAEzD,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,EAAE,CAAC;QAC7D,MAAM,mBAAmB,GAAG,QAAQ,CAAC,qBAAqB,EAAE,mBAAmB,IAAI,EAAE,CAAC;QAEtF,KAAK,MAAM,YAAY,IAAI,mBAAmB,EAAE,CAAC;YAC/C,IAAI,YAAY,CAAC,MAAM,KAAK,kBAAkB,CAAC,WAAW,EAAE,CAAC;gBAC3D,SAAS;YACX,CAAC;YAED,6EAA6E;YAC7E,4EAA4E;YAC5E,kEAAkE;YAClE,MAAM,cAAc,GAAG,YAAY,CAAC,eAAe,EAAE,SAAS,EAAE,cAAc,CAAC;YAC/E,IAAI,cAAc,EAAE,OAAO,KAAK,IAAI,EAAE,CAAC;gBACrC,SAAS;YACX,CAAC;YAED,MAAM,eAAe,GAAG,YAAY,CAAC,eAAe,CAAC;YACrD,IAAI,CAAC,eAAe,EAAE,CAAC;gBACrB,SAAS,CAAC,6DAA6D;YACzE,CAAC;YAED,2EAA2E;YAC3E,MAAM,WAAW,GAAG,OAAO,cAAc,CAAC,WAAW,EAAE,QAAQ,KAAK,UAAU,CAAC;YAC/E,IAAI,WAAW,EAAE,CAAC;gBAChB,SAAS;YACX,CAAC;YAED,2EAA2E;YAC3E,+EAA+E;YAC/E,6EAA6E;YAC7E,iDAAiD;YACjD,IAAI,aAAuB,CAAC;YAC5B,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,qBAAqB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;gBAC7D,MAAM,KAAK,GAAG,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,0BAA0B,EAAE,CAAC,CAAC;gBACrF,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;oBAClB,SAAS,CAAC,WAAW;gBACvB,CAAC;gBACD,aAAa,GAAG;oBACd,GAAG,IAAI,GAAG,CACR,KAAK,CAAC,KAAK,CAAC,MAAM;yBACf,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;yBAChD,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CACrD;iBACF,CAAC;YACJ,CAAC;YAAC,MAAM,CAAC;gBACP,4EAA4E;gBAC5E,SAAS;YACX,CAAC;YAED,UAAU,CAAC,IAAI,CAAC;gBACd,iBAAiB,EAAE,QAAQ,CAAC,kBAAkB;gBAC9C,kBAAkB,EAAE,YAAY,CAAC,aAAa;gBAC9C,eAAe;gBACf,aAAa;gBACb,OAAO,EACL,sBAAsB,QAAQ,CAAC,kBAAkB,cAAc,YAAY,CAAC,aAAa,KAAK;oBAC9F,4FAA4F;oBAC5F,aAAa,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,4DAA4D;oBACjG,sHAAsH;aACzH,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC","sourcesContent":["import { z } from 'zod';\nimport {\n ResourceRelationship,\n RelationshipNature,\n} from '../resources.shared.schemas';\nimport { ResourceType } from '../resources.shared.core.definitions';\nimport { buildCreateRequestDto } from '../resources-config.shared.factory';\n\n/**\n * Registry-level guardrail for the composition `onParentCreate` lifecycle:\n * a composition relationship that OPTS IN to eager seeding\n * (`childOperations.lifecycle.onParentCreate.enabled = true`) must actually be\n * seedable — the child creatable with nothing but its parent FK (its CREATE-DTO\n * defaults fill the rest), OR an `onParentCreate.initialData.override` must\n * supply the non-defaulted fields.\n *\n * ## Why `onParentCreate` is OPT-IN (not mandatory for every composition)\n *\n * `RelationshipNature.COMPOSITION` means the part **dies with** its whole and\n * cannot exist independently — it does NOT mean the part is always created WITH\n * the whole. Those two axes are orthogonal (DDD): an org's `preferences` row is\n * an always-present part (eager), while a todo's `checklist items` are an\n * on-demand part (still composition — they die with the todo — but created as\n * needed). Forcing every composition to eager-seed would fabricate rows for\n * on-demand children. So eager seeding is declared per relationship via\n * `onParentCreate.enabled`, and this guard validates only the ADOPTERS.\n *\n * ## Fail-closed (safe by construction)\n *\n * The guard fires only when a relationship enabled `onParentCreate` but the child\n * cannot be seeded (not default-materializable AND no override) — a genuine\n * misconfiguration whose runtime seed would silently no-op. That is a boot-time\n * `throw`, not a warning. Because it targets only enabled adopters (a small,\n * deliberately-chosen set), it never crash-loops on the dozens of on-demand\n * compositions that legitimately do not seed.\n *\n * The probe itself is wrapped so an exotic child schema `buildCreateRequestDto`\n * cannot shape skips silently (fail-open on the probe), never blocking startup.\n * Pure and side-effect free.\n */\n\n/** Structural subset of a resource configuration this validator needs. */\nexport interface CompositionSeedabilityResourceInput {\n resourceIdentifier: ResourceType;\n mainSchema: z.ZodTypeAny;\n resourceRelationships: {\n parentRelationships: ResourceRelationship[];\n };\n}\n\nexport interface CompositionSeedabilityViolation {\n childResourceType: ResourceType;\n parentResourceType: ResourceType;\n foreignKeyField: string;\n /** Required, non-defaulted CREATE-DTO fields the default seed cannot supply. */\n missingFields: string[];\n message: string;\n}\n\n// Arbitrary 24-hex probe id for the FK slot; never persisted — only the parse\n// success/failure matters.\nconst SEEDABILITY_PROBE_FK_VALUE = '000000000000000000000000';\n\n/**\n * Validate that every composition relationship which opted into\n * `onParentCreate.enabled` is actually seedable (default-materializable from its\n * CREATE DTO + FK, or carries an override). Returns the list of violations\n * (empty when clean); the caller throws on any (fail-closed).\n *\n * @param resourceConfigurations - the registry's `resourceConfigurations` map\n * (`resourceType → configuration`). Each entry is the CHILD in its\n * `parentRelationships`, so `mainSchema` is exactly the schema to probe.\n */\nexport function validateCompositionSeedability(\n resourceConfigurations: Record<string, CompositionSeedabilityResourceInput>,\n): CompositionSeedabilityViolation[] {\n const violations: CompositionSeedabilityViolation[] = [];\n\n for (const resource of Object.values(resourceConfigurations)) {\n const parentRelationships = resource.resourceRelationships?.parentRelationships ?? [];\n\n for (const relationship of parentRelationships) {\n if (relationship.nature !== RelationshipNature.COMPOSITION) {\n continue;\n }\n\n // Only an ENABLED onParentCreate is a seeding adopter that must be seedable.\n // A composition WITHOUT it is a legitimate on-demand child (cascade-deletes\n // with its parent, created on demand) — not this guard's concern.\n const onParentCreate = relationship.childOperations?.lifecycle?.onParentCreate;\n if (onParentCreate?.enabled !== true) {\n continue;\n }\n\n const foreignKeyField = relationship.foreignKeyField;\n if (!foreignKeyField) {\n continue; // fail-open: an enabled seed with no FK can't be probed here\n }\n\n // An override supplies any non-defaulted field → seedable by construction.\n const hasOverride = typeof onParentCreate.initialData?.override === 'function';\n if (hasOverride) {\n continue;\n }\n\n // Probe: is the child default-materializable from its CREATE DTO + the FK?\n // buildCreateRequestDto already strips PK / SYSTEM_MANAGED / excludeFromCreate\n // / virtual / primary-scope FKs; we inject the relationship FK explicitly to\n // cover non-scope parent FKs that stay required.\n let missingFields: string[];\n try {\n const createDto = buildCreateRequestDto(resource.mainSchema);\n const probe = createDto.safeParse({ [foreignKeyField]: SEEDABILITY_PROBE_FK_VALUE });\n if (probe.success) {\n continue; // seedable\n }\n missingFields = [\n ...new Set(\n probe.error.issues\n .map((issue) => issue.path.map(String).join('.'))\n .filter((path): path is string => path.length > 0),\n ),\n ];\n } catch {\n // Fail-open — a probe edge case must never block startup or false-positive.\n continue;\n }\n\n violations.push({\n childResourceType: resource.resourceIdentifier,\n parentResourceType: relationship.resourceType1,\n foreignKeyField,\n missingFields,\n message:\n `Composition child '${resource.resourceIdentifier}' (parent '${relationship.resourceType1}') ` +\n `enabled onParentCreate seeding but is NOT seedable: its CREATE DTO requires non-defaulted ` +\n `field(s) [${missingFields.join(', ')}] and no onParentCreate.initialData.override is declared. ` +\n `The seed would fail (and be swallowed) at runtime. Add field defaults / an override, or drop onParentCreate.enabled.`,\n });\n }\n }\n\n return violations;\n}\n"]}
|
package/dist/esm/resources/utils/context-addressed-composition-singleton.shared.utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-addressed-composition-singleton.shared.utils.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"context-addressed-composition-singleton.shared.utils.d.ts","sourceRoot":"","sources":["../../../../src/resources/utils/context-addressed-composition-singleton.shared.utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2CAA2C,EAAE,MAAM,oCAAoC,CAAC;AACtG,OAAO,EAKL,KAAK,oBAAoB,EACzB,KAAK,YAAY,EAClB,MAAM,6BAA6B,CAAC;AAGrC,MAAM,WAAW,yDAAyD;IACxE,YAAY,EAAE,oBAAoB,CAAC;IACnC,kBAAkB,EAAE,YAAY,CAAC;IACjC,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,kDAAkD,CAChE,YAAY,EAAE,oBAAoB,GACjC,OAAO,CAeT;AAED,wBAAgB,6DAA6D,CAC3E,qBAAqB,EAAE,2CAA2C,GACjE,yDAAyD,EAAE,CAQ7D"}
|
package/dist/esm/resources/utils/context-addressed-composition-singleton.shared.utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-addressed-composition-singleton.shared.utils.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"context-addressed-composition-singleton.shared.utils.js","sourceRoot":"","sources":["../../../../src/resources/utils/context-addressed-composition-singleton.shared.utils.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAClB,uCAAuC,EACvC,+BAA+B,EAC/B,qBAAqB,GAGtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAQlE,MAAM,UAAU,kDAAkD,CAChE,YAAkC;IAElC,+EAA+E;IAC/E,yEAAyE;IACzE,wCAAwC;IACxC,IACE,YAAY,CAAC,MAAM,KAAK,kBAAkB,CAAC,WAAW;WACnD,YAAY,CAAC,YAAY,KAAK,+BAA+B,CAAC,GAAG;WACjE,CAAC,qBAAqB,CAAC,YAAY,CAAC,YAAY,CAAC;WACjD,YAAY,CAAC,mBAAmB,KAAK,uCAAuC,CAAC,UAAU,EAC1F,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,SAAS,GAAG,qBAAqB,CAAC,gCAAgC,CAAC,YAAY,CAAC,CAAC;IACvF,OAAO,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,6DAA6D,CAC3E,qBAAkE;IAElE,OAAO,qBAAqB,CAAC,mBAAmB;SAC7C,MAAM,CAAC,kDAAkD,CAAC;SAC1D,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QACtB,YAAY;QACZ,kBAAkB,EAAE,YAAY,CAAC,aAAa;QAC9C,eAAe,EAAE,qBAAqB,CAAC,gCAAgC,CAAC,YAAY,CAAC,CAAC,WAAW,CAAC,UAAW,CAAC,eAAe;KAC9H,CAAC,CAAC,CAAC;AACR,CAAC","sourcesContent":["import type { ResourceConfiguration_ResourceRelationships } from '../resources-config.shared.schemas';\nimport {\n RelationshipNature,\n ResourceRelationshipAccessScopeStrategy,\n ResourceRelationshipCardinality,\n isOneToOneCardinality,\n type ResourceRelationship,\n type ResourceType,\n} from '../resources.shared.schemas';\nimport { Resources_SharedUtils } from '../resources.shared.utils';\n\nexport interface ContextAddressedCompositionSingletonRelationshipCandidate {\n relationship: ResourceRelationship;\n parentResourceType: ResourceType;\n foreignKeyField: string;\n}\n\nexport function isContextAddressedCompositionSingletonRelationship(\n relationship: ResourceRelationship,\n): boolean {\n // Context-addressed singleton mutation means a required owner context uniquely\n // selects the child row. Optional or collection-side parents must not be\n // promoted into this identity contract.\n if (\n relationship.nature !== RelationshipNature.COMPOSITION\n || relationship.cardinality1 !== ResourceRelationshipCardinality.ONE\n || !isOneToOneCardinality(relationship.cardinality2)\n || relationship.accessScopeStrategy === ResourceRelationshipAccessScopeStrategy.STANDALONE\n ) {\n return false;\n }\n\n const semantics = Resources_SharedUtils.getResolvedRelationshipSemantics(relationship);\n return Boolean(semantics.persistence.foreignKey?.fieldIdentifier);\n}\n\nexport function getContextAddressedCompositionSingletonRelationshipCandidates(\n resourceRelationships: ResourceConfiguration_ResourceRelationships,\n): ContextAddressedCompositionSingletonRelationshipCandidate[] {\n return resourceRelationships.parentRelationships\n .filter(isContextAddressedCompositionSingletonRelationship)\n .map((relationship) => ({\n relationship,\n parentResourceType: relationship.resourceType1,\n foreignKeyField: Resources_SharedUtils.getResolvedRelationshipSemantics(relationship).persistence.foreignKey!.fieldIdentifier,\n }));\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dependent-lifecycle-classification.validation.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"dependent-lifecycle-classification.validation.d.ts","sourceRoot":"","sources":["../../../../src/resources/utils/dependent-lifecycle-classification.validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAEzE,OAAO,EAGL,yBAAyB,EAC1B,MAAM,yDAAyD,CAAC;AACjE,OAAO,EAEL,KAAK,2CAA2C,EACjD,MAAM,+CAA+C,CAAC;AAEvD;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,kCAAkC;IACjD,kBAAkB,EAAE,YAAY,CAAC;IACjC,iBAAiB,EAAE,YAAY,CAAC;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,yBAAyB,CAAC;IACvC,6FAA6F;IAC7F,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,0CAA0C,CACxD,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,2CAA2C,CAAC,GAClF,kCAAkC,EAAE,CAgDtC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dependent-lifecycle-classification.validation.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"dependent-lifecycle-classification.validation.js","sourceRoot":"","sources":["../../../../src/resources/utils/dependent-lifecycle-classification.validation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,+BAA+B,EAAE,MAAM,oCAAoC,CAAC;AACrF,OAAO,EACL,iCAAiC,EACjC,mCAAmC,GAEpC,MAAM,yDAAyD,CAAC;AACjE,OAAO,EACL,oBAAoB,GAErB,MAAM,+CAA+C,CAAC;AAyBvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,UAAU,0CAA0C,CACxD,sBAAmF;IAEnF,MAAM,KAAK,GAAyC,EAAE,CAAC;IACvD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IAEnC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,EAAE,CAAC;QAC1D,MAAM,mBAAmB,GAAG,+BAA+B,CAAC;YAC1D,mBAAmB,EAAE,KAAK,CAAC,qBAAqB,EAAE,mBAAmB,IAAI,EAAE;YAC3E,iBAAiB,EAAE,KAAK,CAAC,qBAAqB,EAAE,iBAAiB,IAAI,EAAE;YACvE,kBAAkB,EAAE,EAAE;SACvB,CAAC,CAAC;QAEH,KAAK,MAAM,YAAY,IAAI,mBAAmB,EAAE,CAAC;YAC/C,MAAM,MAAM,GAAG,sBAAsB,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;YAClE,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,SAAS,CAAC,qDAAqD;YACjE,CAAC;YACD,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,EAAE,CAAC;gBAClC,SAAS,CAAC,+EAA+E;YAC3F,CAAC;YAED,8FAA8F;YAC9F,6FAA6F;YAC7F,8FAA8F;YAC9F,kDAAkD;YAClD,MAAM,cAAc,GAAG,iCAAiC,CACtD,YAAY,EACZ,CAAC,YAAY,EAAE,EAAE,CAAC,sBAAsB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,EAAE,eAAe,CAChF,CAAC;YACF,IAAI,CAAC,mCAAmC,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,CAAC;gBACrE,SAAS;YACX,CAAC;YAED,gGAAgG;YAChG,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,MAAM,CAAC,YAAY,CAAC,eAAe,IAAI,EAAE,CAAC,EAAE,CAAC;YACxI,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,SAAS;YAChC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAElB,KAAK,CAAC,IAAI,CAAC;gBACT,kBAAkB,EAAE,YAAY,CAAC,aAAa;gBAC9C,iBAAiB,EAAE,YAAY,CAAC,aAAa;gBAC7C,GAAG,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,YAAY,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1F,WAAW,EAAE,cAAc,CAAC,WAAW;gBACvC,MAAM,EAAE,cAAc,CAAC,MAAM;aAC9B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import type { ResourceType } from '../resources.shared.core.definitions';\nimport { getParentDirectionRelationships } from '../resources-config.shared.schemas';\nimport {\n classifySubjectErasureDisposition,\n isBlockingSubjectErasureDisposition,\n SubjectErasureDisposition,\n} from '../../compliance/privacy/subject-erasure.shared.schemas';\nimport {\n canFireDeleteCascade,\n type CompositionCascadeDeletabilityResourceInput,\n} from './composition-cascade-deletability.validation';\n\n/**\n * One DEPENDENT edge whose lifecycle nobody has classified (#1095).\n *\n * The classification is the erasure runtime's own — `classifySubjectErasureDisposition` — so the\n * report and the runtime cannot disagree about what an edge says. Two dispositions are reported,\n * exactly the ones {@link isBlockingSubjectErasureDisposition} refuses at runtime:\n *\n * - `UNCLASSIFIED`: a COMPOSITION edge (`lifecycleModelMode: DEPENDENT`) with NO `onParentDelete`\n * at all. `enabled` defaults to `false`, so deleting the parent leaves the children in place under\n * a parent that no longer exists. The tenant purge dispatches the ordinary `ORGANIZATIONS | DELETE`\n * and relies on the same cascade, so an `ORGANIZATIONS → X` edge in this state leaves X's rows\n * behind after the tenant is destroyed; a subject erasure reaching the edge is REFUSED outright.\n * - `UNSUPPORTED_DEFERRED`: `mode: LAZY`, which a subject erasure cannot execute.\n */\nexport interface UnclassifiedDependentLifecycleEdge {\n parentResourceType: ResourceType;\n childResourceType: ResourceType;\n foreignKeyField?: string;\n disposition: SubjectErasureDisposition;\n /** The classifier's own justification, naming the declaration that would settle the edge. */\n reason: string;\n}\n\n/**\n * Collect every DEPENDENT edge whose parent-delete lifecycle the author never classified — the\n * boot-time report `isBlockingSubjectErasureDisposition` was exported for (\"the erasure analogue of\n * `validateCompositionCascadeDeletability`\").\n *\n * ## Why a REPORT and not a refusal\n *\n * `validateCompositionCascadeDeletability` guards edges that OPTED IN to the cascade and cannot run\n * it. This guard is its complement: edges that never opted either way. An undeclared edge is a\n * missing declaration, and the honest reading of \"the framework asked nothing, so the author said\n * nothing\" is a gap to derive and surface, total over the registry, rather than a refusal wired\n * into boot (`application-creation-directive.md`: mark, do not block). The two runtimes that meet\n * such an edge already answer for themselves — the erasure refuses at the edge, the plain delete and\n * the tenant purge orphan silently — and the second is the one nothing reported until now.\n *\n * ## Population\n *\n * Total over every relationship of every configuration, read through the SAME helper the delete\n * cascade and the erasure walker read (`resolveRelationshipLifecycleOnParentDeleteConfig`, inside the\n * classifier). A disabled relationship is not part of the live graph and is skipped by the\n * classifier itself (`NOT_OWNED`).\n *\n * ## Parent-reachability skip, shared with the cascade-deletability guard\n *\n * The delete cascade fires only from the parent's DELETE / DELETE_MANY post-op logic. A parent that\n * can reach neither can never orphan anything, so its undeclared edges are dormant and are NOT\n * reported — `canFireDeleteCascade`, the same predicate the sibling guard uses, so the two guards\n * agree on which edges are live. Self-correcting: the day the parent gains a delete path, its dormant\n * edges are reported.\n *\n * @param resourceConfigurations - the registry's `resourceConfigurations` map (`resourceType →\n * built configuration`). Each entry is the CHILD in its `parentRelationships` and\n * `selfRelationships`; parents are looked up in the same map for the reachability skip.\n */\nexport function collectUnclassifiedDependentLifecycleEdges(\n resourceConfigurations: Record<string, CompositionCascadeDeletabilityResourceInput>,\n): UnclassifiedDependentLifecycleEdge[] {\n const edges: UnclassifiedDependentLifecycleEdge[] = [];\n const reported = new Set<string>();\n\n for (const child of Object.values(resourceConfigurations)) {\n const parentRelationships = getParentDirectionRelationships({\n parentRelationships: child.resourceRelationships?.parentRelationships ?? [],\n selfRelationships: child.resourceRelationships?.selfRelationships ?? [],\n childRelationships: [],\n });\n\n for (const relationship of parentRelationships) {\n const parent = resourceConfigurations[relationship.resourceType1];\n if (!parent) {\n continue; // fail-open: parent not in this map, cannot classify\n }\n if (!canFireDeleteCascade(parent)) {\n continue; // structurally unreachable edge — the parent has no delete path to orphan from\n }\n\n // #1279: the classifier reads the CHILD's own `retentionPolicy` — the declaration that states\n // what an erasure does to its rows — so this guard reports exactly what the runtime will do.\n // The map is keyed by resource type and already carries the resolved policy, so the lookup is\n // the same one the reachability skip above makes.\n const classification = classifySubjectErasureDisposition(\n relationship,\n (resourceType) => resourceConfigurations[String(resourceType)]?.retentionPolicy,\n );\n if (!isBlockingSubjectErasureDisposition(classification.disposition)) {\n continue;\n }\n\n // The same relationship object is registered on both sides of the graph; report each edge once.\n const key = `${String(relationship.resourceType1)}→${String(relationship.resourceType2)}:${String(relationship.foreignKeyField ?? '')}`;\n if (reported.has(key)) continue;\n reported.add(key);\n\n edges.push({\n parentResourceType: relationship.resourceType1,\n childResourceType: relationship.resourceType2,\n ...(relationship.foreignKeyField ? { foreignKeyField: relationship.foreignKeyField } : {}),\n disposition: classification.disposition,\n reason: classification.reason,\n });\n }\n }\n\n return edges;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duplicate-relationship-registration.validation.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"duplicate-relationship-registration.validation.d.ts","sourceRoot":"","sources":["../../../../src/resources/utils/duplicate-relationship-registration.validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqFG;AAEH,0EAA0E;AAC1E,MAAM,WAAW,iCAAiC;IAChD,kBAAkB,EAAE,YAAY,CAAC;IACjC,iBAAiB,EAAE,YAAY,CAAC;IAChC,4FAA4F;IAC5F,WAAW,EAAE,MAAM,CAAC;IACpB,6FAA6F;IAC7F,YAAY,EAAE,oBAAoB,CAAC;IACnC,OAAO,EAAE,MAAM,CAAC;CACjB;AAqDD;;;;;;;;;;;GAWG;AACH,wBAAgB,sCAAsC,CACpD,aAAa,EAAE,SAAS,oBAAoB,EAAE,GAC7C,iCAAiC,EAAE,CAgErC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duplicate-relationship-registration.validation.js","sourceRoot":"","sources":["../../../../../src/resources/utils/duplicate-relationship-registration.validation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ResourceRelationship, ResourceType } from '../resources.shared.schemas';\n\n/**\n * Registry-ASSEMBLY guardrail: the same relationship edge must be registered exactly\n * once in the flat relationship list the registry hands to every resource factory.\n *\n * ## Why this needs a guard at all\n *\n * The registry concatenates four relationship sources (custom-shared, custom-backend,\n * core-shared, core-backend) into one flat list. The resource-config factory then\n * BUCKETS that list by `filter` (`transformResourceRelationships`) — so a list entry\n * that appears twice appears twice in the child's `parentRelationships` and twice in\n * the parent's `childRelationships`. Nothing downstream deduplicates, because nothing\n * downstream can: two entries are indistinguishable, so a consumer cannot tell \"the\n * author declared this edge twice\" from \"there are genuinely two edges here\".\n *\n * That is a SILENT corruption at assembly time, and the consequences are not uniform.\n * Three distinct classes of damage, none of which needs a lifecycle to fire:\n *\n * **1. Broken addressing — throws at REQUEST time.** Several runtime paths assert a\n * cardinality on the relationship buckets and fail closed when it does not hold. A\n * duplicate turns each of those assertions into a `CONFIGURATION` throw on a normal\n * request:\n * - Complete-association authorization and mutation-target resolution require\n * EXACTLY TWO eligible parent relationships (`length !== 2` → throw). A duplicated\n * M:N declaration is worse than a doubled list entry: the factory's\n * many-to-many decomposition runs twice, giving the junction FOUR parent edges.\n * - Context-addressed singleton authorization and mutation reject an AMBIGUOUS target\n * (`length > 1` → throw), and one selector path silently DENIES the operation\n * instead of throwing.\n * - Bulk relationship-field resolution rejects ambiguous matches read straight off the\n * assembled list.\n *\n * **2. Lost or doubled semantics — at RENDER time (frontend).** Frontend form semantics\n * throw in development and return `undefined` in production when two relationships\n * resolve to one relationship-object field identity; quick-create affordances,\n * `PARENT_CONTEXT_SINGLETON` / complete-association addressing modes, and preset\n * relationship-display overrides are dropped by the same ambiguity checks; and a nested\n * child section renders TWICE, with a duplicated React key and a duplicated LIST fetch.\n *\n * **3. Doubled execution — when a lifecycle does fire.**\n * - **Composition seeding** (`onParentCreate`) creates one child per relationship in\n * the list → a duplicated edge seeds the child TWICE, producing a duplicate row for\n * what is usually a 1:1 singleton. This is a data-integrity break.\n * - **The delete cascade** (`onParentDelete`) dispatches once per relationship, each\n * with a fresh visited-set → the teardown runs twice inside the parent's delete\n * transaction.\n *\n * What genuinely absorbs duplicates — and is therefore NOT a signal that the registry is\n * healthy: URL parent-path generation (collapsed into a Map keyed by resource type),\n * Mongoose index derivation (a Set), DTO nested-field shaping (a Record keyed by field\n * name), and resource-context traversal (which re-runs the child query per duplicate and\n * then drops the rows on its circular-reference guard — wasted I/O, not wrong data).\n * Startup guards report the same violation once per duplicate, which reads as several\n * distinct problems and trains operators to discount the channel.\n *\n * Do NOT downgrade this guard to a warning on the theory that duplicates are inert until\n * a lifecycle runs. They are not: classes 1 and 2 above are reachable on an ordinary\n * request against an app that never declares a single lifecycle.\n *\n * ## How the duplication happens in practice\n *\n * Not by declaring the same edge twice in one file — by COMPOSING lists. A host that\n * folds the shared relationship list into the bundle it passes as the BACKEND list,\n * while the shared list also still flows through its own slot, registers every shared\n * edge twice. That is precisely how `platform-apps-manager` doubled its four\n * `wildoApplication` composition edges (surfaced by the cascade-deletability guard on a\n * live boot, 2026-07-29).\n *\n * ## Conservative identity: reference-equal functions, structural everything else\n *\n * Two edges between the same pair of resources are frequently LEGITIMATE and must never\n * be merged — different `foreignKeyField` (two FKs from the child to the same parent),\n * different `discriminator` / `condition`, different `jointResourceType`. So the\n * duplicate key is the WHOLE authored declaration, compared with\n * {@link isSameRelationshipDeclaration}: every own property must match, functions are\n * compared by REFERENCE (never by source), and `resolvedSemantics` is ignored because it\n * is derived, not authored.\n *\n * Comparing functions by reference is the deliberate conservative choice. It catches the\n * real-world failure — the same declaration objects reaching the registry through two\n * slots — while guaranteeing that two independently authored edges can never collide,\n * because their `condition` / `initialData.override` closures are distinct objects. The\n * guard therefore under-detects rather than over-detects: a missed duplicate keeps\n * today's behavior, whereas a false positive would refuse to boot a correct registry.\n *\n * Pure and side-effect free; the caller decides to throw (the registry does, fail-closed).\n */\n\n/** One edge that was registered more than once, with its repeat count. */\nexport interface DuplicateRelationshipRegistration {\n parentResourceType: ResourceType;\n childResourceType: ResourceType;\n /** How many times the identical declaration appears in the assembled list (always >= 2). */\n occurrences: number;\n /** The first occurrence, so callers can report the nature / cardinality / FK of the edge. */\n relationship: ResourceRelationship;\n message: string;\n}\n\n/**\n * Structural equality for a relationship DECLARATION.\n *\n * - `resolvedSemantics` is skipped: it is compiled from the declaration, and the same\n * authored edge can legitimately arrive pre-compiled through one slot and raw through\n * another.\n * - Functions compare by reference (see the rationale in the module JSDoc).\n * - Arrays and plain objects recurse; everything else uses `Object.is` (so `NaN` matches\n * itself and `+0`/`-0` stay distinct).\n */\nfunction isSameRelationshipDeclaration(left: unknown, right: unknown): boolean {\n if (Object.is(left, right)) {\n return true;\n }\n\n if (typeof left === 'function' || typeof right === 'function') {\n // Reference-inequality already established above: distinct closures are distinct\n // declarations, even when their source text matches.\n return false;\n }\n\n if (\n typeof left !== 'object' || left === null ||\n typeof right !== 'object' || right === null\n ) {\n return false;\n }\n\n if (Array.isArray(left) || Array.isArray(right)) {\n if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) {\n return false;\n }\n return left.every((entry, index) => isSameRelationshipDeclaration(entry, right[index]));\n }\n\n const leftRecord = left as Record<string, unknown>;\n const rightRecord = right as Record<string, unknown>;\n const leftKeys = Object.keys(leftRecord).filter((key) => key !== 'resolvedSemantics');\n const rightKeys = Object.keys(rightRecord).filter((key) => key !== 'resolvedSemantics');\n\n if (leftKeys.length !== rightKeys.length) {\n return false;\n }\n\n return leftKeys.every(\n (key) =>\n Object.prototype.hasOwnProperty.call(rightRecord, key) &&\n isSameRelationshipDeclaration(leftRecord[key], rightRecord[key]),\n );\n}\n\n/**\n * Find every relationship declaration registered more than once in an assembled\n * registry list. Returns one entry per duplicated edge (not one per extra occurrence),\n * empty when the list is clean.\n *\n * Bucketing by `parent → child` first keeps the comparison cost proportional to the\n * number of edges that actually share a resource pair, instead of comparing every\n * relationship against every other one.\n *\n * @param relationships - the flat, pre-compilation concatenation of every relationship\n * source the registry was given.\n */\nexport function findDuplicateRelationshipRegistrations(\n relationships: readonly ResourceRelationship[],\n): DuplicateRelationshipRegistration[] {\n const byResourcePair = new Map<string, ResourceRelationship[]>();\n\n for (const relationship of relationships) {\n const pairKey = `${String(relationship.resourceType1)}→${String(relationship.resourceType2)}`;\n const bucket = byResourcePair.get(pairKey);\n if (bucket) {\n bucket.push(relationship);\n } else {\n byResourcePair.set(pairKey, [relationship]);\n }\n }\n\n const duplicates: DuplicateRelationshipRegistration[] = [];\n\n for (const bucket of byResourcePair.values()) {\n if (bucket.length < 2) {\n continue;\n }\n\n // Group the pair's edges into classes of identical declarations. A pair legitimately\n // holding several DISTINCT edges (two FK fields, a discriminated pair, an M:N\n // junction side) produces several classes of size 1 and reports nothing.\n const identityClasses: { representative: ResourceRelationship; occurrences: number }[] = [];\n\n for (const relationship of bucket) {\n const identityClass = identityClasses.find((candidate) =>\n isSameRelationshipDeclaration(candidate.representative, relationship),\n );\n if (identityClass) {\n identityClass.occurrences += 1;\n } else {\n identityClasses.push({ representative: relationship, occurrences: 1 });\n }\n }\n\n for (const identityClass of identityClasses) {\n if (identityClass.occurrences < 2) {\n continue;\n }\n const { representative, occurrences } = identityClass;\n duplicates.push({\n parentResourceType: representative.resourceType1,\n childResourceType: representative.resourceType2,\n occurrences,\n relationship: representative,\n message:\n `Relationship '${String(representative.resourceType1)}' → ` +\n `'${String(representative.resourceType2)}' is registered ${occurrences} times with an ` +\n `identical declaration. The registry buckets relationships by filtering the assembled ` +\n `list, so this edge lands ${occurrences} times in the child's parentRelationships and in ` +\n `the parent's childRelationships — composition seeding would create ${occurrences} child ` +\n `rows per parent create, the onParentDelete cascade would dispatch ${occurrences} times, ` +\n `and every startup guard reports it ${occurrences} times. This is almost always a list ` +\n `COMPOSITION mistake in the application/platform host: the same relationship array reaching ` +\n `the registry through two of its slots (e.g. the shared list folded into the bundle passed ` +\n `as the backend list, while it also still flows through the shared slot). Pass each list ` +\n `through exactly one slot. To declare two genuinely different edges between the same pair, ` +\n `make them differ (distinct foreignKeyField, discriminator/condition, or jointResourceType).`,\n });\n }\n }\n\n return duplicates;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"duplicate-relationship-registration.validation.js","sourceRoot":"","sources":["../../../../src/resources/utils/duplicate-relationship-registration.validation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ResourceRelationship, ResourceType } from '../resources.shared.schemas';\n\n/**\n * Registry-ASSEMBLY guardrail: the same relationship edge must be registered exactly\n * once in the flat relationship list the registry hands to every resource factory.\n *\n * ## Why this needs a guard at all\n *\n * The registry concatenates four relationship sources (custom-shared, custom-backend,\n * core-shared, core-backend) into one flat list. The resource-config factory then\n * BUCKETS that list by `filter` (`transformResourceRelationships`) — so a list entry\n * that appears twice appears twice in the child's `parentRelationships` and twice in\n * the parent's `childRelationships`. Nothing downstream deduplicates, because nothing\n * downstream can: two entries are indistinguishable, so a consumer cannot tell \"the\n * author declared this edge twice\" from \"there are genuinely two edges here\".\n *\n * That is a SILENT corruption at assembly time, and the consequences are not uniform.\n * Three distinct classes of damage, none of which needs a lifecycle to fire:\n *\n * **1. Broken addressing — throws at REQUEST time.** Several runtime paths assert a\n * cardinality on the relationship buckets and fail closed when it does not hold. A\n * duplicate turns each of those assertions into a `CONFIGURATION` throw on a normal\n * request:\n * - Complete-association authorization and mutation-target resolution require\n * EXACTLY TWO eligible parent relationships (`length !== 2` → throw). A duplicated\n * M:N declaration is worse than a doubled list entry: the factory's\n * many-to-many decomposition runs twice, giving the junction FOUR parent edges.\n * - Context-addressed singleton authorization and mutation reject an AMBIGUOUS target\n * (`length > 1` → throw), and one selector path silently DENIES the operation\n * instead of throwing.\n * - Bulk relationship-field resolution rejects ambiguous matches read straight off the\n * assembled list.\n *\n * **2. Lost or doubled semantics — at RENDER time (frontend).** Frontend form semantics\n * throw in development and return `undefined` in production when two relationships\n * resolve to one relationship-object field identity; quick-create affordances,\n * `PARENT_CONTEXT_SINGLETON` / complete-association addressing modes, and preset\n * relationship-display overrides are dropped by the same ambiguity checks; and a nested\n * child section renders TWICE, with a duplicated React key and a duplicated LIST fetch.\n *\n * **3. Doubled execution — when a lifecycle does fire.**\n * - **Composition seeding** (`onParentCreate`) creates one child per relationship in\n * the list → a duplicated edge seeds the child TWICE, producing a duplicate row for\n * what is usually a 1:1 singleton. This is a data-integrity break.\n * - **The delete cascade** (`onParentDelete`) dispatches once per relationship, each\n * with a fresh visited-set → the teardown runs twice inside the parent's delete\n * transaction.\n *\n * What genuinely absorbs duplicates — and is therefore NOT a signal that the registry is\n * healthy: URL parent-path generation (collapsed into a Map keyed by resource type),\n * Mongoose index derivation (a Set), DTO nested-field shaping (a Record keyed by field\n * name), and resource-context traversal (which re-runs the child query per duplicate and\n * then drops the rows on its circular-reference guard — wasted I/O, not wrong data).\n * Startup guards report the same violation once per duplicate, which reads as several\n * distinct problems and trains operators to discount the channel.\n *\n * Do NOT downgrade this guard to a warning on the theory that duplicates are inert until\n * a lifecycle runs. They are not: classes 1 and 2 above are reachable on an ordinary\n * request against an app that never declares a single lifecycle.\n *\n * ## How the duplication happens in practice\n *\n * Not by declaring the same edge twice in one file — by COMPOSING lists. A host that\n * folds the shared relationship list into the bundle it passes as the BACKEND list,\n * while the shared list also still flows through its own slot, registers every shared\n * edge twice. That is precisely how `platform-apps-manager` doubled its four\n * `wildoApplication` composition edges (surfaced by the cascade-deletability guard on a\n * live boot, 2026-07-29).\n *\n * ## Conservative identity: reference-equal functions, structural everything else\n *\n * Two edges between the same pair of resources are frequently LEGITIMATE and must never\n * be merged — different `foreignKeyField` (two FKs from the child to the same parent),\n * different `discriminator` / `condition`, different `jointResourceType`. So the\n * duplicate key is the WHOLE authored declaration, compared with\n * {@link isSameRelationshipDeclaration}: every own property must match, functions are\n * compared by REFERENCE (never by source), and `resolvedSemantics` is ignored because it\n * is derived, not authored.\n *\n * Comparing functions by reference is the deliberate conservative choice. It catches the\n * real-world failure — the same declaration objects reaching the registry through two\n * slots — while guaranteeing that two independently authored edges can never collide,\n * because their `condition` / `initialData.override` closures are distinct objects. The\n * guard therefore under-detects rather than over-detects: a missed duplicate keeps\n * today's behavior, whereas a false positive would refuse to boot a correct registry.\n *\n * Pure and side-effect free; the caller decides to throw (the registry does, fail-closed).\n */\n\n/** One edge that was registered more than once, with its repeat count. */\nexport interface DuplicateRelationshipRegistration {\n parentResourceType: ResourceType;\n childResourceType: ResourceType;\n /** How many times the identical declaration appears in the assembled list (always >= 2). */\n occurrences: number;\n /** The first occurrence, so callers can report the nature / cardinality / FK of the edge. */\n relationship: ResourceRelationship;\n message: string;\n}\n\n/**\n * Structural equality for a relationship DECLARATION.\n *\n * - `resolvedSemantics` is skipped: it is compiled from the declaration, and the same\n * authored edge can legitimately arrive pre-compiled through one slot and raw through\n * another.\n * - Functions compare by reference (see the rationale in the module JSDoc).\n * - Arrays and plain objects recurse; everything else uses `Object.is` (so `NaN` matches\n * itself and `+0`/`-0` stay distinct).\n */\nfunction isSameRelationshipDeclaration(left: unknown, right: unknown): boolean {\n if (Object.is(left, right)) {\n return true;\n }\n\n if (typeof left === 'function' || typeof right === 'function') {\n // Reference-inequality already established above: distinct closures are distinct\n // declarations, even when their source text matches.\n return false;\n }\n\n if (\n typeof left !== 'object' || left === null ||\n typeof right !== 'object' || right === null\n ) {\n return false;\n }\n\n if (Array.isArray(left) || Array.isArray(right)) {\n if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) {\n return false;\n }\n return left.every((entry, index) => isSameRelationshipDeclaration(entry, right[index]));\n }\n\n const leftRecord = left as Record<string, unknown>;\n const rightRecord = right as Record<string, unknown>;\n const leftKeys = Object.keys(leftRecord).filter((key) => key !== 'resolvedSemantics');\n const rightKeys = Object.keys(rightRecord).filter((key) => key !== 'resolvedSemantics');\n\n if (leftKeys.length !== rightKeys.length) {\n return false;\n }\n\n return leftKeys.every(\n (key) =>\n Object.prototype.hasOwnProperty.call(rightRecord, key) &&\n isSameRelationshipDeclaration(leftRecord[key], rightRecord[key]),\n );\n}\n\n/**\n * Find every relationship declaration registered more than once in an assembled\n * registry list. Returns one entry per duplicated edge (not one per extra occurrence),\n * empty when the list is clean.\n *\n * Bucketing by `parent → child` first keeps the comparison cost proportional to the\n * number of edges that actually share a resource pair, instead of comparing every\n * relationship against every other one.\n *\n * @param relationships - the flat, pre-compilation concatenation of every relationship\n * source the registry was given.\n */\nexport function findDuplicateRelationshipRegistrations(\n relationships: readonly ResourceRelationship[],\n): DuplicateRelationshipRegistration[] {\n const byResourcePair = new Map<string, ResourceRelationship[]>();\n\n for (const relationship of relationships) {\n const pairKey = `${String(relationship.resourceType1)}→${String(relationship.resourceType2)}`;\n const bucket = byResourcePair.get(pairKey);\n if (bucket) {\n bucket.push(relationship);\n } else {\n byResourcePair.set(pairKey, [relationship]);\n }\n }\n\n const duplicates: DuplicateRelationshipRegistration[] = [];\n\n for (const bucket of byResourcePair.values()) {\n if (bucket.length < 2) {\n continue;\n }\n\n // Group the pair's edges into classes of identical declarations. A pair legitimately\n // holding several DISTINCT edges (two FK fields, a discriminated pair, an M:N\n // junction side) produces several classes of size 1 and reports nothing.\n const identityClasses: { representative: ResourceRelationship; occurrences: number }[] = [];\n\n for (const relationship of bucket) {\n const identityClass = identityClasses.find((candidate) =>\n isSameRelationshipDeclaration(candidate.representative, relationship),\n );\n if (identityClass) {\n identityClass.occurrences += 1;\n } else {\n identityClasses.push({ representative: relationship, occurrences: 1 });\n }\n }\n\n for (const identityClass of identityClasses) {\n if (identityClass.occurrences < 2) {\n continue;\n }\n const { representative, occurrences } = identityClass;\n duplicates.push({\n parentResourceType: representative.resourceType1,\n childResourceType: representative.resourceType2,\n occurrences,\n relationship: representative,\n message:\n `Relationship '${String(representative.resourceType1)}' → ` +\n `'${String(representative.resourceType2)}' is registered ${occurrences} times with an ` +\n `identical declaration. The registry buckets relationships by filtering the assembled ` +\n `list, so this edge lands ${occurrences} times in the child's parentRelationships and in ` +\n `the parent's childRelationships — composition seeding would create ${occurrences} child ` +\n `rows per parent create, the onParentDelete cascade would dispatch ${occurrences} times, ` +\n `and every startup guard reports it ${occurrences} times. This is almost always a list ` +\n `COMPOSITION mistake in the application/platform host: the same relationship array reaching ` +\n `the registry through two of its slots (e.g. the shared list folded into the bundle passed ` +\n `as the backend list, while it also still flows through the shared slot). Pass each list ` +\n `through exactly one slot. To declare two genuinely different edges between the same pair, ` +\n `make them differ (distinct foreignKeyField, discriminator/condition, or jointResourceType).`,\n });\n }\n }\n\n return duplicates;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-value-disclosure.utils.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"field-value-disclosure.utils.d.ts","sourceRoot":"","sources":["../../../../src/resources/utils/field-value-disclosure.utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAG7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,CAAC,CAAC,UAAU,GAAG,OAAO,CAE7E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-value-disclosure.utils.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"field-value-disclosure.utils.js","sourceRoot":"","sources":["../../../../src/resources/utils/field-value-disclosure.utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,UAAU,0BAA0B,CAAC,WAAyB;IAClE,OAAO,kBAAkB,CAAC,WAAW,CAAC,IAAI,sBAAsB,CAAC,WAAW,CAAC,CAAC;AAChF,CAAC","sourcesContent":["import type { z } from 'zod';\nimport { isBackendOnlyField, isWriteOnlySecretField } from '@wildo-ai/zod-decorators';\n\n/**\n * THE ONE RULE for \"may this field's VALUE leave the backend?\" — the disclosure seam every\n * outward-facing surface derives from, rather than restating.\n *\n * ## What it answers, and what it deliberately does not\n *\n * A field's value is non-disclosable when it is `.isBackendOnly()` (the response DTO drops it) or\n * `.isWriteOnlySecret()` (the response DTO masks it). Those two decorators ARE the disclosure\n * boundary; nothing else is. In particular:\n *\n * - `.isHidden()` gates CHART AGGREGATES (`field-access-validator`), which is a question about\n * which aggregate may expose a value, not about whether the value may be disclosed at all;\n * - `.isEphemeral()` gates the audit field-access trail and a one-time frontend display. An\n * ephemeral field is RETURNED — once, deliberately — so withholding it here would withhold\n * something the response contract promises.\n *\n * Adding either to this predicate would silently narrow surfaces that are working as designed, so\n * they are named here as considered-and-excluded rather than left to the next reader to re-derive.\n *\n * ## Why BOTH decorators are tested, rather than one implying the other\n *\n * They are independent decorators. A future authoring form — or an application — may set one\n * without the other, and a predicate that assumed the implication would open a disclosure path the\n * day that happened. This reasoning is not new: `isFieldWithheldFromSubjectExport` wrote it down\n * for the subject-export surface first, and this module is that rule extracted so the two surfaces\n * cannot drift apart.\n *\n * ## Why it exists as its own module (issue #95)\n *\n * The rule had TWO independent hand-written copies and one surface that carried only half of it:\n *\n * | surface | `.isBackendOnly()` | `.isWriteOnlySecret()` |\n * |---|---|---|\n * | response DTO / `toResponseSafeToolOutput` (REST, MCP `tools/call`, A2A resource tools) | dropped | masked |\n * | subject export (`isFieldWithheldFromSubjectExport`) | withheld | withheld |\n * | RAG retrieval row header (`getSummaryFieldNames`) | excluded | **rendered in full** |\n *\n * The third row is the defect this module closes. A resource may declare a field BOTH\n * `.isSummaryField()` and `.isWriteOnlySecret()` — nothing forbids it — and the retrieval header\n * would then render, verbatim and into a provider payload, the value the response DTO exists to\n * mask. No resource declares that pair today, so the hole was latent; the header is assembled from\n * declarations an application controls, so it stays latent only until one does.\n *\n * assurance-control: WILDO.DATA.CONFIDENTIALITY — material a schema declares non-disclosable does\n * not cross the client boundary. The registered objective names `.isBackendOnly()`; this rule is\n * where its sibling decorator `.isWriteOnlySecret()` is held to the same boundary, since both\n * describe a value the response DTO refuses to emit as authored.\n */\nexport function isNonDisclosableFieldValue(fieldSchema: z.ZodTypeAny): boolean {\n return isBackendOnlyField(fieldSchema) || isWriteOnlySecretField(fieldSchema);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-api-write-declaration.shared.utils.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"http-api-write-declaration.shared.utils.d.ts","sourceRoot":"","sources":["../../../../src/resources/utils/http-api-write-declaration.shared.utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAG7B,OAAO,EAEL,gBAAgB,EAChB,KAAK,sBAAsB,EAC5B,MAAM,wDAAwD,CAAC;AAChE,OAAO,EAAE,0CAA0C,EAAE,MAAM,uCAAuC,CAAC;AACnG,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,EAAE,oCAAoC,EAAE,MAAM,6BAA6B,CAAC;AAEnF;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,EAAE,QAAQ,CAAC,MAAM,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,CAIvG,CAAC;AAEH;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,aAAa,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAK5F;AAeD,6FAA6F;AAC7F,UAAU,0BAA0B;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,yHAAyH;IACzH,QAAQ,CAAC,mBAAmB,EAAE,SAAS,OAAO,EAAE,CAAC;IACjD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;QAC/B,QAAQ,CAAC,cAAc,CAAC,EAAE,0CAA0C,CAAC;QACrE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;KACtC,CAAC,CAAC;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,oCAAoC,CAAC;CACpE;AAED;;;;;;;;GAQG;AACH,wBAAgB,iCAAiC,CAC/C,cAAc,EAAE,SAAS,OAAO,EAAE,EAClC,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,GACrE,0BAA0B,EAAE,CAsB9B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,4CAA4C,CAC1D,QAAQ,EAAE,0CAA0C,GAAG,SAAS,EAChE,kBAAkB,EAAE,OAAO,GAC1B,0CAA0C,GAAG,SAAS,CAGxD;AAiFD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,sCAAsC,CAAC,MAAM,EAAE;IAC7D,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,QAAQ,CAAC,UAAU,EAAE,SAAS,0BAA0B,EAAE,CAAC;IAC3D,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC;CACnC,GAAG,IAAI,CA8GP"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-api-write-declaration.shared.utils.js","sourceRoot":"","sources":["../../../../../src/resources/utils/http-api-write-declaration.shared.utils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The authoring contract of a WRITABLE read-through resource (#1679) — what a resource must declare\n * before the engine will send a create, update or delete to a system of record it does not own.\n *\n * Checked in the resource FACTORY, at authoring, because every rule here is decidable from the one\n * file an author is writing: the binding, the operation list and the schema. What is NOT decidable\n * here — the instance's partition field, whether the dialect implements writes — needs the saas\n * configuration and the engine's dialect registry, so it is checked at boot registration instead.\n *\n * Every refusal names the fix. A write door into somebody else's ERP is the declaration where a\n * silently-accepted mistake costs the most, because the mistake is made against data the platform\n * cannot restore.\n */\n\nimport type { z } from 'zod';\nimport { getZodObjectShape, isExcludedFromCreate, isExcludedFromUpdate, isZodObject, unwrapSchema } from '@wildo-ai/zod-decorators';\n\nimport {\n HttpApiWriteConcurrencyMode,\n HttpApiWriteVerb,\n type HttpApiResourceBinding,\n} from '../../http-api-binding/http-api-binding.shared.schemas';\nimport { ResourceOperationIdempotencyKeyRequirement } from '../../requests/idempotency-key.shared';\nimport { CoreResourceOperation } from '../resources.shared.core.definitions';\nimport { ResourceOperation_ServiceRuntimeMode } from '../resources.shared.schemas';\n\n/**\n * The core operation each opened verb reaches, and the only three a read-through resource may write\n * through. Total over {@link HttpApiWriteVerb}, so a fourth verb is a compile error here until\n * somebody decides which operation it is.\n */\nexport const HTTP_API_WRITE_VERB_CORE_OPERATION: Readonly<Record<HttpApiWriteVerb, CoreResourceOperation>> = Object.freeze({\n [HttpApiWriteVerb.CREATE]: CoreResourceOperation.CREATE,\n [HttpApiWriteVerb.UPDATE]: CoreResourceOperation.UPDATE,\n [HttpApiWriteVerb.DELETE]: CoreResourceOperation.DELETE,\n});\n\n/**\n * The write verb a core operation IS on a read-through resource, or `undefined` for a read.\n *\n * The one mapping both the authoring check and the repository's dispatch read, so the two cannot\n * disagree about whether an operation is a write.\n */\nexport function resolveHttpApiWriteVerb(coreOperation: unknown): HttpApiWriteVerb | undefined {\n for (const [verb, operation] of Object.entries(HTTP_API_WRITE_VERB_CORE_OPERATION) as Array<[HttpApiWriteVerb, CoreResourceOperation]>) {\n if (operation === coreOperation) return verb;\n }\n return undefined;\n}\n\n/**\n * The BULK write operations, refused on a read-through resource whatever the binding opens.\n *\n * A bulk write against a system the platform does not own is N remote calls with no atomicity: any\n * of them can fail after the earlier ones landed, and there is no transaction to roll back into. The\n * engine opens single-row writes only, which is what an author can reason about one row at a time.\n */\nconst BULK_WRITE_OPERATIONS: ReadonlySet<unknown> = new Set<unknown>([\n CoreResourceOperation.CREATE_MANY,\n CoreResourceOperation.UPDATE_MANY,\n CoreResourceOperation.DELETE_MANY,\n]);\n\n/** What the factory knows about ONE declared operation, reduced to what these rules read. */\ninterface HttpApiWriteOperationFacts {\n readonly operationKey: string;\n /** The core semantics of each variant: the operation itself for a core one, `resourceOperationLike` for a custom one. */\n readonly effectiveOperations: readonly unknown[];\n readonly variants: ReadonlyArray<{\n readonly idempotencyKey?: ResourceOperationIdempotencyKeyRequirement;\n readonly haveBulkOperation?: boolean;\n }>;\n readonly serviceRuntimeMode?: ResourceOperation_ServiceRuntimeMode;\n}\n\n/**\n * Reduce the authored operation declarations to {@link HttpApiWriteOperationFacts}.\n *\n * Enumerated by EFFECTIVE semantics, the way the pipeline's CLOSED-population rule enumerates\n * creates: a core operation is its own semantics, a custom one borrows them per variant through\n * `resourceOperationLike`, and both sources are unioned because neither sees the other's members.\n * A custom operation that borrows UPDATE is exactly how an author would write a remote \"confirm\"\n * without thinking of it as a write — so it is a write here too.\n */\nexport function collectHttpApiWriteOperationFacts(\n coreOperations: readonly unknown[],\n operationsConfiguration: Readonly<Record<string, unknown>> | undefined,\n): HttpApiWriteOperationFacts[] {\n const facts = new Map<string, HttpApiWriteOperationFacts>();\n for (const operation of coreOperations) {\n facts.set(String(operation), { operationKey: String(operation), effectiveOperations: [operation], variants: [] });\n }\n for (const [operationKey, operationConfig] of Object.entries(operationsConfiguration ?? {})) {\n const config = (operationConfig ?? {}) as {\n variants?: Array<{ resourceOperationLike?: unknown; idempotencyKey?: ResourceOperationIdempotencyKeyRequirement; haveBulkOperation?: boolean }>;\n serviceRuntimeMode?: ResourceOperation_ServiceRuntimeMode;\n };\n const variants = config.variants ?? [];\n const isCore = coreOperations.includes(operationKey);\n facts.set(operationKey, {\n operationKey,\n effectiveOperations: variants.length > 0 && !isCore\n ? variants.map((variant) => variant.resourceOperationLike ?? operationKey)\n : [operationKey],\n variants,\n serviceRuntimeMode: config.serviceRuntimeMode,\n });\n }\n return [...facts.values()];\n}\n\n/**\n * The `Idempotency-Key` requirement a variant of a read-through WRITE carries — always REQUIRED.\n *\n * DERIVED rather than demanded from the author, because it has one legal value: a remote write cannot\n * be rolled back, so a retry after a lost response must replay the first outcome instead of writing a\n * second time, and only a required key makes every retry replayable. Asking an author to type the one\n * answer the mechanism already knows is a question nobody should be asked (`derive-before-you-ask`).\n * `ACCEPTED` is refused by {@link assertHttpApiWriteDeclarationCoherence}, never silently upgraded.\n *\n * The AUTHORED value comes first so the factory's forwarding line still reads\n * `idempotencyKey: resolveHttpApiWriteIdempotencyKeyRequirement(variantParams.idempotencyKey, …)`, the shape\n * `operation-variant-field-forwarding.guard.test.ts` recognises as forwarding.\n */\nexport function resolveHttpApiWriteIdempotencyKeyRequirement(\n authored: ResourceOperationIdempotencyKeyRequirement | undefined,\n isReadThroughWrite: boolean,\n): ResourceOperationIdempotencyKeyRequirement | undefined {\n if (!isReadThroughWrite) return authored;\n return ResourceOperationIdempotencyKeyRequirement.REQUIRED;\n}\n\n/** A resource operation a declared system-of-record action names as its HTTP door (`actions.<name>.operation`). */\ninterface SystemOfRecordActionDoor {\n readonly actionName: string;\n readonly writes: boolean;\n}\n\n/**\n * The operations the binding's declared actions name as their HTTP doors, keyed by operation.\n *\n * One operation runs one action: two actions naming the same door would make the operation's meaning depend on which\n * one its implementation happens to hand to the executor, so it is refused here rather than decided there.\n */\nfunction collectSystemOfRecordActionDoors(binding: HttpApiResourceBinding): ReadonlyMap<string, SystemOfRecordActionDoor> {\n const doors = new Map<string, SystemOfRecordActionDoor>();\n for (const [actionName, action] of Object.entries(binding.actions ?? {})) {\n if (action.operation === undefined) continue;\n const existing = doors.get(action.operation);\n if (existing !== undefined) {\n throw new Error(\n `operation '${action.operation}' is named as the door of two actions, '${existing.actionName}' and '${actionName}'. `\n + 'One operation runs one action; declare a second operation for the second action.',\n );\n }\n doors.set(action.operation, { actionName, writes: action.writes });\n }\n return doors;\n}\n\n/**\n * Hold an action's HTTP door to the ACTION's rules instead of the row-write rules (#1678 review, F1).\n *\n * A door does not write a row of the bound entity: its implementation hands the request to the system-of-record action\n * executor, which authorizes, confines, sends and audits the action. So `writableVerbs` does not open it, and it opens\n * nothing. What it must still be is honest about the effect it has:\n *\n * - a WRITING action changes remote state that cannot be rolled back, so every variant borrows a SINGLE-ROW mutation verb\n * (never a read: a read-shaped route is a GET and claims its repeat is harmless, and the boot validator refuses a key on\n * one), requires the `Idempotency-Key` (the executor refuses a writing action without one, so anything less is a door\n * that always refuses), and runs INLINE (a queued execution cannot carry the key);\n * - a NON-writing action (a vendor computation) is left to the ordinary rules for the verb it borrows.\n *\n * Never a bulk borrow: one request is one action on one target.\n */\nfunction assertSystemOfRecordActionDoorCoherence(operation: HttpApiWriteOperationFacts, door: SystemOfRecordActionDoor): void {\n const bulk = operation.effectiveOperations.find((effective) => BULK_WRITE_OPERATIONS.has(effective));\n if (bulk !== undefined) {\n throw new Error(\n `operation '${operation.operationKey}' is the door of action '${door.actionName}' and borrows a bulk verb ('${String(bulk)}'). `\n + 'One request runs one action on one target; borrow a single-row verb.',\n );\n }\n if (!door.writes) return;\n const readBorrow = operation.effectiveOperations.find((effective) => resolveHttpApiWriteVerb(effective) === undefined);\n if (readBorrow !== undefined) {\n throw new Error(\n `operation '${operation.operationKey}' is the door of action '${door.actionName}', which writes, and borrows '${String(readBorrow)}', `\n + 'which is not a mutation. A state-changing route must not be read-shaped: it would be a GET, and a required Idempotency-Key '\n + 'on a read is refused at boot. Borrow update (an action on one record) or create (an action that makes one) in resourceOperationLike.',\n );\n }\n const unkeyed = operation.variants.find((variant) => variant.idempotencyKey !== ResourceOperationIdempotencyKeyRequirement.REQUIRED);\n if (unkeyed !== undefined) {\n throw new Error(\n `operation '${operation.operationKey}' is the door of action '${door.actionName}', which writes, and does not require an `\n + 'Idempotency-Key on every variant. The executor refuses a writing action without one, so the route would refuse every request; '\n + `declare idempotencyKey: '${ResourceOperationIdempotencyKeyRequirement.REQUIRED}'.`,\n );\n }\n if (\n operation.serviceRuntimeMode !== undefined\n && operation.serviceRuntimeMode !== ResourceOperation_ServiceRuntimeMode.INLINE\n ) {\n throw new Error(\n `operation '${operation.operationKey}' is the door of action '${door.actionName}' and runs '${operation.serviceRuntimeMode}'. `\n + 'A writing action runs INLINE: a queued or background execution cannot carry its Idempotency-Key. Remove serviceRuntimeMode.',\n );\n }\n}\n\n/**\n * Refuse every write declaration on a read-through resource that the engine could not honour.\n *\n * Throws a plain `Error` naming the rule and the fix; the factory wraps it into its own configuration\n * error with the resource identifier in front.\n *\n * The rules, and why each one exists:\n *\n * 1. **No bulk write operation**, opened or not — see {@link BULK_WRITE_OPERATIONS}. Nor a\n * `haveBulkOperation` twin of a write, which every tier would run as N single-row writes.\n * 2. **Every write operation's verb is OPENED by the binding**, and **every opened verb has an\n * operation**. Both directions: the first is a route that would answer a refusal forever, the\n * second a declared door nobody can reach — and an inert declaration that looks like a control is\n * worse than none.\n * 3. **Every write variant runs INLINE.** A queued or background execution cannot carry the\n * `Idempotency-Key`, so a retried request could not replay; the service tier refuses a key on a\n * non-INLINE operation already, and a key is required here.\n * 4. **No write variant declares `Idempotency-Key: ACCEPTED`.** See\n * {@link resolveHttpApiWriteIdempotencyKeyRequirement}.\n * 5. *(Moved, #2010.)* The erasure-stance rule this list carried — a binding that WRITES personal-data fields\n * may not declare `NO_SUBJECT_DATA` — is now `personalFieldsContradictingNoSubjectDataStance`, which the\n * factory applies to EVERY read-through binding and every pipeline copy. Reading those fields out of a\n * system that \"holds no subject data\" is the same contradiction as writing them into it.\n * 6. **A `VERSION_CHECKED` binding's version field is one the UPDATE can carry and the CREATE cannot** (#1724). The\n * field must exist on the schema, be admitted to the update payload (the caller sends the version it read), and be\n * excluded from create (a new row has no version yet, and the vendor stamps it). It must be a STRING: the check\n * compares the caller's value byte for byte with the vendor's raw one, and a date schema would coerce it on the way\n * in and make every update stale. Whether it maps onto the vendor's `rowVersionField` needs the facet, and is\n * checked at boot.\n */\nexport function assertHttpApiWriteDeclarationCoherence(params: {\n readonly binding: HttpApiResourceBinding;\n readonly operations: readonly HttpApiWriteOperationFacts[];\n readonly mainSchema: z.ZodTypeAny;\n}): void {\n const { binding, operations, mainSchema } = params;\n const opened = new Set<HttpApiWriteVerb>(binding.writableVerbs);\n const reached = new Set<HttpApiWriteVerb>();\n const actionDoors = collectSystemOfRecordActionDoors(binding);\n // Checked BEFORE the operations: a door named after a missing operation usually means the author mistyped it, and the\n // operation they meant would otherwise be refused first as an unopened row write — a message about the wrong thing.\n const declaredOperationKeys = new Set(operations.map((operation) => operation.operationKey));\n for (const [operationKey, door] of actionDoors) {\n if (!declaredOperationKeys.has(operationKey)) {\n throw new Error(\n `actions.${door.actionName} names '${operationKey}' as its door, and this resource declares no such operation. `\n + 'Declare the custom operation, or remove the `operation` from the action.',\n );\n }\n }\n\n for (const operation of operations) {\n const door = actionDoors.get(operation.operationKey);\n if (door !== undefined) {\n assertSystemOfRecordActionDoorCoherence(operation, door);\n continue;\n }\n const bulk = operation.effectiveOperations.find((effective) => BULK_WRITE_OPERATIONS.has(effective));\n if (bulk !== undefined) {\n throw new Error(\n `operation '${operation.operationKey}' is a bulk write ('${String(bulk)}'), which a read-through resource never runs: `\n + 'N remote writes have no transaction to roll back into when one of them fails after the others landed. '\n + 'Declare the single-row create/update/delete instead.',\n );\n }\n const verbs = operation.effectiveOperations\n .map((effective) => resolveHttpApiWriteVerb(effective))\n .filter((verb): verb is HttpApiWriteVerb => verb !== undefined);\n if (verbs.length === 0) continue;\n\n for (const verb of verbs) {\n if (!opened.has(verb)) {\n throw new Error(\n `operation '${operation.operationKey}' writes ('${verb}'), and httpApiBinding.writableVerbs does not open '${verb}'. `\n + `Add '${verb}' to writableVerbs to open the write toward '${binding.system}', or remove the operation.`,\n );\n }\n reached.add(verb);\n }\n if (operation.variants.some((variant) => variant.haveBulkOperation === true)) {\n throw new Error(\n `operation '${operation.operationKey}' declares a bulk twin (haveBulkOperation), which a read-through resource never runs — `\n + 'one request would become N remote writes with no atomicity. Remove haveBulkOperation.',\n );\n }\n if (\n operation.serviceRuntimeMode !== undefined\n && operation.serviceRuntimeMode !== ResourceOperation_ServiceRuntimeMode.INLINE\n ) {\n throw new Error(\n `operation '${operation.operationKey}' writes to '${binding.system}' with serviceRuntimeMode '${operation.serviceRuntimeMode}'. `\n + 'A remote write runs INLINE: its Idempotency-Key is required, and a queued or background execution cannot carry one, '\n + 'so a retried request could not replay its first outcome. Remove serviceRuntimeMode.',\n );\n }\n const accepted = operation.variants.find((variant) => variant.idempotencyKey === ResourceOperationIdempotencyKeyRequirement.ACCEPTED);\n if (accepted !== undefined) {\n throw new Error(\n `operation '${operation.operationKey}' declares idempotencyKey 'accepted'. A write to a system of record cannot be rolled back, `\n + 'so every retry must replay the first outcome: the key is REQUIRED on every write variant, and the engine sets it for you. '\n + 'Remove the idempotencyKey declaration.',\n );\n }\n }\n\n for (const verb of opened) {\n if (!reached.has(verb)) {\n throw new Error(\n `httpApiBinding.writableVerbs opens '${verb}', and no operation of this resource performs it. An opened write nobody can `\n + `reach is a declaration that decides nothing; declare the ${HTTP_API_WRITE_VERB_CORE_OPERATION[verb]} operation, or remove the verb.`,\n );\n }\n }\n\n if (binding.writeConcurrency?.mode === HttpApiWriteConcurrencyMode.VERSION_CHECKED && isZodObject(mainSchema)) {\n const versionField = binding.writeConcurrency.versionField;\n const fieldSchema = getZodObjectShape(mainSchema)[versionField] as z.ZodTypeAny | undefined;\n if (fieldSchema === undefined) {\n throw new Error(\n `httpApiBinding.writeConcurrency.versionField names '${versionField}', which this resource's schema does not declare. `\n + 'Declare the field (mapped to the vendor\\'s row version, e.g. Odoo `write_date`) so a caller can read it and send it back.',\n );\n }\n const unwrapped = unwrapSchema(fieldSchema as never) as { _zod?: { def?: { type?: unknown } } };\n if (unwrapped?._zod?.def?.type !== 'string') {\n throw new Error(\n `httpApiBinding.writeConcurrency.versionField '${versionField}' must be a string schema: the version is compared byte for `\n + 'byte with what the vendor served (Odoo `write_date`, \"YYYY-MM-DD HH:MM:SS\"), and a date or number schema would re-format it.',\n );\n }\n if (isExcludedFromUpdate(fieldSchema)) {\n throw new Error(\n `httpApiBinding.writeConcurrency.versionField '${versionField}' is excluded from UPDATE, so no caller could send the version `\n + 'it read and every update would be refused. Remove .excludeFromUpdate() from it.',\n );\n }\n if (opened.has(HttpApiWriteVerb.CREATE) && !isExcludedFromCreate(fieldSchema)) {\n throw new Error(\n `httpApiBinding.writeConcurrency.versionField '${versionField}' may be sent on CREATE, and a new row has no version: the `\n + 'vendor stamps it. Declare it .excludeFromCreate().',\n );\n }\n }\n\n}\n"]}
|
|
1
|
+
{"version":3,"file":"http-api-write-declaration.shared.utils.js","sourceRoot":"","sources":["../../../../src/resources/utils/http-api-write-declaration.shared.utils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The authoring contract of a WRITABLE read-through resource (#1679) — what a resource must declare\n * before the engine will send a create, update or delete to a system of record it does not own.\n *\n * Checked in the resource FACTORY, at authoring, because every rule here is decidable from the one\n * file an author is writing: the binding, the operation list and the schema. What is NOT decidable\n * here — the instance's partition field, whether the dialect implements writes — needs the saas\n * configuration and the engine's dialect registry, so it is checked at boot registration instead.\n *\n * Every refusal names the fix. A write door into somebody else's ERP is the declaration where a\n * silently-accepted mistake costs the most, because the mistake is made against data the platform\n * cannot restore.\n */\n\nimport type { z } from 'zod';\nimport { getZodObjectShape, isExcludedFromCreate, isExcludedFromUpdate, isZodObject, unwrapSchema } from '@wildo-ai/zod-decorators';\n\nimport {\n HttpApiWriteConcurrencyMode,\n HttpApiWriteVerb,\n type HttpApiResourceBinding,\n} from '../../http-api-binding/http-api-binding.shared.schemas';\nimport { ResourceOperationIdempotencyKeyRequirement } from '../../requests/idempotency-key.shared';\nimport { CoreResourceOperation } from '../resources.shared.core.definitions';\nimport { ResourceOperation_ServiceRuntimeMode } from '../resources.shared.schemas';\n\n/**\n * The core operation each opened verb reaches, and the only three a read-through resource may write\n * through. Total over {@link HttpApiWriteVerb}, so a fourth verb is a compile error here until\n * somebody decides which operation it is.\n */\nexport const HTTP_API_WRITE_VERB_CORE_OPERATION: Readonly<Record<HttpApiWriteVerb, CoreResourceOperation>> = Object.freeze({\n [HttpApiWriteVerb.CREATE]: CoreResourceOperation.CREATE,\n [HttpApiWriteVerb.UPDATE]: CoreResourceOperation.UPDATE,\n [HttpApiWriteVerb.DELETE]: CoreResourceOperation.DELETE,\n});\n\n/**\n * The write verb a core operation IS on a read-through resource, or `undefined` for a read.\n *\n * The one mapping both the authoring check and the repository's dispatch read, so the two cannot\n * disagree about whether an operation is a write.\n */\nexport function resolveHttpApiWriteVerb(coreOperation: unknown): HttpApiWriteVerb | undefined {\n for (const [verb, operation] of Object.entries(HTTP_API_WRITE_VERB_CORE_OPERATION) as Array<[HttpApiWriteVerb, CoreResourceOperation]>) {\n if (operation === coreOperation) return verb;\n }\n return undefined;\n}\n\n/**\n * The BULK write operations, refused on a read-through resource whatever the binding opens.\n *\n * A bulk write against a system the platform does not own is N remote calls with no atomicity: any\n * of them can fail after the earlier ones landed, and there is no transaction to roll back into. The\n * engine opens single-row writes only, which is what an author can reason about one row at a time.\n */\nconst BULK_WRITE_OPERATIONS: ReadonlySet<unknown> = new Set<unknown>([\n CoreResourceOperation.CREATE_MANY,\n CoreResourceOperation.UPDATE_MANY,\n CoreResourceOperation.DELETE_MANY,\n]);\n\n/** What the factory knows about ONE declared operation, reduced to what these rules read. */\ninterface HttpApiWriteOperationFacts {\n readonly operationKey: string;\n /** The core semantics of each variant: the operation itself for a core one, `resourceOperationLike` for a custom one. */\n readonly effectiveOperations: readonly unknown[];\n readonly variants: ReadonlyArray<{\n readonly idempotencyKey?: ResourceOperationIdempotencyKeyRequirement;\n readonly haveBulkOperation?: boolean;\n }>;\n readonly serviceRuntimeMode?: ResourceOperation_ServiceRuntimeMode;\n}\n\n/**\n * Reduce the authored operation declarations to {@link HttpApiWriteOperationFacts}.\n *\n * Enumerated by EFFECTIVE semantics, the way the pipeline's CLOSED-population rule enumerates\n * creates: a core operation is its own semantics, a custom one borrows them per variant through\n * `resourceOperationLike`, and both sources are unioned because neither sees the other's members.\n * A custom operation that borrows UPDATE is exactly how an author would write a remote \"confirm\"\n * without thinking of it as a write — so it is a write here too.\n */\nexport function collectHttpApiWriteOperationFacts(\n coreOperations: readonly unknown[],\n operationsConfiguration: Readonly<Record<string, unknown>> | undefined,\n): HttpApiWriteOperationFacts[] {\n const facts = new Map<string, HttpApiWriteOperationFacts>();\n for (const operation of coreOperations) {\n facts.set(String(operation), { operationKey: String(operation), effectiveOperations: [operation], variants: [] });\n }\n for (const [operationKey, operationConfig] of Object.entries(operationsConfiguration ?? {})) {\n const config = (operationConfig ?? {}) as {\n variants?: Array<{ resourceOperationLike?: unknown; idempotencyKey?: ResourceOperationIdempotencyKeyRequirement; haveBulkOperation?: boolean }>;\n serviceRuntimeMode?: ResourceOperation_ServiceRuntimeMode;\n };\n const variants = config.variants ?? [];\n const isCore = coreOperations.includes(operationKey);\n facts.set(operationKey, {\n operationKey,\n effectiveOperations: variants.length > 0 && !isCore\n ? variants.map((variant) => variant.resourceOperationLike ?? operationKey)\n : [operationKey],\n variants,\n serviceRuntimeMode: config.serviceRuntimeMode,\n });\n }\n return [...facts.values()];\n}\n\n/**\n * The `Idempotency-Key` requirement a variant of a read-through WRITE carries — always REQUIRED.\n *\n * DERIVED rather than demanded from the author, because it has one legal value: a remote write cannot\n * be rolled back, so a retry after a lost response must replay the first outcome instead of writing a\n * second time, and only a required key makes every retry replayable. Asking an author to type the one\n * answer the mechanism already knows is a question nobody should be asked (`derive-before-you-ask`).\n * `ACCEPTED` is refused by {@link assertHttpApiWriteDeclarationCoherence}, never silently upgraded.\n *\n * The AUTHORED value comes first so the factory's forwarding line still reads\n * `idempotencyKey: resolveHttpApiWriteIdempotencyKeyRequirement(variantParams.idempotencyKey, …)`, the shape\n * `operation-variant-field-forwarding.guard.test.ts` recognises as forwarding.\n */\nexport function resolveHttpApiWriteIdempotencyKeyRequirement(\n authored: ResourceOperationIdempotencyKeyRequirement | undefined,\n isReadThroughWrite: boolean,\n): ResourceOperationIdempotencyKeyRequirement | undefined {\n if (!isReadThroughWrite) return authored;\n return ResourceOperationIdempotencyKeyRequirement.REQUIRED;\n}\n\n/** A resource operation a declared system-of-record action names as its HTTP door (`actions.<name>.operation`). */\ninterface SystemOfRecordActionDoor {\n readonly actionName: string;\n readonly writes: boolean;\n}\n\n/**\n * The operations the binding's declared actions name as their HTTP doors, keyed by operation.\n *\n * One operation runs one action: two actions naming the same door would make the operation's meaning depend on which\n * one its implementation happens to hand to the executor, so it is refused here rather than decided there.\n */\nfunction collectSystemOfRecordActionDoors(binding: HttpApiResourceBinding): ReadonlyMap<string, SystemOfRecordActionDoor> {\n const doors = new Map<string, SystemOfRecordActionDoor>();\n for (const [actionName, action] of Object.entries(binding.actions ?? {})) {\n if (action.operation === undefined) continue;\n const existing = doors.get(action.operation);\n if (existing !== undefined) {\n throw new Error(\n `operation '${action.operation}' is named as the door of two actions, '${existing.actionName}' and '${actionName}'. `\n + 'One operation runs one action; declare a second operation for the second action.',\n );\n }\n doors.set(action.operation, { actionName, writes: action.writes });\n }\n return doors;\n}\n\n/**\n * Hold an action's HTTP door to the ACTION's rules instead of the row-write rules (#1678 review, F1).\n *\n * A door does not write a row of the bound entity: its implementation hands the request to the system-of-record action\n * executor, which authorizes, confines, sends and audits the action. So `writableVerbs` does not open it, and it opens\n * nothing. What it must still be is honest about the effect it has:\n *\n * - a WRITING action changes remote state that cannot be rolled back, so every variant borrows a SINGLE-ROW mutation verb\n * (never a read: a read-shaped route is a GET and claims its repeat is harmless, and the boot validator refuses a key on\n * one), requires the `Idempotency-Key` (the executor refuses a writing action without one, so anything less is a door\n * that always refuses), and runs INLINE (a queued execution cannot carry the key);\n * - a NON-writing action (a vendor computation) is left to the ordinary rules for the verb it borrows.\n *\n * Never a bulk borrow: one request is one action on one target.\n */\nfunction assertSystemOfRecordActionDoorCoherence(operation: HttpApiWriteOperationFacts, door: SystemOfRecordActionDoor): void {\n const bulk = operation.effectiveOperations.find((effective) => BULK_WRITE_OPERATIONS.has(effective));\n if (bulk !== undefined) {\n throw new Error(\n `operation '${operation.operationKey}' is the door of action '${door.actionName}' and borrows a bulk verb ('${String(bulk)}'). `\n + 'One request runs one action on one target; borrow a single-row verb.',\n );\n }\n if (!door.writes) return;\n const readBorrow = operation.effectiveOperations.find((effective) => resolveHttpApiWriteVerb(effective) === undefined);\n if (readBorrow !== undefined) {\n throw new Error(\n `operation '${operation.operationKey}' is the door of action '${door.actionName}', which writes, and borrows '${String(readBorrow)}', `\n + 'which is not a mutation. A state-changing route must not be read-shaped: it would be a GET, and a required Idempotency-Key '\n + 'on a read is refused at boot. Borrow update (an action on one record) or create (an action that makes one) in resourceOperationLike.',\n );\n }\n const unkeyed = operation.variants.find((variant) => variant.idempotencyKey !== ResourceOperationIdempotencyKeyRequirement.REQUIRED);\n if (unkeyed !== undefined) {\n throw new Error(\n `operation '${operation.operationKey}' is the door of action '${door.actionName}', which writes, and does not require an `\n + 'Idempotency-Key on every variant. The executor refuses a writing action without one, so the route would refuse every request; '\n + `declare idempotencyKey: '${ResourceOperationIdempotencyKeyRequirement.REQUIRED}'.`,\n );\n }\n if (\n operation.serviceRuntimeMode !== undefined\n && operation.serviceRuntimeMode !== ResourceOperation_ServiceRuntimeMode.INLINE\n ) {\n throw new Error(\n `operation '${operation.operationKey}' is the door of action '${door.actionName}' and runs '${operation.serviceRuntimeMode}'. `\n + 'A writing action runs INLINE: a queued or background execution cannot carry its Idempotency-Key. Remove serviceRuntimeMode.',\n );\n }\n}\n\n/**\n * Refuse every write declaration on a read-through resource that the engine could not honour.\n *\n * Throws a plain `Error` naming the rule and the fix; the factory wraps it into its own configuration\n * error with the resource identifier in front.\n *\n * The rules, and why each one exists:\n *\n * 1. **No bulk write operation**, opened or not — see {@link BULK_WRITE_OPERATIONS}. Nor a\n * `haveBulkOperation` twin of a write, which every tier would run as N single-row writes.\n * 2. **Every write operation's verb is OPENED by the binding**, and **every opened verb has an\n * operation**. Both directions: the first is a route that would answer a refusal forever, the\n * second a declared door nobody can reach — and an inert declaration that looks like a control is\n * worse than none.\n * 3. **Every write variant runs INLINE.** A queued or background execution cannot carry the\n * `Idempotency-Key`, so a retried request could not replay; the service tier refuses a key on a\n * non-INLINE operation already, and a key is required here.\n * 4. **No write variant declares `Idempotency-Key: ACCEPTED`.** See\n * {@link resolveHttpApiWriteIdempotencyKeyRequirement}.\n * 5. *(Moved, #2010.)* The erasure-stance rule this list carried — a binding that WRITES personal-data fields\n * may not declare `NO_SUBJECT_DATA` — is now `personalFieldsContradictingNoSubjectDataStance`, which the\n * factory applies to EVERY read-through binding and every pipeline copy. Reading those fields out of a\n * system that \"holds no subject data\" is the same contradiction as writing them into it.\n * 6. **A `VERSION_CHECKED` binding's version field is one the UPDATE can carry and the CREATE cannot** (#1724). The\n * field must exist on the schema, be admitted to the update payload (the caller sends the version it read), and be\n * excluded from create (a new row has no version yet, and the vendor stamps it). It must be a STRING: the check\n * compares the caller's value byte for byte with the vendor's raw one, and a date schema would coerce it on the way\n * in and make every update stale. Whether it maps onto the vendor's `rowVersionField` needs the facet, and is\n * checked at boot.\n */\nexport function assertHttpApiWriteDeclarationCoherence(params: {\n readonly binding: HttpApiResourceBinding;\n readonly operations: readonly HttpApiWriteOperationFacts[];\n readonly mainSchema: z.ZodTypeAny;\n}): void {\n const { binding, operations, mainSchema } = params;\n const opened = new Set<HttpApiWriteVerb>(binding.writableVerbs);\n const reached = new Set<HttpApiWriteVerb>();\n const actionDoors = collectSystemOfRecordActionDoors(binding);\n // Checked BEFORE the operations: a door named after a missing operation usually means the author mistyped it, and the\n // operation they meant would otherwise be refused first as an unopened row write — a message about the wrong thing.\n const declaredOperationKeys = new Set(operations.map((operation) => operation.operationKey));\n for (const [operationKey, door] of actionDoors) {\n if (!declaredOperationKeys.has(operationKey)) {\n throw new Error(\n `actions.${door.actionName} names '${operationKey}' as its door, and this resource declares no such operation. `\n + 'Declare the custom operation, or remove the `operation` from the action.',\n );\n }\n }\n\n for (const operation of operations) {\n const door = actionDoors.get(operation.operationKey);\n if (door !== undefined) {\n assertSystemOfRecordActionDoorCoherence(operation, door);\n continue;\n }\n const bulk = operation.effectiveOperations.find((effective) => BULK_WRITE_OPERATIONS.has(effective));\n if (bulk !== undefined) {\n throw new Error(\n `operation '${operation.operationKey}' is a bulk write ('${String(bulk)}'), which a read-through resource never runs: `\n + 'N remote writes have no transaction to roll back into when one of them fails after the others landed. '\n + 'Declare the single-row create/update/delete instead.',\n );\n }\n const verbs = operation.effectiveOperations\n .map((effective) => resolveHttpApiWriteVerb(effective))\n .filter((verb): verb is HttpApiWriteVerb => verb !== undefined);\n if (verbs.length === 0) continue;\n\n for (const verb of verbs) {\n if (!opened.has(verb)) {\n throw new Error(\n `operation '${operation.operationKey}' writes ('${verb}'), and httpApiBinding.writableVerbs does not open '${verb}'. `\n + `Add '${verb}' to writableVerbs to open the write toward '${binding.system}', or remove the operation.`,\n );\n }\n reached.add(verb);\n }\n if (operation.variants.some((variant) => variant.haveBulkOperation === true)) {\n throw new Error(\n `operation '${operation.operationKey}' declares a bulk twin (haveBulkOperation), which a read-through resource never runs — `\n + 'one request would become N remote writes with no atomicity. Remove haveBulkOperation.',\n );\n }\n if (\n operation.serviceRuntimeMode !== undefined\n && operation.serviceRuntimeMode !== ResourceOperation_ServiceRuntimeMode.INLINE\n ) {\n throw new Error(\n `operation '${operation.operationKey}' writes to '${binding.system}' with serviceRuntimeMode '${operation.serviceRuntimeMode}'. `\n + 'A remote write runs INLINE: its Idempotency-Key is required, and a queued or background execution cannot carry one, '\n + 'so a retried request could not replay its first outcome. Remove serviceRuntimeMode.',\n );\n }\n const accepted = operation.variants.find((variant) => variant.idempotencyKey === ResourceOperationIdempotencyKeyRequirement.ACCEPTED);\n if (accepted !== undefined) {\n throw new Error(\n `operation '${operation.operationKey}' declares idempotencyKey 'accepted'. A write to a system of record cannot be rolled back, `\n + 'so every retry must replay the first outcome: the key is REQUIRED on every write variant, and the engine sets it for you. '\n + 'Remove the idempotencyKey declaration.',\n );\n }\n }\n\n for (const verb of opened) {\n if (!reached.has(verb)) {\n throw new Error(\n `httpApiBinding.writableVerbs opens '${verb}', and no operation of this resource performs it. An opened write nobody can `\n + `reach is a declaration that decides nothing; declare the ${HTTP_API_WRITE_VERB_CORE_OPERATION[verb]} operation, or remove the verb.`,\n );\n }\n }\n\n if (binding.writeConcurrency?.mode === HttpApiWriteConcurrencyMode.VERSION_CHECKED && isZodObject(mainSchema)) {\n const versionField = binding.writeConcurrency.versionField;\n const fieldSchema = getZodObjectShape(mainSchema)[versionField] as z.ZodTypeAny | undefined;\n if (fieldSchema === undefined) {\n throw new Error(\n `httpApiBinding.writeConcurrency.versionField names '${versionField}', which this resource's schema does not declare. `\n + 'Declare the field (mapped to the vendor\\'s row version, e.g. Odoo `write_date`) so a caller can read it and send it back.',\n );\n }\n const unwrapped = unwrapSchema(fieldSchema as never) as { _zod?: { def?: { type?: unknown } } };\n if (unwrapped?._zod?.def?.type !== 'string') {\n throw new Error(\n `httpApiBinding.writeConcurrency.versionField '${versionField}' must be a string schema: the version is compared byte for `\n + 'byte with what the vendor served (Odoo `write_date`, \"YYYY-MM-DD HH:MM:SS\"), and a date or number schema would re-format it.',\n );\n }\n if (isExcludedFromUpdate(fieldSchema)) {\n throw new Error(\n `httpApiBinding.writeConcurrency.versionField '${versionField}' is excluded from UPDATE, so no caller could send the version `\n + 'it read and every update would be refused. Remove .excludeFromUpdate() from it.',\n );\n }\n if (opened.has(HttpApiWriteVerb.CREATE) && !isExcludedFromCreate(fieldSchema)) {\n throw new Error(\n `httpApiBinding.writeConcurrency.versionField '${versionField}' may be sent on CREATE, and a new row has no version: the `\n + 'vendor stamps it. Declare it .excludeFromCreate().',\n );\n }\n }\n\n}\n"]}
|