@wildo-ai/saas-models 1.1.2 → 1.1.3
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/applications/applications-context.schemas.d.ts +14 -10
- package/dist/esm/applications/applications-context.schemas.d.ts.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 +4 -3
- package/dist/esm/applications/applications.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/billing/billing-configuration.shared.schemas.d.ts +0 -4
- package/dist/esm/billing/billing-configuration.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/billing-configuration.shared.schemas.js +59 -17
- package/dist/esm/billing/billing-configuration.shared.schemas.js.map +1 -1
- package/dist/esm/billing/billing-enums.shared.schemas.d.ts +77 -21
- package/dist/esm/billing/billing-enums.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/billing-enums.shared.schemas.js +85 -23
- package/dist/esm/billing/billing-enums.shared.schemas.js.map +1 -1
- package/dist/esm/billing/billing-types.shared.schemas.d.ts +3 -3
- package/dist/esm/billing/price.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/price.shared.schemas.js +7 -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 +52 -11
- package/dist/esm/billing/product-behavior-policy.shared.schemas.js.map +1 -1
- package/dist/esm/billing/product-definition.shared.schemas.d.ts +2 -2
- package/dist/esm/billing/product.shared.resources-config.schemas.d.ts +2 -2
- package/dist/esm/billing/product.shared.schemas.d.ts +2 -2
- package/dist/esm/billing/product.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/product.shared.schemas.js +7 -3
- package/dist/esm/billing/product.shared.schemas.js.map +1 -1
- package/dist/esm/billing/subscription.shared.resources-config.schemas.d.ts +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 +15 -1
- package/dist/esm/billing/subscription.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/billing/usage-record.shared.schemas.d.ts +7 -3
- package/dist/esm/billing/usage-record.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/usage-record.shared.schemas.js +22 -3
- package/dist/esm/billing/usage-record.shared.schemas.js.map +1 -1
- package/dist/esm/companion/provider-discovery.shared.schemas.d.ts +69 -2
- package/dist/esm/companion/provider-discovery.shared.schemas.d.ts.map +1 -1
- package/dist/esm/companion/provider-discovery.shared.schemas.js +20 -1
- package/dist/esm/companion/provider-discovery.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/audit-trails/application-audit-logs.shared.resources-config.schemas.d.ts +85 -0
- package/dist/esm/compliance/audit-trails/application-audit-logs.shared.resources-config.schemas.d.ts.map +1 -0
- package/dist/esm/compliance/audit-trails/application-audit-logs.shared.resources-config.schemas.js +157 -0
- package/dist/esm/compliance/audit-trails/application-audit-logs.shared.resources-config.schemas.js.map +1 -0
- package/dist/esm/compliance/audit-trails/audit-trail-config.shared.schemas.d.ts +23 -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 +56 -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 +480 -20
- 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 +547 -23
- package/dist/esm/compliance/audit-trails/auditable-events.shared.schema.js.map +1 -1
- package/dist/esm/compliance/audit-trails/security-audit-event-envelope.shared.schema.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/security-audit-event-envelope.shared.schema.js +82 -3
- package/dist/esm/compliance/audit-trails/security-audit-event-envelope.shared.schema.js.map +1 -1
- package/dist/esm/compliance/privacy/operating-jurisdictions.shared.schemas.d.ts +31 -30
- package/dist/esm/compliance/privacy/operating-jurisdictions.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/operating-jurisdictions.shared.schemas.js +98 -3
- package/dist/esm/compliance/privacy/operating-jurisdictions.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/privacy.shared.schemas.d.ts +17 -0
- package/dist/esm/compliance/privacy/privacy.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/privacy.shared.schemas.js +27 -4
- package/dist/esm/compliance/privacy/privacy.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/redaction.shared.schemas.d.ts +82 -29
- package/dist/esm/compliance/privacy/redaction.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/redaction.shared.schemas.js +95 -29
- package/dist/esm/compliance/privacy/redaction.shared.schemas.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 +12 -5
- package/dist/esm/compliance/privacy/subject-export.shared.schemas.js.map +1 -1
- package/dist/esm/config/analytics-value-moments.shared.schemas.d.ts +21 -0
- package/dist/esm/config/analytics-value-moments.shared.schemas.d.ts.map +1 -1
- package/dist/esm/config/analytics-value-moments.shared.schemas.js +20 -0
- package/dist/esm/config/analytics-value-moments.shared.schemas.js.map +1 -1
- package/dist/esm/config/app-configuration-shared.shared.schemas.d.ts +7 -5
- package/dist/esm/config/app-configuration-shared.shared.schemas.d.ts.map +1 -1
- package/dist/esm/config/auth-config-resolution.shared.utils.d.ts +8 -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 +29 -0
- package/dist/esm/config/auth-config-resolution.shared.utils.js.map +1 -1
- package/dist/esm/config/entity-identity-config.shared.schemas.d.ts +95 -17
- package/dist/esm/config/entity-identity-config.shared.schemas.d.ts.map +1 -1
- package/dist/esm/config/entity-identity-config.shared.schemas.js +86 -8
- package/dist/esm/config/entity-identity-config.shared.schemas.js.map +1 -1
- package/dist/esm/config/frontend/chart-definition.shared.schemas.d.ts +12 -12
- package/dist/esm/errors/errors.custom-message-ref.shared.definitions.d.ts +28 -0
- 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 +28 -0
- package/dist/esm/errors/errors.custom-message-ref.shared.definitions.js.map +1 -1
- package/dist/esm/external-data/external-data-pipeline.shared.schemas.d.ts +45 -12
- 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-providers/engine-capabilities.shared.schemas.d.ts +103 -58
- package/dist/esm/external-providers/engine-capabilities.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/engine-capabilities.shared.schemas.js +176 -15
- 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 +15 -3
- 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 +32 -5
- package/dist/esm/external-providers/engine-capability-resolution-mode.shared.js.map +1 -1
- package/dist/esm/external-providers/frontend-bootstrap.shared.schemas.d.ts +83 -7
- package/dist/esm/external-providers/frontend-bootstrap.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/frontend-capability-public-config.shared.schemas.d.ts +59 -0
- package/dist/esm/external-providers/frontend-capability-public-config.shared.schemas.d.ts.map +1 -0
- package/dist/esm/external-providers/frontend-capability-public-config.shared.schemas.js +61 -0
- package/dist/esm/external-providers/frontend-capability-public-config.shared.schemas.js.map +1 -0
- package/dist/esm/external-providers/frontend-capability-runtime.shared.types.d.ts +97 -0
- package/dist/esm/external-providers/frontend-capability-runtime.shared.types.d.ts.map +1 -0
- package/dist/esm/external-providers/frontend-capability-runtime.shared.types.js +41 -0
- package/dist/esm/external-providers/frontend-capability-runtime.shared.types.js.map +1 -0
- package/dist/esm/external-providers/frontend-provider-entry.shared.schemas.d.ts +148 -2
- 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 +56 -1
- package/dist/esm/external-providers/frontend-provider-entry.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/provider-capability.shared.schemas.d.ts +5 -28
- package/dist/esm/external-providers/provider-capability.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-capability.shared.schemas.js +4 -2
- 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 +18 -8
- 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 +9 -4
- package/dist/esm/external-providers/provider-compliance-profile.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/provider-frontend-surface.shared.schemas.d.ts +338 -0
- package/dist/esm/external-providers/provider-frontend-surface.shared.schemas.d.ts.map +1 -0
- package/dist/esm/external-providers/provider-frontend-surface.shared.schemas.js +332 -0
- package/dist/esm/external-providers/provider-frontend-surface.shared.schemas.js.map +1 -0
- package/dist/esm/external-providers/provider-metadata.shared.schemas.d.ts +178 -9
- package/dist/esm/external-providers/provider-metadata.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-metadata.shared.schemas.js +181 -9
- package/dist/esm/external-providers/provider-metadata.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/provider-protocol.shared.schemas.d.ts +7 -5
- package/dist/esm/external-providers/provider-protocol.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-protocol.shared.schemas.js +7 -5
- package/dist/esm/external-providers/provider-protocol.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/provider-tier-rule.shared.utils.d.ts +40 -0
- package/dist/esm/external-providers/provider-tier-rule.shared.utils.d.ts.map +1 -0
- package/dist/esm/external-providers/provider-tier-rule.shared.utils.js +80 -0
- package/dist/esm/external-providers/provider-tier-rule.shared.utils.js.map +1 -0
- package/dist/esm/features/core-feature-definitions.shared.d.ts.map +1 -1
- package/dist/esm/features/core-feature-definitions.shared.js +7 -1
- package/dist/esm/features/core-feature-definitions.shared.js.map +1 -1
- package/dist/esm/features/feature-builders.shared.d.ts +32 -0
- package/dist/esm/features/feature-builders.shared.d.ts.map +1 -1
- package/dist/esm/features/feature-builders.shared.js +32 -0
- package/dist/esm/features/feature-builders.shared.js.map +1 -1
- package/dist/esm/files/file-upload-grant.shared.schemas.d.ts +14 -2
- package/dist/esm/files/file-upload-grant.shared.schemas.d.ts.map +1 -1
- package/dist/esm/files/file-upload-grant.shared.schemas.js +44 -5
- package/dist/esm/files/file-upload-grant.shared.schemas.js.map +1 -1
- package/dist/esm/files/files.shared.schemas.d.ts +15 -8
- package/dist/esm/files/files.shared.schemas.d.ts.map +1 -1
- package/dist/esm/files/files.shared.schemas.js +15 -8
- package/dist/esm/files/files.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 +3 -2
- package/dist/esm/flows-actors/actors.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/agents.shared.schemas.d.ts +54 -5
- 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/apps-blueprint/apps-blueprint.shared.schemas.d.ts +6 -6
- package/dist/esm/flows-actors/deliberation.shared.schemas.d.ts +0 -3
- package/dist/esm/flows-actors/deliberation.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/deliberation.shared.schemas.js +0 -5
- package/dist/esm/flows-actors/deliberation.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/flows-actors-execution.shared.schemas.d.ts +14 -0
- 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 +40 -3
- package/dist/esm/flows-actors/flows-actors-execution.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/flows-actors.commons.shared.schemas.d.ts +19 -0
- 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 +33 -0
- package/dist/esm/flows-actors/flows-actors.commons.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/flows-actors.io.shared.schemas.d.ts +14 -9
- 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 +14 -9
- package/dist/esm/flows-actors/flows-actors.io.shared.schemas.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 +3 -2
- 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 +3 -2
- package/dist/esm/flows-actors/flows.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/mcp-servers.shared.schemas.d.ts +128 -0
- package/dist/esm/flows-actors/mcp-servers.shared.schemas.d.ts.map +1 -0
- package/dist/esm/flows-actors/mcp-servers.shared.schemas.js +142 -0
- package/dist/esm/flows-actors/mcp-servers.shared.schemas.js.map +1 -0
- package/dist/esm/flows-actors/meta-workflows/budget-authority.meta-workflows.shared.schemas.d.ts +0 -3
- package/dist/esm/flows-actors/meta-workflows/budget-authority.meta-workflows.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/meta-workflows/budget-authority.meta-workflows.shared.schemas.js +1 -4
- package/dist/esm/flows-actors/meta-workflows/budget-authority.meta-workflows.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/meta-workflows/context-selection.meta-workflows.shared.schemas.d.ts +0 -16
- package/dist/esm/flows-actors/meta-workflows/context-selection.meta-workflows.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/meta-workflows/context-selection.meta-workflows.shared.schemas.js +1 -17
- package/dist/esm/flows-actors/meta-workflows/context-selection.meta-workflows.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/meta-workflows/decisions.meta-workflows.shared.schemas.d.ts +3 -3
- package/dist/esm/flows-actors/meta-workflows/decisions.meta-workflows.shared.schemas.js +3 -3
- package/dist/esm/flows-actors/meta-workflows/decisions.meta-workflows.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/meta-workflows/execution-binding-common.meta-workflows.shared.schemas.d.ts +2 -8
- package/dist/esm/flows-actors/meta-workflows/execution-binding-common.meta-workflows.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/meta-workflows/execution-binding-common.meta-workflows.shared.schemas.js +4 -15
- package/dist/esm/flows-actors/meta-workflows/execution-binding-common.meta-workflows.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 +1 -0
- package/dist/esm/guidance/guidance-state.shared.utils.js.map +1 -1
- package/dist/esm/guidance/progression-state.shared.resources-config.schemas.d.ts +8 -0
- package/dist/esm/guidance/progression-state.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/progression-state.shared.schemas.d.ts +46 -0
- package/dist/esm/guidance/progression-state.shared.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/progression-state.shared.schemas.js +49 -0
- package/dist/esm/guidance/progression-state.shared.schemas.js.map +1 -1
- package/dist/esm/http-api-binding/http-api-binding.shared.schemas.d.ts +320 -50
- 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 +137 -36
- package/dist/esm/http-api-binding/http-api-binding.shared.schemas.js.map +1 -1
- package/dist/esm/index.d.ts +9 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +9 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/notifications/email/email-template-registry.shared.schemas.d.ts +11 -2
- 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 +15 -0
- package/dist/esm/notifications/email/email-template.shared.enums.d.ts.map +1 -1
- package/dist/esm/notifications/email/email-template.shared.enums.js +15 -0
- package/dist/esm/notifications/email/email-template.shared.enums.js.map +1 -1
- package/dist/esm/notifications/m2m/webhook-config.shared.resources-config.schemas.d.ts +1 -0
- 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 +19 -0
- 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 +30 -0
- package/dist/esm/notifications/m2m/webhook-config.shared.schemas.d.ts.map +1 -1
- package/dist/esm/notifications/m2m/webhook-config.shared.schemas.js +65 -1
- package/dist/esm/notifications/m2m/webhook-config.shared.schemas.js.map +1 -1
- package/dist/esm/notifications/notification-badges.core.definitions.d.ts +6 -4
- package/dist/esm/notifications/notification-badges.core.definitions.d.ts.map +1 -1
- package/dist/esm/notifications/notification-badges.core.definitions.js +6 -4
- package/dist/esm/notifications/notification-badges.core.definitions.js.map +1 -1
- package/dist/esm/notifications/notification-badges.schemas.d.ts +167 -5
- package/dist/esm/notifications/notification-badges.schemas.d.ts.map +1 -1
- package/dist/esm/notifications/notification-badges.schemas.js +191 -6
- package/dist/esm/notifications/notification-badges.schemas.js.map +1 -1
- package/dist/esm/notifications/notifications.shared.schemas.d.ts +107 -0
- package/dist/esm/notifications/notifications.shared.schemas.d.ts.map +1 -1
- package/dist/esm/notifications/notifications.shared.schemas.js +149 -1
- package/dist/esm/notifications/notifications.shared.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 +22 -1
- package/dist/esm/organizations/organization-notifications.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-preferences.shared.schemas.d.ts +26 -0
- package/dist/esm/organizations/organization-preferences.shared.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-preferences.shared.schemas.js +25 -0
- package/dist/esm/organizations/organization-preferences.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-profile.shared.schemas.d.ts +25 -0
- package/dist/esm/organizations/organization-profile.shared.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-profile.shared.schemas.js +42 -17
- package/dist/esm/organizations/organization-profile.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-unit-narrowing.shared.d.ts +3 -2
- package/dist/esm/organizations/organization-unit-narrowing.shared.d.ts.map +1 -1
- package/dist/esm/organizations/organization-unit-narrowing.shared.js +9 -2
- package/dist/esm/organizations/organization-unit-narrowing.shared.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 +18 -3
- package/dist/esm/organizations/organizations.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/public-runtime/index.d.ts +49 -2
- package/dist/esm/public-runtime/index.d.ts.map +1 -1
- package/dist/esm/public-runtime/index.js +48 -1
- package/dist/esm/public-runtime/index.js.map +1 -1
- package/dist/esm/queue/jobs.shared.resources-config.schemas.d.ts +6 -5
- package/dist/esm/queue/jobs.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/queue/jobs.shared.resources-config.schemas.js +6 -5
- package/dist/esm/queue/jobs.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/queue/jobs.shared.schemas.d.ts +16 -3
- package/dist/esm/queue/jobs.shared.schemas.d.ts.map +1 -1
- package/dist/esm/queue/jobs.shared.schemas.js +16 -3
- package/dist/esm/queue/jobs.shared.schemas.js.map +1 -1
- package/dist/esm/requests/manual-controllers-routes-documentation.d.ts +137 -0
- package/dist/esm/requests/manual-controllers-routes-documentation.d.ts.map +1 -0
- package/dist/esm/requests/manual-controllers-routes-documentation.js +1201 -0
- package/dist/esm/requests/manual-controllers-routes-documentation.js.map +1 -0
- package/dist/esm/requests/manual-controllers-routes-urls.d.ts +67 -0
- package/dist/esm/requests/manual-controllers-routes-urls.d.ts.map +1 -1
- package/dist/esm/requests/manual-controllers-routes-urls.js +78 -0
- package/dist/esm/requests/manual-controllers-routes-urls.js.map +1 -1
- package/dist/esm/requests/rate-limits.shared.schemas.d.ts +11 -1
- package/dist/esm/requests/rate-limits.shared.schemas.d.ts.map +1 -1
- package/dist/esm/requests/rate-limits.shared.schemas.js +11 -1
- package/dist/esm/requests/rate-limits.shared.schemas.js.map +1 -1
- package/dist/esm/requests/websocket.shared.schemas.d.ts +27 -4
- package/dist/esm/requests/websocket.shared.schemas.d.ts.map +1 -1
- package/dist/esm/requests/websocket.shared.schemas.js +35 -0
- package/dist/esm/requests/websocket.shared.schemas.js.map +1 -1
- package/dist/esm/resources/resources-config.shared.factory.d.ts +1 -0
- package/dist/esm/resources/resources-config.shared.factory.d.ts.map +1 -1
- package/dist/esm/resources/resources-config.shared.factory.js +105 -20
- package/dist/esm/resources/resources-config.shared.factory.js.map +1 -1
- package/dist/esm/resources/resources-config.shared.schemas.d.ts +254 -72
- 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 +97 -5
- 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 +15 -0
- package/dist/esm/resources/resources-relationships.shared.factory.js.map +1 -1
- package/dist/esm/resources/resources.shared.core.definitions.d.ts +37 -0
- package/dist/esm/resources/resources.shared.core.definitions.d.ts.map +1 -1
- package/dist/esm/resources/resources.shared.core.definitions.js +51 -0
- package/dist/esm/resources/resources.shared.core.definitions.js.map +1 -1
- package/dist/esm/resources/resources.shared.schemas.d.ts +11 -2
- package/dist/esm/resources/resources.shared.schemas.d.ts.map +1 -1
- package/dist/esm/resources/resources.shared.schemas.js +34 -3
- package/dist/esm/resources/resources.shared.schemas.js.map +1 -1
- package/dist/esm/resources/utils/field-value-disclosure.utils.d.ts +51 -0
- package/dist/esm/resources/utils/field-value-disclosure.utils.d.ts.map +1 -0
- package/dist/esm/resources/utils/field-value-disclosure.utils.js +53 -0
- package/dist/esm/resources/utils/field-value-disclosure.utils.js.map +1 -0
- package/dist/esm/resources/utils/resources-summary.utils.d.ts +16 -2
- package/dist/esm/resources/utils/resources-summary.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/resources-summary.utils.js +19 -5
- package/dist/esm/resources/utils/resources-summary.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 +11 -0
- package/dist/esm/resources/utils/shared-persistence-collection.utils.js.map +1 -1
- package/dist/esm/runtime/domain-module.shared.definitions.d.ts +25 -0
- 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/security/api-keys/api-keys-application.shared.resources-config.schemas.d.ts +1 -0
- 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 +38 -0
- 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 +1 -0
- 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 +38 -0
- package/dist/esm/security/api-keys/api-keys-organization.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/authentications/authentication.shared.dto.schemas.d.ts +4 -11
- package/dist/esm/security/authentications/authentication.shared.dto.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/authentication.shared.dto.schemas.js +0 -1
- package/dist/esm/security/authentications/authentication.shared.dto.schemas.js.map +1 -1
- package/dist/esm/security/authentications/authentication.shared.schemas.d.ts +84 -5
- package/dist/esm/security/authentications/authentication.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/authentication.shared.schemas.js +83 -3
- package/dist/esm/security/authentications/authentication.shared.schemas.js.map +1 -1
- package/dist/esm/security/authentications/registration.shared.dto.schemas.d.ts +1 -0
- package/dist/esm/security/authentications/registration.shared.dto.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/registration.shared.dto.schemas.js +11 -0
- package/dist/esm/security/authentications/registration.shared.dto.schemas.js.map +1 -1
- package/dist/esm/security/authentications/scim/scim-provisioning-config.shared.schemas.d.ts +15 -0
- 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 +21 -4
- package/dist/esm/security/authentications/scim/scim-provisioning-config.shared.schemas.js.map +1 -1
- package/dist/esm/security/authentications/sso/sso-config.shared.resources-config.schemas.d.ts +61 -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 +208 -6
- 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 +37 -27
- 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 +134 -12
- package/dist/esm/security/authentications/sso/sso-config.shared.schemas.js.map +1 -1
- package/dist/esm/security/authentications/sso/sso-connection.shared.schemas.d.ts +0 -6
- 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 +17 -8
- package/dist/esm/security/authentications/sso/sso-connection.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 +27 -0
- 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 +52 -7
- 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 +45 -8
- package/dist/esm/security/authorizations/platform-access-grants.shared.schemas.js.map +1 -1
- package/dist/esm/security/connected-accounts/provider-credentials-organization.shared.resources-config.schemas.d.ts +31 -0
- package/dist/esm/security/connected-accounts/provider-credentials-organization.shared.resources-config.schemas.d.ts.map +1 -0
- package/dist/esm/security/connected-accounts/provider-credentials-organization.shared.resources-config.schemas.js +198 -0
- package/dist/esm/security/connected-accounts/provider-credentials-organization.shared.resources-config.schemas.js.map +1 -0
- package/dist/esm/security/connected-accounts/provider-credentials-user.shared.resources-config.schemas.d.ts +31 -0
- package/dist/esm/security/connected-accounts/provider-credentials-user.shared.resources-config.schemas.d.ts.map +1 -0
- package/dist/esm/security/connected-accounts/provider-credentials-user.shared.resources-config.schemas.js +191 -0
- package/dist/esm/security/connected-accounts/provider-credentials-user.shared.resources-config.schemas.js.map +1 -0
- package/dist/esm/security/connected-accounts/provider-credentials.shared.schemas.d.ts +250 -0
- package/dist/esm/security/connected-accounts/provider-credentials.shared.schemas.d.ts.map +1 -0
- package/dist/esm/security/connected-accounts/provider-credentials.shared.schemas.js +486 -0
- package/dist/esm/security/connected-accounts/provider-credentials.shared.schemas.js.map +1 -0
- package/dist/esm/security/oauth-clients/oauth-clients-application.shared.resources-config.schemas.d.ts +4 -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 +29 -0
- 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 +4 -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 +29 -0
- 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 +6 -0
- 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 +31 -0
- package/dist/esm/security/oauth-clients/oauth-clients.shared.schemas.js.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-consent-grants.shared.schemas.d.ts +13 -0
- 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 +24 -3
- package/dist/esm/security/oauth-clients/oauth-consent-grants.shared.schemas.js.map +1 -1
- package/dist/esm/users/user-preferences.shared.resources-config.schemas.d.ts +4 -4
- package/dist/esm/users/user-self-preferences.shared.resources-config.schemas.d.ts +4 -4
- 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 +33 -3
- 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 +17 -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 +136 -5
- package/dist/esm/users/users.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/users.shared.schemas.d.ts +43 -12
- package/dist/esm/users/users.shared.schemas.d.ts.map +1 -1
- package/dist/esm/users/users.shared.schemas.js +38 -7
- package/dist/esm/users/users.shared.schemas.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -4
|
@@ -25,5 +25,18 @@ export declare const OAuthConsentGrantSchema: import("@wildo-ai/zod-decorators")
|
|
|
25
25
|
createdAt: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<z.ZodDefault<z.ZodDate>>>>>;
|
|
26
26
|
updatedAt: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<z.ZodDefault<z.ZodDate>>>>;
|
|
27
27
|
}, z.core.$strip>>;
|
|
28
|
+
/**
|
|
29
|
+
* How long a remembered consent lasts when the application authors no policy of its own.
|
|
30
|
+
*
|
|
31
|
+
* **180 days**, and the reasoning matters more than the number. A remembered consent is a standing
|
|
32
|
+
* delegation of authority to a third party, so it should lapse on its own if nobody re-affirms it —
|
|
33
|
+
* but a prompt the user meets every few weeks trains them to click through, which makes the consent
|
|
34
|
+
* screen worth less rather than more. Half a year is long enough not to nag and short enough that an
|
|
35
|
+
* authorization the user has forgotten about does not outlive their interest in the client by years.
|
|
36
|
+
*
|
|
37
|
+
* An application overrides it with `auth.consentGrantLifetimeDays`. There is deliberately no way to
|
|
38
|
+
* express "never expires": that was the state this default replaced, and it was not chosen.
|
|
39
|
+
*/
|
|
40
|
+
export declare const OAUTH_CONSENT_GRANT_DEFAULT_LIFETIME_DAYS = 180;
|
|
28
41
|
export type OAuthConsentGrant = z.infer<typeof OAuthConsentGrantSchema>;
|
|
29
42
|
//# sourceMappingURL=oauth-consent-grants.shared.schemas.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-consent-grants.shared.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/security/oauth-clients/oauth-consent-grants.shared.schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,uBAAuB;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"oauth-consent-grants.shared.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/security/oauth-clients/oauth-consent-grants.shared.schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,uBAAuB;;;;;;;;;kBAsDlC,CAAC;AAEH;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,yCAAyC,MAAM,CAAC;AAE7D,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC"}
|
|
@@ -44,9 +44,17 @@ export const OAuthConsentGrantSchema = z.object({
|
|
|
44
44
|
// needs a string. The value comes from the schema, so there is no second copy to drift.
|
|
45
45
|
scopes: addImpersonalizeWith(z.array(z.string()).default([]).dataCategories(PersonalDataCategory.USAGE), RedactionType.RESET),
|
|
46
46
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
47
|
+
* Expiry. The authorize lookup ignores a grant past this instant, fail-closed to a fresh consent
|
|
48
|
+
* prompt.
|
|
49
|
+
*
|
|
50
|
+
* SET ON EVERY AFFIRMATIVE CONSENT since 2026-09-08 (#465) — on creation and again on every widen,
|
|
51
|
+
* because a widen is the user approving again and a re-affirmation should restart the clock. It
|
|
52
|
+
* was declared here with a reader and NO WRITER before that, so a remembered approval lived until
|
|
53
|
+
* the person revoked it while the field read to an operator as a policy knob that existed.
|
|
54
|
+
*
|
|
55
|
+
* Still optional on the SCHEMA, for two reasons that are not the same: grants created before that
|
|
56
|
+
* date carry none and must keep working (an absent expiry means "never", which is what they were
|
|
57
|
+
* granted under), and a resource may be written by a path that has no operator policy in hand.
|
|
50
58
|
*/
|
|
51
59
|
expiresAt: z.date().optional().isDBIndexed(),
|
|
52
60
|
createdAt: z.date().default(() => new Date()).isDBIndexed().isSummaryField().excludeFromCreate().excludeFromUpdate(),
|
|
@@ -56,4 +64,17 @@ export const OAuthConsentGrantSchema = z.object({
|
|
|
56
64
|
'clientId',
|
|
57
65
|
'resource',
|
|
58
66
|
]);
|
|
67
|
+
/**
|
|
68
|
+
* How long a remembered consent lasts when the application authors no policy of its own.
|
|
69
|
+
*
|
|
70
|
+
* **180 days**, and the reasoning matters more than the number. A remembered consent is a standing
|
|
71
|
+
* delegation of authority to a third party, so it should lapse on its own if nobody re-affirms it —
|
|
72
|
+
* but a prompt the user meets every few weeks trains them to click through, which makes the consent
|
|
73
|
+
* screen worth less rather than more. Half a year is long enough not to nag and short enough that an
|
|
74
|
+
* authorization the user has forgotten about does not outlive their interest in the client by years.
|
|
75
|
+
*
|
|
76
|
+
* An application overrides it with `auth.consentGrantLifetimeDays`. There is deliberately no way to
|
|
77
|
+
* express "never expires": that was the state this default replaced, and it was not chosen.
|
|
78
|
+
*/
|
|
79
|
+
export const OAUTH_CONSENT_GRANT_DEFAULT_LIFETIME_DAYS = 180;
|
|
59
80
|
//# sourceMappingURL=oauth-consent-grants.shared.schemas.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-consent-grants.shared.schemas.js","sourceRoot":"","sources":["../../../../../src/security/oauth-clients/oauth-consent-grants.shared.schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,MAAM,gEAAgE,CAAC;AACtG,OAAO,EAAE,aAAa,EAAE,MAAM,mDAAmD,CAAC;AAClF,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhE,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,cAAc,EAAE;IAEtD,6EAA6E;IAC7E,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,YAAY,EAAE,CAAC,cAAc,EAAE,CAAC,iBAAiB,EAAE;IAE3F,iGAAiG;IACjG,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,cAAc,EAAE;IAE1D;;;;OAIG;IACH,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,CAAC,cAAc,EAAE;IAE9D;;;;;OAKG;IACH,+FAA+F;IAC/F,wFAAwF;IACxF,2IAA2I;IAC3I,iGAAiG;IACjG,iGAAiG;IACjG,wFAAwF;IACxF,MAAM,EAAE,oBAAoB,CAC5B,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,cAAc,CAAC,oBAAoB,CAAC,KAAK,CAAC,EACxE,aAAa,CAAC,KAAK,CACpB;IAED
|
|
1
|
+
{"version":3,"file":"oauth-consent-grants.shared.schemas.js","sourceRoot":"","sources":["../../../../../src/security/oauth-clients/oauth-consent-grants.shared.schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,MAAM,gEAAgE,CAAC;AACtG,OAAO,EAAE,aAAa,EAAE,MAAM,mDAAmD,CAAC;AAClF,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhE,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,cAAc,EAAE;IAEtD,6EAA6E;IAC7E,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,YAAY,EAAE,CAAC,cAAc,EAAE,CAAC,iBAAiB,EAAE;IAE3F,iGAAiG;IACjG,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,cAAc,EAAE;IAE1D;;;;OAIG;IACH,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,CAAC,cAAc,EAAE;IAE9D;;;;;OAKG;IACH,+FAA+F;IAC/F,wFAAwF;IACxF,2IAA2I;IAC3I,iGAAiG;IACjG,iGAAiG;IACjG,wFAAwF;IACxF,MAAM,EAAE,oBAAoB,CAC5B,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,cAAc,CAAC,oBAAoB,CAAC,KAAK,CAAC,EACxE,aAAa,CAAC,KAAK,CACpB;IAED;;;;;;;;;;;;OAYG;IACH,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE;IAE5C,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,cAAc,EAAE,CAAC,iBAAiB,EAAE,CAAC,iBAAiB,EAAE;IACpH,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,iBAAiB,EAAE,CAAC,iBAAiB,EAAE;CACpG,CAAC,CAAC,cAAc,CAAC;IAChB,QAAQ;IACR,UAAU;IACV,UAAU;CACX,CAAC,CAAC;AAEH;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,yCAAyC,GAAG,GAAG,CAAC","sourcesContent":["/**\n * OIDC Persistent Consent Grants (\"remember this app\")\n *\n * A durable \"user X authorized OAuth client Y for identity scopes Z (at resource R)\" record. It is\n * CREATED (via the system write primitive) when a user APPROVES an interactive-consent request AND\n * opts to remember the app, and READ at `/oauth/authorize` to SKIP re-prompting when an existing grant\n * already covers the requested scopes. The user can list their grants (\"authorized apps\") and revoke\n * one.\n *\n * USER-scoped: owned by `userId` (USER_SELF primary scope, derived from the `USERS → OAUTH_CONSENT_GRANTS`\n * composition relationship). One grant per `(userId, clientId, resource)` — a re-consent UPDATES the\n * granted scopes rather than creating a duplicate. `resource` participates in the grain because two\n * authorize requests from the same client for different RFC 8707 resources (distinct A2A / MCP agent\n * endpoints) are genuinely distinct delegations; an OIDC-only login carries no `resource` and yields a\n * single resource-less grant.\n */\n\nimport { z } from 'zod';\nimport { PersonalDataCategory } from '../../compliance/privacy/personal-data-category.shared.schemas';\nimport { RedactionType } from '../../compliance/privacy/redaction.shared.schemas';\nimport { addImpersonalizeWith } from '@wildo-ai/zod-decorators';\n\nexport const OAuthConsentGrantSchema = z.object({\n _id: z.string().min(1).isPrimaryKey().isSummaryField(),\n\n /** FK → USERS — the user who granted consent (the USER_SELF scope owner). */\n userId: z.string().min(1).isDBIndexed().isForeignKey().isSummaryField().excludeFromUpdate(),\n\n /** The registered OAuth client (`_id`, `oc_*`) the user authorized. Part of the business key. */\n clientId: z.string().min(1).isDBIndexed().isSummaryField(),\n\n /**\n * The RFC 8707 `resource` (the target A2A / MCP agent endpoint) this grant covers. Absent for an\n * OIDC-only login with no delegation. Part of the business key — a grant authorizes one client for\n * one resource, so different agent endpoints require separate, explicit consent.\n */\n resource: z.string().optional().isDBIndexed().isSummaryField(),\n\n /**\n * The IDENTITY scopes the user granted (e.g. `openid`, `profile`, `email`). A later authorize whose\n * requested scopes are a SUBSET of these skips the prompt; a request for a scope NOT in the grant\n * re-prompts (silent scope expansion is forbidden). Identity only — scopes carry no authorization\n * weight (authorization is roles-only).\n */\n // USAGE — what this person authorized a third-party client to reach on their behalf, and when.\n // A consent record is an observation of a decision they made, not an attribute of them.\n // RESET on erasure — returns this field to its schema default. It holds which scopes this person authorized a third-party client to reach,\n // which the category above correctly declares as personal data. RESET rather than REMOVE or MASK\n // because the field is non-nullable WITH a `.default()`: REMOVE needs a clearable field and MASK\n // needs a string. The value comes from the schema, so there is no second copy to drift.\n scopes: addImpersonalizeWith(\n z.array(z.string()).default([]).dataCategories(PersonalDataCategory.USAGE),\n RedactionType.RESET,\n ),\n\n /**\n * Expiry. The authorize lookup ignores a grant past this instant, fail-closed to a fresh consent\n * prompt.\n *\n * SET ON EVERY AFFIRMATIVE CONSENT since 2026-09-08 (#465) — on creation and again on every widen,\n * because a widen is the user approving again and a re-affirmation should restart the clock. It\n * was declared here with a reader and NO WRITER before that, so a remembered approval lived until\n * the person revoked it while the field read to an operator as a policy knob that existed.\n *\n * Still optional on the SCHEMA, for two reasons that are not the same: grants created before that\n * date carry none and must keep working (an absent expiry means \"never\", which is what they were\n * granted under), and a resource may be written by a path that has no operator policy in hand.\n */\n expiresAt: z.date().optional().isDBIndexed(),\n\n createdAt: z.date().default(() => new Date()).isDBIndexed().isSummaryField().excludeFromCreate().excludeFromUpdate(),\n updatedAt: z.date().default(() => new Date()).isDBIndexed().excludeFromCreate().excludeFromUpdate(),\n}).businessKeySet([\n 'userId',\n 'clientId',\n 'resource',\n]);\n\n/**\n * How long a remembered consent lasts when the application authors no policy of its own.\n *\n * **180 days**, and the reasoning matters more than the number. A remembered consent is a standing\n * delegation of authority to a third party, so it should lapse on its own if nobody re-affirms it —\n * but a prompt the user meets every few weeks trains them to click through, which makes the consent\n * screen worth less rather than more. Half a year is long enough not to nag and short enough that an\n * authorization the user has forgotten about does not outlive their interest in the client by years.\n *\n * An application overrides it with `auth.consentGrantLifetimeDays`. There is deliberately no way to\n * express \"never expires\": that was the state this default replaced, and it was not chosen.\n */\nexport const OAUTH_CONSENT_GRANT_DEFAULT_LIFETIME_DAYS = 180;\n\nexport type OAuthConsentGrant = z.infer<typeof OAuthConsentGrantSchema>;\n"]}
|
|
@@ -24,10 +24,10 @@ export declare const userPreferencesResourceConfiguration_InitializationFactory:
|
|
|
24
24
|
theme: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodDefault<import("zod").ZodEnum<typeof import("./users.shared.schemas").UserTheme>>>;
|
|
25
25
|
}, import("zod/v4/core").$strip>>>;
|
|
26
26
|
regional: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodDefault<import("zod").ZodObject<{
|
|
27
|
-
timezone: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").
|
|
28
|
-
dateFormat: import("zod").
|
|
29
|
-
timeFormat: import("zod").
|
|
30
|
-
locale: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").
|
|
27
|
+
timezone: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodEnum<typeof import("@wildo-ai/presets-components-models").CommonTimezone>, import("zod").ZodString]>>>;
|
|
28
|
+
dateFormat: import("zod").ZodOptional<import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodEnum<typeof import("@wildo-ai/presets-components-models").DateFormat>>>;
|
|
29
|
+
timeFormat: import("zod").ZodOptional<import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodEnum<typeof import("@wildo-ai/presets-components-models").TimeFormat>>>;
|
|
30
|
+
locale: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodOptional<import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodEnum<typeof import("@wildo-ai/presets-components-models").AvailableLanguage>>>>;
|
|
31
31
|
}, import("zod/v4/core").$strip>>>>;
|
|
32
32
|
languagePreferences: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodDefault<import("zod").ZodObject<{
|
|
33
33
|
primaryLanguage: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodDefault<import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodEnum<typeof import("@wildo-ai/presets-components-models").AvailableLanguage>>>>;
|
|
@@ -28,10 +28,10 @@ export declare const userSelfPreferencesResourceConfiguration_InitializationFact
|
|
|
28
28
|
theme: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodDefault<import("zod").ZodEnum<typeof import("./users.shared.schemas").UserTheme>>>;
|
|
29
29
|
}, import("zod/v4/core").$strip>>>;
|
|
30
30
|
regional: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodDefault<import("zod").ZodObject<{
|
|
31
|
-
timezone: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").
|
|
32
|
-
dateFormat: import("zod").
|
|
33
|
-
timeFormat: import("zod").
|
|
34
|
-
locale: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").
|
|
31
|
+
timezone: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodEnum<typeof import("@wildo-ai/presets-components-models").CommonTimezone>, import("zod").ZodString]>>>;
|
|
32
|
+
dateFormat: import("zod").ZodOptional<import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodEnum<typeof import("@wildo-ai/presets-components-models").DateFormat>>>;
|
|
33
|
+
timeFormat: import("zod").ZodOptional<import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodEnum<typeof import("@wildo-ai/presets-components-models").TimeFormat>>>;
|
|
34
|
+
locale: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodOptional<import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodEnum<typeof import("@wildo-ai/presets-components-models").AvailableLanguage>>>>;
|
|
35
35
|
}, import("zod/v4/core").$strip>>>>;
|
|
36
36
|
languagePreferences: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodDefault<import("zod").ZodObject<{
|
|
37
37
|
primaryLanguage: import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodDefault<import("@wildo-ai/zod-decorators").DecoratedPrimitiveZodType<import("zod").ZodEnum<typeof import("@wildo-ai/presets-components-models").AvailableLanguage>>>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-self.shared.resources-config.schemas.d.ts","sourceRoot":"","sources":["../../../../src/users/user-self.shared.resources-config.schemas.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAc,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,gDAAgD,CAAC;AACvF,OAAO,EAA8B,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAQzG,OAAO,EAAE,cAAc,EAAE,MAAM,iDAAiD,CAAC;AA2FjF,oBAAY,mBAAmB;IAC7B,kBAAkB,uBAAuB,CAAE,iCAAiC;IAC5E,kBAAkB,uBAAuB;CAC1C;AAED,KAAK,sBAAsB,GACvB,qBAAqB,CAAC,IAAI,GAC1B,qBAAqB,CAAC,IAAI,GAC1B,qBAAqB,CAAC,MAAM,GAC5B,qBAAqB,CAAC,WAAW,CAAC;AAKtC,eAAO,MAAM,mDAAmD,GAAI,wBAAwB,oBAAoB,EAAE;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"user-self.shared.resources-config.schemas.d.ts","sourceRoot":"","sources":["../../../../src/users/user-self.shared.resources-config.schemas.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAc,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,gDAAgD,CAAC;AACvF,OAAO,EAA8B,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAQzG,OAAO,EAAE,cAAc,EAAE,MAAM,iDAAiD,CAAC;AA2FjF,oBAAY,mBAAmB;IAC7B,kBAAkB,uBAAuB,CAAE,iCAAiC;IAC5E,kBAAkB,uBAAuB;CAC1C;AAED,KAAK,sBAAsB,GACvB,qBAAqB,CAAC,IAAI,GAC1B,qBAAqB,CAAC,IAAI,GAC1B,qBAAqB,CAAC,MAAM,GAC5B,qBAAqB,CAAC,WAAW,CAAC;AAKtC,eAAO,MAAM,mDAAmD,GAAI,wBAAwB,oBAAoB,EAAE;;;;;;;;;kBAyThH,CAAC"}
|
|
@@ -308,9 +308,29 @@ export const userSelfResourceConfiguration_InitializationFactory = (resourcesRel
|
|
|
308
308
|
//
|
|
309
309
|
// Minting a new admin-tier reactivation verb purely to give the sweep a door would
|
|
310
310
|
// manufacture a routed surface nobody asked for — the exact pattern this workstream
|
|
311
|
-
// removed six times over.
|
|
312
|
-
//
|
|
313
|
-
//
|
|
311
|
+
// removed six times over.
|
|
312
|
+
//
|
|
313
|
+
// CORRECTED 2026-09-08 (#430). This paragraph used to end "Voluntary deactivation is
|
|
314
|
+
// reversible by its subject at any time through REACTIVATE_ACCOUNT, so a scheduled
|
|
315
|
+
// auto-return was a convenience, not a promise". That is FALSE, and it was load-bearing:
|
|
316
|
+
// it is the stated reason the auto-return was rejected. REACTIVATE_ACCOUNT needs a
|
|
317
|
+
// SESSION, and `_enforceUserStatus` (authentication-orchestrator.backend.service.ts:709-716)
|
|
318
|
+
// refuses every non-ACTIVE status at sign-in — so a self-deactivated person cannot reach
|
|
319
|
+
// the verb that would reverse it.
|
|
320
|
+
//
|
|
321
|
+
// RESOLVED, and the answer is that reversal is an ADMINISTRATIVE act: `users |
|
|
322
|
+
// reactivate_user` (INACTIVE → ACTIVE, `APP_ADMIN_SUPER_ADMIN`, mandatory `reason`,
|
|
323
|
+
// audited) is the door. So deactivation is NOT reversible by its subject, and the
|
|
324
|
+
// operation's own SPECIFICATION says so — that is where the words a person reads come
|
|
325
|
+
// from (`.claude/rules/display-text-comes-from-i18n.md`: display text is authored in the
|
|
326
|
+
// spec and generated into the label tree, never invented at the call site).
|
|
327
|
+
//
|
|
328
|
+
// The two alternatives rejected above are still rejected for the reasons given, which is
|
|
329
|
+
// why they are kept: widening `unsuspend_user` conflates an imposed suspension with a
|
|
330
|
+
// chosen departure, and `admitsCrossSubjectUserAdministration` on an `APP_USER` verb
|
|
331
|
+
// would let any authenticated user reactivate anyone. The third — admitting INACTIVE at
|
|
332
|
+
// sign-in with a session scoped to one verb — was rejected on #430 for widening what a
|
|
333
|
+
// sign-in returns.
|
|
314
334
|
//
|
|
315
335
|
// Note the ADMIN time-boxing is unaffected and IS honoured: `users | suspend_user` takes
|
|
316
336
|
// `suspensionDuration` and the hourly sweep lifts it, because `unsuspend_user` is a door a
|
|
@@ -328,6 +348,11 @@ export const userSelfResourceConfiguration_InitializationFactory = (resourcesRel
|
|
|
328
348
|
{
|
|
329
349
|
target: CoreUserNotificationTarget.USER_SELF,
|
|
330
350
|
channel: CoreUserNotificationChannel.EMAIL,
|
|
351
|
+
// Delivered even to a person who switched email notifications off (#409). An account
|
|
352
|
+
// lifecycle change is the alert that matters most precisely when the account holder did
|
|
353
|
+
// NOT perform it, and this email is how they find out. A preference about routine
|
|
354
|
+
// notifications must not be able to silence it.
|
|
355
|
+
alwaysDeliver: true,
|
|
331
356
|
}
|
|
332
357
|
]
|
|
333
358
|
},
|
|
@@ -372,6 +397,11 @@ export const userSelfResourceConfiguration_InitializationFactory = (resourcesRel
|
|
|
372
397
|
{
|
|
373
398
|
target: CoreUserNotificationTarget.USER_SELF,
|
|
374
399
|
channel: CoreUserNotificationChannel.EMAIL,
|
|
400
|
+
// Delivered even to a person who switched email notifications off (#409). An account
|
|
401
|
+
// lifecycle change is the alert that matters most precisely when the account holder did
|
|
402
|
+
// NOT perform it, and this email is how they find out. A preference about routine
|
|
403
|
+
// notifications must not be able to silence it.
|
|
404
|
+
alwaysDeliver: true,
|
|
375
405
|
}
|
|
376
406
|
]
|
|
377
407
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-self.shared.resources-config.schemas.js","sourceRoot":"","sources":["../../../../src/users/user-self.shared.resources-config.schemas.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * User Self Shared Resource Configuration\n *\n * Resource configuration for user self-management operations.\n * Handles profile management, preferences, and personal data operations.\n */\n\nimport { z } from 'zod';\nimport { UserSchema, UserStatus } from './users.shared.schemas';\nimport { CoreResourceOperation } from '../resources/resources.shared.core.definitions';\nimport { ResourceOperationRiskLevel, ResourceRelationship } from '../resources/resources.shared.schemas';\nimport { CoreResourceType, coreResourceShared_FieldIdentifier } from '../resources/resources.shared.core.definitions';\nimport { ResourceOperationVariantType } from '../resources/resources.shared.schemas';\nimport { CoreUserNotificationTarget, CoreUserNotificationChannel } from '../notifications/notifications.shared.schemas';\n\nimport { createResourceConfiguration_Initialization } from '../resources/resources-config.shared.factory';\nimport { ErasureRetentionMode, ResourceDataSubjectKind } from '../compliance/privacy/impersonalization.shared.schemas';\n\nimport { CORE_APP_ROLES } from '../security/authorizations/roles.shared.schemas';\nimport { ResourceSystemAccessMode } from '../resources/resources-config.shared.schemas';\nimport { DataPortabilityProvenance } from '../compliance/privacy/subject-export.shared.schemas';\n\n// Custom operations enum for user self management\n//\n// PASSWORD CHANGE IS NOT A RESOURCE OPERATION — IT IS AN AUTH ROUTE. `CHANGE_PASSWORD` was\n// declared here as an `APP_USER`-gated `riskLevel: HIGH` operation taking\n// `{ currentPassword, newPassword, confirmPassword }`, and was removed on 2026-08-01: it was\n// ROUTED but never implemented, so the request fell through to the generic core UPDATE, which\n// persists only fields the resource schema declares. A password verifier is not one of them\n// (credentials are a separate store), so every call answered **HTTP 200 having changed nothing**\n// — the caller is told their password rotated while the old one still works.\n//\n// The real implementation already exists and is the ONLY correct home for it:\n// `POST /auth/password/change` → `AuthMethodManagementBackendService.changePassword`, which\n// verifies the current-password proof, applies the per-user-type password policy, hashes,\n// invalidates every refresh token for the user, and writes a `USER_PASSWORD_CHANGED` audit\n// record. It is rate-limited (5/min/IP) and parses its body with `z.strictObject` so an\n// identity field smuggled into the payload is rejected loudly rather than silently ignored.\n// The frontend already calls exactly that route (`AppPage_SecuritySettings` →\n// `getManualCallsHttpClient().passwordChange(...)`).\n//\n// Do NOT re-declare this as a resource operation. Beyond duplicating a solved problem, it would\n// route a plaintext credential through the generic resource-write pipeline (DTO parse, repository\n// projection, notification fan-out) that the auth route deliberately bypasses.\n// See `.claude/plans/routed-unimplemented-operations-fail-closed.md`.\n//\n// NOR ARE PROFILE / PREFERENCES WRITES — THEY BELONG TO THEIR OWN RESOURCES. `UPDATE_PROFILE` and\n// `UPDATE_PREFERENCES` were removed on 2026-08-01. Both ran `resourceOperationLike: UPDATE` against\n// THIS resource — whose `mainSchema` is the USER — while declaring the request DTO of a DIFFERENT\n// resource (`UserProfileSchema.partial()` / `UserPreferencesSchema.partial()`). A core UPDATE writes\n// only its own resource's row, so every declared field was dropped; the single intersecting key was\n// `_id`, which `ResourceOperationsHelper.cleanInputData` force-deletes before validation. The write\n// was therefore empty and the route answered **HTTP 200 having persisted nothing**.\n//\n// The persisted documents already have dedicated self-scoped resources, and they are already the\n// wired path: `USER_SELF_PROFILES` exposes READ/CREATE/UPDATE over its own `mainSchema`, while\n// `USER_SELF_PREFERENCES` exposes READ/UPDATE plus its selective reset operation over the eagerly\n// seeded preferences row. Both are embedded as child resources of this one in the frontend preset,\n// carry their own resource specifications, and — for preferences — are the MCP-exposed read/update\n// tools.\n// This resource's own specification already directed engineers there for \"the persisted documents\".\n//\n// Do NOT re-declare either verb here. A single `user_self`-rooted write across child resources\n// cannot be a core UPDATE at all; it would need a custom multi-resource implementation declaring\n// `transactionParticipants` — new machinery duplicating a path that already exists. Route clients\n// to `userSelfProfiles` / `userSelfPreferences` instead.\n//\n// NOR IS SELF-SERVICE ACCOUNT DELETION — DATA-SUBJECT ERASURE IS A SYSTEM-LEVEL API WITH NO ROUTE.\n// `DELETE_ACCOUNT` was removed on 2026-08-01. It was an `APP_USER`-gated `riskLevel: CRITICAL`\n// operation taking `{ password, reason }` and declaring a scheduled-deletion\n// `customResponseDto: { scheduledDeletionDate, recoveryPeriodDays, dataExportUrl }`. It was broken\n// in four independent ways, each verified against the built configuration:\n//\n// - **The password was never verified.** Neither declared field is a persisted `UserSchema` path\n// and no custom implementation was bound to the operation path, so the built `repositoryDto`\n// was EMPTY: the controller strict-parsed the body, the repository re-parsed it, and both\n// fields were discarded. A UI collecting the password as a confirmation gate was providing\n// false assurance.\n// - **It could never answer successfully.** `transformOutput` skips default-envelope composition\n// for an op declaring a `customResponseDto` and validates the raw service output against it.\n// A core DELETE returns the deleted `_id` as a bare string, so every call threw\n// `service_resource_transformation_failed` → HTTP 500. Retries too: a second call returns `''`,\n// which is not `null`, so it fails the same parse.\n// - **Its destructive effect was NONDETERMINISTIC.** `resourceOperationLike: DELETE` reaches\n// `_doDelete` through the repository's operations map (which holds custom ops), bypassing the\n// `coreOperations` gate this config never opened — and fires `onParentDelete`. Neither\n// `USER_SELF_PROFILES` nor `USER_SELF_PREFERENCES` declares a DELETE, so a user WITH either row\n// hit `ErrorType.CONFIGURATION` inside the delete transaction and was rolled back, while a user\n// with NEITHER row was destroyed. Same 500, opposite persistence outcomes.\n// - **It contradicted this resource's own retention contract.** `retentionPolicy` below declares\n// `RETAIN_AND_IMPERSONALIZE`: user rows are RETAINED and scrubbed in place, never hard-deleted.\n//\n// The erasure capability already exists and is the only correct home: `eraseSubjectAsSystem` /\n// `eraseSubjectInPlace` walk every dependent edge, derive delete-vs-retain from each edge's own\n// `onParentDelete` declaration, fail closed on unclassified edges, and return a\n// `SubjectErasureReport`. Like the four export/portability verbs removed the same day, they\n// **deliberately ship with NO ROUTE** — data-subject rights are a system-level API, not a\n// self-service HTTP verb. `dataExportUrl` compounded this: it named the portability artifact that\n// removal established does not exist.\n//\n// Do NOT re-declare this as a resource operation. Voluntary self-service closure is\n// `DEACTIVATE_ACCOUNT` below; actual erasure runs through the compliance capability. If a product\n// ever needs a user-initiated erasure REQUEST, it is a scheduling verb over a persisted\n// request state (with its own cancel path and a batch that calls `eraseSubjectAsSystem`) — not a\n// routed DELETE, and not something the generic core delete can express.\n// See `.claude/plans/routed-unimplemented-operations-fail-closed.md`.\n//\n// assurance-control: WILDO.DATA.SECURE_LIFECYCLE — a destructive identity operation\n// must verify the principal and leave evidence; erasure must honour the declared retention mode.\nexport enum UserSelf_Operations {\n DEACTIVATE_ACCOUNT = 'deactivate_account', // Temporarily deactivate account\n REACTIVATE_ACCOUNT = 'reactivate_account', // Reactivate account\n}\n\ntype UserSelfCoreOperations =\n | CoreResourceOperation.READ\n | CoreResourceOperation.LIST\n | CoreResourceOperation.UPDATE\n | CoreResourceOperation.UPDATE_MANY;\n\n/*\nUser Self Resource Configuration Factory\n*/\nexport const userSelfResourceConfiguration_InitializationFactory = (resourcesRelationships: ResourceRelationship[]) => createResourceConfiguration_Initialization<\n typeof UserSelf_Operations,\n UserSelfCoreOperations,\n typeof UserSchema\n>({\n mainSchema: UserSchema,\n resourceIdentifier: CoreResourceType.USER_SELF,\n resourceFieldIdentifier: coreResourceShared_FieldIdentifier[CoreResourceType.USER_SELF],\n resourceRelationships: resourcesRelationships,\n isSystemResource: true, // Self-scoped\n\n /**\n * `/user-self/{userId}` names the CALLER. Declared EXPLICITLY even though `true` is the default,\n * because the sibling `USERS` configuration — over the SAME collection, with the SAME\n * `resourceFieldIdentifier` — declares `false`, and a reader comparing the two must be able to see\n * that the difference is intentional rather than an omission.\n *\n * This is the value that keeps the horizontal-IDOR refusal alive: user A addressing user B's\n * self row is refused `403 authorization_user_id_mismatch` by the identity-coherence guard. Pinned\n * by `external-access-auth.e2e.ts` (M4) and `users-administration.e2e.ts` (U-11). Flipping this to\n * `false` would open that hole silently — nothing downstream would catch it, because the addressed\n * id still reaches the contextual filter and would scope the read to B.\n */\n primaryKeyIdentifiesInitiator: true,\n\n /**\n * ⚠️ MUST MIRROR `USERS`. This config and `USERS` are two doors onto the SAME rows: they share\n * `UserSchema` above and, per `getCollectionNameForResource` in the zod→mongoose convertor,\n * `USER_SELF` builds a SEPARATE Mongoose model over the `USERS` COLLECTION.\n *\n * Retention governance is per-resource-config, so a `USERS`-only opt-in would leave two holes on\n * these shared rows:\n * - an ERASED user's row would stay READABLE and UPDATABLE through this door, whose READ/UPDATE\n * are open to `APP_USER` and would carry neither the retention hide filter nor the freeze;\n * - this model would emit a PLAIN unique index on `email` next to the `USERS` model's\n * retention-scoped one, so the SECOND erased user would collide (E11000) on the shared mask\n * address and abort the erasure.\n *\n * Declaring the same mode makes both models inject the same marker and emit the identical partial\n * index, so the collection has one coherent retention contract. Change the two configs together.\n * The scrub treatment needs no restating — it lives on the shared `UserSchema`.\n */\n retentionPolicy: {\n mode: ErasureRetentionMode.RETAIN_AND_IMPERSONALIZE,\n },\n\n /**\n * Same subject as `USERS` over the same collection — the self-service door onto the identity row.\n * Mirrors that config's `SELF_PRINCIPAL` declaration; the two must be changed together.\n */\n dataSubjectPolicy: { kind: ResourceDataSubjectKind.SELF_PRINCIPAL },\n\n /**\n * Subject-export disclosure. The self-service export subject. The identity row is what the user signed up with.\n */\n systemAccessPolicy: { exportSubject: ResourceSystemAccessMode.ALLOWED },\n\n /**\n * Subject-export disclosure. The self-service export subject. The identity row is what the user signed up with.\n */\n portabilityPolicy: { defaultProvenance: DataPortabilityProvenance.SUBJECT_PROVIDED },\n\n coreOperations: [\n CoreResourceOperation.READ,\n // LIST + UPDATE_MANY exist for the retention capability ONLY, as INTERNAL_CALL variants that\n // register no route: `retentionPolicy` requires UPDATE_MANY (the in-place scrub via\n // `updateManyAsSystem`) plus READ + LIST (the audited see-through read of retained rows). There\n // is deliberately no HTTP \"list my selves\" — see the variants below.\n CoreResourceOperation.LIST,\n CoreResourceOperation.UPDATE,\n CoreResourceOperation.UPDATE_MANY,\n ],\n\n customOperation: UserSelf_Operations,\n\n\n operationsConfiguration: {\n [CoreResourceOperation.READ]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER], // v1: app-only, user reading their own data\n riskLevel: ResourceOperationRiskLevel.LOW,\n // Default variant returns basic User data only\n }\n ]\n },\n\n [CoreResourceOperation.LIST]: {\n variants: [\n {\n // Retention capability only — INTERNAL_CALL registers NO HTTP route. A user-facing\n // \"list my selves\" would be meaningless (this resource is addressed as the caller's own\n // row); the op exists solely so `listRetainedAsSystem` has a read path through which a\n // compliance auditor can see-through to retained rows on this collection.\n //\n // ⚠️ INTERNAL_CALL, *not* REPOSITORY_ONLY — see the UPDATE_MANY note below for why the\n // distinction is load-bearing. `roles` is inert on a non-URL-bearing variant.\n variantType: ResourceOperationVariantType.INTERNAL_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER],\n riskLevel: ResourceOperationRiskLevel.LOW,\n }\n ]\n },\n\n [CoreResourceOperation.UPDATE]: {\n variants: [\n {\n // ⚠️ INTERNAL_CALL — registers NO HTTP route. This was an `API_CALL` open to\n // `APP_USER` with an auto-derived request DTO, and on THIS resource the auto-derived\n // user update DTO is `{status, appRoles, userTypes}`: every writable field on the\n // `USER_SELF` row is server-owned. `email` is `.excludeFromUpdate()` and the editable\n // self data (names, avatar, bio, phone / notification + UI preferences) lives on the\n // `USER_SELF_PROFILES` and `USER_SELF_PREFERENCES` child resources, which is where the\n // UI actually writes it. So the route offered a self-service caller nothing legitimate\n // and three things it must never set:\n //\n // - `appRoles` — the app-level authorization axis. No ceiling gate exists on this\n // path (`assertRequestedRolesWithinCallerCeiling` is wired into org-member CREATE,\n // org-unit-members, oauth-clients and api-keys only, and no custom implementation is\n // registered for `USERS` / `USER_SELF`), so a plain authenticated user could grant\n // themselves any role, up to `APP_ADMIN_SUPER_ADMIN`.\n // - `userTypes` — selects auth policy and registration context.\n // - `status` — the account lifecycle axis, which belongs to the dedicated\n // DEACTIVATE_ACCOUNT / REACTIVATE_ACCOUNT transitions below (and to the admin\n // SUSPEND_USER / UNSUSPEND_USER verbs on the `USERS` door). A self-service caller\n // flipping it directly bypasses every state gate those verbs declare.\n //\n // Narrowing `requestDto` would have left the route in place answering an empty write;\n // removing the HTTP surface is the honest fix, because no caller wants it. Verified\n // before the change: the engine presets surface no `UPDATE` action for `USER_SELF`\n // (self edits go to the child resources), and no backend caller invokes `USER_SELF`\n // update — the trusted internal door for user rows is `USERS`.\n //\n // The operation itself is KEPT (not dropped from `coreOperations`) because the custom\n // self verbs borrow it through `resourceOperationLike: UPDATE`, and INTERNAL_CALL is\n // the resource's established idiom for a route-less operation — see `LIST` and\n // `UPDATE_MANY` above/below, and the note there on why INTERNAL_CALL rather than\n // REPOSITORY_ONLY. `roles` is inert on a non-URL-bearing variant.\n //\n // assurance-control: WILDO.ACCESS.LEAST_PRIVILEGE — a self-service surface\n // must not be a privilege-assignment or lifecycle-override surface.\n variantType: ResourceOperationVariantType.INTERNAL_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER],\n riskLevel: ResourceOperationRiskLevel.MEDIUM,\n }\n ],\n userNotifications: [\n {\n target: CoreUserNotificationTarget.USER_SELF,\n channel: CoreUserNotificationChannel.FRONT_END_SUCCESS,\n }\n ]\n },\n\n [CoreResourceOperation.UPDATE_MANY]: {\n variants: [\n {\n // Retention capability only — INTERNAL_CALL registers NO HTTP route. Required by\n // `retentionPolicy` because the impersonalize writer scrubs in place through\n // `updateManyAsSystem`. A user bulk-updating rows through the self door would be\n // nonsensical AND dangerous, so the only caller is the trusted system writer.\n //\n // ⚠️ INTERNAL_CALL, *not* REPOSITORY_ONLY. Both are route-less, but the three retention\n // primitives (`updateManyAsSystem`, `readRetainedAsSystem`, `listRetainedAsSystem`) resolve\n // through `getServiceOperationPathDefault`, which matches only INTERNAL_CALL / API_CALL /\n // API_CALL_WITH_CALLBACK — REPOSITORY_ONLY is excluded there and served by the separate\n // `getRepositoryOperationPathDefault` transport. A REPOSITORY_ONLY variant would satisfy the\n // factory's boot guard and then FAIL TO RESOLVE when an erasure actually runs. `roles` is inert\n // on a non-URL-bearing variant; the real gate is the derived `systemAccessPolicy` grant.\n variantType: ResourceOperationVariantType.INTERNAL_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER],\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n }\n ],\n },\n\n // Profile / preferences writes ride the dedicated `USER_SELF_PROFILES` and\n // `USER_SELF_PREFERENCES` resources — the `UPDATE_PROFILE` / `UPDATE_PREFERENCES` verbs were\n // removed on 2026-08-01 (they declared another resource's schema, so they answered 200 having\n // persisted nothing). Self-service account DELETION was removed the same day: erasure is a\n // system-level API with no route, and a hard delete contradicted the `retentionPolicy` above.\n // Both removals are explained in the enum comment.\n [UserSelf_Operations.DEACTIVATE_ACCOUNT]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER], // v1: app-only, high risk - affects access\n riskLevel: ResourceOperationRiskLevel.HIGH,\n resourceOperationLike: CoreResourceOperation.UPDATE,\n // Implemented by the shared status-transition factory (ACTIVE → INACTIVE). INACTIVE, not\n // SUSPENDED: the distinction is the point — SUSPENDED is imposed and only an admin lifts\n // it, while INACTIVE is chosen and the user lifts it themselves via REACTIVATE_ACCOUNT.\n // NO `reactivationDate`. It was declared here and persisted to\n // `User.scheduledReactivationAt`, but nothing could ever honour it: the reactivation sweep\n // dispatches each resource's own lifecycle verb, and the only verb that lifts `INACTIVE`\n // is REACTIVATE_ACCOUNT below — self-scoped and `APP_USER`-gated, so a system principal\n // cannot address another person's row through it.\n //\n // The two ways to make it work were both worse than the gap. Widening\n // `users | unsuspend_user` to accept `INACTIVE` merges an IMPOSED suspension with a CHOSEN\n // deactivation into one verb — two states whose whole distinction is who may lift them.\n // And `admitsCrossSubjectUserAdministration` (the framework's per-variant \"this verb\n // administers another person\" opt-in) relaxes WHOSE row may be addressed but never WHO may\n // call, so putting it on an `APP_USER` verb would let any authenticated user reactivate\n // anyone's account.\n //\n // Minting a new admin-tier reactivation verb purely to give the sweep a door would\n // manufacture a routed surface nobody asked for — the exact pattern this workstream\n // removed six times over. Voluntary deactivation is reversible by its subject at any time\n // through REACTIVATE_ACCOUNT, so a scheduled auto-return was a convenience, not a promise\n // the product makes anywhere else.\n //\n // Note the ADMIN time-boxing is unaffected and IS honoured: `users | suspend_user` takes\n // `suspensionDuration` and the hourly sweep lifts it, because `unsuspend_user` is a door a\n // system principal can dispatch. That is the case that actually matters — an operator who\n // said \"seven days\" must get seven days.\n requestDto: z.object({\n reason: z.string().max(500).optional(),\n }),\n enabledCondition: ({ currentObject }) => {\n return currentObject.status === UserStatus.ACTIVE;\n }\n }\n ],\n userNotifications: [\n {\n target: CoreUserNotificationTarget.USER_SELF,\n channel: CoreUserNotificationChannel.EMAIL,\n }\n ]\n },\n\n [UserSelf_Operations.REACTIVATE_ACCOUNT]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER], // v1: app-only, medium risk\n riskLevel: ResourceOperationRiskLevel.MEDIUM,\n resourceOperationLike: CoreResourceOperation.UPDATE,\n // Self-service reactivation FORCES the one transition it names. Omitting\n // `requestDto` would auto-derive the FULL user update DTO — which on this resource\n // is `{status, appRoles, userTypes}` — so an end-user-facing verb would accept its\n // own `appRoles` and `userTypes`, with no ceiling gate anywhere on the path\n // (`assertRequestedRolesWithinCallerCeiling` is not called here). Narrowing to an\n // empty contract removes the role surface entirely, which is why this needs no\n // ceiling call.\n // assurance-control: WILDO.ACCESS.LEAST_PRIVILEGE — a self-service verb must not be a\n // role-assignment surface.\n requestDto: z.object({}),\n // The transition itself is implemented by the SHARED status-transition factory, like its\n // inverse DEACTIVATE_ACCOUNT above — not by a `basicPrefixOperation` here.\n //\n // It used to be the hook, and the asymmetry cost three things: the pending\n // `scheduledReactivationAt` was never cleared (leaving a date on an ACTIVE row that no\n // longer described anything), no transition audit row was emitted (so the self-service\n // pair was half-trailed — the departure recorded, the return not), and the\n // administrative-continuity floors did not run. Harmless individually, but it made the\n // one lifecycle verb in the family that bypassed the shared authority the one nobody\n // would think to check.\n //\n // The factory's registration declares `authoritativeFields: ['status',\n // 'scheduledReactivationAt']`, which is what carries the patch past the repository's\n // strict re-parse — the protection the hook's own declaration used to provide.\n enabledCondition: ({ currentObject }) => {\n return currentObject.status === UserStatus.INACTIVE;\n }\n }\n ],\n userNotifications: [\n {\n target: CoreUserNotificationTarget.USER_SELF,\n channel: CoreUserNotificationChannel.EMAIL,\n }\n ]\n }\n },\n});\n"]}
|
|
1
|
+
{"version":3,"file":"user-self.shared.resources-config.schemas.js","sourceRoot":"","sources":["../../../../src/users/user-self.shared.resources-config.schemas.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * User Self Shared Resource Configuration\n *\n * Resource configuration for user self-management operations.\n * Handles profile management, preferences, and personal data operations.\n */\n\nimport { z } from 'zod';\nimport { UserSchema, UserStatus } from './users.shared.schemas';\nimport { CoreResourceOperation } from '../resources/resources.shared.core.definitions';\nimport { ResourceOperationRiskLevel, ResourceRelationship } from '../resources/resources.shared.schemas';\nimport { CoreResourceType, coreResourceShared_FieldIdentifier } from '../resources/resources.shared.core.definitions';\nimport { ResourceOperationVariantType } from '../resources/resources.shared.schemas';\nimport { CoreUserNotificationTarget, CoreUserNotificationChannel } from '../notifications/notifications.shared.schemas';\n\nimport { createResourceConfiguration_Initialization } from '../resources/resources-config.shared.factory';\nimport { ErasureRetentionMode, ResourceDataSubjectKind } from '../compliance/privacy/impersonalization.shared.schemas';\n\nimport { CORE_APP_ROLES } from '../security/authorizations/roles.shared.schemas';\nimport { ResourceSystemAccessMode } from '../resources/resources-config.shared.schemas';\nimport { DataPortabilityProvenance } from '../compliance/privacy/subject-export.shared.schemas';\n\n// Custom operations enum for user self management\n//\n// PASSWORD CHANGE IS NOT A RESOURCE OPERATION — IT IS AN AUTH ROUTE. `CHANGE_PASSWORD` was\n// declared here as an `APP_USER`-gated `riskLevel: HIGH` operation taking\n// `{ currentPassword, newPassword, confirmPassword }`, and was removed on 2026-08-01: it was\n// ROUTED but never implemented, so the request fell through to the generic core UPDATE, which\n// persists only fields the resource schema declares. A password verifier is not one of them\n// (credentials are a separate store), so every call answered **HTTP 200 having changed nothing**\n// — the caller is told their password rotated while the old one still works.\n//\n// The real implementation already exists and is the ONLY correct home for it:\n// `POST /auth/password/change` → `AuthMethodManagementBackendService.changePassword`, which\n// verifies the current-password proof, applies the per-user-type password policy, hashes,\n// invalidates every refresh token for the user, and writes a `USER_PASSWORD_CHANGED` audit\n// record. It is rate-limited (5/min/IP) and parses its body with `z.strictObject` so an\n// identity field smuggled into the payload is rejected loudly rather than silently ignored.\n// The frontend already calls exactly that route (`AppPage_SecuritySettings` →\n// `getManualCallsHttpClient().passwordChange(...)`).\n//\n// Do NOT re-declare this as a resource operation. Beyond duplicating a solved problem, it would\n// route a plaintext credential through the generic resource-write pipeline (DTO parse, repository\n// projection, notification fan-out) that the auth route deliberately bypasses.\n// See `.claude/plans/routed-unimplemented-operations-fail-closed.md`.\n//\n// NOR ARE PROFILE / PREFERENCES WRITES — THEY BELONG TO THEIR OWN RESOURCES. `UPDATE_PROFILE` and\n// `UPDATE_PREFERENCES` were removed on 2026-08-01. Both ran `resourceOperationLike: UPDATE` against\n// THIS resource — whose `mainSchema` is the USER — while declaring the request DTO of a DIFFERENT\n// resource (`UserProfileSchema.partial()` / `UserPreferencesSchema.partial()`). A core UPDATE writes\n// only its own resource's row, so every declared field was dropped; the single intersecting key was\n// `_id`, which `ResourceOperationsHelper.cleanInputData` force-deletes before validation. The write\n// was therefore empty and the route answered **HTTP 200 having persisted nothing**.\n//\n// The persisted documents already have dedicated self-scoped resources, and they are already the\n// wired path: `USER_SELF_PROFILES` exposes READ/CREATE/UPDATE over its own `mainSchema`, while\n// `USER_SELF_PREFERENCES` exposes READ/UPDATE plus its selective reset operation over the eagerly\n// seeded preferences row. Both are embedded as child resources of this one in the frontend preset,\n// carry their own resource specifications, and — for preferences — are the MCP-exposed read/update\n// tools.\n// This resource's own specification already directed engineers there for \"the persisted documents\".\n//\n// Do NOT re-declare either verb here. A single `user_self`-rooted write across child resources\n// cannot be a core UPDATE at all; it would need a custom multi-resource implementation declaring\n// `transactionParticipants` — new machinery duplicating a path that already exists. Route clients\n// to `userSelfProfiles` / `userSelfPreferences` instead.\n//\n// NOR IS SELF-SERVICE ACCOUNT DELETION — DATA-SUBJECT ERASURE IS A SYSTEM-LEVEL API WITH NO ROUTE.\n// `DELETE_ACCOUNT` was removed on 2026-08-01. It was an `APP_USER`-gated `riskLevel: CRITICAL`\n// operation taking `{ password, reason }` and declaring a scheduled-deletion\n// `customResponseDto: { scheduledDeletionDate, recoveryPeriodDays, dataExportUrl }`. It was broken\n// in four independent ways, each verified against the built configuration:\n//\n// - **The password was never verified.** Neither declared field is a persisted `UserSchema` path\n// and no custom implementation was bound to the operation path, so the built `repositoryDto`\n// was EMPTY: the controller strict-parsed the body, the repository re-parsed it, and both\n// fields were discarded. A UI collecting the password as a confirmation gate was providing\n// false assurance.\n// - **It could never answer successfully.** `transformOutput` skips default-envelope composition\n// for an op declaring a `customResponseDto` and validates the raw service output against it.\n// A core DELETE returns the deleted `_id` as a bare string, so every call threw\n// `service_resource_transformation_failed` → HTTP 500. Retries too: a second call returns `''`,\n// which is not `null`, so it fails the same parse.\n// - **Its destructive effect was NONDETERMINISTIC.** `resourceOperationLike: DELETE` reaches\n// `_doDelete` through the repository's operations map (which holds custom ops), bypassing the\n// `coreOperations` gate this config never opened — and fires `onParentDelete`. Neither\n// `USER_SELF_PROFILES` nor `USER_SELF_PREFERENCES` declares a DELETE, so a user WITH either row\n// hit `ErrorType.CONFIGURATION` inside the delete transaction and was rolled back, while a user\n// with NEITHER row was destroyed. Same 500, opposite persistence outcomes.\n// - **It contradicted this resource's own retention contract.** `retentionPolicy` below declares\n// `RETAIN_AND_IMPERSONALIZE`: user rows are RETAINED and scrubbed in place, never hard-deleted.\n//\n// The erasure capability already exists and is the only correct home: `eraseSubjectAsSystem` /\n// `eraseSubjectInPlace` walk every dependent edge, derive delete-vs-retain from each edge's own\n// `onParentDelete` declaration, fail closed on unclassified edges, and return a\n// `SubjectErasureReport`. Like the four export/portability verbs removed the same day, they\n// **deliberately ship with NO ROUTE** — data-subject rights are a system-level API, not a\n// self-service HTTP verb. `dataExportUrl` compounded this: it named the portability artifact that\n// removal established does not exist.\n//\n// Do NOT re-declare this as a resource operation. Voluntary self-service closure is\n// `DEACTIVATE_ACCOUNT` below; actual erasure runs through the compliance capability. If a product\n// ever needs a user-initiated erasure REQUEST, it is a scheduling verb over a persisted\n// request state (with its own cancel path and a batch that calls `eraseSubjectAsSystem`) — not a\n// routed DELETE, and not something the generic core delete can express.\n// See `.claude/plans/routed-unimplemented-operations-fail-closed.md`.\n//\n// assurance-control: WILDO.DATA.SECURE_LIFECYCLE — a destructive identity operation\n// must verify the principal and leave evidence; erasure must honour the declared retention mode.\nexport enum UserSelf_Operations {\n DEACTIVATE_ACCOUNT = 'deactivate_account', // Temporarily deactivate account\n REACTIVATE_ACCOUNT = 'reactivate_account', // Reactivate account\n}\n\ntype UserSelfCoreOperations =\n | CoreResourceOperation.READ\n | CoreResourceOperation.LIST\n | CoreResourceOperation.UPDATE\n | CoreResourceOperation.UPDATE_MANY;\n\n/*\nUser Self Resource Configuration Factory\n*/\nexport const userSelfResourceConfiguration_InitializationFactory = (resourcesRelationships: ResourceRelationship[]) => createResourceConfiguration_Initialization<\n typeof UserSelf_Operations,\n UserSelfCoreOperations,\n typeof UserSchema\n>({\n mainSchema: UserSchema,\n resourceIdentifier: CoreResourceType.USER_SELF,\n resourceFieldIdentifier: coreResourceShared_FieldIdentifier[CoreResourceType.USER_SELF],\n resourceRelationships: resourcesRelationships,\n isSystemResource: true, // Self-scoped\n\n /**\n * `/user-self/{userId}` names the CALLER. Declared EXPLICITLY even though `true` is the default,\n * because the sibling `USERS` configuration — over the SAME collection, with the SAME\n * `resourceFieldIdentifier` — declares `false`, and a reader comparing the two must be able to see\n * that the difference is intentional rather than an omission.\n *\n * This is the value that keeps the horizontal-IDOR refusal alive: user A addressing user B's\n * self row is refused `403 authorization_user_id_mismatch` by the identity-coherence guard. Pinned\n * by `external-access-auth.e2e.ts` (M4) and `users-administration.e2e.ts` (U-11). Flipping this to\n * `false` would open that hole silently — nothing downstream would catch it, because the addressed\n * id still reaches the contextual filter and would scope the read to B.\n */\n primaryKeyIdentifiesInitiator: true,\n\n /**\n * ⚠️ MUST MIRROR `USERS`. This config and `USERS` are two doors onto the SAME rows: they share\n * `UserSchema` above and, per `getCollectionNameForResource` in the zod→mongoose convertor,\n * `USER_SELF` builds a SEPARATE Mongoose model over the `USERS` COLLECTION.\n *\n * Retention governance is per-resource-config, so a `USERS`-only opt-in would leave two holes on\n * these shared rows:\n * - an ERASED user's row would stay READABLE and UPDATABLE through this door, whose READ/UPDATE\n * are open to `APP_USER` and would carry neither the retention hide filter nor the freeze;\n * - this model would emit a PLAIN unique index on `email` next to the `USERS` model's\n * retention-scoped one, so the SECOND erased user would collide (E11000) on the shared mask\n * address and abort the erasure.\n *\n * Declaring the same mode makes both models inject the same marker and emit the identical partial\n * index, so the collection has one coherent retention contract. Change the two configs together.\n * The scrub treatment needs no restating — it lives on the shared `UserSchema`.\n */\n retentionPolicy: {\n mode: ErasureRetentionMode.RETAIN_AND_IMPERSONALIZE,\n },\n\n /**\n * Same subject as `USERS` over the same collection — the self-service door onto the identity row.\n * Mirrors that config's `SELF_PRINCIPAL` declaration; the two must be changed together.\n */\n dataSubjectPolicy: { kind: ResourceDataSubjectKind.SELF_PRINCIPAL },\n\n /**\n * Subject-export disclosure. The self-service export subject. The identity row is what the user signed up with.\n */\n systemAccessPolicy: { exportSubject: ResourceSystemAccessMode.ALLOWED },\n\n /**\n * Subject-export disclosure. The self-service export subject. The identity row is what the user signed up with.\n */\n portabilityPolicy: { defaultProvenance: DataPortabilityProvenance.SUBJECT_PROVIDED },\n\n coreOperations: [\n CoreResourceOperation.READ,\n // LIST + UPDATE_MANY exist for the retention capability ONLY, as INTERNAL_CALL variants that\n // register no route: `retentionPolicy` requires UPDATE_MANY (the in-place scrub via\n // `updateManyAsSystem`) plus READ + LIST (the audited see-through read of retained rows). There\n // is deliberately no HTTP \"list my selves\" — see the variants below.\n CoreResourceOperation.LIST,\n CoreResourceOperation.UPDATE,\n CoreResourceOperation.UPDATE_MANY,\n ],\n\n customOperation: UserSelf_Operations,\n\n\n operationsConfiguration: {\n [CoreResourceOperation.READ]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER], // v1: app-only, user reading their own data\n riskLevel: ResourceOperationRiskLevel.LOW,\n // Default variant returns basic User data only\n }\n ]\n },\n\n [CoreResourceOperation.LIST]: {\n variants: [\n {\n // Retention capability only — INTERNAL_CALL registers NO HTTP route. A user-facing\n // \"list my selves\" would be meaningless (this resource is addressed as the caller's own\n // row); the op exists solely so `listRetainedAsSystem` has a read path through which a\n // compliance auditor can see-through to retained rows on this collection.\n //\n // ⚠️ INTERNAL_CALL, *not* REPOSITORY_ONLY — see the UPDATE_MANY note below for why the\n // distinction is load-bearing. `roles` is inert on a non-URL-bearing variant.\n variantType: ResourceOperationVariantType.INTERNAL_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER],\n riskLevel: ResourceOperationRiskLevel.LOW,\n }\n ]\n },\n\n [CoreResourceOperation.UPDATE]: {\n variants: [\n {\n // ⚠️ INTERNAL_CALL — registers NO HTTP route. This was an `API_CALL` open to\n // `APP_USER` with an auto-derived request DTO, and on THIS resource the auto-derived\n // user update DTO is `{status, appRoles, userTypes}`: every writable field on the\n // `USER_SELF` row is server-owned. `email` is `.excludeFromUpdate()` and the editable\n // self data (names, avatar, bio, phone / notification + UI preferences) lives on the\n // `USER_SELF_PROFILES` and `USER_SELF_PREFERENCES` child resources, which is where the\n // UI actually writes it. So the route offered a self-service caller nothing legitimate\n // and three things it must never set:\n //\n // - `appRoles` — the app-level authorization axis. No ceiling gate exists on this\n // path (`assertRequestedRolesWithinCallerCeiling` is wired into org-member CREATE,\n // org-unit-members, oauth-clients and api-keys only, and no custom implementation is\n // registered for `USERS` / `USER_SELF`), so a plain authenticated user could grant\n // themselves any role, up to `APP_ADMIN_SUPER_ADMIN`.\n // - `userTypes` — selects auth policy and registration context.\n // - `status` — the account lifecycle axis, which belongs to the dedicated\n // DEACTIVATE_ACCOUNT / REACTIVATE_ACCOUNT transitions below (and to the admin\n // SUSPEND_USER / UNSUSPEND_USER verbs on the `USERS` door). A self-service caller\n // flipping it directly bypasses every state gate those verbs declare.\n //\n // Narrowing `requestDto` would have left the route in place answering an empty write;\n // removing the HTTP surface is the honest fix, because no caller wants it. Verified\n // before the change: the engine presets surface no `UPDATE` action for `USER_SELF`\n // (self edits go to the child resources), and no backend caller invokes `USER_SELF`\n // update — the trusted internal door for user rows is `USERS`.\n //\n // The operation itself is KEPT (not dropped from `coreOperations`) because the custom\n // self verbs borrow it through `resourceOperationLike: UPDATE`, and INTERNAL_CALL is\n // the resource's established idiom for a route-less operation — see `LIST` and\n // `UPDATE_MANY` above/below, and the note there on why INTERNAL_CALL rather than\n // REPOSITORY_ONLY. `roles` is inert on a non-URL-bearing variant.\n //\n // assurance-control: WILDO.ACCESS.LEAST_PRIVILEGE — a self-service surface\n // must not be a privilege-assignment or lifecycle-override surface.\n variantType: ResourceOperationVariantType.INTERNAL_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER],\n riskLevel: ResourceOperationRiskLevel.MEDIUM,\n }\n ],\n userNotifications: [\n {\n target: CoreUserNotificationTarget.USER_SELF,\n channel: CoreUserNotificationChannel.FRONT_END_SUCCESS,\n }\n ]\n },\n\n [CoreResourceOperation.UPDATE_MANY]: {\n variants: [\n {\n // Retention capability only — INTERNAL_CALL registers NO HTTP route. Required by\n // `retentionPolicy` because the impersonalize writer scrubs in place through\n // `updateManyAsSystem`. A user bulk-updating rows through the self door would be\n // nonsensical AND dangerous, so the only caller is the trusted system writer.\n //\n // ⚠️ INTERNAL_CALL, *not* REPOSITORY_ONLY. Both are route-less, but the three retention\n // primitives (`updateManyAsSystem`, `readRetainedAsSystem`, `listRetainedAsSystem`) resolve\n // through `getServiceOperationPathDefault`, which matches only INTERNAL_CALL / API_CALL /\n // API_CALL_WITH_CALLBACK — REPOSITORY_ONLY is excluded there and served by the separate\n // `getRepositoryOperationPathDefault` transport. A REPOSITORY_ONLY variant would satisfy the\n // factory's boot guard and then FAIL TO RESOLVE when an erasure actually runs. `roles` is inert\n // on a non-URL-bearing variant; the real gate is the derived `systemAccessPolicy` grant.\n variantType: ResourceOperationVariantType.INTERNAL_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER],\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n }\n ],\n },\n\n // Profile / preferences writes ride the dedicated `USER_SELF_PROFILES` and\n // `USER_SELF_PREFERENCES` resources — the `UPDATE_PROFILE` / `UPDATE_PREFERENCES` verbs were\n // removed on 2026-08-01 (they declared another resource's schema, so they answered 200 having\n // persisted nothing). Self-service account DELETION was removed the same day: erasure is a\n // system-level API with no route, and a hard delete contradicted the `retentionPolicy` above.\n // Both removals are explained in the enum comment.\n [UserSelf_Operations.DEACTIVATE_ACCOUNT]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER], // v1: app-only, high risk - affects access\n riskLevel: ResourceOperationRiskLevel.HIGH,\n resourceOperationLike: CoreResourceOperation.UPDATE,\n // Implemented by the shared status-transition factory (ACTIVE → INACTIVE). INACTIVE, not\n // SUSPENDED: the distinction is the point — SUSPENDED is imposed and only an admin lifts\n // it, while INACTIVE is chosen and the user lifts it themselves via REACTIVATE_ACCOUNT.\n // NO `reactivationDate`. It was declared here and persisted to\n // `User.scheduledReactivationAt`, but nothing could ever honour it: the reactivation sweep\n // dispatches each resource's own lifecycle verb, and the only verb that lifts `INACTIVE`\n // is REACTIVATE_ACCOUNT below — self-scoped and `APP_USER`-gated, so a system principal\n // cannot address another person's row through it.\n //\n // The two ways to make it work were both worse than the gap. Widening\n // `users | unsuspend_user` to accept `INACTIVE` merges an IMPOSED suspension with a CHOSEN\n // deactivation into one verb — two states whose whole distinction is who may lift them.\n // And `admitsCrossSubjectUserAdministration` (the framework's per-variant \"this verb\n // administers another person\" opt-in) relaxes WHOSE row may be addressed but never WHO may\n // call, so putting it on an `APP_USER` verb would let any authenticated user reactivate\n // anyone's account.\n //\n // Minting a new admin-tier reactivation verb purely to give the sweep a door would\n // manufacture a routed surface nobody asked for — the exact pattern this workstream\n // removed six times over.\n //\n // CORRECTED 2026-09-08 (#430). This paragraph used to end \"Voluntary deactivation is\n // reversible by its subject at any time through REACTIVATE_ACCOUNT, so a scheduled\n // auto-return was a convenience, not a promise\". That is FALSE, and it was load-bearing:\n // it is the stated reason the auto-return was rejected. REACTIVATE_ACCOUNT needs a\n // SESSION, and `_enforceUserStatus` (authentication-orchestrator.backend.service.ts:709-716)\n // refuses every non-ACTIVE status at sign-in — so a self-deactivated person cannot reach\n // the verb that would reverse it.\n //\n // RESOLVED, and the answer is that reversal is an ADMINISTRATIVE act: `users |\n // reactivate_user` (INACTIVE → ACTIVE, `APP_ADMIN_SUPER_ADMIN`, mandatory `reason`,\n // audited) is the door. So deactivation is NOT reversible by its subject, and the\n // operation's own SPECIFICATION says so — that is where the words a person reads come\n // from (`.claude/rules/display-text-comes-from-i18n.md`: display text is authored in the\n // spec and generated into the label tree, never invented at the call site).\n //\n // The two alternatives rejected above are still rejected for the reasons given, which is\n // why they are kept: widening `unsuspend_user` conflates an imposed suspension with a\n // chosen departure, and `admitsCrossSubjectUserAdministration` on an `APP_USER` verb\n // would let any authenticated user reactivate anyone. The third — admitting INACTIVE at\n // sign-in with a session scoped to one verb — was rejected on #430 for widening what a\n // sign-in returns.\n //\n // Note the ADMIN time-boxing is unaffected and IS honoured: `users | suspend_user` takes\n // `suspensionDuration` and the hourly sweep lifts it, because `unsuspend_user` is a door a\n // system principal can dispatch. That is the case that actually matters — an operator who\n // said \"seven days\" must get seven days.\n requestDto: z.object({\n reason: z.string().max(500).optional(),\n }),\n enabledCondition: ({ currentObject }) => {\n return currentObject.status === UserStatus.ACTIVE;\n }\n }\n ],\n userNotifications: [\n {\n target: CoreUserNotificationTarget.USER_SELF,\n channel: CoreUserNotificationChannel.EMAIL,\n // Delivered even to a person who switched email notifications off (#409). An account\n // lifecycle change is the alert that matters most precisely when the account holder did\n // NOT perform it, and this email is how they find out. A preference about routine\n // notifications must not be able to silence it.\n alwaysDeliver: true,\n }\n ]\n },\n\n [UserSelf_Operations.REACTIVATE_ACCOUNT]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER], // v1: app-only, medium risk\n riskLevel: ResourceOperationRiskLevel.MEDIUM,\n resourceOperationLike: CoreResourceOperation.UPDATE,\n // Self-service reactivation FORCES the one transition it names. Omitting\n // `requestDto` would auto-derive the FULL user update DTO — which on this resource\n // is `{status, appRoles, userTypes}` — so an end-user-facing verb would accept its\n // own `appRoles` and `userTypes`, with no ceiling gate anywhere on the path\n // (`assertRequestedRolesWithinCallerCeiling` is not called here). Narrowing to an\n // empty contract removes the role surface entirely, which is why this needs no\n // ceiling call.\n // assurance-control: WILDO.ACCESS.LEAST_PRIVILEGE — a self-service verb must not be a\n // role-assignment surface.\n requestDto: z.object({}),\n // The transition itself is implemented by the SHARED status-transition factory, like its\n // inverse DEACTIVATE_ACCOUNT above — not by a `basicPrefixOperation` here.\n //\n // It used to be the hook, and the asymmetry cost three things: the pending\n // `scheduledReactivationAt` was never cleared (leaving a date on an ACTIVE row that no\n // longer described anything), no transition audit row was emitted (so the self-service\n // pair was half-trailed — the departure recorded, the return not), and the\n // administrative-continuity floors did not run. Harmless individually, but it made the\n // one lifecycle verb in the family that bypassed the shared authority the one nobody\n // would think to check.\n //\n // The factory's registration declares `authoritativeFields: ['status',\n // 'scheduledReactivationAt']`, which is what carries the patch past the repository's\n // strict re-parse — the protection the hook's own declaration used to provide.\n enabledCondition: ({ currentObject }) => {\n return currentObject.status === UserStatus.INACTIVE;\n }\n }\n ],\n userNotifications: [\n {\n target: CoreUserNotificationTarget.USER_SELF,\n channel: CoreUserNotificationChannel.EMAIL,\n // Delivered even to a person who switched email notifications off (#409). An account\n // lifecycle change is the alert that matters most precisely when the account holder did\n // NOT perform it, and this email is how they find out. A preference about routine\n // notifications must not be able to silence it.\n alwaysDeliver: true,\n }\n ]\n }\n },\n});\n"]}
|
|
@@ -14,7 +14,23 @@ export declare enum Users_Operations {
|
|
|
14
14
|
REVOKE_ROLES = "revoke_roles",// Revoke application roles
|
|
15
15
|
SUSPEND_USER = "suspend_user",// Suspend user account
|
|
16
16
|
UNSUSPEND_USER = "unsuspend_user",// Unsuspend user account
|
|
17
|
-
|
|
17
|
+
REACTIVATE_USER = "reactivate_user",// Reactivate a SELF-deactivated account (INACTIVE → ACTIVE)
|
|
18
|
+
FORCE_PASSWORD_RESET = "force_password_reset",// Force password reset
|
|
19
|
+
/**
|
|
20
|
+
* The audited see-through read of a RETAINED (erased-and-impersonalized) user row (#490).
|
|
21
|
+
*
|
|
22
|
+
* `retentionPolicy: RETAIN_AND_IMPERSONALIZE` keeps the row and scrubs its subject, and the M5a
|
|
23
|
+
* hide-predicate then makes it unreadable through every ordinary door — deliberately. The engine
|
|
24
|
+
* has held the audited way back in (`readRetainedAsSystem`) since that landed, and **nothing could
|
|
25
|
+
* reach it**: the primitive was referenced by the factory that derives its grant and by prose, and
|
|
26
|
+
* by no caller. So the only route to a retained record was a database console, which is the
|
|
27
|
+
* unaudited path the primitive exists to replace.
|
|
28
|
+
*
|
|
29
|
+
* This is that route. It is not a second read of the users table — it reveals personal data a
|
|
30
|
+
* retention policy deliberately made unreadable, which is why it is its own operation with its own
|
|
31
|
+
* role gate, its own mandatory justification and its own audit row.
|
|
32
|
+
*/
|
|
33
|
+
READ_RETAINED = "read_retained"
|
|
18
34
|
}
|
|
19
35
|
type UsersCoreOperations = CoreResourceOperation.READ | CoreResourceOperation.LIST | CoreResourceOperation.SEARCH | CoreResourceOperation.CREATE | CoreResourceOperation.UPDATE | CoreResourceOperation.UPDATE_MANY | CoreResourceOperation.DELETE;
|
|
20
36
|
export declare const usersResourceConfiguration_InitializationFactory: (resourcesRelationships: ResourceRelationship[]) => import("..").ResourceConfiguration<typeof Users_Operations, UsersCoreOperations, z.ZodObject<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"users.shared.resources-config.schemas.d.ts","sourceRoot":"","sources":["../../../../src/users/users.shared.resources-config.schemas.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAEL,UAAU,EAEX,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,qBAAqB,EAAE,MAAM,gDAAgD,CAAC;AACvF,OAAO,EAAoD,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAS/H,OAAO,EAAE,cAAc,EAAE,MAAM,iDAAiD,CAAC;
|
|
1
|
+
{"version":3,"file":"users.shared.resources-config.schemas.d.ts","sourceRoot":"","sources":["../../../../src/users/users.shared.resources-config.schemas.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAEL,UAAU,EAEX,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,qBAAqB,EAAE,MAAM,gDAAgD,CAAC;AACvF,OAAO,EAAoD,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAS/H,OAAO,EAAE,cAAc,EAAE,MAAM,iDAAiD,CAAC;AA4HjF,oBAAY,gBAAgB;IAC1B,YAAY,iBAAiB,CAAE,2BAA2B;IAC1D,YAAY,iBAAiB,CAAE,2BAA2B;IAC1D,YAAY,iBAAiB,CAAE,uBAAuB;IACtD,cAAc,mBAAmB,CAAE,yBAAyB;IAC5D,eAAe,oBAAoB,CAAE,4DAA4D;IACjG,oBAAoB,yBAAyB,CAAE,uBAAuB;IACtE;;;;;;;;;;;;;OAaG;IACH,aAAa,kBAAkB;CAChC;AAED,KAAK,mBAAmB,GACpB,qBAAqB,CAAC,IAAI,GAC1B,qBAAqB,CAAC,IAAI,GAC1B,qBAAqB,CAAC,MAAM,GAC5B,qBAAqB,CAAC,MAAM,GAC5B,qBAAqB,CAAC,MAAM,GAC5B,qBAAqB,CAAC,WAAW,GACjC,qBAAqB,CAAC,MAAM,CAAC;AAKjC,eAAO,MAAM,gDAAgD,GAAI,wBAAwB,oBAAoB,EAAE;;;;;;;;;kBAioB7G,CAAC"}
|
|
@@ -102,10 +102,11 @@ const USERS_ADMIN_SORT_FIELDS = [...USERS_SORT_FIELDS, 'status'];
|
|
|
102
102
|
// every app-defined resource the engine cannot enumerate), and the framework has no such primitive
|
|
103
103
|
// today: the closest prior art, `AnonymousSessionBackendService.transposeOwnership()`, loops
|
|
104
104
|
// resource types accumulating `failedTypes[]` and reports partial failure instead of rolling back.
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
// (
|
|
105
|
+
// The same problem in its EASIER form — a receiving identity with no competing state — was also
|
|
106
|
+
// left undone: `ResourceTranspositionPolicy.MERGE` was declared vocabulary that no resource
|
|
107
|
+
// selected and that warned "not yet implemented — falling back to ADD". It was REMOVED from the
|
|
108
|
+
// enum on 2026-09-08 (#418) rather than implemented, on the same reasoning as this note: a merge
|
|
109
|
+
// primitive is owed before either surface can offer one.
|
|
109
110
|
//
|
|
110
111
|
// Re-declaring requires, as one workstream:
|
|
111
112
|
// 1. a duplicate-detection surface that produces merge candidates — without it the verb has no
|
|
@@ -139,7 +140,23 @@ export var Users_Operations;
|
|
|
139
140
|
Users_Operations["REVOKE_ROLES"] = "revoke_roles";
|
|
140
141
|
Users_Operations["SUSPEND_USER"] = "suspend_user";
|
|
141
142
|
Users_Operations["UNSUSPEND_USER"] = "unsuspend_user";
|
|
143
|
+
Users_Operations["REACTIVATE_USER"] = "reactivate_user";
|
|
142
144
|
Users_Operations["FORCE_PASSWORD_RESET"] = "force_password_reset";
|
|
145
|
+
/**
|
|
146
|
+
* The audited see-through read of a RETAINED (erased-and-impersonalized) user row (#490).
|
|
147
|
+
*
|
|
148
|
+
* `retentionPolicy: RETAIN_AND_IMPERSONALIZE` keeps the row and scrubs its subject, and the M5a
|
|
149
|
+
* hide-predicate then makes it unreadable through every ordinary door — deliberately. The engine
|
|
150
|
+
* has held the audited way back in (`readRetainedAsSystem`) since that landed, and **nothing could
|
|
151
|
+
* reach it**: the primitive was referenced by the factory that derives its grant and by prose, and
|
|
152
|
+
* by no caller. So the only route to a retained record was a database console, which is the
|
|
153
|
+
* unaudited path the primitive exists to replace.
|
|
154
|
+
*
|
|
155
|
+
* This is that route. It is not a second read of the users table — it reveals personal data a
|
|
156
|
+
* retention policy deliberately made unreadable, which is why it is its own operation with its own
|
|
157
|
+
* role gate, its own mandatory justification and its own audit row.
|
|
158
|
+
*/
|
|
159
|
+
Users_Operations["READ_RETAINED"] = "read_retained";
|
|
143
160
|
})(Users_Operations || (Users_Operations = {}));
|
|
144
161
|
/*
|
|
145
162
|
Users Resource Configuration Factory
|
|
@@ -158,7 +175,7 @@ export const usersResourceConfiguration_InitializationFactory = (resourcesRelati
|
|
|
158
175
|
* `/users/{targetId}` request as "the caller claims to be targetId" and refused it with
|
|
159
176
|
* `403 authorization_user_id_mismatch`, which made the ENTIRE administrative surface unreachable
|
|
160
177
|
* cross-user: `assign_roles`, `revoke_roles`, `suspend_user`, `unsuspend_user`,
|
|
161
|
-
* `force_password_reset`, the admin READ and the core UPDATE/DELETE. Every one of those is
|
|
178
|
+
* `reactivate_user`, `force_password_reset`, the admin READ and the core UPDATE/DELETE. Every one of those is
|
|
162
179
|
* documented in the resource specification as acting on "another user's record" and is surfaced in
|
|
163
180
|
* the admin UI as a per-row action, so the framework contradicted itself.
|
|
164
181
|
*
|
|
@@ -580,6 +597,68 @@ export const usersResourceConfiguration_InitializationFactory = (resourcesRelati
|
|
|
580
597
|
}
|
|
581
598
|
]
|
|
582
599
|
},
|
|
600
|
+
/**
|
|
601
|
+
* The only door back from a SELF-deactivated account (#430).
|
|
602
|
+
*
|
|
603
|
+
* `user_self | deactivate_account` writes INACTIVE, and until this verb existed nothing could
|
|
604
|
+
* lift it: `REACTIVATE_ACCOUNT` needs a session, sign-in admits only ACTIVE users
|
|
605
|
+
* (`_enforceUserStatus` refuses every other status), `unsuspend_user` refuses INACTIVE BY
|
|
606
|
+
* DESIGN, and `status` is excluded from update. A person who deactivated their own account was
|
|
607
|
+
* out permanently, and the only route back was a database write.
|
|
608
|
+
*
|
|
609
|
+
* ADMIN-TIER, which is door 2 of the three that were on the table, and its two costs were
|
|
610
|
+
* accepted rather than discovered: every self-deactivated user becomes a support ticket, and an
|
|
611
|
+
* administrator can reactivate an account whose owner did not ask. The second is why `reason`
|
|
612
|
+
* is MANDATORY here while `unsuspend_user` leaves it optional — an administrator reversing
|
|
613
|
+
* someone else's own choice about their account owes an auditor a sentence, where lifting an
|
|
614
|
+
* administrative suspension is merely undoing an administrative act.
|
|
615
|
+
*
|
|
616
|
+
* INACTIVE ONLY. A SUSPENDED account stays `unsuspend_user`'s business: an imposed halt and a
|
|
617
|
+
* chosen departure are two states whose whole distinction is who may lift them, and widening
|
|
618
|
+
* one verb to cover both was the option rejected precisely because it erases that.
|
|
619
|
+
*
|
|
620
|
+
* Implemented by the shared status-transition factory — which is also what routes the write
|
|
621
|
+
* through the SYSTEM door. `status` is `.excludeFromUpdate()`, so a handler writing it directly
|
|
622
|
+
* is stripped by the repository's strict re-parse and the operation reports success having
|
|
623
|
+
* persisted nothing; that failure mode has already cost this repository four sibling
|
|
624
|
+
* activations (`.claude/rules/invariant-call-site-enumeration.md` #8).
|
|
625
|
+
*
|
|
626
|
+
* assurance-control: WILDO.IDENTITY.LIFECYCLE — reinstating a deactivated principal is a
|
|
627
|
+
* privileged identity-lifecycle change and must be authorized, attributable and audited.
|
|
628
|
+
*/
|
|
629
|
+
[Users_Operations.REACTIVATE_USER]: {
|
|
630
|
+
variants: [
|
|
631
|
+
{
|
|
632
|
+
variantType: ResourceOperationVariantType.API_CALL,
|
|
633
|
+
isDefault: true,
|
|
634
|
+
roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN],
|
|
635
|
+
// Administers ANOTHER user — see `admitsCrossSubjectUserAdministration`. The caller is
|
|
636
|
+
// still gated by `roles` above; this only admits the SUBJECT to be someone else.
|
|
637
|
+
admitsCrossSubjectUserAdministration: true,
|
|
638
|
+
riskLevel: ResourceOperationRiskLevel.MEDIUM,
|
|
639
|
+
resourceOperationLike: CoreResourceOperation.UPDATE,
|
|
640
|
+
// MEDIUM is below `AUTOMATIC_AUDIT_RISK_FLOOR`, so without this the trail would record
|
|
641
|
+
// the departure (DEACTIVATE_ACCOUNT) and not the return — an account reinstated by an
|
|
642
|
+
// administrator reading as still deactivated. Same reasoning as `unsuspend_user`.
|
|
643
|
+
// assurance-control: WILDO.ACCESS.PRIVILEGE_EVIDENCE
|
|
644
|
+
auditableEvent: { auditBelowRiskFloor: true },
|
|
645
|
+
requestDto: z.object({
|
|
646
|
+
// MANDATORY, unlike `unsuspend_user`'s: see the JSDoc above.
|
|
647
|
+
reason: z.string().min(1).max(500),
|
|
648
|
+
notifyUser: z.boolean().default(true),
|
|
649
|
+
}),
|
|
650
|
+
enabledCondition: ({ currentObject }) => {
|
|
651
|
+
return currentObject.status === UserStatus.INACTIVE;
|
|
652
|
+
},
|
|
653
|
+
},
|
|
654
|
+
],
|
|
655
|
+
userNotifications: [
|
|
656
|
+
{
|
|
657
|
+
target: CoreUserNotificationTarget.APPLICATION_ADMINISTRATOR,
|
|
658
|
+
channel: CoreUserNotificationChannel.EMAIL,
|
|
659
|
+
},
|
|
660
|
+
],
|
|
661
|
+
},
|
|
583
662
|
/**
|
|
584
663
|
* Administrator-compelled credential reset.
|
|
585
664
|
*
|
|
@@ -606,6 +685,58 @@ export const usersResourceConfiguration_InitializationFactory = (resourcesRelati
|
|
|
606
685
|
* assurance-control: WILDO.IDENTITY.CREDENTIAL_LIFECYCLE — privileged credential
|
|
607
686
|
* intervention is authorized, attributable, justified, and evicts existing access.
|
|
608
687
|
*/
|
|
688
|
+
/**
|
|
689
|
+
* See-through read of a retained subject (#490).
|
|
690
|
+
*
|
|
691
|
+
* ## Why it is UPDATE-like, when it plainly reads
|
|
692
|
+
*
|
|
693
|
+
* Same reasoning the webhook `testEndpoint` probe records, and for a sharper reason. Borrowing
|
|
694
|
+
* READ yields a GET, and a GET carries its parameters in the URL — which would put the operator's
|
|
695
|
+
* free-text `reason` into every access log, proxy log and browser history between here and the
|
|
696
|
+
* server. A justification for revealing scrubbed personal data routinely NAMES someone: a
|
|
697
|
+
* dispute, a legal hold, a subject. Putting it in a query string is a privacy defect, not an
|
|
698
|
+
* inconvenience.
|
|
699
|
+
*
|
|
700
|
+
* The operation also has a real side effect — every call emits a `RETAINED_DATA_ACCESS` audit row
|
|
701
|
+
* — so `x-idempotent` would have had to be false on a GET, which is the self-contradiction that
|
|
702
|
+
* argument already produced once.
|
|
703
|
+
*
|
|
704
|
+
* ## Why `reason` is in the DTO and the caller's identity is NOT
|
|
705
|
+
*
|
|
706
|
+
* `accessingUserId` and `accessingUserRoles` reach the primitive from the EXECUTION CONTEXT, never
|
|
707
|
+
* from the request. A body-supplied identity is a claim the caller writes about themselves, and
|
|
708
|
+
* the entire value of the audit row is that it says who really looked. `reason` is the one thing
|
|
709
|
+
* only the human can supply, so it is the one thing the request carries.
|
|
710
|
+
*
|
|
711
|
+
* `admitsCrossSubjectUserAdministration` is declared because the subject is by definition someone
|
|
712
|
+
* else: a retained row belongs to an erased person, and the caller is an administrator. The
|
|
713
|
+
* `roles` gate above still decides WHO may call it.
|
|
714
|
+
*/
|
|
715
|
+
[Users_Operations.READ_RETAINED]: {
|
|
716
|
+
variants: [
|
|
717
|
+
{
|
|
718
|
+
variantType: ResourceOperationVariantType.API_CALL,
|
|
719
|
+
isDefault: true,
|
|
720
|
+
roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN],
|
|
721
|
+
admitsCrossSubjectUserAdministration: true,
|
|
722
|
+
// The highest risk level the vocabulary has, and it is not decoration: this is the only
|
|
723
|
+
// operation in the resource that reveals personal data an erasure was performed to remove.
|
|
724
|
+
riskLevel: ResourceOperationRiskLevel.HIGH,
|
|
725
|
+
resourceOperationLike: CoreResourceOperation.UPDATE,
|
|
726
|
+
requestDto: z.object({
|
|
727
|
+
/**
|
|
728
|
+
* Why this reveal is happening — a legal hold, a dispute, an investigation.
|
|
729
|
+
*
|
|
730
|
+
* Required, and the length floor is enforced twice on purpose: here, so the request is
|
|
731
|
+
* refused before anything is read, and again inside `readRetainedAsSystem`, which
|
|
732
|
+
* fail-closes on a blank attribution because the audit store persists `eventData`
|
|
733
|
+
* unparsed. A reveal with no reason is an anonymous reveal.
|
|
734
|
+
*/
|
|
735
|
+
reason: z.string().trim().min(1).max(500),
|
|
736
|
+
}),
|
|
737
|
+
}
|
|
738
|
+
],
|
|
739
|
+
},
|
|
609
740
|
[Users_Operations.FORCE_PASSWORD_RESET]: {
|
|
610
741
|
variants: [
|
|
611
742
|
{
|