@wildo-ai/saas-models 1.1.3 → 1.1.4

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.
Files changed (496) hide show
  1. package/dist/esm/__tests__/setup.d.ts.map +1 -1
  2. package/dist/esm/_inspect.d.ts.map +1 -1
  3. package/dist/esm/applications/application-metadata.shared.resources-config.schemas.d.ts.map +1 -1
  4. package/dist/esm/applications/application-subject.shared.schemas.d.ts.map +1 -1
  5. package/dist/esm/applications/application-versions.shared.resources-config.schemas.d.ts.map +1 -1
  6. package/dist/esm/applications/applications-context.schemas.d.ts.map +1 -1
  7. package/dist/esm/applications/applications.shared.resources-config.schemas.d.ts.map +1 -1
  8. package/dist/esm/applications/applications.shared.resources-config.schemas.js.map +1 -1
  9. package/dist/esm/applications/applications.shared.schemas.d.ts.map +1 -1
  10. package/dist/esm/billing/billing-account.shared.resources-config.schemas.d.ts.map +1 -1
  11. package/dist/esm/billing/billing-account.shared.schemas.d.ts.map +1 -1
  12. package/dist/esm/billing/billing-configuration.shared.schemas.d.ts.map +1 -1
  13. package/dist/esm/billing/billing-configuration.shared.schemas.js.map +1 -1
  14. package/dist/esm/billing/billing-enums.shared.schemas.d.ts.map +1 -1
  15. package/dist/esm/billing/billing-enums.shared.schemas.js.map +1 -1
  16. package/dist/esm/billing/billing-types.shared.schemas.d.ts +1 -0
  17. package/dist/esm/billing/billing-types.shared.schemas.d.ts.map +1 -1
  18. package/dist/esm/billing/billing-types.shared.schemas.js +45 -0
  19. package/dist/esm/billing/billing-types.shared.schemas.js.map +1 -1
  20. package/dist/esm/billing/credit-pool.shared.resources-config.schemas.d.ts.map +1 -1
  21. package/dist/esm/billing/credit-pool.shared.schemas.d.ts.map +1 -1
  22. package/dist/esm/billing/invoice-ref.shared.resources-config.schemas.d.ts.map +1 -1
  23. package/dist/esm/billing/invoice-ref.shared.schemas.d.ts.map +1 -1
  24. package/dist/esm/billing/price.shared.resources-config.schemas.d.ts.map +1 -1
  25. package/dist/esm/billing/price.shared.schemas.d.ts.map +1 -1
  26. package/dist/esm/billing/price.shared.schemas.js.map +1 -1
  27. package/dist/esm/billing/product-behavior-policy.shared.schemas.d.ts.map +1 -1
  28. package/dist/esm/billing/product-behavior-policy.shared.schemas.js.map +1 -1
  29. package/dist/esm/billing/product-definition.shared.schemas.d.ts.map +1 -1
  30. package/dist/esm/billing/product.shared.resources-config.schemas.d.ts.map +1 -1
  31. package/dist/esm/billing/product.shared.schemas.d.ts.map +1 -1
  32. package/dist/esm/billing/product.shared.schemas.js.map +1 -1
  33. package/dist/esm/billing/promotions.shared.resources-config.schemas.d.ts.map +1 -1
  34. package/dist/esm/billing/promotions.shared.schemas.d.ts.map +1 -1
  35. package/dist/esm/billing/referral.shared.resources-config.schemas.d.ts.map +1 -1
  36. package/dist/esm/billing/referral.shared.schemas.d.ts.map +1 -1
  37. package/dist/esm/billing/subscription.shared.resources-config.schemas.d.ts.map +1 -1
  38. package/dist/esm/billing/subscription.shared.resources-config.schemas.js.map +1 -1
  39. package/dist/esm/billing/subscription.shared.schemas.d.ts.map +1 -1
  40. package/dist/esm/billing/usage-record.shared.resources-config.schemas.d.ts.map +1 -1
  41. package/dist/esm/billing/usage-record.shared.schemas.d.ts.map +1 -1
  42. package/dist/esm/billing/usage-record.shared.schemas.js.map +1 -1
  43. package/dist/esm/charts/aggregation-query.shared.schemas.d.ts.map +1 -1
  44. package/dist/esm/charts/chart-definition-builder.shared.d.ts.map +1 -1
  45. package/dist/esm/companion/provider-discovery.shared.schemas.d.ts +2 -0
  46. package/dist/esm/companion/provider-discovery.shared.schemas.d.ts.map +1 -1
  47. package/dist/esm/companion/provider-discovery.shared.schemas.js.map +1 -1
  48. package/dist/esm/companion/shared-library-companion.shared.definitions.d.ts.map +1 -1
  49. package/dist/esm/companion-exports.d.ts.map +1 -1
  50. package/dist/esm/compliance/audit-trails/application-audit-logs.shared.resources-config.schemas.d.ts.map +1 -1
  51. package/dist/esm/compliance/audit-trails/application-audit-logs.shared.resources-config.schemas.js.map +1 -1
  52. package/dist/esm/compliance/audit-trails/audit-log-sink.shared.schemas.d.ts.map +1 -1
  53. package/dist/esm/compliance/audit-trails/audit-logs.shared.resources-config.schemas.d.ts.map +1 -1
  54. package/dist/esm/compliance/audit-trails/audit-trail-config.shared.schemas.d.ts.map +1 -1
  55. package/dist/esm/compliance/audit-trails/audit-trail-config.shared.schemas.js.map +1 -1
  56. package/dist/esm/compliance/audit-trails/auditable-events.shared.schema.d.ts +178 -6
  57. package/dist/esm/compliance/audit-trails/auditable-events.shared.schema.d.ts.map +1 -1
  58. package/dist/esm/compliance/audit-trails/auditable-events.shared.schema.js +326 -4
  59. package/dist/esm/compliance/audit-trails/auditable-events.shared.schema.js.map +1 -1
  60. package/dist/esm/compliance/audit-trails/security-audit-event-envelope.shared.schema.d.ts.map +1 -1
  61. package/dist/esm/compliance/audit-trails/security-audit-event-envelope.shared.schema.js +22 -0
  62. package/dist/esm/compliance/audit-trails/security-audit-event-envelope.shared.schema.js.map +1 -1
  63. package/dist/esm/compliance/documents/governed-documents.shared.schemas.d.ts.map +1 -1
  64. package/dist/esm/compliance/privacy/ai-use-posture.shared.schemas.d.ts.map +1 -1
  65. package/dist/esm/compliance/privacy/client-storage.shared.schemas.d.ts.map +1 -1
  66. package/dist/esm/compliance/privacy/data-retention.shared.schemas.d.ts.map +1 -1
  67. package/dist/esm/compliance/privacy/impersonalization-scrub.shared.utils.d.ts.map +1 -1
  68. package/dist/esm/compliance/privacy/impersonalization.shared.schemas.d.ts.map +1 -1
  69. package/dist/esm/compliance/privacy/operating-jurisdictions.shared.schemas.d.ts +27 -0
  70. package/dist/esm/compliance/privacy/operating-jurisdictions.shared.schemas.d.ts.map +1 -1
  71. package/dist/esm/compliance/privacy/operating-jurisdictions.shared.schemas.js +36 -2
  72. package/dist/esm/compliance/privacy/operating-jurisdictions.shared.schemas.js.map +1 -1
  73. package/dist/esm/compliance/privacy/operator-compliance-identity.shared.schemas.d.ts.map +1 -1
  74. package/dist/esm/compliance/privacy/personal-data-category.shared.schemas.d.ts.map +1 -1
  75. package/dist/esm/compliance/privacy/personal-data-declaration.shared.utils.d.ts.map +1 -1
  76. package/dist/esm/compliance/privacy/privacy.shared.schemas.d.ts.map +1 -1
  77. package/dist/esm/compliance/privacy/privacy.shared.schemas.js.map +1 -1
  78. package/dist/esm/compliance/privacy/redaction.shared.schemas.d.ts.map +1 -1
  79. package/dist/esm/compliance/privacy/redaction.shared.schemas.js.map +1 -1
  80. package/dist/esm/compliance/privacy/retention-schedule.shared.schemas.d.ts.map +1 -1
  81. package/dist/esm/compliance/privacy/subject-erasure.shared.schemas.d.ts.map +1 -1
  82. package/dist/esm/compliance/privacy/subject-export-render.shared.utils.d.ts.map +1 -1
  83. package/dist/esm/compliance/privacy/subject-export.shared.schemas.d.ts.map +1 -1
  84. package/dist/esm/compliance/privacy/subject-export.shared.schemas.js.map +1 -1
  85. package/dist/esm/config/analytics-value-moments.shared.schemas.d.ts.map +1 -1
  86. package/dist/esm/config/analytics-value-moments.shared.schemas.js.map +1 -1
  87. package/dist/esm/config/app-configuration-shared.shared.schemas.d.ts.map +1 -1
  88. package/dist/esm/config/auth-config-resolution.shared.utils.d.ts.map +1 -1
  89. package/dist/esm/config/auth-config-resolution.shared.utils.js.map +1 -1
  90. package/dist/esm/config/brand-assets.shared.schemas.d.ts.map +1 -1
  91. package/dist/esm/config/entity-identity-config.shared.schemas.d.ts.map +1 -1
  92. package/dist/esm/config/entity-identity-config.shared.schemas.js.map +1 -1
  93. package/dist/esm/config/frontend/chart-definition.shared.schemas.d.ts +14 -14
  94. package/dist/esm/config/frontend/chart-definition.shared.schemas.d.ts.map +1 -1
  95. package/dist/esm/config/frontend/chart-registration-alignment.shared.d.ts +139 -3
  96. package/dist/esm/config/frontend/chart-registration-alignment.shared.d.ts.map +1 -1
  97. package/dist/esm/config/frontend/chart-registration-alignment.shared.js +151 -4
  98. package/dist/esm/config/frontend/chart-registration-alignment.shared.js.map +1 -1
  99. package/dist/esm/config/frontend/navigation.shared.schemas.d.ts.map +1 -1
  100. package/dist/esm/config/frontend/onboarding.shared.schemas.d.ts.map +1 -1
  101. package/dist/esm/config/registration-acquisition-policy.shared.utils.d.ts.map +1 -1
  102. package/dist/esm/config-authoring.entry.d.ts.map +1 -1
  103. package/dist/esm/crdt/crdt-merge.shared.utils.d.ts.map +1 -1
  104. package/dist/esm/data-seeding/data-seeding-config.shared.schemas.d.ts.map +1 -1
  105. package/dist/esm/errors/errors.custom-message-ref.shared.definitions.d.ts +6 -0
  106. package/dist/esm/errors/errors.custom-message-ref.shared.definitions.d.ts.map +1 -1
  107. package/dist/esm/errors/errors.custom-message-ref.shared.definitions.js +6 -0
  108. package/dist/esm/errors/errors.custom-message-ref.shared.definitions.js.map +1 -1
  109. package/dist/esm/errors/errors.shared.definitions.d.ts.map +1 -1
  110. package/dist/esm/errors/errors.shared.schemas.d.ts.map +1 -1
  111. package/dist/esm/errors/errors.shared.utils.d.ts.map +1 -1
  112. package/dist/esm/external-data/external-data-pipeline.shared.schemas.d.ts.map +1 -1
  113. package/dist/esm/external-data/external-data-pipeline.shared.schemas.js.map +1 -1
  114. package/dist/esm/external-data.exports.d.ts.map +1 -1
  115. package/dist/esm/external-providers/compose-provider-registry.shared.d.ts.map +1 -1
  116. package/dist/esm/external-providers/engine-capabilities.shared.schemas.d.ts +7 -0
  117. package/dist/esm/external-providers/engine-capabilities.shared.schemas.d.ts.map +1 -1
  118. package/dist/esm/external-providers/engine-capabilities.shared.schemas.js +7 -0
  119. package/dist/esm/external-providers/engine-capabilities.shared.schemas.js.map +1 -1
  120. package/dist/esm/external-providers/engine-capability-resolution-mode.shared.d.ts.map +1 -1
  121. package/dist/esm/external-providers/engine-capability-resolution-mode.shared.js.map +1 -1
  122. package/dist/esm/external-providers/external-providers.shared.schemas.d.ts.map +1 -1
  123. package/dist/esm/external-providers/frontend-bootstrap.shared.schemas.d.ts +4 -0
  124. package/dist/esm/external-providers/frontend-bootstrap.shared.schemas.d.ts.map +1 -1
  125. package/dist/esm/external-providers/frontend-capability-public-config.shared.schemas.d.ts.map +1 -1
  126. package/dist/esm/external-providers/frontend-capability-public-config.shared.schemas.js.map +1 -1
  127. package/dist/esm/external-providers/frontend-capability-runtime.shared.types.d.ts.map +1 -1
  128. package/dist/esm/external-providers/frontend-capability-runtime.shared.types.js.map +1 -1
  129. package/dist/esm/external-providers/frontend-provider-entry.shared.schemas.d.ts +57 -0
  130. package/dist/esm/external-providers/frontend-provider-entry.shared.schemas.d.ts.map +1 -1
  131. package/dist/esm/external-providers/frontend-provider-entry.shared.schemas.js +29 -0
  132. package/dist/esm/external-providers/frontend-provider-entry.shared.schemas.js.map +1 -1
  133. package/dist/esm/external-providers/frontend-provider-public-config.shared.d.ts +175 -0
  134. package/dist/esm/external-providers/frontend-provider-public-config.shared.d.ts.map +1 -0
  135. package/dist/esm/external-providers/frontend-provider-public-config.shared.js +207 -0
  136. package/dist/esm/external-providers/frontend-provider-public-config.shared.js.map +1 -0
  137. package/dist/esm/external-providers/provider-capability.shared.schemas.d.ts.map +1 -1
  138. package/dist/esm/external-providers/provider-capability.shared.schemas.js.map +1 -1
  139. package/dist/esm/external-providers/provider-compliance-profile.shared.schemas.d.ts +18 -8
  140. package/dist/esm/external-providers/provider-compliance-profile.shared.schemas.d.ts.map +1 -1
  141. package/dist/esm/external-providers/provider-compliance-profile.shared.schemas.js +10 -4
  142. package/dist/esm/external-providers/provider-compliance-profile.shared.schemas.js.map +1 -1
  143. package/dist/esm/external-providers/provider-frontend-component-contract.shared.types.d.ts +165 -0
  144. package/dist/esm/external-providers/provider-frontend-component-contract.shared.types.d.ts.map +1 -0
  145. package/dist/esm/external-providers/provider-frontend-component-contract.shared.types.js +39 -0
  146. package/dist/esm/external-providers/provider-frontend-component-contract.shared.types.js.map +1 -0
  147. package/dist/esm/external-providers/provider-frontend-surface.shared.schemas.d.ts.map +1 -1
  148. package/dist/esm/external-providers/provider-frontend-surface.shared.schemas.js.map +1 -1
  149. package/dist/esm/external-providers/provider-metadata.shared.schemas.d.ts.map +1 -1
  150. package/dist/esm/external-providers/provider-metadata.shared.schemas.js.map +1 -1
  151. package/dist/esm/external-providers/provider-protocol.shared.schemas.d.ts.map +1 -1
  152. package/dist/esm/external-providers/provider-protocol.shared.schemas.js.map +1 -1
  153. package/dist/esm/external-providers/provider-tier-rule.shared.utils.d.ts.map +1 -1
  154. package/dist/esm/external-providers/provider-tier-rule.shared.utils.js.map +1 -1
  155. package/dist/esm/external-providers/provider-usage-pricing.shared.schemas.d.ts.map +1 -1
  156. package/dist/esm/features/application-features.shared.resources-config.schemas.d.ts.map +1 -1
  157. package/dist/esm/features/application-features.shared.resources-config.schemas.js +12 -0
  158. package/dist/esm/features/application-features.shared.resources-config.schemas.js.map +1 -1
  159. package/dist/esm/features/core-feature-definitions.shared.d.ts.map +1 -1
  160. package/dist/esm/features/core-feature-definitions.shared.js.map +1 -1
  161. package/dist/esm/features/feature-builders.shared.d.ts.map +1 -1
  162. package/dist/esm/features/feature-builders.shared.js.map +1 -1
  163. package/dist/esm/features/feature-definition.shared.schemas.d.ts.map +1 -1
  164. package/dist/esm/features/feature-registry.shared.d.ts.map +1 -1
  165. package/dist/esm/features/feature-resolution.shared.schemas.d.ts.map +1 -1
  166. package/dist/esm/features/scope-features.shared.schemas.d.ts.map +1 -1
  167. package/dist/esm/features/user-features.shared.resources-config.schemas.d.ts.map +1 -1
  168. package/dist/esm/features/user-features.shared.resources-config.schemas.js +12 -0
  169. package/dist/esm/features/user-features.shared.resources-config.schemas.js.map +1 -1
  170. package/dist/esm/files/file-remote-reference-link.shared.schemas.d.ts +73 -0
  171. package/dist/esm/files/file-remote-reference-link.shared.schemas.d.ts.map +1 -0
  172. package/dist/esm/files/file-remote-reference-link.shared.schemas.js +62 -0
  173. package/dist/esm/files/file-remote-reference-link.shared.schemas.js.map +1 -0
  174. package/dist/esm/files/file-upload-grant.shared.schemas.d.ts.map +1 -1
  175. package/dist/esm/files/file-upload-grant.shared.schemas.js.map +1 -1
  176. package/dist/esm/files/files.shared.resources-config.schemas.d.ts.map +1 -1
  177. package/dist/esm/files/files.shared.schemas.d.ts.map +1 -1
  178. package/dist/esm/files/files.shared.schemas.js.map +1 -1
  179. package/dist/esm/files/files.shared.utils.d.ts.map +1 -1
  180. package/dist/esm/flows-actors/a2a-push-delivery-log.shared.resources-config.schemas.d.ts.map +1 -1
  181. package/dist/esm/flows-actors/a2a-push-delivery-log.shared.schemas.d.ts.map +1 -1
  182. package/dist/esm/flows-actors/a2a-token-budget-state.shared.resources-config.schemas.d.ts.map +1 -1
  183. package/dist/esm/flows-actors/a2a-token-budget-state.shared.schemas.d.ts.map +1 -1
  184. package/dist/esm/flows-actors/actors.shared.schemas.d.ts.map +1 -1
  185. package/dist/esm/flows-actors/actors.shared.schemas.js.map +1 -1
  186. package/dist/esm/flows-actors/agent-traceability.shared.schemas.d.ts.map +1 -1
  187. package/dist/esm/flows-actors/agents.shared.schemas.d.ts.map +1 -1
  188. package/dist/esm/flows-actors/agents.shared.schemas.js.map +1 -1
  189. package/dist/esm/flows-actors/apps-blueprint/apps-blueprint.shared.schemas.d.ts +6 -6
  190. package/dist/esm/flows-actors/apps-blueprint/apps-blueprint.shared.schemas.d.ts.map +1 -1
  191. package/dist/esm/flows-actors/apps-blueprint/artifacts.apps-blueprint.shared.schemas.d.ts.map +1 -1
  192. package/dist/esm/flows-actors/deliberation.shared.schemas.d.ts.map +1 -1
  193. package/dist/esm/flows-actors/deliberation.shared.schemas.js.map +1 -1
  194. package/dist/esm/flows-actors/flows-actors-execution.shared.resources-config.schemas.d.ts.map +1 -1
  195. package/dist/esm/flows-actors/flows-actors-execution.shared.schemas.d.ts.map +1 -1
  196. package/dist/esm/flows-actors/flows-actors-execution.shared.schemas.js.map +1 -1
  197. package/dist/esm/flows-actors/flows-actors-task.shared.resources-config.schemas.d.ts.map +1 -1
  198. package/dist/esm/flows-actors/flows-actors-task.shared.schemas.d.ts.map +1 -1
  199. package/dist/esm/flows-actors/flows-actors.commons.shared.schemas.d.ts.map +1 -1
  200. package/dist/esm/flows-actors/flows-actors.commons.shared.schemas.js.map +1 -1
  201. package/dist/esm/flows-actors/flows-actors.configuration.shared.schemas.d.ts.map +1 -1
  202. package/dist/esm/flows-actors/flows-actors.frontend.shared.schemas.d.ts.map +1 -1
  203. package/dist/esm/flows-actors/flows-actors.io.shared.schemas.d.ts.map +1 -1
  204. package/dist/esm/flows-actors/flows-actors.io.shared.schemas.js.map +1 -1
  205. package/dist/esm/flows-actors/flows-actors.system.shared.definitions.d.ts.map +1 -1
  206. package/dist/esm/flows-actors/flows-actors.system.shared.schemas.d.ts.map +1 -1
  207. package/dist/esm/flows-actors/flows-actors.system.shared.schemas.js.map +1 -1
  208. package/dist/esm/flows-actors/flows.shared.schemas.d.ts.map +1 -1
  209. package/dist/esm/flows-actors/flows.shared.schemas.js.map +1 -1
  210. package/dist/esm/flows-actors/mcp-servers.shared.schemas.d.ts +2 -0
  211. package/dist/esm/flows-actors/mcp-servers.shared.schemas.d.ts.map +1 -1
  212. package/dist/esm/flows-actors/mcp-servers.shared.schemas.js +11 -0
  213. package/dist/esm/flows-actors/mcp-servers.shared.schemas.js.map +1 -1
  214. package/dist/esm/flows-actors/meta-workflows/actions.meta-workflows.shared.schemas.d.ts.map +1 -1
  215. package/dist/esm/flows-actors/meta-workflows/budget-authority.meta-workflows.shared.schemas.d.ts.map +1 -1
  216. package/dist/esm/flows-actors/meta-workflows/budget-authority.meta-workflows.shared.schemas.js.map +1 -1
  217. package/dist/esm/flows-actors/meta-workflows/catalog.meta-workflows.shared.schemas.d.ts.map +1 -1
  218. package/dist/esm/flows-actors/meta-workflows/context-selection.meta-workflows.shared.schemas.d.ts.map +1 -1
  219. package/dist/esm/flows-actors/meta-workflows/context-selection.meta-workflows.shared.schemas.js.map +1 -1
  220. package/dist/esm/flows-actors/meta-workflows/continuity-identifiers.meta-workflows.shared.schemas.d.ts.map +1 -1
  221. package/dist/esm/flows-actors/meta-workflows/decisions.meta-workflows.shared.schemas.d.ts.map +1 -1
  222. package/dist/esm/flows-actors/meta-workflows/decisions.meta-workflows.shared.schemas.js.map +1 -1
  223. package/dist/esm/flows-actors/meta-workflows/execution-binding-common.meta-workflows.shared.schemas.d.ts.map +1 -1
  224. package/dist/esm/flows-actors/meta-workflows/execution-binding-common.meta-workflows.shared.schemas.js.map +1 -1
  225. package/dist/esm/flows-actors/meta-workflows/portable-primitives.meta-workflows.shared.schemas.d.ts.map +1 -1
  226. package/dist/esm/flows-actors/prompt-ir.shared.schemas.d.ts.map +1 -1
  227. package/dist/esm/flows-actors/task-continuity-binding.actors.shared.schemas.d.ts.map +1 -1
  228. package/dist/esm/flows-actors/tasks.actors.shared.schemas.d.ts.map +1 -1
  229. package/dist/esm/frontend-definitions/settings-destination-ref.definitions.d.ts +112 -0
  230. package/dist/esm/frontend-definitions/settings-destination-ref.definitions.d.ts.map +1 -0
  231. package/dist/esm/frontend-definitions/settings-destination-ref.definitions.js +113 -0
  232. package/dist/esm/frontend-definitions/settings-destination-ref.definitions.js.map +1 -0
  233. package/dist/esm/guidance/guidance-flow.shared.schemas.d.ts.map +1 -1
  234. package/dist/esm/guidance/guidance-state.shared.resources-config.schemas.d.ts.map +1 -1
  235. package/dist/esm/guidance/guidance-state.shared.schemas.d.ts.map +1 -1
  236. package/dist/esm/guidance/guidance-state.shared.utils.d.ts.map +1 -1
  237. package/dist/esm/guidance/guidance-state.shared.utils.js.map +1 -1
  238. package/dist/esm/guidance/lifecycle-config.shared.schemas.d.ts.map +1 -1
  239. package/dist/esm/guidance/lifecycle-state.shared.resources-config.schemas.d.ts.map +1 -1
  240. package/dist/esm/guidance/lifecycle-state.shared.schemas.d.ts.map +1 -1
  241. package/dist/esm/guidance/milestone-builders.shared.d.ts.map +1 -1
  242. package/dist/esm/guidance/milestone-definition.shared.schemas.d.ts.map +1 -1
  243. package/dist/esm/guidance/progression-state.shared.resources-config.schemas.d.ts.map +1 -1
  244. package/dist/esm/guidance/progression-state.shared.schemas.d.ts.map +1 -1
  245. package/dist/esm/guidance/progression-state.shared.schemas.js.map +1 -1
  246. package/dist/esm/http-api-binding/http-api-binding-id.shared.utils.d.ts.map +1 -1
  247. package/dist/esm/http-api-binding/http-api-binding.shared.schemas.d.ts.map +1 -1
  248. package/dist/esm/http-api-binding/http-api-binding.shared.schemas.js.map +1 -1
  249. package/dist/esm/i18n/labelling.dto.shared.schemas.d.ts.map +1 -1
  250. package/dist/esm/index.d.ts +6 -0
  251. package/dist/esm/index.d.ts.map +1 -1
  252. package/dist/esm/index.js +6 -0
  253. package/dist/esm/index.js.map +1 -1
  254. package/dist/esm/meta-workflows.exports.d.ts.map +1 -1
  255. package/dist/esm/monitoring/monitoring.shared.schemas.d.ts.map +1 -1
  256. package/dist/esm/notifications/email/email-context.shared.schemas.d.ts.map +1 -1
  257. package/dist/esm/notifications/email/email-template-registry.shared.schemas.d.ts.map +1 -1
  258. package/dist/esm/notifications/email/email-template-registry.shared.schemas.js.map +1 -1
  259. package/dist/esm/notifications/email/email-template.shared.enums.d.ts.map +1 -1
  260. package/dist/esm/notifications/email/email-template.shared.enums.js.map +1 -1
  261. package/dist/esm/notifications/m2m/m2m-webhook-delivery-contract.shared.d.ts.map +1 -1
  262. package/dist/esm/notifications/m2m/m2m-webhook-delivery-log.shared.resources-config.schemas.d.ts.map +1 -1
  263. package/dist/esm/notifications/m2m/m2m-webhook-delivery-log.shared.schemas.d.ts.map +1 -1
  264. package/dist/esm/notifications/m2m/webhook-config.shared.resources-config.schemas.d.ts.map +1 -1
  265. package/dist/esm/notifications/m2m/webhook-config.shared.resources-config.schemas.js.map +1 -1
  266. package/dist/esm/notifications/m2m/webhook-config.shared.schemas.d.ts.map +1 -1
  267. package/dist/esm/notifications/m2m/webhook-config.shared.schemas.js.map +1 -1
  268. package/dist/esm/notifications/notification-badges.core.definitions.d.ts.map +1 -1
  269. package/dist/esm/notifications/notification-badges.core.definitions.js.map +1 -1
  270. package/dist/esm/notifications/notification-badges.schemas.d.ts.map +1 -1
  271. package/dist/esm/notifications/notification-badges.schemas.js.map +1 -1
  272. package/dist/esm/notifications/notification-badges.shared.resources-config.schemas.d.ts.map +1 -1
  273. package/dist/esm/notifications/notifications.shared.schemas.d.ts +51 -0
  274. package/dist/esm/notifications/notifications.shared.schemas.d.ts.map +1 -1
  275. package/dist/esm/notifications/notifications.shared.schemas.js +51 -0
  276. package/dist/esm/notifications/notifications.shared.schemas.js.map +1 -1
  277. package/dist/esm/organizations/organization-features.shared.resources-config.schemas.d.ts.map +1 -1
  278. package/dist/esm/organizations/organization-features.shared.resources-config.schemas.js +13 -0
  279. package/dist/esm/organizations/organization-features.shared.resources-config.schemas.js.map +1 -1
  280. package/dist/esm/organizations/organization-members.shared.resources-config.schemas.d.ts.map +1 -1
  281. package/dist/esm/organizations/organization-members.shared.schemas.d.ts.map +1 -1
  282. package/dist/esm/organizations/organization-notifications.shared.resources-config.schemas.d.ts.map +1 -1
  283. package/dist/esm/organizations/organization-notifications.shared.schemas.d.ts.map +1 -1
  284. package/dist/esm/organizations/organization-notifications.shared.schemas.js.map +1 -1
  285. package/dist/esm/organizations/organization-preferences.shared.resources-config.schemas.d.ts.map +1 -1
  286. package/dist/esm/organizations/organization-preferences.shared.schemas.d.ts.map +1 -1
  287. package/dist/esm/organizations/organization-preferences.shared.schemas.js.map +1 -1
  288. package/dist/esm/organizations/organization-profile.shared.resources-config.schemas.d.ts.map +1 -1
  289. package/dist/esm/organizations/organization-profile.shared.schemas.d.ts.map +1 -1
  290. package/dist/esm/organizations/organization-profile.shared.schemas.js.map +1 -1
  291. package/dist/esm/organizations/organization-unit-inheritance.shared.d.ts.map +1 -1
  292. package/dist/esm/organizations/organization-unit-members.shared.resources-config.schemas.d.ts.map +1 -1
  293. package/dist/esm/organizations/organization-unit-members.shared.schemas.d.ts.map +1 -1
  294. package/dist/esm/organizations/organization-unit-narrowing-decision.shared.d.ts.map +1 -1
  295. package/dist/esm/organizations/organization-unit-narrowing.example.d.ts.map +1 -1
  296. package/dist/esm/organizations/organization-unit-narrowing.shared.d.ts.map +1 -1
  297. package/dist/esm/organizations/organization-unit-narrowing.shared.js.map +1 -1
  298. package/dist/esm/organizations/organization-units.shared.resources-config.schemas.d.ts.map +1 -1
  299. package/dist/esm/organizations/organization-units.shared.schemas.d.ts.map +1 -1
  300. package/dist/esm/organizations/organizations.shared.resources-config.schemas.d.ts.map +1 -1
  301. package/dist/esm/organizations/organizations.shared.resources-config.schemas.js.map +1 -1
  302. package/dist/esm/organizations/organizations.shared.schemas.d.ts.map +1 -1
  303. package/dist/esm/organizations/tenant-teardown-config.shared.schemas.d.ts +13 -0
  304. package/dist/esm/organizations/tenant-teardown-config.shared.schemas.d.ts.map +1 -1
  305. package/dist/esm/organizations/tenant-teardown-config.shared.schemas.js +13 -0
  306. package/dist/esm/organizations/tenant-teardown-config.shared.schemas.js.map +1 -1
  307. package/dist/esm/provider-registration-runtime.exports.d.ts.map +1 -1
  308. package/dist/esm/public-runtime/index.d.ts +22 -0
  309. package/dist/esm/public-runtime/index.d.ts.map +1 -1
  310. package/dist/esm/public-runtime/index.js +14 -0
  311. package/dist/esm/public-runtime/index.js.map +1 -1
  312. package/dist/esm/queue/jobs.shared.resources-config.schemas.d.ts.map +1 -1
  313. package/dist/esm/queue/jobs.shared.resources-config.schemas.js.map +1 -1
  314. package/dist/esm/queue/jobs.shared.schemas.d.ts.map +1 -1
  315. package/dist/esm/queue/jobs.shared.schemas.js.map +1 -1
  316. package/dist/esm/queue/jobs.shared.utils.d.ts.map +1 -1
  317. package/dist/esm/queue/queues.shared.schemas.d.ts.map +1 -1
  318. package/dist/esm/queue/queues.shared.utils.d.ts.map +1 -1
  319. package/dist/esm/requests/manual-controllers-routes-documentation.d.ts.map +1 -1
  320. package/dist/esm/requests/manual-controllers-routes-documentation.js +57 -3
  321. package/dist/esm/requests/manual-controllers-routes-documentation.js.map +1 -1
  322. package/dist/esm/requests/manual-controllers-routes-urls.d.ts +47 -0
  323. package/dist/esm/requests/manual-controllers-routes-urls.d.ts.map +1 -1
  324. package/dist/esm/requests/manual-controllers-routes-urls.js +51 -0
  325. package/dist/esm/requests/manual-controllers-routes-urls.js.map +1 -1
  326. package/dist/esm/requests/rate-limits.shared.schemas.d.ts.map +1 -1
  327. package/dist/esm/requests/rate-limits.shared.schemas.js.map +1 -1
  328. package/dist/esm/requests/websocket.shared.schemas.d.ts +9 -7
  329. package/dist/esm/requests/websocket.shared.schemas.d.ts.map +1 -1
  330. package/dist/esm/requests/websocket.shared.schemas.js +17 -0
  331. package/dist/esm/requests/websocket.shared.schemas.js.map +1 -1
  332. package/dist/esm/resources/child-operations.shared.schemas.d.ts.map +1 -1
  333. package/dist/esm/resources/context-policy.shared.schemas.d.ts.map +1 -1
  334. package/dist/esm/resources/relationship-display.shared.schemas.d.ts.map +1 -1
  335. package/dist/esm/resources/resources-config.shared.factory.d.ts.map +1 -1
  336. package/dist/esm/resources/resources-config.shared.factory.js +98 -5
  337. package/dist/esm/resources/resources-config.shared.factory.js.map +1 -1
  338. package/dist/esm/resources/resources-config.shared.schemas.d.ts +48 -1
  339. package/dist/esm/resources/resources-config.shared.schemas.d.ts.map +1 -1
  340. package/dist/esm/resources/resources-config.shared.schemas.js.map +1 -1
  341. package/dist/esm/resources/resources-registry.shared.core.definitions.d.ts.map +1 -1
  342. package/dist/esm/resources/resources-registry.shared.core.definitions.js +54 -0
  343. package/dist/esm/resources/resources-registry.shared.core.definitions.js.map +1 -1
  344. package/dist/esm/resources/resources-relationships.shared.factory.d.ts.map +1 -1
  345. package/dist/esm/resources/resources-relationships.shared.factory.js.map +1 -1
  346. package/dist/esm/resources/resources-serialization.shared.schemas.d.ts.map +1 -1
  347. package/dist/esm/resources/resources.shared.core.definitions.d.ts +17 -0
  348. package/dist/esm/resources/resources.shared.core.definitions.d.ts.map +1 -1
  349. package/dist/esm/resources/resources.shared.core.definitions.js +18 -0
  350. package/dist/esm/resources/resources.shared.core.definitions.js.map +1 -1
  351. package/dist/esm/resources/resources.shared.schemas.d.ts.map +1 -1
  352. package/dist/esm/resources/resources.shared.schemas.js.map +1 -1
  353. package/dist/esm/resources/resources.shared.utils.d.ts +32 -7
  354. package/dist/esm/resources/resources.shared.utils.d.ts.map +1 -1
  355. package/dist/esm/resources/resources.shared.utils.js +32 -7
  356. package/dist/esm/resources/resources.shared.utils.js.map +1 -1
  357. package/dist/esm/resources/utils/collection-export.shared.utils.d.ts.map +1 -1
  358. package/dist/esm/resources/utils/composition-cascade-deletability.validation.d.ts.map +1 -1
  359. package/dist/esm/resources/utils/composition-seedability.validation.d.ts.map +1 -1
  360. package/dist/esm/resources/utils/context-addressed-composition-singleton.shared.utils.d.ts.map +1 -1
  361. package/dist/esm/resources/utils/duplicate-relationship-registration.validation.d.ts.map +1 -1
  362. package/dist/esm/resources/utils/field-value-disclosure.utils.d.ts.map +1 -1
  363. package/dist/esm/resources/utils/field-value-disclosure.utils.js.map +1 -1
  364. package/dist/esm/resources/utils/persistence-adapter-discrimination.shared.utils.d.ts.map +1 -1
  365. package/dist/esm/resources/utils/repository-dto-builder.utils.d.ts.map +1 -1
  366. package/dist/esm/resources/utils/required-fk-fillability.validation.d.ts.map +1 -1
  367. package/dist/esm/resources/utils/resource-operation-type-guards.utils.d.ts.map +1 -1
  368. package/dist/esm/resources/utils/resource-polymorphism.factory.d.ts.map +1 -1
  369. package/dist/esm/resources/utils/resource-polymorphism.relationships.d.ts.map +1 -1
  370. package/dist/esm/resources/utils/resource-polymorphism.schemas.d.ts.map +1 -1
  371. package/dist/esm/resources/utils/resource-polymorphism.utils.d.ts.map +1 -1
  372. package/dist/esm/resources/utils/resource-subtree.utils.d.ts.map +1 -1
  373. package/dist/esm/resources/utils/resources-config-context-needs.utils.d.ts.map +1 -1
  374. package/dist/esm/resources/utils/resources-config-operations.dtos-builder.utils.d.ts.map +1 -1
  375. package/dist/esm/resources/utils/resources-config-operations.path.utils.d.ts.map +1 -1
  376. package/dist/esm/resources/utils/resources-config-operations.urls-builder.utils.d.ts.map +1 -1
  377. package/dist/esm/resources/utils/resources-config-operations.utils.d.ts.map +1 -1
  378. package/dist/esm/resources/utils/resources-serialization.utils.d.ts.map +1 -1
  379. package/dist/esm/resources/utils/resources-summary.utils.d.ts.map +1 -1
  380. package/dist/esm/resources/utils/resources-summary.utils.js.map +1 -1
  381. package/dist/esm/resources/utils/schema-family-builder.utils.d.ts.map +1 -1
  382. package/dist/esm/resources/utils/schema-type-inference.utils.d.ts.map +1 -1
  383. package/dist/esm/resources/utils/schema-type-utils.d.ts.map +1 -1
  384. package/dist/esm/resources/utils/schema-variant-resolver.utils.d.ts.map +1 -1
  385. package/dist/esm/resources/utils/shared-persistence-collection.utils.d.ts.map +1 -1
  386. package/dist/esm/resources/utils/shared-persistence-collection.utils.js.map +1 -1
  387. package/dist/esm/resources/utils/templatable-file-fields.shared.utils.d.ts.map +1 -1
  388. package/dist/esm/runtime/domain-module.shared.definitions.d.ts.map +1 -1
  389. package/dist/esm/runtime/domain-module.shared.definitions.js.map +1 -1
  390. package/dist/esm/runtime/execution-context.shared.schemas.d.ts.map +1 -1
  391. package/dist/esm/security/api-keys/api-keys-application.shared.resources-config.schemas.d.ts.map +1 -1
  392. package/dist/esm/security/api-keys/api-keys-application.shared.resources-config.schemas.js.map +1 -1
  393. package/dist/esm/security/api-keys/api-keys-organization.shared.resources-config.schemas.d.ts.map +1 -1
  394. package/dist/esm/security/api-keys/api-keys-organization.shared.resources-config.schemas.js.map +1 -1
  395. package/dist/esm/security/api-keys/api-keys.shared.schemas.d.ts.map +1 -1
  396. package/dist/esm/security/authentications/anonymous-session/anonymous-session.shared.contract.d.ts.map +1 -1
  397. package/dist/esm/security/authentications/authentication.shared.dto.schemas.d.ts +1 -1
  398. package/dist/esm/security/authentications/authentication.shared.dto.schemas.d.ts.map +1 -1
  399. package/dist/esm/security/authentications/authentication.shared.dto.schemas.js.map +1 -1
  400. package/dist/esm/security/authentications/authentication.shared.schemas.d.ts.map +1 -1
  401. package/dist/esm/security/authentications/authentication.shared.schemas.js.map +1 -1
  402. package/dist/esm/security/authentications/authentication.shared.utils.d.ts.map +1 -1
  403. package/dist/esm/security/authentications/consumable-token.shared.schemas.d.ts.map +1 -1
  404. package/dist/esm/security/authentications/consumable-token.shared.schemas.js.map +1 -1
  405. package/dist/esm/security/authentications/cross-frontend-handoff.shared.dto.schemas.d.ts.map +1 -1
  406. package/dist/esm/security/authentications/password-reset.shared.dto.schemas.d.ts.map +1 -1
  407. package/dist/esm/security/authentications/registration.shared.dto.schemas.d.ts.map +1 -1
  408. package/dist/esm/security/authentications/registration.shared.dto.schemas.js.map +1 -1
  409. package/dist/esm/security/authentications/scim/scim-organization-unit-mapping.shared.d.ts.map +1 -1
  410. package/dist/esm/security/authentications/scim/scim-provisioning-config.shared.resources-config.schemas.d.ts.map +1 -1
  411. package/dist/esm/security/authentications/scim/scim-provisioning-config.shared.schemas.d.ts.map +1 -1
  412. package/dist/esm/security/authentications/scim/scim-provisioning-config.shared.schemas.js.map +1 -1
  413. package/dist/esm/security/authentications/scim/scim-tokens.shared.resources-config.schemas.d.ts.map +1 -1
  414. package/dist/esm/security/authentications/scim/scim-tokens.shared.schemas.d.ts.map +1 -1
  415. package/dist/esm/security/authentications/siem/siem-delivery-dlq.shared.resources-config.schemas.d.ts.map +1 -1
  416. package/dist/esm/security/authentications/siem/siem-delivery-dlq.shared.schemas.d.ts.map +1 -1
  417. package/dist/esm/security/authentications/siem/siem-delivery-reliability-contract.shared.d.ts.map +1 -1
  418. package/dist/esm/security/authentications/siem/siem-delivery-reliability-contract.shared.js.map +1 -1
  419. package/dist/esm/security/authentications/siem/siem-export-config.shared.resources-config.schemas.d.ts.map +1 -1
  420. package/dist/esm/security/authentications/siem/siem-export-config.shared.schemas.d.ts.map +1 -1
  421. package/dist/esm/security/authentications/sso/sso-config.shared.resources-config.schemas.d.ts +3 -3
  422. package/dist/esm/security/authentications/sso/sso-config.shared.resources-config.schemas.d.ts.map +1 -1
  423. package/dist/esm/security/authentications/sso/sso-config.shared.resources-config.schemas.js +35 -5
  424. package/dist/esm/security/authentications/sso/sso-config.shared.resources-config.schemas.js.map +1 -1
  425. package/dist/esm/security/authentications/sso/sso-config.shared.schemas.d.ts.map +1 -1
  426. package/dist/esm/security/authentications/sso/sso-config.shared.schemas.js.map +1 -1
  427. package/dist/esm/security/authentications/sso/sso-connection.shared.resources-config.schemas.d.ts.map +1 -1
  428. package/dist/esm/security/authentications/sso/sso-connection.shared.schemas.d.ts +2 -0
  429. package/dist/esm/security/authentications/sso/sso-connection.shared.schemas.d.ts.map +1 -1
  430. package/dist/esm/security/authentications/sso/sso-connection.shared.schemas.js +15 -0
  431. package/dist/esm/security/authentications/sso/sso-connection.shared.schemas.js.map +1 -1
  432. package/dist/esm/security/authorizations/administrative-continuity.shared.schemas.d.ts +45 -2
  433. package/dist/esm/security/authorizations/administrative-continuity.shared.schemas.d.ts.map +1 -1
  434. package/dist/esm/security/authorizations/administrative-continuity.shared.schemas.js +45 -2
  435. package/dist/esm/security/authorizations/administrative-continuity.shared.schemas.js.map +1 -1
  436. package/dist/esm/security/authorizations/application-access-grants.shared.resources-config.schemas.d.ts +35 -0
  437. package/dist/esm/security/authorizations/application-access-grants.shared.resources-config.schemas.d.ts.map +1 -0
  438. package/dist/esm/security/authorizations/application-access-grants.shared.resources-config.schemas.js +257 -0
  439. package/dist/esm/security/authorizations/application-access-grants.shared.resources-config.schemas.js.map +1 -0
  440. package/dist/esm/security/authorizations/application-access-grants.shared.schemas.d.ts +143 -0
  441. package/dist/esm/security/authorizations/application-access-grants.shared.schemas.d.ts.map +1 -0
  442. package/dist/esm/security/authorizations/application-access-grants.shared.schemas.js +219 -0
  443. package/dist/esm/security/authorizations/application-access-grants.shared.schemas.js.map +1 -0
  444. package/dist/esm/security/authorizations/platform-access-grants.shared.resources-config.schemas.d.ts.map +1 -1
  445. package/dist/esm/security/authorizations/platform-access-grants.shared.resources-config.schemas.js.map +1 -1
  446. package/dist/esm/security/authorizations/platform-access-grants.shared.schemas.d.ts +23 -0
  447. package/dist/esm/security/authorizations/platform-access-grants.shared.schemas.d.ts.map +1 -1
  448. package/dist/esm/security/authorizations/platform-access-grants.shared.schemas.js +24 -0
  449. package/dist/esm/security/authorizations/platform-access-grants.shared.schemas.js.map +1 -1
  450. package/dist/esm/security/authorizations/roles.shared.defaults.d.ts.map +1 -1
  451. package/dist/esm/security/authorizations/roles.shared.schemas.d.ts.map +1 -1
  452. package/dist/esm/security/authorizations/roles.shared.utils.d.ts.map +1 -1
  453. package/dist/esm/security/connected-accounts/provider-credentials-organization.shared.resources-config.schemas.d.ts.map +1 -1
  454. package/dist/esm/security/connected-accounts/provider-credentials-organization.shared.resources-config.schemas.js.map +1 -1
  455. package/dist/esm/security/connected-accounts/provider-credentials-user.shared.resources-config.schemas.d.ts.map +1 -1
  456. package/dist/esm/security/connected-accounts/provider-credentials-user.shared.resources-config.schemas.js.map +1 -1
  457. package/dist/esm/security/connected-accounts/provider-credentials.shared.schemas.d.ts +57 -0
  458. package/dist/esm/security/connected-accounts/provider-credentials.shared.schemas.d.ts.map +1 -1
  459. package/dist/esm/security/connected-accounts/provider-credentials.shared.schemas.js +44 -0
  460. package/dist/esm/security/connected-accounts/provider-credentials.shared.schemas.js.map +1 -1
  461. package/dist/esm/security/oauth-clients/oauth-clients-application.shared.resources-config.schemas.d.ts.map +1 -1
  462. package/dist/esm/security/oauth-clients/oauth-clients-application.shared.resources-config.schemas.js.map +1 -1
  463. package/dist/esm/security/oauth-clients/oauth-clients-organization.shared.resources-config.schemas.d.ts.map +1 -1
  464. package/dist/esm/security/oauth-clients/oauth-clients-organization.shared.resources-config.schemas.js.map +1 -1
  465. package/dist/esm/security/oauth-clients/oauth-clients.shared.schemas.d.ts.map +1 -1
  466. package/dist/esm/security/oauth-clients/oauth-clients.shared.schemas.js.map +1 -1
  467. package/dist/esm/security/oauth-clients/oauth-consent-grants.shared.resources-config.schemas.d.ts.map +1 -1
  468. package/dist/esm/security/oauth-clients/oauth-consent-grants.shared.schemas.d.ts.map +1 -1
  469. package/dist/esm/security/oauth-clients/oauth-consent-grants.shared.schemas.js.map +1 -1
  470. package/dist/esm/security/oauth-clients/oauth-resource-server.shared.schemas.d.ts.map +1 -1
  471. package/dist/esm/testing/resource-config-builders.d.ts.map +1 -1
  472. package/dist/esm/testing.d.ts.map +1 -1
  473. package/dist/esm/users/anonymous-user-marketing-metadata.shared.schemas.d.ts.map +1 -1
  474. package/dist/esm/users/anonymous-users.shared.resources-config.schemas.d.ts.map +1 -1
  475. package/dist/esm/users/anonymous-users.shared.schema.d.ts.map +1 -1
  476. package/dist/esm/users/inbound-contacts.shared.resources-config.schemas.d.ts.map +1 -1
  477. package/dist/esm/users/inbound-contacts.shared.schemas.d.ts.map +1 -1
  478. package/dist/esm/users/user-credentials.shared.resources-config.schemas.d.ts.map +1 -1
  479. package/dist/esm/users/user-credentials.shared.schemas.d.ts.map +1 -1
  480. package/dist/esm/users/user-identity-links.shared.resources-config.schemas.d.ts.map +1 -1
  481. package/dist/esm/users/user-identity-links.shared.schemas.d.ts.map +1 -1
  482. package/dist/esm/users/user-preferences-reset.shared.utils.d.ts.map +1 -1
  483. package/dist/esm/users/user-preferences.shared.resources-config.schemas.d.ts.map +1 -1
  484. package/dist/esm/users/user-profiles.shared.resources-config.schemas.d.ts.map +1 -1
  485. package/dist/esm/users/user-self-preferences.shared.resources-config.schemas.d.ts.map +1 -1
  486. package/dist/esm/users/user-self-profiles.shared.resources-config.schemas.d.ts.map +1 -1
  487. package/dist/esm/users/user-self.shared.resources-config.schemas.d.ts.map +1 -1
  488. package/dist/esm/users/user-self.shared.resources-config.schemas.js.map +1 -1
  489. package/dist/esm/users/users.shared.resources-config.schemas.d.ts.map +1 -1
  490. package/dist/esm/users/users.shared.resources-config.schemas.js.map +1 -1
  491. package/dist/esm/users/users.shared.schemas.d.ts +17 -1
  492. package/dist/esm/users/users.shared.schemas.d.ts.map +1 -1
  493. package/dist/esm/users/users.shared.schemas.js +18 -2
  494. package/dist/esm/users/users.shared.schemas.js.map +1 -1
  495. package/dist/tsconfig.build.tsbuildinfo +1 -1
  496. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"platform-access-grants.shared.schemas.js","sourceRoot":"","sources":["../../../../../src/security/authorizations/platform-access-grants.shared.schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;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;;;;;GAKG;AACH,MAAM,CAAN,IAAY,yBAoBX;AApBD,WAAY,yBAAyB;IACnC,wFAAwF;IACxF,kEAAqC,CAAA;IACrC,yFAAyF;IACzF,8CAAiB,CAAA;IACjB,gGAAgG;IAChG,8CAAiB,CAAA;IACjB;;;;;;;;;OASG;IACH,gDAAmB,CAAA;IACnB,2EAA2E;IAC3E,gDAAmB,CAAA;AACrB,CAAC,EApBW,yBAAyB,KAAzB,yBAAyB,QAoBpC;AAED;;;;;;;GAOG;AACH,MAAM,CAAN,IAAY,sCAgBX;AAhBD,WAAY,sCAAsC;IAChD,iEAAuB,CAAA;IACvB,+DAAqB,CAAA;IACrB,2DAAiB,CAAA;IACjB,6DAAmB,CAAA;IACnB;;;;;;;;;OASG;IACH,6DAAmB,CAAA;AACrB,CAAC,EAhBW,sCAAsC,KAAtC,sCAAsC,QAgBjD;AAED,yGAAyG;AACzG,MAAM,CAAN,IAAY,qCAUX;AAVD,WAAY,qCAAqC;IAC/C,kGAAkG;IAClG,sGAA6D,CAAA;IAC7D;;;;;OAKG;IACH,wFAA+C,CAAA;AACjD,CAAC,EAVW,qCAAqC,KAArC,qCAAqC,QAUhD;AAED,wFAAwF;AACxF,MAAM,iBAAiB,GAAG,UAAU,CAAC;AAErC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,8CAA8C,GAAG,EAAE,CAAC;AAEjE;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,8CAA8C,GAAG,GAAG,CAAC;AAElE,0DAA0D;AAC1D,MAAM,CAAC,MAAM,wCAAwC,GAAyC;IAC5F,yBAAyB,CAAC,gBAAgB;IAC1C,yBAAyB,CAAC,MAAM;CACjC,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,cAAc,EAAE;IAEtD;;;;;;OAMG;IACH,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,YAAY,EAAE,CAAC,cAAc,EAAE,CAAC,iBAAiB,EAAE,CAAC,eAAe,EAAE;IAErH,yGAAyG;IACzG,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,YAAY,EAAE,CAAC,cAAc,EAAE,CAAC,iBAAiB,EAAE,CAAC,iBAAiB,EAAE,CAAC,eAAe,EAAE;IAEzI;;;;;;OAMG;IACH,+FAA+F;IAC/F,8FAA8F;IAC9F,gGAAgG;IAChG,sGAAsG;IACtG,+FAA+F;IAC/F,6FAA6F;IAC7F,oEAAoE;IACpE,aAAa,EAAE,oBAAoB,CACjC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,cAAc,EAAE;SAC3C,cAAc,CAAC,oBAAoB,CAAC,YAAY,CAAC,EAClD,aAAa,CAAC,IAAI,EAClB,EAAE,SAAS,EAAE,iBAAiB,EAAE,CACjC;IAED,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC;SACtC,UAAU,CAAC,2BAA2B,CAAC;SACvC,OAAO,CAAC,yBAAyB,CAAC,gBAAgB,CAAC;SACnD,WAAW,EAAE;SACb,cAAc,EAAE;SAChB,iBAAiB,EAAE;SACnB,iBAAiB,EAAE;SACnB,eAAe,EAAE;IAEpB;;;;;;OAMG;IACH,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,cAAc,EAAE,CAAC,iBAAiB,EAAE,CAAC,iBAAiB,EAAE,CAAC,eAAe,EAAE;IAE5G,mHAAmH;IACnH,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,YAAY,EAAE,CAAC,iBAAiB,EAAE,CAAC,iBAAiB,EAAE,CAAC,eAAe,EAAE;IACvH,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE,CAAC,iBAAiB,EAAE;IAEvE;;;;;OAKG;IACH,kBAAkB,EAAE,CAAC,CAAC,IAAI,CAAC,qCAAqC,CAAC;SAC9D,UAAU,CAAC,uCAAuC,CAAC;SACnD,QAAQ,EAAE;SACV,iBAAiB,EAAE;SACnB,iBAAiB,EAAE;SACnB,eAAe,EAAE;IAEpB,iFAAiF;IACjF,2DAA2D;IAC3D,cAAc,EAAE,oBAAoB,CAClC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE,CAAC,iBAAiB,EAAE;SACtE,cAAc,CAAC,oBAAoB,CAAC,YAAY,CAAC,EAClD,aAAa,CAAC,MAAM,CACrB;IAED,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IAC9B,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC;AAIH;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,2BAA2B,CACzC,KAAoE,EACpE,GAAS;IAET,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,IAAI,KAAK,CAAC,MAAM,KAAK,yBAAyB,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACpE,OAAO,KAAK,CAAC,SAAS,YAAY,IAAI;QACpC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE;QAC3C,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC;AAC1D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gCAAgC,CAAC,wBAA4C,EAAE,GAAS;IACtG,MAAM,SAAS,GAAG,wBAAwB,IAAI,wBAAwB,GAAG,CAAC;QACxE,CAAC,CAAC,wBAAwB;QAC1B,CAAC,CAAC,8CAA8C,CAAC;IACnD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,8CAA8C,CAAC,CAAC;IACpF,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC;AACpD,CAAC;AAED;;;;;;;;;;GAUG;AACH;;;;;;;;GAQG;AACH,MAAM,CAAN,IAAY,+BAWX;AAXD,WAAY,+BAA+B;IACzC,mEAAgC,CAAA;IAChC,sDAAmB,CAAA;IACnB,gDAAa,CAAA;IACb,oDAAiB,CAAA;IACjB;;;;OAIG;IACH,oDAAiB,CAAA;AACnB,CAAC,EAXW,+BAA+B,KAA/B,+BAA+B,QAW1C","sourcesContent":["/**\n * Platform Access Grants — time-bound, justified, optionally tenant-approved elevation that lets a\n * platform operator cross the tenant boundary.\n *\n * ## Where this sits\n *\n * Wildo's answer to \"may a platform super-administrator administer any tenant?\" is YES, as at most\n * B2B platforms. The question this resource answers is the narrower one that follows: *on what\n * terms?* The progression, recorded in `.claude/rules/administrative-continuity-floors.md`:\n *\n * ambient+unaudited → ambient+audited → declared, deny-by-default → **JIT/time-bound (here)**\n * → customer-approved (here, when the tenant opts in)\n *\n * Declaring a crossing per operation variant (`admitsCrossTenantPlatformAdministration`) removed\n * AMBIENT authority: a crossing must now be asked for in code, reviewed, and specified. It did not\n * remove STANDING authority — every platform administrator still held every declared crossing,\n * permanently, over every tenant. That is the shape zero-standing-privilege programmes exist to\n * eliminate, and what NIST SP 800-53 AC-2 / AC-6(1) mean by least privilege: privileged access is\n * requested, scoped, time-boxed, and expires on its own.\n *\n * A grant is therefore required IN ADDITION to the variant's declaration. The declaration says\n * \"this verb MAY cross\"; the grant says \"this operator MAY cross into THIS tenant, until THIS time,\n * for THIS reason\". Neither is sufficient alone.\n *\n * ## The tenant-approval half (Lockbox)\n *\n * Microsoft Customer Lockbox and Google Access Approval let the CUSTOMER approve provider access\n * before it happens. Wildo models that as {@link PlatformAccessGrantStatus.PENDING_APPROVAL}, gated\n * per tenant so it is an opt-in posture rather than a deployment-wide one — the same shape those\n * products ship, and for the same reason: a tenant that has not staffed an approver must not be\n * unable to receive support.\n *\n * ## ⚠️ The interaction that is easy to get wrong\n *\n * Tenant approval and the administrative-continuity floors are in direct tension. Approval requires\n * an administrator; the floors exist precisely because a tenant can end up WITHOUT one. Requiring a\n * stranded tenant to approve its own repair is circular — the tenant cannot approve, so the repair\n * cannot happen, so the tenant stays stranded.\n *\n * This is resolved by measurement, not by exception: when the target tenant has no administratively\n * usable owner, the grant is auto-approved with\n * {@link PlatformAccessGrantAutoApprovalReason.TENANT_CANNOT_APPROVE} and recorded loudly. The\n * condition is evaluated with the SAME predicate the owner floor uses to refuse writes, so the two\n * can never disagree about whether a tenant can administer itself. An operator cannot manufacture\n * the condition either: stranding a tenant is exactly what the floors refuse.\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\n/**\n * Lifecycle of one elevation request.\n *\n * A closed vocabulary with one named runtime source: schemas, guards, fixtures and comparisons all\n * derive from this enum rather than repeating literals.\n */\nexport enum PlatformAccessGrantStatus {\n /** Awaiting a decision from an administrator of the TARGET tenant (Lockbox posture). */\n PENDING_APPROVAL = 'pending_approval',\n /** Usable now. The admission predicate accepts this status, and only while unexpired. */\n ACTIVE = 'active',\n /** The tenant refused. Terminal — a new request must be raised rather than this one retried. */\n DENIED = 'denied',\n /**\n * The window elapsed. Terminal, and written by the credential-expiry sweep since 2026-09-08\n * (#413) — before that it was reached by NO writer at all, so an elapsed grant read as ACTIVE\n * forever in the customer-facing listing of its own resource.\n *\n * The label is still bookkeeping for humans and reporting, NEVER the control: the admission\n * predicate compares `expiresAt` against now, so an expired grant stops working whether or not\n * the sweep has run. That separation is deliberate and must survive — if admission ever starts\n * reading this label, a lagging sweep becomes an authorization hole rather than a stale display.\n */\n EXPIRED = 'expired',\n /** Withdrawn before expiry, by the tenant or by the platform. Terminal. */\n REVOKED = 'revoked',\n}\n\n/**\n * Which step of a grant's life an audit row records.\n *\n * Distinct from {@link PlatformAccessGrantStatus}: a status is where the grant IS, a transition is\n * what just happened to it. They differ where it matters — an auto-approved grant lands in `ACTIVE`\n * through `REQUESTED`, never through `APPROVED`, and collapsing the two would erase exactly the\n * distinction a customer audit asks about.\n */\nexport enum PlatformAccessGrantLifecycleTransition {\n REQUESTED = 'requested',\n APPROVED = 'approved',\n DENIED = 'denied',\n REVOKED = 'revoked',\n /**\n * The window elapsed and the sweep relabelled the grant (#413). The ONE transition with no human\n * actor — every other member records a decision somebody made, so an audit row for this one\n * carries no `decidedByUserId`, and that absence is the fact rather than a gap.\n *\n * It is recorded even though the label is bookkeeping and never the control: a customer reading\n * the history of an operator's access to their tenant should see the access END, and a grant that\n * simply stops appearing as ACTIVE with no corresponding row is the version of that history that\n * raises questions.\n */\n EXPIRED = 'expired',\n}\n\n/** Why a grant became {@link PlatformAccessGrantStatus.ACTIVE} without a tenant administrator acting. */\nexport enum PlatformAccessGrantAutoApprovalReason {\n /** The tenant has not opted into approval. The default posture, matching Lockbox being opt-in. */\n TENANT_APPROVAL_NOT_REQUIRED = 'tenant_approval_not_required',\n /**\n * The tenant has NO administratively usable owner, so no principal exists who could approve.\n * Evaluated with the owner floor's own predicate — see this file's header for why the alternative\n * (refusing) is circular. Recorded at high severity: this is the one path where operator access\n * proceeds against a tenant that never consented and never could.\n */\n TENANT_CANNOT_APPROVE = 'tenant_cannot_approve',\n}\n\n/** Fixed replacement for grant free-text that cannot be cleared (a `.min(1)` field). */\nconst ERASED_GRANT_TEXT = '[erased]';\n\n/**\n * The default life of a grant whose request names no duration.\n *\n * ONE HOUR, and deliberately far below the ceiling. A request that states no duration is the\n * unconsidered case, and the unconsidered case should get the narrowest window that still works —\n * not the widest the system allows. Until 2026-09-08 this was 240, equal to the maximum, so every\n * grant that did not ask was issued a four-hour elevation; that is the opposite of what a\n * just-in-time mechanism is for.\n *\n * Sixty rather than thirty, and the reasoning is the part worth keeping: the failure mode of a\n * too-short default is not a security one, it is that an operator re-requesting mid-incident learns\n * to ask for the maximum every time — which would restore the old behaviour through the front door\n * and make the ceiling the effective default. An hour covers an ordinary support interaction\n * without teaching that habit. An operator who genuinely needs longer asks, and that ask is the\n * record we want.\n */\nexport const PLATFORM_ACCESS_GRANT_DEFAULT_DURATION_MINUTES = 60;\n\n/**\n * The maximum life of a grant, whatever a request asks for.\n *\n * Four hours is a working session, not a working week: long enough that an operator is not\n * re-requesting mid-incident, short enough that a forgotten grant is not a standing privilege by\n * another name. Callers may request LESS; the ceiling is enforced server-side so a client cannot\n * mint a long-lived elevation by asking for one.\n */\nexport const PLATFORM_ACCESS_GRANT_MAXIMUM_DURATION_MINUTES = 240;\n\n/** Statuses from which a grant can still be withdrawn. */\nexport const PLATFORM_ACCESS_GRANT_REVOCABLE_STATUSES: readonly PlatformAccessGrantStatus[] = [\n PlatformAccessGrantStatus.PENDING_APPROVAL,\n PlatformAccessGrantStatus.ACTIVE,\n];\n\nexport const PlatformAccessGrantSchema = z.object({\n _id: z.string().min(1).isPrimaryKey().isSummaryField(),\n\n /**\n * The TARGET tenant — the one being reached into, never the operator's own.\n *\n * This is the scope anchor: the grant is an organization-scoped row so the tenant can see, approve\n * and revoke elevations raised against it. A grant the tenant cannot see would defeat the point of\n * modelling consent at all.\n */\n organizationId: z.string().min(1).isDBIndexed().isForeignKey().isSummaryField().excludeFromUpdate().isAuditEvidence(),\n\n /** The operator who requested the elevation. Server-authored from the session, never client-supplied. */\n operatorUserId: z.string().min(1).isDBIndexed().isForeignKey().isSummaryField().excludeFromCreate().excludeFromUpdate().isAuditEvidence(),\n\n /**\n * Why the operator needs access. REQUIRED, and deliberately not optional anywhere in the flow.\n *\n * An elevation record without a reason answers \"who and when\" but not \"why\", which is the only\n * question a reviewer or a customer actually asks. `AC-2(7)` wants privileged assignment monitored;\n * an unexplained monitored assignment is a log line, not a control.\n */\n // USER_CONTENT — free prose an OPERATOR typed, about why they need to reach a customer tenant.\n // The data subject here is the operator, not the tenant's users; a notice covering staff must\n // enumerate it, and it is exactly the free-text surface that can name a third party in passing.\n // MASK on erasure, not REMOVE: `.min(1)` makes this non-clearable, so a null would be rejected by the\n // strict update-DTO parse the impersonalize writer runs. A fixed non-empty string is accepted.\n // It must be scrubbed at all because it is free text an operator wrote about why they needed\n // access — exactly the surface that names a third party in passing.\n justification: addImpersonalizeWith(\n z.string().min(1).max(1000).isSummaryField()\n .dataCategories(PersonalDataCategory.USER_CONTENT),\n RedactionType.MASK,\n { maskValue: ERASED_GRANT_TEXT },\n ),\n\n status: z.enum(PlatformAccessGrantStatus)\n .systemEnum('PlatformAccessGrantStatus')\n .default(PlatformAccessGrantStatus.PENDING_APPROVAL)\n .isDBIndexed()\n .isSummaryField()\n .excludeFromCreate()\n .excludeFromUpdate()\n .isAuditEvidence(),\n\n /**\n * When the elevation stops working.\n *\n * Server-authored from the requested duration, clamped to\n * {@link PLATFORM_ACCESS_GRANT_MAXIMUM_DURATION_MINUTES}. The admission predicate reads THIS field\n * rather than trusting `status`, so expiry needs no sweeper to take effect.\n */\n expiresAt: z.date().isDBIndexed().isSummaryField().excludeFromCreate().excludeFromUpdate().isAuditEvidence(),\n\n /** Set when a tenant administrator approved. Absent on an auto-approved grant — see {@link autoApprovalReason}. */\n approvedByUserId: z.string().min(1).optional().isForeignKey().excludeFromCreate().excludeFromUpdate().isAuditEvidence(),\n approvedAt: z.date().optional().excludeFromCreate().excludeFromUpdate(),\n\n /**\n * Present exactly when the grant became ACTIVE with no tenant administrator acting.\n *\n * Its absence on an ACTIVE grant is therefore meaningful: a human in the tenant approved it. That\n * distinction is what a customer audit needs and what a single `approved: true` boolean would erase.\n */\n autoApprovalReason: z.enum(PlatformAccessGrantAutoApprovalReason)\n .systemEnum('PlatformAccessGrantAutoApprovalReason')\n .optional()\n .excludeFromCreate()\n .excludeFromUpdate()\n .isAuditEvidence(),\n\n /** The tenant's reason for refusing, or the revoker's reason for withdrawing. */\n // REMOVE — free text again, and clearable (`.optional()`).\n decisionReason: addImpersonalizeWith(\n z.string().max(1000).optional().excludeFromCreate().excludeFromUpdate()\n .dataCategories(PersonalDataCategory.USER_CONTENT),\n RedactionType.REMOVE,\n ),\n\n createdAt: z.date().optional(),\n updatedAt: z.date().optional(),\n});\n\nexport type PlatformAccessGrant = z.infer<typeof PlatformAccessGrantSchema>;\n\n/**\n * Is this grant usable RIGHT NOW?\n *\n * The single predicate every consumer must use — the admission check, the tenant's UI, and any\n * report. Two independent conditions, and the expiry half is why this is a function rather than a\n * status comparison: a grant whose window elapsed is unusable the moment it elapses, with no writer\n * involved. Reading `status === ACTIVE` alone would honour a stale row for as long as no sweeper had\n * run, turning a time-bound elevation back into a standing one.\n *\n * `now` is injected so callers can evaluate a grant at a decision time they already fixed, and so\n * this stays testable without clock control.\n */\nexport function isPlatformAccessGrantUsable(\n grant: Pick<PlatformAccessGrant, 'status' | 'expiresAt'> | undefined,\n now: Date,\n): boolean {\n if (!grant) return false;\n if (grant.status !== PlatformAccessGrantStatus.ACTIVE) return false;\n return grant.expiresAt instanceof Date\n ? grant.expiresAt.getTime() > now.getTime()\n : new Date(grant.expiresAt).getTime() > now.getTime();\n}\n\n/**\n * Clamp a requested duration to the server-side ceiling.\n *\n * Applied to every request path, including trusted ones. A caller asking for a longer window is not\n * refused — being told \"no, ask again with a smaller number\" during an incident is friction with no\n * security benefit, since the ceiling is what actually binds. They simply get the ceiling.\n */\nexport function resolvePlatformAccessGrantExpiry(requestedDurationMinutes: number | undefined, now: Date): Date {\n const requested = requestedDurationMinutes && requestedDurationMinutes > 0\n ? requestedDurationMinutes\n : PLATFORM_ACCESS_GRANT_DEFAULT_DURATION_MINUTES;\n const minutes = Math.min(requested, PLATFORM_ACCESS_GRANT_MAXIMUM_DURATION_MINUTES);\n return new Date(now.getTime() + minutes * 60_000);\n}\n\n/**\n * NOTE ON PLACEMENT — this enum lives with the VOCABULARY, not with the resource configuration,\n * and moving it back would reintroduce a real defect.\n *\n * The authorization layer needs `REQUEST_ACCESS` by name (it is the bootstrap verb, exempt from the\n * grant requirement it bootstraps). Importing that value from the resources-config module dragged\n * resource-configuration evaluation into the authorizer's module graph, and schema construction that\n * runs before the Zod decorators are initialised loses decorator metadata — which surfaced, far from\n * here, as the ephemeral-disclosure catalogue losing an operation-level declaration. A vocabulary has\n * no such side effects.\n */\n/**\n * Custom verbs. Ordinary CREATE/UPDATE/DELETE are deliberately NOT exposed:\n *\n * - CREATE would let a caller author `status`, `expiresAt` and `operatorUserId` directly, which are\n * precisely the fields whose server authorship IS the control.\n * - UPDATE would be a second, ungated path to the status transitions `approve`/`deny`/`revoke` own.\n * - DELETE exists but has NO client door — see its configuration below. An elevation either side could\n * erase is not evidence; the terminal statuses (DENIED / EXPIRED / REVOKED) are how a grant ends.\n */\nexport enum PlatformAccessGrants_Operations {\n REQUEST_ACCESS = 'requestAccess',\n APPROVE = 'approve',\n DENY = 'deny',\n REVOKE = 'revoke',\n /**\n * ACTIVE → EXPIRED once the window has elapsed, dispatched by the credential-expiry sweep and by\n * nothing else (#413). Not an operator verb: an operator who wants access to end early uses\n * REVOKE, and nobody needs a button that declares a date has passed.\n */\n EXPIRE = 'expire',\n}\n"]}
1
+ {"version":3,"file":"platform-access-grants.shared.schemas.js","sourceRoot":"","sources":["../../../../src/security/authorizations/platform-access-grants.shared.schemas.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Platform Access Grants — time-bound, justified, optionally tenant-approved elevation that lets a\n * platform operator cross the tenant boundary.\n *\n * ## Where this sits\n *\n * Wildo's answer to \"may a platform super-administrator administer any tenant?\" is YES, as at most\n * B2B platforms. The question this resource answers is the narrower one that follows: *on what\n * terms?* The progression, recorded in `.claude/rules/administrative-continuity-floors.md`:\n *\n * ambient+unaudited → ambient+audited → declared, deny-by-default → **JIT/time-bound (here)**\n * → customer-approved (here, when the tenant opts in)\n *\n * Declaring a crossing per operation variant (`admitsCrossTenantPlatformAdministration`) removed\n * AMBIENT authority: a crossing must now be asked for in code, reviewed, and specified. It did not\n * remove STANDING authority — every platform administrator still held every declared crossing,\n * permanently, over every tenant. That is the shape zero-standing-privilege programmes exist to\n * eliminate, and what NIST SP 800-53 AC-2 / AC-6(1) mean by least privilege: privileged access is\n * requested, scoped, time-boxed, and expires on its own.\n *\n * A grant is therefore required IN ADDITION to the variant's declaration. The declaration says\n * \"this verb MAY cross\"; the grant says \"this operator MAY cross into THIS tenant, until THIS time,\n * for THIS reason\". Neither is sufficient alone.\n *\n * ## The tenant-approval half (Lockbox)\n *\n * Microsoft Customer Lockbox and Google Access Approval let the CUSTOMER approve provider access\n * before it happens. Wildo models that as {@link PlatformAccessGrantStatus.PENDING_APPROVAL}, gated\n * per tenant so it is an opt-in posture rather than a deployment-wide one — the same shape those\n * products ship, and for the same reason: a tenant that has not staffed an approver must not be\n * unable to receive support.\n *\n * ## ⚠️ The interaction that is easy to get wrong\n *\n * Tenant approval and the administrative-continuity floors are in direct tension. Approval requires\n * an administrator; the floors exist precisely because a tenant can end up WITHOUT one. Requiring a\n * stranded tenant to approve its own repair is circular — the tenant cannot approve, so the repair\n * cannot happen, so the tenant stays stranded.\n *\n * This is resolved by measurement, not by exception: when the target tenant has no administratively\n * usable owner, the grant is auto-approved with\n * {@link PlatformAccessGrantAutoApprovalReason.TENANT_CANNOT_APPROVE} and recorded loudly. The\n * condition is evaluated with the SAME predicate the owner floor uses to refuse writes, so the two\n * can never disagree about whether a tenant can administer itself. An operator cannot manufacture\n * the condition either: stranding a tenant is exactly what the floors refuse.\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\n/**\n * WHAT an elevation reaches, and therefore WHO can approve it.\n *\n * A closed two-member vocabulary with one named runtime source, because the two members answer a\n * question no boolean can carry: approval AUTHORITY follows scope. A `TENANT` grant names one\n * organization and is approved by that organization (the Lockbox posture); an `APPLICATION_WIDE`\n * grant names none, so there is no customer to ask and approval falls to a SECOND platform\n * administrator under the two-person rule.\n *\n * It exists as a vocabulary rather than being inferred from which resource a row came from because\n * the AUDIT TRAIL needs it: `authorizingGrantId` on a crossing names a row id, and a reviewer given\n * only an id cannot tell which of the two collections to look in. Carrying the scope beside the id\n * is what makes the join mechanical instead of a guess.\n */\nexport enum PlatformAccessGrantScope {\n /** Scoped to ONE named organization. Approved by that organization, or auto-approved per its posture. */\n TENANT = 'tenant',\n /**\n * Application-wide: an unconfined directory read or a declared cross-tenant read that names no\n * single tenant. Approved by a SECOND platform administrator — never the requester.\n */\n APPLICATION_WIDE = 'application_wide',\n}\n\n/**\n * Lifecycle of one elevation request.\n *\n * A closed vocabulary with one named runtime source: schemas, guards, fixtures and comparisons all\n * derive from this enum rather than repeating literals.\n */\nexport enum PlatformAccessGrantStatus {\n /** Awaiting a decision from an administrator of the TARGET tenant (Lockbox posture). */\n PENDING_APPROVAL = 'pending_approval',\n /** Usable now. The admission predicate accepts this status, and only while unexpired. */\n ACTIVE = 'active',\n /** The tenant refused. Terminal — a new request must be raised rather than this one retried. */\n DENIED = 'denied',\n /**\n * The window elapsed. Terminal, and written by the credential-expiry sweep since 2026-09-08\n * (#413) — before that it was reached by NO writer at all, so an elapsed grant read as ACTIVE\n * forever in the customer-facing listing of its own resource.\n *\n * The label is still bookkeeping for humans and reporting, NEVER the control: the admission\n * predicate compares `expiresAt` against now, so an expired grant stops working whether or not\n * the sweep has run. That separation is deliberate and must survive — if admission ever starts\n * reading this label, a lagging sweep becomes an authorization hole rather than a stale display.\n */\n EXPIRED = 'expired',\n /** Withdrawn before expiry, by the tenant or by the platform. Terminal. */\n REVOKED = 'revoked',\n}\n\n/**\n * Which step of a grant's life an audit row records.\n *\n * Distinct from {@link PlatformAccessGrantStatus}: a status is where the grant IS, a transition is\n * what just happened to it. They differ where it matters — an auto-approved grant lands in `ACTIVE`\n * through `REQUESTED`, never through `APPROVED`, and collapsing the two would erase exactly the\n * distinction a customer audit asks about.\n */\nexport enum PlatformAccessGrantLifecycleTransition {\n REQUESTED = 'requested',\n APPROVED = 'approved',\n DENIED = 'denied',\n REVOKED = 'revoked',\n /**\n * The window elapsed and the sweep relabelled the grant (#413). The ONE transition with no human\n * actor — every other member records a decision somebody made, so an audit row for this one\n * carries no `decidedByUserId`, and that absence is the fact rather than a gap.\n *\n * It is recorded even though the label is bookkeeping and never the control: a customer reading\n * the history of an operator's access to their tenant should see the access END, and a grant that\n * simply stops appearing as ACTIVE with no corresponding row is the version of that history that\n * raises questions.\n */\n EXPIRED = 'expired',\n}\n\n/** Why a grant became {@link PlatformAccessGrantStatus.ACTIVE} without a tenant administrator acting. */\nexport enum PlatformAccessGrantAutoApprovalReason {\n /** The tenant has not opted into approval. The default posture, matching Lockbox being opt-in. */\n TENANT_APPROVAL_NOT_REQUIRED = 'tenant_approval_not_required',\n /**\n * The tenant has NO administratively usable owner, so no principal exists who could approve.\n * Evaluated with the owner floor's own predicate — see this file's header for why the alternative\n * (refusing) is circular. Recorded at high severity: this is the one path where operator access\n * proceeds against a tenant that never consented and never could.\n */\n TENANT_CANNOT_APPROVE = 'tenant_cannot_approve',\n}\n\n/** Fixed replacement for grant free-text that cannot be cleared (a `.min(1)` field). */\nconst ERASED_GRANT_TEXT = '[erased]';\n\n/**\n * The default life of a grant whose request names no duration.\n *\n * ONE HOUR, and deliberately far below the ceiling. A request that states no duration is the\n * unconsidered case, and the unconsidered case should get the narrowest window that still works —\n * not the widest the system allows. Until 2026-09-08 this was 240, equal to the maximum, so every\n * grant that did not ask was issued a four-hour elevation; that is the opposite of what a\n * just-in-time mechanism is for.\n *\n * Sixty rather than thirty, and the reasoning is the part worth keeping: the failure mode of a\n * too-short default is not a security one, it is that an operator re-requesting mid-incident learns\n * to ask for the maximum every time — which would restore the old behaviour through the front door\n * and make the ceiling the effective default. An hour covers an ordinary support interaction\n * without teaching that habit. An operator who genuinely needs longer asks, and that ask is the\n * record we want.\n */\nexport const PLATFORM_ACCESS_GRANT_DEFAULT_DURATION_MINUTES = 60;\n\n/**\n * The maximum life of a grant, whatever a request asks for.\n *\n * Four hours is a working session, not a working week: long enough that an operator is not\n * re-requesting mid-incident, short enough that a forgotten grant is not a standing privilege by\n * another name. Callers may request LESS; the ceiling is enforced server-side so a client cannot\n * mint a long-lived elevation by asking for one.\n */\nexport const PLATFORM_ACCESS_GRANT_MAXIMUM_DURATION_MINUTES = 240;\n\n/** Statuses from which a grant can still be withdrawn. */\nexport const PLATFORM_ACCESS_GRANT_REVOCABLE_STATUSES: readonly PlatformAccessGrantStatus[] = [\n PlatformAccessGrantStatus.PENDING_APPROVAL,\n PlatformAccessGrantStatus.ACTIVE,\n];\n\nexport const PlatformAccessGrantSchema = z.object({\n _id: z.string().min(1).isPrimaryKey().isSummaryField(),\n\n /**\n * The TARGET tenant — the one being reached into, never the operator's own.\n *\n * This is the scope anchor: the grant is an organization-scoped row so the tenant can see, approve\n * and revoke elevations raised against it. A grant the tenant cannot see would defeat the point of\n * modelling consent at all.\n */\n organizationId: z.string().min(1).isDBIndexed().isForeignKey().isSummaryField().excludeFromUpdate().isAuditEvidence(),\n\n /** The operator who requested the elevation. Server-authored from the session, never client-supplied. */\n operatorUserId: z.string().min(1).isDBIndexed().isForeignKey().isSummaryField().excludeFromCreate().excludeFromUpdate().isAuditEvidence(),\n\n /**\n * Why the operator needs access. REQUIRED, and deliberately not optional anywhere in the flow.\n *\n * An elevation record without a reason answers \"who and when\" but not \"why\", which is the only\n * question a reviewer or a customer actually asks. `AC-2(7)` wants privileged assignment monitored;\n * an unexplained monitored assignment is a log line, not a control.\n */\n // USER_CONTENT — free prose an OPERATOR typed, about why they need to reach a customer tenant.\n // The data subject here is the operator, not the tenant's users; a notice covering staff must\n // enumerate it, and it is exactly the free-text surface that can name a third party in passing.\n // MASK on erasure, not REMOVE: `.min(1)` makes this non-clearable, so a null would be rejected by the\n // strict update-DTO parse the impersonalize writer runs. A fixed non-empty string is accepted.\n // It must be scrubbed at all because it is free text an operator wrote about why they needed\n // access — exactly the surface that names a third party in passing.\n justification: addImpersonalizeWith(\n z.string().min(1).max(1000).isSummaryField()\n .dataCategories(PersonalDataCategory.USER_CONTENT),\n RedactionType.MASK,\n { maskValue: ERASED_GRANT_TEXT },\n ),\n\n status: z.enum(PlatformAccessGrantStatus)\n .systemEnum('PlatformAccessGrantStatus')\n .default(PlatformAccessGrantStatus.PENDING_APPROVAL)\n .isDBIndexed()\n .isSummaryField()\n .excludeFromCreate()\n .excludeFromUpdate()\n .isAuditEvidence(),\n\n /**\n * When the elevation stops working.\n *\n * Server-authored from the requested duration, clamped to\n * {@link PLATFORM_ACCESS_GRANT_MAXIMUM_DURATION_MINUTES}. The admission predicate reads THIS field\n * rather than trusting `status`, so expiry needs no sweeper to take effect.\n */\n expiresAt: z.date().isDBIndexed().isSummaryField().excludeFromCreate().excludeFromUpdate().isAuditEvidence(),\n\n /** Set when a tenant administrator approved. Absent on an auto-approved grant — see {@link autoApprovalReason}. */\n approvedByUserId: z.string().min(1).optional().isForeignKey().excludeFromCreate().excludeFromUpdate().isAuditEvidence(),\n approvedAt: z.date().optional().excludeFromCreate().excludeFromUpdate(),\n\n /**\n * Present exactly when the grant became ACTIVE with no tenant administrator acting.\n *\n * Its absence on an ACTIVE grant is therefore meaningful: a human in the tenant approved it. That\n * distinction is what a customer audit needs and what a single `approved: true` boolean would erase.\n */\n autoApprovalReason: z.enum(PlatformAccessGrantAutoApprovalReason)\n .systemEnum('PlatformAccessGrantAutoApprovalReason')\n .optional()\n .excludeFromCreate()\n .excludeFromUpdate()\n .isAuditEvidence(),\n\n /** The tenant's reason for refusing, or the revoker's reason for withdrawing. */\n // REMOVE — free text again, and clearable (`.optional()`).\n decisionReason: addImpersonalizeWith(\n z.string().max(1000).optional().excludeFromCreate().excludeFromUpdate()\n .dataCategories(PersonalDataCategory.USER_CONTENT),\n RedactionType.REMOVE,\n ),\n\n createdAt: z.date().optional(),\n updatedAt: z.date().optional(),\n});\n\nexport type PlatformAccessGrant = z.infer<typeof PlatformAccessGrantSchema>;\n\n/**\n * Is this grant usable RIGHT NOW?\n *\n * The single predicate every consumer must use — the admission check, the tenant's UI, and any\n * report. Two independent conditions, and the expiry half is why this is a function rather than a\n * status comparison: a grant whose window elapsed is unusable the moment it elapses, with no writer\n * involved. Reading `status === ACTIVE` alone would honour a stale row for as long as no sweeper had\n * run, turning a time-bound elevation back into a standing one.\n *\n * `now` is injected so callers can evaluate a grant at a decision time they already fixed, and so\n * this stays testable without clock control.\n */\nexport function isPlatformAccessGrantUsable(\n grant: Pick<PlatformAccessGrant, 'status' | 'expiresAt'> | undefined,\n now: Date,\n): boolean {\n if (!grant) return false;\n if (grant.status !== PlatformAccessGrantStatus.ACTIVE) return false;\n return grant.expiresAt instanceof Date\n ? grant.expiresAt.getTime() > now.getTime()\n : new Date(grant.expiresAt).getTime() > now.getTime();\n}\n\n/**\n * Clamp a requested duration to the server-side ceiling.\n *\n * Applied to every request path, including trusted ones. A caller asking for a longer window is not\n * refused — being told \"no, ask again with a smaller number\" during an incident is friction with no\n * security benefit, since the ceiling is what actually binds. They simply get the ceiling.\n */\nexport function resolvePlatformAccessGrantExpiry(requestedDurationMinutes: number | undefined, now: Date): Date {\n const requested = requestedDurationMinutes && requestedDurationMinutes > 0\n ? requestedDurationMinutes\n : PLATFORM_ACCESS_GRANT_DEFAULT_DURATION_MINUTES;\n const minutes = Math.min(requested, PLATFORM_ACCESS_GRANT_MAXIMUM_DURATION_MINUTES);\n return new Date(now.getTime() + minutes * 60_000);\n}\n\n/**\n * NOTE ON PLACEMENT — this enum lives with the VOCABULARY, not with the resource configuration,\n * and moving it back would reintroduce a real defect.\n *\n * The authorization layer needs `REQUEST_ACCESS` by name (it is the bootstrap verb, exempt from the\n * grant requirement it bootstraps). Importing that value from the resources-config module dragged\n * resource-configuration evaluation into the authorizer's module graph, and schema construction that\n * runs before the Zod decorators are initialised loses decorator metadata — which surfaced, far from\n * here, as the ephemeral-disclosure catalogue losing an operation-level declaration. A vocabulary has\n * no such side effects.\n */\n/**\n * Custom verbs. Ordinary CREATE/UPDATE/DELETE are deliberately NOT exposed:\n *\n * - CREATE would let a caller author `status`, `expiresAt` and `operatorUserId` directly, which are\n * precisely the fields whose server authorship IS the control.\n * - UPDATE would be a second, ungated path to the status transitions `approve`/`deny`/`revoke` own.\n * - DELETE exists but has NO client door — see its configuration below. An elevation either side could\n * erase is not evidence; the terminal statuses (DENIED / EXPIRED / REVOKED) are how a grant ends.\n */\nexport enum PlatformAccessGrants_Operations {\n REQUEST_ACCESS = 'requestAccess',\n APPROVE = 'approve',\n DENY = 'deny',\n REVOKE = 'revoke',\n /**\n * ACTIVE → EXPIRED once the window has elapsed, dispatched by the credential-expiry sweep and by\n * nothing else (#413). Not an operator verb: an operator who wants access to end early uses\n * REVOKE, and nobody needs a button that declares a date has passed.\n */\n EXPIRE = 'expire',\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"roles.shared.defaults.d.ts","sourceRoot":"","sources":["../../../../../src/security/authorizations/roles.shared.defaults.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAkC,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5F,eAAO,MAAM,8BAA8B,EAAE,kBAwC5C,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,kBA8BxC,CAAC"}
1
+ {"version":3,"file":"roles.shared.defaults.d.ts","sourceRoot":"","sources":["../../../../src/security/authorizations/roles.shared.defaults.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAkC,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5F,eAAO,MAAM,8BAA8B,EAAE,kBAwC5C,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,kBA8BxC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"roles.shared.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/security/authorizations/roles.shared.schemas.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAEhF,oBAAY,cAAc;IACxB;;;;;;;;;;;;;;;OAeG;IACH,UAAU,eAAe;IACzB,qBAAqB,0BAA0B;IAC/C,yBAAyB,8BAA8B;IACvD,0BAA0B,+BAA+B;IACzD,gBAAgB,qBAAqB;IACrC,QAAQ,aAAa;IACrB,iGAAiG;IACjG,aAAa,kBAAkB;CAChC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,qCAAqC,EAAE,SAAS,cAAc,EAKzE,CAAC;AAEH,oBAAY,cAAc;IACxB,SAAS,cAAc;IACvB,SAAS,cAAc;IACvB,SAAS,cAAc;IACvB,WAAW,gBAAgB;IAC3B,UAAU,eAAe;CAC1B;AAGD,eAAO,MAAM,eAAe,2FAG1B,CAAC;AAEH,eAAO,MAAM,WAAW,wGAItB,CAAC;AAEH,eAAO,MAAM,cAAc,sEAGzB,CAAC;AAEH,eAAO,MAAM,cAAc,sEAGzB,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;iBAK/B,CAAC;AAGH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,wBAAwB;;;;;kBAYpC,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAChD,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AACxD,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AACtD,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AACtD,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC"}
1
+ {"version":3,"file":"roles.shared.schemas.d.ts","sourceRoot":"","sources":["../../../../src/security/authorizations/roles.shared.schemas.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAEhF,oBAAY,cAAc;IACxB;;;;;;;;;;;;;;;OAeG;IACH,UAAU,eAAe;IACzB,qBAAqB,0BAA0B;IAC/C,yBAAyB,8BAA8B;IACvD,0BAA0B,+BAA+B;IACzD,gBAAgB,qBAAqB;IACrC,QAAQ,aAAa;IACrB,iGAAiG;IACjG,aAAa,kBAAkB;CAChC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,qCAAqC,EAAE,SAAS,cAAc,EAKzE,CAAC;AAEH,oBAAY,cAAc;IACxB,SAAS,cAAc;IACvB,SAAS,cAAc;IACvB,SAAS,cAAc;IACvB,WAAW,gBAAgB;IAC3B,UAAU,eAAe;CAC1B;AAGD,eAAO,MAAM,eAAe,2FAG1B,CAAC;AAEH,eAAO,MAAM,WAAW,wGAItB,CAAC;AAEH,eAAO,MAAM,cAAc,sEAGzB,CAAC;AAEH,eAAO,MAAM,cAAc,sEAGzB,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;iBAK/B,CAAC;AAGH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,wBAAwB;;;;;kBAYpC,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAChD,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AACxD,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AACtD,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AACtD,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"roles.shared.utils.d.ts","sourceRoot":"","sources":["../../../../../src/security/authorizations/roles.shared.utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAkC,KAAK,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAMjG;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,kBAAkB,GAAG,MAAM,EAAE,CAQ/F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,wBAAgB,gCAAgC,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAAG,OAAO,CAEtG;AAeD,4DAA4D;AAC5D,MAAM,WAAW,mCAAmC;IAClD,qFAAqF;IACrF,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC7C,wEAAwE;IACxE,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,0GAA0G;IAC1G,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,mFAAmF;IACnF,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACpC,+EAA+E;IAC/E,cAAc,CAAC,EAAE,kBAAkB,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,mCAAmC,GAAG,OAAO,CAoClG;AAsCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,cAAc,GAAE,kBAAmD,EACnE,cAAc,GAAE,kBAA+C,GAC9D,MAAM,CAMR;AAED,sFAAsF;AACtF,MAAM,WAAW,qBAAqB;IACpC,8FAA8F;IAC9F,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,qBAAqB,EAC9B,cAAc,CAAC,EAAE,kBAAkB,EACnC,cAAc,CAAC,EAAE,kBAAkB,GAClC,MAAM,CAIR;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,SAAS,qBAAqB,EACzE,QAAQ,EAAE,SAAS,CAAC,EAAE,EACtB,cAAc,CAAC,EAAE,kBAAkB,EACnC,cAAc,CAAC,EAAE,kBAAkB,GAClC,CAAC,EAAE,CAQL"}
1
+ {"version":3,"file":"roles.shared.utils.d.ts","sourceRoot":"","sources":["../../../../src/security/authorizations/roles.shared.utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAkC,KAAK,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAMjG;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,kBAAkB,GAAG,MAAM,EAAE,CAQ/F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,wBAAgB,gCAAgC,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAAG,OAAO,CAEtG;AAeD,4DAA4D;AAC5D,MAAM,WAAW,mCAAmC;IAClD,qFAAqF;IACrF,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC7C,wEAAwE;IACxE,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,0GAA0G;IAC1G,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,mFAAmF;IACnF,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACpC,+EAA+E;IAC/E,cAAc,CAAC,EAAE,kBAAkB,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,mCAAmC,GAAG,OAAO,CAoClG;AAsCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,cAAc,GAAE,kBAAmD,EACnE,cAAc,GAAE,kBAA+C,GAC9D,MAAM,CAMR;AAED,sFAAsF;AACtF,MAAM,WAAW,qBAAqB;IACpC,8FAA8F;IAC9F,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,qBAAqB,EAC9B,cAAc,CAAC,EAAE,kBAAkB,EACnC,cAAc,CAAC,EAAE,kBAAkB,GAClC,MAAM,CAIR;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,SAAS,qBAAqB,EACzE,QAAQ,EAAE,SAAS,CAAC,EAAE,EACtB,cAAc,CAAC,EAAE,kBAAkB,EACnC,cAAc,CAAC,EAAE,kBAAkB,GAClC,CAAC,EAAE,CAQL"}
@@ -1 +1 @@
1
- {"version":3,"file":"provider-credentials-organization.shared.resources-config.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/security/connected-accounts/provider-credentials-organization.shared.resources-config.schemas.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAEL,iCAAiC,EAClC,MAAM,uCAAuC,CAAC;AAK/C,OAAO,EAAE,qBAAqB,EAAwD,MAAM,mDAAmD,CAAC;AAChJ,OAAO,EAA4D,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAY1I,KAAK,oCAAoC,GACrC,qBAAqB,CAAC,IAAI,GAC1B,qBAAqB,CAAC,IAAI,GAC1B,qBAAqB,CAAC,MAAM,GAC5B,qBAAqB,CAAC,MAAM,GAC5B,qBAAqB,CAAC,MAAM,GAC5B,qBAAqB,CAAC,WAAW,CAAC;AAEtC,eAAO,MAAM,iEAAiE,GAC5E,wBAAwB,oBAAoB,EAAE;;;;;;;;;;;;;;;;;mBA8L9C,CAAC"}
1
+ {"version":3,"file":"provider-credentials-organization.shared.resources-config.schemas.d.ts","sourceRoot":"","sources":["../../../../src/security/connected-accounts/provider-credentials-organization.shared.resources-config.schemas.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAEL,iCAAiC,EAClC,MAAM,uCAAuC,CAAC;AAK/C,OAAO,EAAE,qBAAqB,EAAwD,MAAM,mDAAmD,CAAC;AAChJ,OAAO,EAA4D,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAY1I,KAAK,oCAAoC,GACrC,qBAAqB,CAAC,IAAI,GAC1B,qBAAqB,CAAC,IAAI,GAC1B,qBAAqB,CAAC,MAAM,GAC5B,qBAAqB,CAAC,MAAM,GAC5B,qBAAqB,CAAC,MAAM,GAC5B,qBAAqB,CAAC,WAAW,CAAC;AAEtC,eAAO,MAAM,iEAAiE,GAC5E,wBAAwB,oBAAoB,EAAE;;;;;;;;;;;;;;;;;mBA8L9C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"provider-credentials-organization.shared.resources-config.schemas.js","sourceRoot":"","sources":["../../../../../src/security/connected-accounts/provider-credentials-organization.shared.resources-config.schemas.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Organization Provider Credentials — resource configuration.\n *\n * The tenant-owned service credential toward a third-party provider. See\n * `provider-credentials.shared.schemas.ts` for what the resource is and what it deliberately is not.\n */\n\nimport { z } from 'zod';\n\nimport {\n OrganizationProviderCredentialSchema,\n ProviderCredentialValidationState,\n} from './provider-credentials.shared.schemas';\n\nimport { ErasureRetentionMode, ResourceDataSubjectKind } from '../../compliance/privacy/impersonalization.shared.schemas';\nimport { createResourceConfiguration_Initialization } from '../../resources/resources-config.shared.factory';\nimport { ResourceSystemAccessMode } from '../../resources/resources-config.shared.schemas';\nimport { CoreResourceOperation, CoreResourceType, coreResourceShared_FieldIdentifier } from '../../resources/resources.shared.core.definitions';\nimport { ResourceOperationRiskLevel, ResourceOperationVariantType, ResourceRelationship } from '../../resources/resources.shared.schemas';\nimport { CORE_APP_ROLES, CORE_ORG_ROLES } from '../authorizations/roles.shared.schemas';\n\nconst ORG_PROVIDER_CREDENTIALS_SORT_FIELDS = ['createdAt', 'updatedAt', 'providerRef', 'lastUsedAt'] as const;\n\nconst ORG_PROVIDER_CREDENTIALS_FILTER_FIELDS = {\n providerRef: z.string(),\n secretSlug: z.string(),\n enabled: z.boolean(),\n validationState: z.enum(ProviderCredentialValidationState),\n};\n\ntype OrgProviderCredentialsCoreOperations =\n | CoreResourceOperation.READ\n | CoreResourceOperation.LIST\n | CoreResourceOperation.CREATE\n | CoreResourceOperation.UPDATE\n | CoreResourceOperation.DELETE\n | CoreResourceOperation.UPDATE_MANY;\n\nexport const orgProviderCredentialsResourceConfiguration_InitializationFactory = (\n resourcesRelationships: ResourceRelationship[],\n) => createResourceConfiguration_Initialization<\n undefined,\n OrgProviderCredentialsCoreOperations,\n typeof OrganizationProviderCredentialSchema\n>({\n mainSchema: OrganizationProviderCredentialSchema,\n resourceIdentifier: CoreResourceType.ORG_PROVIDER_CREDENTIALS,\n resourceFieldIdentifier: coreResourceShared_FieldIdentifier[CoreResourceType.ORG_PROVIDER_CREDENTIALS],\n resourceRelationships: resourcesRelationships,\n isSystemResource: true,\n\n /**\n * ## `read` / `list` — the RESOLVER's door\n *\n * A provider call happens on whatever execution context the caller holds: a batch, a queue\n * consumer, an anonymous webhook return leg. None of those carry an ORG_ADMIN role, and the\n * resolution must still work — so the resolver reads through `readAsSystem`, which is fail-closed\n * on this opt-in. The scope is supplied as the organization FK in the system context map, so the\n * bypass is of the ROLE check only, never of the tenant boundary.\n *\n * ## `update` — the resolver's WRITE-BACK door\n *\n * `lastUsedAt`, `validationState`, `validationError` and `lastValidatedAt` are all\n * `.excludeFromUpdate()`, so the strict re-parse on the ordinary update path strips them. The\n * trusted `updateAsSystem` path is the only one that re-attaches them, which is why it is opted\n * into here and why those fields are not client-writable: a tenant administrator must not be able\n * to declare their own credential `VALID`.\n *\n * ## `create` — deliberately NOT opted in\n *\n * A credential comes into existence only when a human supplies one. There is no seed, no\n * provisioning step and no import that should mint one on a tenant's behalf, so the system create\n * door stays shut.\n *\n * ## `exportSubject: FORBIDDEN`\n *\n * The reserved class. This row is a live credential toward a third party; a subject export that\n * carried one would hand a working secret to whoever requested the export.\n */\n /**\n * `create` is open for the reason its user-owned sibling documents at length: a credential a\n * vendor MINTS has no HTTP write that could carry it. An OAuth2 grant arrives through a redirect\n * after a tenant administrator authorized it on the vendor's consent screen, so the exchange —\n * engine code, never a request payload — is the only thing that can store it.\n */\n systemAccessPolicy: {\n exportSubject: ResourceSystemAccessMode.FORBIDDEN,\n read: ResourceSystemAccessMode.ALLOWED,\n list: ResourceSystemAccessMode.ALLOWED,\n update: ResourceSystemAccessMode.ALLOWED,\n create: ResourceSystemAccessMode.ALLOWED,\n },\n\n /**\n * Subject erasure RETAINS this row and scrubs nothing, because there is nothing here that belongs\n * to a person.\n *\n * The row is a TENANT's credential. `setByUserId` names an ACTOR — the administrator who typed it\n * — which is the first population `NO_PRINCIPAL` describes, and it is exactly the field an\n * erasure must not use as a reason to destroy the row: a tenant losing its Slack integration\n * because the admin who configured it left the company is a bug, not a privacy guarantee.\n *\n * The erasure walk cannot reach this resource in any case, because no `USERS` relationship is\n * registered for `setByUserId` — withheld deliberately, since that edge would also put a\n * credential on the Art. 15 export graph. `RETAIN_ONLY` is therefore a statement of what WOULD\n * happen rather than a path that runs today, and it is worth declaring for that reason: the next\n * author who registers a USERS edge inherits the correct answer instead of the default.\n *\n * The assertion is checked in both directions by the factory — `RETAIN_ONLY` is refused if any\n * field carries an impersonalize treatment or declares a personal-data category.\n */\n retentionPolicy: {\n mode: ErasureRetentionMode.RETAIN_ONLY,\n },\n\n dataSubjectPolicy: { kind: ResourceDataSubjectKind.NO_PRINCIPAL },\n\n coreOperations: [\n CoreResourceOperation.READ,\n CoreResourceOperation.LIST,\n CoreResourceOperation.CREATE,\n CoreResourceOperation.UPDATE,\n // Required by the ORGANIZATIONS cascade: `onParentDelete` dispatches the child's DELETE, and a\n // relationship declaring the cascade against a resource with no DELETE core operation throws at\n // config build. It is also the tenant's own \"remove this credential\" door.\n CoreResourceOperation.DELETE,\n // Route-less; `retentionPolicy` requires READ + LIST + UPDATE_MANY.\n CoreResourceOperation.UPDATE_MANY,\n ],\n\n operationsConfiguration: {\n /*\n * ORG_ADMIN everywhere, and NO super-administrator variant anywhere — a deliberate refusal, not\n * an omission.\n *\n * Every sibling security resource (org API keys, org OAuth clients) carries an `admin` variant\n * so a platform operator can support a tenant. This one does not, because the thing being\n * supported is a live credential toward a THIRD PARTY: an operator who can list, rotate or spend\n * a tenant's Slack token can act as that tenant toward Slack, and no audit event afterwards\n * makes that reversible. `administrative-continuity-floors.md` asks for the reversibility test\n * before crossing a tenant boundary, and this verb fails it in both directions — reading is\n * masked but LISTing reveals which vendors a tenant integrates with, and rotating locks the\n * tenant out of its own integration.\n *\n * The cost is real and accepted: a tenant that loses every ORG_ADMIN cannot have its credentials\n * repaired by support. That is what `organizationMembers.grantOwnership` exists for — restore an\n * administrator to the tenant, and the tenant repairs its own credentials. The repair path runs\n * through identity, where it is audited and reversible, rather than through the credential\n * store, where it would not be.\n */\n [CoreResourceOperation.READ]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_ADMIN],\n // LOW because the value never leaves: `.isWriteOnlySecret()` redacts it at the client\n // boundary, so a READ returns metadata and a placeholder.\n riskLevel: ResourceOperationRiskLevel.LOW,\n },\n ],\n },\n\n [CoreResourceOperation.LIST]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_ADMIN],\n riskLevel: ResourceOperationRiskLevel.LOW,\n filterFields: ORG_PROVIDER_CREDENTIALS_FILTER_FIELDS,\n sortFields: ORG_PROVIDER_CREDENTIALS_SORT_FIELDS,\n maxPaginatedResultPerPageLimit: 100,\n },\n ],\n },\n\n [CoreResourceOperation.CREATE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_ADMIN],\n // CRITICAL: this is the act of granting the application authority to act as the tenant\n // toward a third party.\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n },\n ],\n },\n\n [CoreResourceOperation.UPDATE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_ADMIN],\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n },\n ],\n },\n\n [CoreResourceOperation.DELETE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_ADMIN],\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n },\n ],\n },\n\n /*\n * Route-less retention plumbing. INTERNAL_CALL registers NO route, and must not be\n * REPOSITORY_ONLY: that satisfies the factory's boot-time presence guard and then fails to\n * resolve when an erasure actually runs, because the retention primitives resolve through\n * `getServiceOperationPathDefault`, which excludes REPOSITORY_ONLY.\n */\n [CoreResourceOperation.UPDATE_MANY]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.INTERNAL_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN],\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n },\n ],\n },\n },\n});\n"]}
1
+ {"version":3,"file":"provider-credentials-organization.shared.resources-config.schemas.js","sourceRoot":"","sources":["../../../../src/security/connected-accounts/provider-credentials-organization.shared.resources-config.schemas.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Organization Provider Credentials — resource configuration.\n *\n * The tenant-owned service credential toward a third-party provider. See\n * `provider-credentials.shared.schemas.ts` for what the resource is and what it deliberately is not.\n */\n\nimport { z } from 'zod';\n\nimport {\n OrganizationProviderCredentialSchema,\n ProviderCredentialValidationState,\n} from './provider-credentials.shared.schemas';\n\nimport { ErasureRetentionMode, ResourceDataSubjectKind } from '../../compliance/privacy/impersonalization.shared.schemas';\nimport { createResourceConfiguration_Initialization } from '../../resources/resources-config.shared.factory';\nimport { ResourceSystemAccessMode } from '../../resources/resources-config.shared.schemas';\nimport { CoreResourceOperation, CoreResourceType, coreResourceShared_FieldIdentifier } from '../../resources/resources.shared.core.definitions';\nimport { ResourceOperationRiskLevel, ResourceOperationVariantType, ResourceRelationship } from '../../resources/resources.shared.schemas';\nimport { CORE_APP_ROLES, CORE_ORG_ROLES } from '../authorizations/roles.shared.schemas';\n\nconst ORG_PROVIDER_CREDENTIALS_SORT_FIELDS = ['createdAt', 'updatedAt', 'providerRef', 'lastUsedAt'] as const;\n\nconst ORG_PROVIDER_CREDENTIALS_FILTER_FIELDS = {\n providerRef: z.string(),\n secretSlug: z.string(),\n enabled: z.boolean(),\n validationState: z.enum(ProviderCredentialValidationState),\n};\n\ntype OrgProviderCredentialsCoreOperations =\n | CoreResourceOperation.READ\n | CoreResourceOperation.LIST\n | CoreResourceOperation.CREATE\n | CoreResourceOperation.UPDATE\n | CoreResourceOperation.DELETE\n | CoreResourceOperation.UPDATE_MANY;\n\nexport const orgProviderCredentialsResourceConfiguration_InitializationFactory = (\n resourcesRelationships: ResourceRelationship[],\n) => createResourceConfiguration_Initialization<\n undefined,\n OrgProviderCredentialsCoreOperations,\n typeof OrganizationProviderCredentialSchema\n>({\n mainSchema: OrganizationProviderCredentialSchema,\n resourceIdentifier: CoreResourceType.ORG_PROVIDER_CREDENTIALS,\n resourceFieldIdentifier: coreResourceShared_FieldIdentifier[CoreResourceType.ORG_PROVIDER_CREDENTIALS],\n resourceRelationships: resourcesRelationships,\n isSystemResource: true,\n\n /**\n * ## `read` / `list` — the RESOLVER's door\n *\n * A provider call happens on whatever execution context the caller holds: a batch, a queue\n * consumer, an anonymous webhook return leg. None of those carry an ORG_ADMIN role, and the\n * resolution must still work — so the resolver reads through `readAsSystem`, which is fail-closed\n * on this opt-in. The scope is supplied as the organization FK in the system context map, so the\n * bypass is of the ROLE check only, never of the tenant boundary.\n *\n * ## `update` — the resolver's WRITE-BACK door\n *\n * `lastUsedAt`, `validationState`, `validationError` and `lastValidatedAt` are all\n * `.excludeFromUpdate()`, so the strict re-parse on the ordinary update path strips them. The\n * trusted `updateAsSystem` path is the only one that re-attaches them, which is why it is opted\n * into here and why those fields are not client-writable: a tenant administrator must not be able\n * to declare their own credential `VALID`.\n *\n * ## `create` — deliberately NOT opted in\n *\n * A credential comes into existence only when a human supplies one. There is no seed, no\n * provisioning step and no import that should mint one on a tenant's behalf, so the system create\n * door stays shut.\n *\n * ## `exportSubject: FORBIDDEN`\n *\n * The reserved class. This row is a live credential toward a third party; a subject export that\n * carried one would hand a working secret to whoever requested the export.\n */\n /**\n * `create` is open for the reason its user-owned sibling documents at length: a credential a\n * vendor MINTS has no HTTP write that could carry it. An OAuth2 grant arrives through a redirect\n * after a tenant administrator authorized it on the vendor's consent screen, so the exchange —\n * engine code, never a request payload — is the only thing that can store it.\n */\n systemAccessPolicy: {\n exportSubject: ResourceSystemAccessMode.FORBIDDEN,\n read: ResourceSystemAccessMode.ALLOWED,\n list: ResourceSystemAccessMode.ALLOWED,\n update: ResourceSystemAccessMode.ALLOWED,\n create: ResourceSystemAccessMode.ALLOWED,\n },\n\n /**\n * Subject erasure RETAINS this row and scrubs nothing, because there is nothing here that belongs\n * to a person.\n *\n * The row is a TENANT's credential. `setByUserId` names an ACTOR — the administrator who typed it\n * — which is the first population `NO_PRINCIPAL` describes, and it is exactly the field an\n * erasure must not use as a reason to destroy the row: a tenant losing its Slack integration\n * because the admin who configured it left the company is a bug, not a privacy guarantee.\n *\n * The erasure walk cannot reach this resource in any case, because no `USERS` relationship is\n * registered for `setByUserId` — withheld deliberately, since that edge would also put a\n * credential on the Art. 15 export graph. `RETAIN_ONLY` is therefore a statement of what WOULD\n * happen rather than a path that runs today, and it is worth declaring for that reason: the next\n * author who registers a USERS edge inherits the correct answer instead of the default.\n *\n * The assertion is checked in both directions by the factory — `RETAIN_ONLY` is refused if any\n * field carries an impersonalize treatment or declares a personal-data category.\n */\n retentionPolicy: {\n mode: ErasureRetentionMode.RETAIN_ONLY,\n },\n\n dataSubjectPolicy: { kind: ResourceDataSubjectKind.NO_PRINCIPAL },\n\n coreOperations: [\n CoreResourceOperation.READ,\n CoreResourceOperation.LIST,\n CoreResourceOperation.CREATE,\n CoreResourceOperation.UPDATE,\n // Required by the ORGANIZATIONS cascade: `onParentDelete` dispatches the child's DELETE, and a\n // relationship declaring the cascade against a resource with no DELETE core operation throws at\n // config build. It is also the tenant's own \"remove this credential\" door.\n CoreResourceOperation.DELETE,\n // Route-less; `retentionPolicy` requires READ + LIST + UPDATE_MANY.\n CoreResourceOperation.UPDATE_MANY,\n ],\n\n operationsConfiguration: {\n /*\n * ORG_ADMIN everywhere, and NO super-administrator variant anywhere — a deliberate refusal, not\n * an omission.\n *\n * Every sibling security resource (org API keys, org OAuth clients) carries an `admin` variant\n * so a platform operator can support a tenant. This one does not, because the thing being\n * supported is a live credential toward a THIRD PARTY: an operator who can list, rotate or spend\n * a tenant's Slack token can act as that tenant toward Slack, and no audit event afterwards\n * makes that reversible. `administrative-continuity-floors.md` asks for the reversibility test\n * before crossing a tenant boundary, and this verb fails it in both directions — reading is\n * masked but LISTing reveals which vendors a tenant integrates with, and rotating locks the\n * tenant out of its own integration.\n *\n * The cost is real and accepted: a tenant that loses every ORG_ADMIN cannot have its credentials\n * repaired by support. That is what `organizationMembers.grantOwnership` exists for — restore an\n * administrator to the tenant, and the tenant repairs its own credentials. The repair path runs\n * through identity, where it is audited and reversible, rather than through the credential\n * store, where it would not be.\n */\n [CoreResourceOperation.READ]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_ADMIN],\n // LOW because the value never leaves: `.isWriteOnlySecret()` redacts it at the client\n // boundary, so a READ returns metadata and a placeholder.\n riskLevel: ResourceOperationRiskLevel.LOW,\n },\n ],\n },\n\n [CoreResourceOperation.LIST]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_ADMIN],\n riskLevel: ResourceOperationRiskLevel.LOW,\n filterFields: ORG_PROVIDER_CREDENTIALS_FILTER_FIELDS,\n sortFields: ORG_PROVIDER_CREDENTIALS_SORT_FIELDS,\n maxPaginatedResultPerPageLimit: 100,\n },\n ],\n },\n\n [CoreResourceOperation.CREATE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_ADMIN],\n // CRITICAL: this is the act of granting the application authority to act as the tenant\n // toward a third party.\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n },\n ],\n },\n\n [CoreResourceOperation.UPDATE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_ADMIN],\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n },\n ],\n },\n\n [CoreResourceOperation.DELETE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_ORG_ROLES.ORG_ADMIN],\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n },\n ],\n },\n\n /*\n * Route-less retention plumbing. INTERNAL_CALL registers NO route, and must not be\n * REPOSITORY_ONLY: that satisfies the factory's boot-time presence guard and then fails to\n * resolve when an erasure actually runs, because the retention primitives resolve through\n * `getServiceOperationPathDefault`, which excludes REPOSITORY_ONLY.\n */\n [CoreResourceOperation.UPDATE_MANY]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.INTERNAL_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN],\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n },\n ],\n },\n },\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"provider-credentials-user.shared.resources-config.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/security/connected-accounts/provider-credentials-user.shared.resources-config.schemas.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EACL,iCAAiC,EAElC,MAAM,uCAAuC,CAAC;AAK/C,OAAO,EAAE,qBAAqB,EAAwD,MAAM,mDAAmD,CAAC;AAChJ,OAAO,EAA4D,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAY1I,KAAK,qCAAqC,GACtC,qBAAqB,CAAC,IAAI,GAC1B,qBAAqB,CAAC,IAAI,GAC1B,qBAAqB,CAAC,MAAM,GAC5B,qBAAqB,CAAC,MAAM,GAC5B,qBAAqB,CAAC,MAAM,GAC5B,qBAAqB,CAAC,WAAW,CAAC;AAEtC,eAAO,MAAM,kEAAkE,GAC7E,wBAAwB,oBAAoB,EAAE;;;;;;;;;;;;;;;;mBAsL9C,CAAC"}
1
+ {"version":3,"file":"provider-credentials-user.shared.resources-config.schemas.d.ts","sourceRoot":"","sources":["../../../../src/security/connected-accounts/provider-credentials-user.shared.resources-config.schemas.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EACL,iCAAiC,EAElC,MAAM,uCAAuC,CAAC;AAK/C,OAAO,EAAE,qBAAqB,EAAwD,MAAM,mDAAmD,CAAC;AAChJ,OAAO,EAA4D,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAY1I,KAAK,qCAAqC,GACtC,qBAAqB,CAAC,IAAI,GAC1B,qBAAqB,CAAC,IAAI,GAC1B,qBAAqB,CAAC,MAAM,GAC5B,qBAAqB,CAAC,MAAM,GAC5B,qBAAqB,CAAC,MAAM,GAC5B,qBAAqB,CAAC,WAAW,CAAC;AAEtC,eAAO,MAAM,kEAAkE,GAC7E,wBAAwB,oBAAoB,EAAE;;;;;;;;;;;;;;;;mBAsL9C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"provider-credentials-user.shared.resources-config.schemas.js","sourceRoot":"","sources":["../../../../../src/security/connected-accounts/provider-credentials-user.shared.resources-config.schemas.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * User Provider Credentials — resource configuration.\n *\n * A PERSON's own credential toward a third party. See `provider-credentials.shared.schemas.ts` for\n * what the resource is, why it is separate from the organization-owned sibling, and why it is not a\n * delegated OAuth grant.\n */\n\nimport { z } from 'zod';\n\nimport {\n ProviderCredentialValidationState,\n UserProviderCredentialSchema,\n} from './provider-credentials.shared.schemas';\n\nimport { ErasureRetentionMode, ResourceDataSubjectKind } from '../../compliance/privacy/impersonalization.shared.schemas';\nimport { createResourceConfiguration_Initialization } from '../../resources/resources-config.shared.factory';\nimport { ResourceSystemAccessMode } from '../../resources/resources-config.shared.schemas';\nimport { CoreResourceOperation, CoreResourceType, coreResourceShared_FieldIdentifier } from '../../resources/resources.shared.core.definitions';\nimport { ResourceOperationRiskLevel, ResourceOperationVariantType, ResourceRelationship } from '../../resources/resources.shared.schemas';\nimport { CORE_APP_ROLES } from '../authorizations/roles.shared.schemas';\n\nconst USER_PROVIDER_CREDENTIALS_SORT_FIELDS = ['createdAt', 'updatedAt', 'providerRef', 'lastUsedAt'] as const;\n\nconst USER_PROVIDER_CREDENTIALS_FILTER_FIELDS = {\n providerRef: z.string(),\n secretSlug: z.string(),\n enabled: z.boolean(),\n validationState: z.enum(ProviderCredentialValidationState),\n};\n\ntype UserProviderCredentialsCoreOperations =\n | CoreResourceOperation.READ\n | CoreResourceOperation.LIST\n | CoreResourceOperation.CREATE\n | CoreResourceOperation.UPDATE\n | CoreResourceOperation.DELETE\n | CoreResourceOperation.UPDATE_MANY;\n\nexport const userProviderCredentialsResourceConfiguration_InitializationFactory = (\n resourcesRelationships: ResourceRelationship[],\n) => createResourceConfiguration_Initialization<\n undefined,\n UserProviderCredentialsCoreOperations,\n typeof UserProviderCredentialSchema\n>({\n mainSchema: UserProviderCredentialSchema,\n resourceIdentifier: CoreResourceType.USER_PROVIDER_CREDENTIALS,\n resourceFieldIdentifier: coreResourceShared_FieldIdentifier[CoreResourceType.USER_PROVIDER_CREDENTIALS],\n resourceRelationships: resourcesRelationships,\n isSystemResource: true,\n\n /**\n * The same four system doors as the organization-owned sibling, for the same reasons: a provider\n * call runs on whatever execution context the caller holds, so the resolver reads through\n * `readAsSystem`, and writes back `lastUsedAt` / `validationState` through `updateAsSystem` because\n * those fields are `.excludeFromUpdate()` and a holder must not be able to declare their own\n * credential VALID.\n *\n * ## `create` was shut, and the sentence that shut it stopped being true\n *\n * It read: \"a credential exists only because a person supplied one.\" That is exactly right for a\n * credential somebody PASTES, and false for one a vendor MINTS. An OAuth2 grant exists because a\n * person authorized it on the vendor's own consent screen and came back through a redirect;\n * nobody ever types it, so there is no HTTP write that could carry it. Leaving the door shut would\n * mean the authorization exchange completes, the vendor records the grant, and this application\n * has nowhere to put it.\n *\n * What keeps that narrow is the door itself rather than a second check: `createAsSystem` is\n * reachable only from engine code — never an HTTP payload — its re-attach allowlist is DERIVED\n * from the schema rather than caller-supplied, and the row identity the seal binds to comes from\n * the scope map, so a caller cannot name whose credential it is writing.\n *\n * ## `exportSubject: FORBIDDEN` matters MORE here than on the sibling, and the difference is real\n *\n * The organization-owned row is unreachable on the subject-export graph anyway, because no `USERS`\n * relationship is registered for its `setByUserId` — the export walk simply never arrives. This row\n * IS reachable: `userId` is a registered `USERS` composition, which is what gives the resource its\n * USER_SELF scope in the first place. So the export walk arrives here BY CONSTRUCTION, and this\n * refusal is the only thing standing between a subject-access request and a working third-party\n * credential in the response.\n */\n systemAccessPolicy: {\n exportSubject: ResourceSystemAccessMode.FORBIDDEN,\n read: ResourceSystemAccessMode.ALLOWED,\n list: ResourceSystemAccessMode.ALLOWED,\n update: ResourceSystemAccessMode.ALLOWED,\n create: ResourceSystemAccessMode.ALLOWED,\n },\n\n /**\n * `RETAIN_ONLY`, and the row still does not survive its owner — the CASCADE removes it.\n *\n * These are two different mechanisms and reading them as one produces the wrong answer in both\n * directions. The retention policy governs what the erasure WALK does to a row it retains: here,\n * nothing, because a secret is not personal data to be pseudonymised. You do not scrub a\n * credential, you destroy it. The `USERS → USER_PROVIDER_CREDENTIALS` composition is what destroys\n * it, dispatching this resource's DELETE when the person is removed.\n *\n * So a person who exercises erasure does not leave a live credential behind, and the mechanism that\n * guarantees it is the relationship rather than the policy. Declaring `RETAIN_AND_IMPERSONALIZE`\n * instead would be actively wrong: it would keep the row and replace its fields, leaving a sealed\n * envelope whose key material still opens against a subject who asked to be forgotten.\n */\n retentionPolicy: {\n mode: ErasureRetentionMode.RETAIN_ONLY,\n },\n\n /**\n * `NO_PRINCIPAL` on the axis this enum actually decides: erasing a credential revokes no session,\n * because no login is reachable from it. `userId` names the OWNER, not a login this row confers.\n */\n dataSubjectPolicy: { kind: ResourceDataSubjectKind.NO_PRINCIPAL },\n\n coreOperations: [\n CoreResourceOperation.READ,\n CoreResourceOperation.LIST,\n CoreResourceOperation.CREATE,\n CoreResourceOperation.UPDATE,\n // Required by the USERS cascade — `onParentDelete` dispatches this DELETE — and it is also the\n // holder's own \"remove this credential\" door.\n CoreResourceOperation.DELETE,\n // Route-less; `retentionPolicy` requires READ + LIST + UPDATE_MANY.\n CoreResourceOperation.UPDATE_MANY,\n ],\n\n operationsConfiguration: {\n /*\n * `APP_USER` everywhere, and NO administrative variant anywhere — a stronger refusal than the\n * organization-owned sibling's, which refuses only the PLATFORM operator.\n *\n * Here an organization administrator is refused too. The row is a key its holder authored against\n * their own account with a vendor; consent to store it is not consent for somebody else to spend\n * it, and the vendor would record the act as the holder's own. There is no support story that\n * makes that reversible, and the USER_SELF primary-scope filter is what enforces it structurally\n * rather than by a role list somebody could widen.\n *\n * The cost is that a personal credential cannot be repaired by anyone but its owner, which is the\n * correct outcome: if the person is gone, the credential should be too, and the cascade sees to it.\n */\n [CoreResourceOperation.READ]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER],\n // LOW because the value never leaves: `.isWriteOnlySecret()` redacts it at the client\n // boundary, so a READ returns metadata and a placeholder.\n riskLevel: ResourceOperationRiskLevel.LOW,\n },\n ],\n },\n\n [CoreResourceOperation.LIST]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER],\n riskLevel: ResourceOperationRiskLevel.LOW,\n filterFields: USER_PROVIDER_CREDENTIALS_FILTER_FIELDS,\n sortFields: USER_PROVIDER_CREDENTIALS_SORT_FIELDS,\n maxPaginatedResultPerPageLimit: 100,\n },\n ],\n },\n\n [CoreResourceOperation.CREATE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER],\n // CRITICAL: the act of granting this application authority to act as the person toward a\n // third party. That it is the person's own decision makes it consented, not low-risk.\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n },\n ],\n },\n\n [CoreResourceOperation.UPDATE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER],\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n },\n ],\n },\n\n [CoreResourceOperation.DELETE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER],\n // Revoking one's own credential is the safe direction and must never be harder than\n // granting it.\n riskLevel: ResourceOperationRiskLevel.LOW,\n },\n ],\n },\n\n /**\n * Route-less and INTERNAL_CALL only — the retention machinery's own door, never a client's.\n *\n * `retentionPolicy` requires READ + LIST + UPDATE_MANY to exist, and a bulk update reachable over\n * HTTP on this resource would be a way to change many credentials at once, which no holder needs\n * and no administrator may have.\n */\n [CoreResourceOperation.UPDATE_MANY]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.INTERNAL_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN],\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n },\n ],\n },\n },\n});\n"]}
1
+ {"version":3,"file":"provider-credentials-user.shared.resources-config.schemas.js","sourceRoot":"","sources":["../../../../src/security/connected-accounts/provider-credentials-user.shared.resources-config.schemas.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * User Provider Credentials — resource configuration.\n *\n * A PERSON's own credential toward a third party. See `provider-credentials.shared.schemas.ts` for\n * what the resource is, why it is separate from the organization-owned sibling, and why it is not a\n * delegated OAuth grant.\n */\n\nimport { z } from 'zod';\n\nimport {\n ProviderCredentialValidationState,\n UserProviderCredentialSchema,\n} from './provider-credentials.shared.schemas';\n\nimport { ErasureRetentionMode, ResourceDataSubjectKind } from '../../compliance/privacy/impersonalization.shared.schemas';\nimport { createResourceConfiguration_Initialization } from '../../resources/resources-config.shared.factory';\nimport { ResourceSystemAccessMode } from '../../resources/resources-config.shared.schemas';\nimport { CoreResourceOperation, CoreResourceType, coreResourceShared_FieldIdentifier } from '../../resources/resources.shared.core.definitions';\nimport { ResourceOperationRiskLevel, ResourceOperationVariantType, ResourceRelationship } from '../../resources/resources.shared.schemas';\nimport { CORE_APP_ROLES } from '../authorizations/roles.shared.schemas';\n\nconst USER_PROVIDER_CREDENTIALS_SORT_FIELDS = ['createdAt', 'updatedAt', 'providerRef', 'lastUsedAt'] as const;\n\nconst USER_PROVIDER_CREDENTIALS_FILTER_FIELDS = {\n providerRef: z.string(),\n secretSlug: z.string(),\n enabled: z.boolean(),\n validationState: z.enum(ProviderCredentialValidationState),\n};\n\ntype UserProviderCredentialsCoreOperations =\n | CoreResourceOperation.READ\n | CoreResourceOperation.LIST\n | CoreResourceOperation.CREATE\n | CoreResourceOperation.UPDATE\n | CoreResourceOperation.DELETE\n | CoreResourceOperation.UPDATE_MANY;\n\nexport const userProviderCredentialsResourceConfiguration_InitializationFactory = (\n resourcesRelationships: ResourceRelationship[],\n) => createResourceConfiguration_Initialization<\n undefined,\n UserProviderCredentialsCoreOperations,\n typeof UserProviderCredentialSchema\n>({\n mainSchema: UserProviderCredentialSchema,\n resourceIdentifier: CoreResourceType.USER_PROVIDER_CREDENTIALS,\n resourceFieldIdentifier: coreResourceShared_FieldIdentifier[CoreResourceType.USER_PROVIDER_CREDENTIALS],\n resourceRelationships: resourcesRelationships,\n isSystemResource: true,\n\n /**\n * The same four system doors as the organization-owned sibling, for the same reasons: a provider\n * call runs on whatever execution context the caller holds, so the resolver reads through\n * `readAsSystem`, and writes back `lastUsedAt` / `validationState` through `updateAsSystem` because\n * those fields are `.excludeFromUpdate()` and a holder must not be able to declare their own\n * credential VALID.\n *\n * ## `create` was shut, and the sentence that shut it stopped being true\n *\n * It read: \"a credential exists only because a person supplied one.\" That is exactly right for a\n * credential somebody PASTES, and false for one a vendor MINTS. An OAuth2 grant exists because a\n * person authorized it on the vendor's own consent screen and came back through a redirect;\n * nobody ever types it, so there is no HTTP write that could carry it. Leaving the door shut would\n * mean the authorization exchange completes, the vendor records the grant, and this application\n * has nowhere to put it.\n *\n * What keeps that narrow is the door itself rather than a second check: `createAsSystem` is\n * reachable only from engine code — never an HTTP payload — its re-attach allowlist is DERIVED\n * from the schema rather than caller-supplied, and the row identity the seal binds to comes from\n * the scope map, so a caller cannot name whose credential it is writing.\n *\n * ## `exportSubject: FORBIDDEN` matters MORE here than on the sibling, and the difference is real\n *\n * The organization-owned row is unreachable on the subject-export graph anyway, because no `USERS`\n * relationship is registered for its `setByUserId` — the export walk simply never arrives. This row\n * IS reachable: `userId` is a registered `USERS` composition, which is what gives the resource its\n * USER_SELF scope in the first place. So the export walk arrives here BY CONSTRUCTION, and this\n * refusal is the only thing standing between a subject-access request and a working third-party\n * credential in the response.\n */\n systemAccessPolicy: {\n exportSubject: ResourceSystemAccessMode.FORBIDDEN,\n read: ResourceSystemAccessMode.ALLOWED,\n list: ResourceSystemAccessMode.ALLOWED,\n update: ResourceSystemAccessMode.ALLOWED,\n create: ResourceSystemAccessMode.ALLOWED,\n },\n\n /**\n * `RETAIN_ONLY`, and the row still does not survive its owner — the CASCADE removes it.\n *\n * These are two different mechanisms and reading them as one produces the wrong answer in both\n * directions. The retention policy governs what the erasure WALK does to a row it retains: here,\n * nothing, because a secret is not personal data to be pseudonymised. You do not scrub a\n * credential, you destroy it. The `USERS → USER_PROVIDER_CREDENTIALS` composition is what destroys\n * it, dispatching this resource's DELETE when the person is removed.\n *\n * So a person who exercises erasure does not leave a live credential behind, and the mechanism that\n * guarantees it is the relationship rather than the policy. Declaring `RETAIN_AND_IMPERSONALIZE`\n * instead would be actively wrong: it would keep the row and replace its fields, leaving a sealed\n * envelope whose key material still opens against a subject who asked to be forgotten.\n */\n retentionPolicy: {\n mode: ErasureRetentionMode.RETAIN_ONLY,\n },\n\n /**\n * `NO_PRINCIPAL` on the axis this enum actually decides: erasing a credential revokes no session,\n * because no login is reachable from it. `userId` names the OWNER, not a login this row confers.\n */\n dataSubjectPolicy: { kind: ResourceDataSubjectKind.NO_PRINCIPAL },\n\n coreOperations: [\n CoreResourceOperation.READ,\n CoreResourceOperation.LIST,\n CoreResourceOperation.CREATE,\n CoreResourceOperation.UPDATE,\n // Required by the USERS cascade — `onParentDelete` dispatches this DELETE — and it is also the\n // holder's own \"remove this credential\" door.\n CoreResourceOperation.DELETE,\n // Route-less; `retentionPolicy` requires READ + LIST + UPDATE_MANY.\n CoreResourceOperation.UPDATE_MANY,\n ],\n\n operationsConfiguration: {\n /*\n * `APP_USER` everywhere, and NO administrative variant anywhere — a stronger refusal than the\n * organization-owned sibling's, which refuses only the PLATFORM operator.\n *\n * Here an organization administrator is refused too. The row is a key its holder authored against\n * their own account with a vendor; consent to store it is not consent for somebody else to spend\n * it, and the vendor would record the act as the holder's own. There is no support story that\n * makes that reversible, and the USER_SELF primary-scope filter is what enforces it structurally\n * rather than by a role list somebody could widen.\n *\n * The cost is that a personal credential cannot be repaired by anyone but its owner, which is the\n * correct outcome: if the person is gone, the credential should be too, and the cascade sees to it.\n */\n [CoreResourceOperation.READ]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER],\n // LOW because the value never leaves: `.isWriteOnlySecret()` redacts it at the client\n // boundary, so a READ returns metadata and a placeholder.\n riskLevel: ResourceOperationRiskLevel.LOW,\n },\n ],\n },\n\n [CoreResourceOperation.LIST]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER],\n riskLevel: ResourceOperationRiskLevel.LOW,\n filterFields: USER_PROVIDER_CREDENTIALS_FILTER_FIELDS,\n sortFields: USER_PROVIDER_CREDENTIALS_SORT_FIELDS,\n maxPaginatedResultPerPageLimit: 100,\n },\n ],\n },\n\n [CoreResourceOperation.CREATE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER],\n // CRITICAL: the act of granting this application authority to act as the person toward a\n // third party. That it is the person's own decision makes it consented, not low-risk.\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n },\n ],\n },\n\n [CoreResourceOperation.UPDATE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER],\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n },\n ],\n },\n\n [CoreResourceOperation.DELETE]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.API_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_USER],\n // Revoking one's own credential is the safe direction and must never be harder than\n // granting it.\n riskLevel: ResourceOperationRiskLevel.LOW,\n },\n ],\n },\n\n /**\n * Route-less and INTERNAL_CALL only — the retention machinery's own door, never a client's.\n *\n * `retentionPolicy` requires READ + LIST + UPDATE_MANY to exist, and a bulk update reachable over\n * HTTP on this resource would be a way to change many credentials at once, which no holder needs\n * and no administrator may have.\n */\n [CoreResourceOperation.UPDATE_MANY]: {\n variants: [\n {\n variantType: ResourceOperationVariantType.INTERNAL_CALL,\n isDefault: true,\n roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN],\n riskLevel: ResourceOperationRiskLevel.CRITICAL,\n },\n ],\n },\n },\n});\n"]}
@@ -200,6 +200,63 @@ export type UserProviderCredential = z.infer<typeof UserProviderCredentialSchema
200
200
  * understand `PROVIDER_OAUTH2_GRANT_PREFIX`: the prefix is how the shape is recognised WITHOUT
201
201
  * parsing, and this is what it recognises.
202
202
  */
203
+ /**
204
+ * Why a provider cannot be connected HERE, even though the vendor is in the catalogue.
205
+ *
206
+ * "Connectable" is a property of the DEPLOYMENT and not of the vendor, and conflating the two put a
207
+ * Connect button on a screen that could only ever fail. Asana supports OAuth2 perfectly well; this
208
+ * application has simply never registered with Asana, and no amount of pressing the button changes
209
+ * that.
210
+ *
211
+ * The two members lead to different actions by different people, which is the whole reason they are
212
+ * distinguished rather than collapsed into a boolean.
213
+ */
214
+ /**
215
+ * HOW a connection to a provider is established — the shape of the act, which decides the screen.
216
+ *
217
+ * A connect surface cannot be one form. Granting consent at a vendor and typing a key are different
218
+ * acts with different inputs and different failure modes, and a screen that offered one button for
219
+ * both would be wrong for whichever it was not built around.
220
+ */
221
+ export declare enum ProviderAuthMethod {
222
+ /** The authorization-code round trip: leave, consent at the vendor, come back with a grant. */
223
+ OAUTH2_AUTHORIZATION_CODE = "oauth2-authorization-code",
224
+ /**
225
+ * A value somebody holds and types — an API key, a personal access token. The fields are DECLARED
226
+ * by the provider's secrets contract, so a screen names them rather than asking for a slug.
227
+ */
228
+ DECLARED_SECRET = "declared-secret"
229
+ }
230
+ export declare enum ProviderConnectabilityBlocker {
231
+ /**
232
+ * The vendor has no authorization flow in the catalogue: its credential is PASTED, not granted.
233
+ * Nothing is missing and nothing is broken — this provider is authored on the credential screen
234
+ * instead, and an application author is the one who acts.
235
+ */
236
+ NO_AUTHORIZATION_FLOW = "no-authorization-flow",
237
+ /**
238
+ * The vendor has a flow and THIS DEPLOYMENT has not registered with it — no client id, or no client
239
+ * secret. An OPERATOR acts: register an application with the vendor and set the two environment
240
+ * variables the provider's contract names. Distinct from the above because the vendor is perfectly
241
+ * connectable and the gap is ours.
242
+ */
243
+ APPLICATION_NOT_REGISTERED = "application-not-registered"
244
+ }
245
+ /**
246
+ * One secret slot a provider declares, as a SCREEN needs it — never the value.
247
+ *
248
+ * Exists so nothing is typed by hand. The slug names the field, the environment variable tells an
249
+ * operator exactly what to set, and `configured` lets a missing one be REPORTED rather than
250
+ * discovered by pressing a button that fails.
251
+ */
252
+ export interface ProviderSecretSlotView {
253
+ readonly slug: string;
254
+ readonly envVarName: string;
255
+ readonly required: boolean;
256
+ readonly description: string;
257
+ /** Whether the deployment supplies it. There is deliberately no field for the value. */
258
+ readonly configured: boolean;
259
+ }
203
260
  export declare enum ProviderStoredCredentialKind {
204
261
  /** An OAuth2 grant: an access token, and what is needed to renew it. */
205
262
  OAUTH2_GRANT = "oauth2-grant"
@@ -1 +1 @@
1
- {"version":3,"file":"provider-credentials.shared.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/security/connected-accounts/provider-credentials.shared.schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;GAOG;AACH,oBAAY,iCAAiC;IAC3C,0FAA0F;IAC1F,WAAW,gBAAgB;IAC3B,gDAAgD;IAChD,KAAK,UAAU;IACf,8EAA8E;IAC9E,OAAO,YAAY;CACpB;AAED;;;;;;;;;;;GAWG;AACH;;;;;;;;GAQG;AACH,oBAAY,kCAAkC;IAC5C,yEAAyE;IACzE,uBAAuB,4BAA4B;IACnD;;;OAGG;IACH,sBAAsB,2BAA2B;IACjD;;;;;;;;;OASG;IACH,eAAe,oBAAoB;CACpC;AAED,6CAA6C;AAC7C,oBAAY,gCAAgC;IAC1C,wDAAwD;IACxD,qBAAqB,0BAA0B;IAC/C,iGAAiG;IACjG,mBAAmB,wBAAwB;IAC3C,gEAAgE;IAChE,aAAa,kBAAkB;IAC/B;;;;;;OAMG;IACH,WAAW,gBAAgB;CAC5B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gDAAgD,0DAInD,CAAC;AAEX,eAAO,MAAM,oCAAoC;;;;;;;;;;;;;;;;;kBAwHuB,CAAC;AAEzE,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAC;AAQlG;;;;;;GAMG;AACH,eAAO,MAAM,wCAAwC,kDAI3C,CAAC;AAEX;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;kBAgFuB,CAAC;AAEjE,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAsBlF;;;;;;GAMG;AACH;;;;;;;;GAQG;AACH,oBAAY,4BAA4B;IACtC,wEAAwE;IACxE,YAAY,iBAAiB;CAC9B;AAED,eAAO,MAAM,yBAAyB;;;;;;;iBAgDpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,wBAAwB,CAAC;AAElE,0EAA0E;AAC1E,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAEzE;AAED,mFAAmF;AACnF,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAE/E;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAqB3F;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oCAAoC,KAAK,CAAC;AAEvD,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,mBAAmB,EAAE,GAAG,GAAE,IAAiB,GAAG,OAAO,CAK3G"}
1
+ {"version":3,"file":"provider-credentials.shared.schemas.d.ts","sourceRoot":"","sources":["../../../../src/security/connected-accounts/provider-credentials.shared.schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;GAOG;AACH,oBAAY,iCAAiC;IAC3C,0FAA0F;IAC1F,WAAW,gBAAgB;IAC3B,gDAAgD;IAChD,KAAK,UAAU;IACf,8EAA8E;IAC9E,OAAO,YAAY;CACpB;AAED;;;;;;;;;;;GAWG;AACH;;;;;;;;GAQG;AACH,oBAAY,kCAAkC;IAC5C,yEAAyE;IACzE,uBAAuB,4BAA4B;IACnD;;;OAGG;IACH,sBAAsB,2BAA2B;IACjD;;;;;;;;;OASG;IACH,eAAe,oBAAoB;CACpC;AAED,6CAA6C;AAC7C,oBAAY,gCAAgC;IAC1C,wDAAwD;IACxD,qBAAqB,0BAA0B;IAC/C,iGAAiG;IACjG,mBAAmB,wBAAwB;IAC3C,gEAAgE;IAChE,aAAa,kBAAkB;IAC/B;;;;;;OAMG;IACH,WAAW,gBAAgB;CAC5B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gDAAgD,0DAInD,CAAC;AAEX,eAAO,MAAM,oCAAoC;;;;;;;;;;;;;;;;;kBAwHuB,CAAC;AAEzE,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAC;AAQlG;;;;;;GAMG;AACH,eAAO,MAAM,wCAAwC,kDAI3C,CAAC;AAEX;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;kBAgFuB,CAAC;AAEjE,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAsBlF;;;;;;GAMG;AACH;;;;;;;;GAQG;AACH;;;;;;;;;;GAUG;AACH;;;;;;GAMG;AACH,oBAAY,kBAAkB;IAC5B,+FAA+F;IAC/F,yBAAyB,8BAA8B;IACvD;;;OAGG;IACH,eAAe,oBAAoB;CACpC;AAED,oBAAY,6BAA6B;IACvC;;;;OAIG;IACH,qBAAqB,0BAA0B;IAC/C;;;;;OAKG;IACH,0BAA0B,+BAA+B;CAC1D;AAED;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,wFAAwF;IACxF,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAED,oBAAY,4BAA4B;IACtC,wEAAwE;IACxE,YAAY,iBAAiB;CAC9B;AAED,eAAO,MAAM,yBAAyB;;;;;;;iBAgDpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,wBAAwB,CAAC;AAElE,0EAA0E;AAC1E,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAEzE;AAED,mFAAmF;AACnF,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAE/E;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAqB3F;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oCAAoC,KAAK,CAAC;AAEvD,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,mBAAmB,EAAE,GAAG,GAAE,IAAiB,GAAG,OAAO,CAK3G"}
@@ -370,6 +370,50 @@ export const UserProviderCredentialSchema = z.object({
370
370
  * understand `PROVIDER_OAUTH2_GRANT_PREFIX`: the prefix is how the shape is recognised WITHOUT
371
371
  * parsing, and this is what it recognises.
372
372
  */
373
+ /**
374
+ * Why a provider cannot be connected HERE, even though the vendor is in the catalogue.
375
+ *
376
+ * "Connectable" is a property of the DEPLOYMENT and not of the vendor, and conflating the two put a
377
+ * Connect button on a screen that could only ever fail. Asana supports OAuth2 perfectly well; this
378
+ * application has simply never registered with Asana, and no amount of pressing the button changes
379
+ * that.
380
+ *
381
+ * The two members lead to different actions by different people, which is the whole reason they are
382
+ * distinguished rather than collapsed into a boolean.
383
+ */
384
+ /**
385
+ * HOW a connection to a provider is established — the shape of the act, which decides the screen.
386
+ *
387
+ * A connect surface cannot be one form. Granting consent at a vendor and typing a key are different
388
+ * acts with different inputs and different failure modes, and a screen that offered one button for
389
+ * both would be wrong for whichever it was not built around.
390
+ */
391
+ export var ProviderAuthMethod;
392
+ (function (ProviderAuthMethod) {
393
+ /** The authorization-code round trip: leave, consent at the vendor, come back with a grant. */
394
+ ProviderAuthMethod["OAUTH2_AUTHORIZATION_CODE"] = "oauth2-authorization-code";
395
+ /**
396
+ * A value somebody holds and types — an API key, a personal access token. The fields are DECLARED
397
+ * by the provider's secrets contract, so a screen names them rather than asking for a slug.
398
+ */
399
+ ProviderAuthMethod["DECLARED_SECRET"] = "declared-secret";
400
+ })(ProviderAuthMethod || (ProviderAuthMethod = {}));
401
+ export var ProviderConnectabilityBlocker;
402
+ (function (ProviderConnectabilityBlocker) {
403
+ /**
404
+ * The vendor has no authorization flow in the catalogue: its credential is PASTED, not granted.
405
+ * Nothing is missing and nothing is broken — this provider is authored on the credential screen
406
+ * instead, and an application author is the one who acts.
407
+ */
408
+ ProviderConnectabilityBlocker["NO_AUTHORIZATION_FLOW"] = "no-authorization-flow";
409
+ /**
410
+ * The vendor has a flow and THIS DEPLOYMENT has not registered with it — no client id, or no client
411
+ * secret. An OPERATOR acts: register an application with the vendor and set the two environment
412
+ * variables the provider's contract names. Distinct from the above because the vendor is perfectly
413
+ * connectable and the gap is ours.
414
+ */
415
+ ProviderConnectabilityBlocker["APPLICATION_NOT_REGISTERED"] = "application-not-registered";
416
+ })(ProviderConnectabilityBlocker || (ProviderConnectabilityBlocker = {}));
373
417
  export var ProviderStoredCredentialKind;
374
418
  (function (ProviderStoredCredentialKind) {
375
419
  /** An OAuth2 grant: an access token, and what is needed to renew it. */
@@ -1 +1 @@
1
- {"version":3,"file":"provider-credentials.shared.schemas.js","sourceRoot":"","sources":["../../../../../src/security/connected-accounts/provider-credentials.shared.schemas.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Organization Provider Credentials — shared schemas.\n *\n * ## What this resource is, and what it is NOT\n *\n * It is an ORGANIZATION's OWN credential toward a third party: the Slack workspace token, the CRM\n * API key, the SMTP password that belongs to THAT tenant. The organization is the third-party\n * principal, and the credential is a service credential the tenant's administrator supplies.\n *\n * It is NOT a user's delegated OAuth grant. A delegated grant is a different object with a\n * different lifetime (a refresh loop, a revocation the USER can perform, a consent record) and it\n * lands as `connected accounts` beside this file — see issue #333. Merging the two would give one\n * row two owners and two revocation semantics.\n *\n * ## Why it has to exist\n *\n * Before this resource, every provider secret resolved from `process.env` through the\n * `SecretsContract`, so a credential was per-PROCESS and per-DEPLOYMENT. One application serving\n * many organizations therefore had ONE Slack token for all of them, and the failure was silent in\n * the worst direction: an operator sets one key and every tenant thereafter acts as the SAME\n * third-party principal, with nothing anywhere saying so.\n *\n * ## The value is sealed, and this file is where that is stated\n *\n * `secretValue` holds an AES-256-GCM envelope, never the plaintext an operator typed. The seal is\n * applied on the way in and opened only by the resolver — see\n * `provider-credential-envelope.backend.utils.ts` for the envelope and its key derivation. The\n * schema cannot enforce that (a string is a string), so the write path is what guarantees it and\n * the pins are what keep it guaranteed.\n */\n\nimport { z } from 'zod';\n\n/**\n * Whether the stored credential has been shown to work against the provider.\n *\n * A closed vocabulary rather than a boolean because \"we have never tried\" and \"we tried and it\n * failed\" are different states with different operator actions, and a boolean would merge them\n * into the same falsy answer. `UNVALIDATED` is the honest default: storing a credential proves\n * only that somebody typed one.\n */\nexport enum ProviderCredentialValidationState {\n /** Stored, never exercised against the provider. The state every credential starts in. */\n UNVALIDATED = 'unvalidated',\n /** The provider accepted it on its last use. */\n VALID = 'valid',\n /** The provider rejected it on its last use — the operator must rotate it. */\n INVALID = 'invalid',\n}\n\n/**\n * The organization's credential for one (provider, secret slug) pair.\n *\n * ## The scope identifier is TOP-LEVEL and stays that way\n *\n * `organizationId` is the only `organizationId`-named path in this schema, and nothing nested may\n * ever be named `organizationId` or `userId`. `buildContextualFilter` injects the scope FK by\n * matching that field name at EVERY schema path, so a nested key of the same name adds a phantom\n * exact-subdocument clause and the scoped read silently matches zero rows — a credential that\n * exists and cannot be resolved, which reads exactly like a credential that was never set.\n * `setByUserId` is deliberately spelled so it cannot be caught by that matcher.\n */\n/**\n * WHERE a resolved provider secret came from.\n *\n * The whole point of this slice is that the answer used to be unanswerable: every secret came from\n * `process.env`, so \"which principal did this tenant act as?\" had one answer for every tenant and\n * nothing recorded it. Making the source an explicit, closed value means an audit reader can see a\n * tenant falling back to the shared deployment credential — the exact condition the resource exists\n * to make visible — instead of having to infer it from an absence.\n */\nexport enum ProviderCredentialResolutionSource {\n /** The organization's own credential row. The tenant acted as itself. */\n ORGANIZATION_CREDENTIAL = 'organization_credential',\n /**\n * The deployment's env-projected `SecretsContract`. Legitimate — a single-tenant deployment, or a\n * provider the operator intends every tenant to share — but never silent.\n */\n DEPLOYMENT_ENVIRONMENT = 'deployment_environment',\n /**\n * A PERSON's own credential row. The application acted as that individual.\n *\n * This member has no sibling fallback, and that asymmetry is deliberate rather than an omission.\n * An organization with no credential of its own may legitimately fall through to the deployment's\n * — an operator can intend every tenant to share one integration. A person cannot: the vendor\n * attributes the act to whoever's token was spent, so acting for someone under the deployment's\n * principal would put the wrong name on the record that outlives us. A person who has connected\n * nothing gets a refusal, not a substitute.\n */\n USER_CREDENTIAL = 'user_credential',\n}\n\n/** Why a credential row stopped existing. */\nexport enum ProviderCredentialDeletionReason {\n /** An administrator of the owning tenant removed it. */\n ADMINISTRATOR_REVOKED = 'administrator_revoked',\n /** The owning organization was purged and the composition cascade removed it with the tenant. */\n ORGANIZATION_PURGED = 'organization_purged',\n /** The person whose credential it was removed it themselves. */\n OWNER_REVOKED = 'owner_revoked',\n /**\n * The owning user was erased and the composition cascade destroyed it with them.\n *\n * Distinct from `ORGANIZATION_PURGED` because this one is EVIDENCE: it is what an operator points\n * at when asked whether a subject-erasure request reached the person's third-party credentials.\n * Collapsing the two into a generic \"cascade\" would make that question unanswerable from the trail.\n */\n USER_ERASED = 'user_erased',\n}\n\n/**\n * The fields that IDENTIFY a credential within its tenant.\n *\n * One tenant holds at most one credential per (provider, slug). Exported rather than repeated so\n * the uniqueness contract, the resolver's lookup and the tests cannot drift apart — three copies\n * of a compound key is how two of them come to disagree about what identity means.\n */\nexport const ORGANIZATION_PROVIDER_CREDENTIAL_IDENTITY_FIELDS = [\n 'organizationId',\n 'providerRef',\n 'secretSlug',\n] as const;\n\nexport const OrganizationProviderCredentialSchema = z.object({\n _id: z.string().min(1).isPrimaryKey().isSummaryField(),\n\n /**\n * The tenant that owns this credential. Injected by the context machinery from the request\n * scope, never from a caller-supplied field — which is what makes the isolation structural\n * rather than a filter somebody has to remember to write.\n */\n organizationId: z.string().min(1).isDBIndexed().isForeignKey().isSummaryField().excludeFromUpdate(),\n\n /**\n * The provider this credential authenticates toward (`slack`, `stripe`, a generated package's\n * ref). An OPEN string, matching `ProviderRef`'s own openness — the whole point of the provider\n * work is that the set is not closed, so a closed enum here would refuse every generated\n * provider.\n */\n providerRef: z.string().min(1).max(200).isDBIndexed().isSummaryField().excludeFromUpdate(),\n\n /**\n * The slug in the provider's `secretsContract` that this value satisfies — the same identifier\n * the deployment's env projection carries, so the two resolution places name the same thing.\n * Immutable: re-pointing a stored secret at a different slug would silently hand one vendor\n * credential to a different vendor field.\n */\n secretSlug: z.string().min(1).max(200).isDBIndexed().isSummaryField().excludeFromUpdate(),\n\n /**\n * The credential, SEALED.\n *\n * `.isWriteOnlySecret()` is the framework's write-then-masked contract and is exactly right\n * here: the operator supplies and rotates the value, so it must stay in the CREATE/UPDATE\n * request DTO; the framework redacts it to a placeholder at the client boundary, so no read\n * ever returns it; and the backend keeps the stored content for its own resolution.\n *\n * `.isBackendOnly()` was rejected — it strips the field from the client DTO, so the operator's\n * typed value is dropped before it is ever stored and the surface silently accepts nothing.\n *\n * What is PERSISTED is the envelope, never the plaintext. The write path seals it; a value that\n * reaches persistence unsealed is a defect, not a tolerated legacy shape.\n */\n secretValue: z.string().min(1).isWriteOnlySecret(),\n\n /**\n * Whether this credential may be spent. An operator can park a credential without deleting it —\n * which matters during an incident, where deleting is not reversible and disabling is.\n */\n enabled: z.boolean().default(true).isDBIndexed().isSummaryField(),\n\n validationState: z\n .enum(ProviderCredentialValidationState)\n .default(ProviderCredentialValidationState.UNVALIDATED)\n .isDBIndexed()\n .isSummaryField(),\n\n /**\n * Why the last use failed, when it did. PROVIDER-supplied text about the CREDENTIAL's status —\n * never the credential. A resolver writing anything derived from `secretValue` here would defeat\n * every other precaution in this file, because this field IS client-readable.\n */\n validationError: z.string().max(500).optional().excludeFromCreate().excludeFromUpdate(),\n\n lastValidatedAt: z.date().optional().excludeFromCreate().excludeFromUpdate(),\n lastUsedAt: z.date().optional().isDBIndexed().excludeFromCreate().excludeFromUpdate(),\n\n /**\n * WHO set it — the acting user's id, recorded for the audit trail.\n *\n * Deliberately NOT a registered `USERS` relationship. Declaring that edge would put a CREDENTIAL\n * row on the Art. 15 subject-export graph, and a credential is precisely the class of row that\n * must never reach a data subject. The id is recorded because \"who set this\" is the first\n * question of any credential incident; the edge is withheld because the answer must not travel\n * with a subject export.\n */\n setByUserId: z.string().min(1).optional().isDBIndexed().excludeFromCreate().excludeFromUpdate(),\n\n /** When the stored VALUE last changed — distinct from `updatedAt`, which any field write moves. */\n secretSetAt: z.date().optional().excludeFromCreate().excludeFromUpdate(),\n\n /** Free-text operator note. Never a place for the value; enforced by the write-path pins. */\n /**\n * Answers for the `{placeholder}` holes this provider's OAuth2 endpoints carry — which cloud,\n * which directory, which region.\n *\n * On the ROW rather than only in the connect flow, because a REFRESH needs them again. The\n * authorization record that held them lives ten minutes; the token it produced is renewed for as\n * long as the connection lasts, and a templated token URL is still templated an hour later.\n * Without them here, every one of the 21 vendors whose endpoints carry a placeholder — Microsoft,\n * Azure, and everything regional — would connect successfully and then fail its first renewal with\n * `needs a value for 'cloud'`: the exact failure the placeholder machinery exists to prevent, one\n * layer up.\n *\n * NOT secret, and deliberately client-readable: a tenant id is an identifier a person needs to see\n * to recognise which account they connected. The secret half is the grant, and it is sealed.\n *\n * `.excludeFromUpdate()` — chosen at connect time, and they describe the ACCOUNT the grant is for.\n * Changing them under a live grant would point the refresh at a different directory than the one\n * that issued the token, failing at the vendor with nothing local explaining why. Reconnecting is\n * the honest way to change them.\n */\n connectionParameters: z.record(z.string(), z.string()).optional().excludeFromUpdate(),\n\n\n description: z.string().max(500).optional(),\n\n createdAt: z.date().default(() => new Date()).isDBIndexed().isSummaryField().excludeFromCreate().excludeFromUpdate(),\n updatedAt: z.date().default(() => new Date()).isDBIndexed().excludeFromCreate().excludeFromUpdate(),\n})\n /**\n * One credential per tenant per (provider, slug), enforced by a compound UNIQUE index rather\n * than by a read-then-write.\n *\n * The race it closes is not academic: two administrators saving a rotated Slack token in the\n * same minute would otherwise leave two rows, and the resolver would then pick one of them\n * arbitrarily — so half the tenant's outbound calls would carry the old credential and nobody\n * could tell which half.\n *\n * No `customMessageReference`: that option exists so an integrator can tell WHICH identity a\n * duplicate violated, and this resource declares exactly one. A dedicated reference here would\n * disambiguate nothing.\n */\n .businessKeySet([...ORGANIZATION_PROVIDER_CREDENTIAL_IDENTITY_FIELDS]);\n\nexport type OrganizationProviderCredential = z.infer<typeof OrganizationProviderCredentialSchema>;\n\n\n\n// =============================================================================\n// USER-OWNED CREDENTIALS\n// =============================================================================\n\n/**\n * The fields that IDENTIFY a credential within its OWNER.\n *\n * Exported per owner rather than shared, because the compound key differs in its first component and\n * a single constant would have to be assembled by each side — which is how two copies of a key come\n * to disagree about what identity means.\n */\nexport const USER_PROVIDER_CREDENTIAL_IDENTITY_FIELDS = [\n 'userId',\n 'providerRef',\n 'secretSlug',\n] as const;\n\n/**\n * A PERSON's own credential toward a third party — the key they authored for themselves.\n *\n * ## Why this is a separate resource and not a nullable column beside the organization's\n *\n * Wildo's tenancy is STRUCTURAL: the contextual filter injects the scope FK by matching a field name\n * at every schema path, so a resource belongs to exactly one primary scope. One table holding both a\n * nullable `organizationId` and a nullable `userId` would turn that structural guarantee into a\n * filter somebody has to remember to write, on the one resource where forgetting it discloses a\n * credential. Two resources, each scoped by construction, is the framework working as designed\n * rather than a duplication.\n *\n * ## Not a delegated OAuth grant, and the difference is not subtle\n *\n * This is a key the user PASTED: they hold an account with the vendor and chose to let this\n * application spend it. A delegated grant is the vendor minting a token because the user approved a\n * consent screen, and it carries a refresh loop, an expiry and a revocation the vendor also honours.\n * Merging them would give one row two lifecycles and two revocation semantics — see #333, which owns\n * the second.\n *\n * ## Only the holder may spend it\n *\n * Not an administrator of their organization, and not a platform operator. Consent to STORE a\n * personal key is not consent for somebody else to use it, and the vendor would record the act as\n * the holder's own. The authorization side of that is\n * `InitiatorMembershipConnectionTargetAuthorization`; this schema is what makes the row reachable\n * only through the owner's own scope.\n */\nexport const UserProviderCredentialSchema = z.object({\n _id: z.string().min(1).isPrimaryKey().isSummaryField(),\n\n /**\n * The person who owns this credential. Injected by the context machinery from the authenticated\n * scope, never from a caller-supplied field — the same structural isolation the organization-owned\n * sibling relies on, which is what makes \"another user's key\" unreachable rather than filtered.\n */\n userId: z.string().min(1).isDBIndexed().isForeignKey().isSummaryField().excludeFromUpdate(),\n\n /** As the organization-owned sibling: an OPEN string, because the provider set is not closed. */\n providerRef: z.string().min(1).max(200).isDBIndexed().isSummaryField().excludeFromUpdate(),\n\n /** The slug in the provider's `secretsContract` this value satisfies. Immutable, for the same\n * reason as the sibling: re-pointing a stored secret at a different slug would hand one vendor\n * credential to a different vendor field. */\n secretSlug: z.string().min(1).max(200).isDBIndexed().isSummaryField().excludeFromUpdate(),\n\n /**\n * The credential, SEALED — an AES-256-GCM envelope bound to this row's identity, never plaintext.\n *\n * `.isWriteOnlySecret()` for the same reason as the sibling: the holder supplies and rotates it, so\n * it must survive into the CREATE/UPDATE request DTO, and the framework masks it at the client\n * boundary so no read ever returns it.\n */\n secretValue: z.string().min(1).isWriteOnlySecret(),\n\n enabled: z.boolean().default(true).isDBIndexed().isSummaryField(),\n\n validationState: z\n .enum(ProviderCredentialValidationState)\n .default(ProviderCredentialValidationState.UNVALIDATED)\n .isDBIndexed()\n .isSummaryField(),\n\n /** Why the last use failed. PROVIDER text about the CREDENTIAL, never anything derived from it —\n * this field IS client-readable. */\n validationError: z.string().max(500).optional().excludeFromCreate().excludeFromUpdate(),\n\n lastValidatedAt: z.date().optional().excludeFromCreate().excludeFromUpdate(),\n lastUsedAt: z.date().optional().isDBIndexed().excludeFromCreate().excludeFromUpdate(),\n\n /** When the stored VALUE last changed — distinct from `updatedAt`, which any field write moves. */\n secretSetAt: z.date().optional().excludeFromCreate().excludeFromUpdate(),\n\n /** The holder's own note. Never a place for the value; enforced by the write-path pins. */\n /**\n * Answers for the `{placeholder}` holes this provider's OAuth2 endpoints carry — which cloud,\n * which directory, which region.\n *\n * On the ROW rather than only in the connect flow, because a REFRESH needs them again. The\n * authorization record that held them lives ten minutes; the token it produced is renewed for as\n * long as the connection lasts, and a templated token URL is still templated an hour later.\n * Without them here, every one of the 21 vendors whose endpoints carry a placeholder — Microsoft,\n * Azure, and everything regional — would connect successfully and then fail its first renewal with\n * `needs a value for 'cloud'`: the exact failure the placeholder machinery exists to prevent, one\n * layer up.\n *\n * NOT secret, and deliberately client-readable: a tenant id is an identifier a person needs to see\n * to recognise which account they connected. The secret half is the grant, and it is sealed.\n *\n * `.excludeFromUpdate()` — chosen at connect time, and they describe the ACCOUNT the grant is for.\n * Changing them under a live grant would point the refresh at a different directory than the one\n * that issued the token, failing at the vendor with nothing local explaining why. Reconnecting is\n * the honest way to change them.\n */\n connectionParameters: z.record(z.string(), z.string()).optional().excludeFromUpdate(),\n\n\n description: z.string().max(500).optional(),\n\n createdAt: z.date().default(() => new Date()).isDBIndexed().isSummaryField().excludeFromCreate().excludeFromUpdate(),\n updatedAt: z.date().default(() => new Date()).isDBIndexed().excludeFromCreate().excludeFromUpdate(),\n})\n /**\n * One credential per person per (provider, slug), enforced by a compound UNIQUE index rather than\n * a read-then-write — the same race the organization-owned sibling closes, and for the same\n * reason: two rows would leave the resolver picking one arbitrarily, so half the holder's outbound\n * calls would carry a rotated-away credential and nothing would say which half.\n */\n .businessKeySet([...USER_PROVIDER_CREDENTIAL_IDENTITY_FIELDS]);\n\nexport type UserProviderCredential = z.infer<typeof UserProviderCredentialSchema>;\n\n\n// ══════════════════════════════════════════════════════════════════════════════════════════════\n// OAUTH2 GRANTS\n//\n// A credential a vendor MINTS rather than one a person pastes. It rides in the same `secretValue`\n// field of the same two resources — sealed, as JSON — and that reuse is deliberate.\n//\n// ## Why the same rows rather than a third resource\n//\n// The identity is the same triple (owner, providerRef, secretSlug), the ownership semantics are the\n// same, the authorization is the same, the erasure is the same, and the resolver already routes by\n// scope. Only the PAYLOAD differs. A separate resource would duplicate every one of those and force\n// each consumer to ask \"which store?\" before it could ask anything useful.\n//\n// Note this is the OPPOSITE call from the one that split USER from ORGANIZATION, and the difference\n// is what makes both right: there the TENANCY differed, and tenancy in this framework is structural\n// — one table with a nullable owner would turn a structural guarantee into a filter somebody must\n// remember to write. Here nothing about ownership changes; a string becomes an object.\n// ══════════════════════════════════════════════════════════════════════════════════════════════\n\n/**\n * What an authorization exchange gives back, as it is stored.\n *\n * Sealed as JSON into `secretValue`, so `.isWriteOnlySecret()` keeps masking it at the client\n * boundary and the envelope keeps binding it to its row — both mechanisms work on a string and\n * neither needs to know the string is structured.\n */\n/**\n * What SHAPE a sealed credential holds, once opened.\n *\n * One member today and a named vocabulary anyway, because the day a second sealed payload exists —\n * a service-account key, a signed JWT assertion — the discriminant is what tells them apart, and a\n * bare literal is where per-member explanation cannot live. It is also the value a reader needs to\n * understand `PROVIDER_OAUTH2_GRANT_PREFIX`: the prefix is how the shape is recognised WITHOUT\n * parsing, and this is what it recognises.\n */\nexport enum ProviderStoredCredentialKind {\n /** An OAuth2 grant: an access token, and what is needed to renew it. */\n OAUTH2_GRANT = 'oauth2-grant',\n}\n\nexport const ProviderOAuth2GrantSchema = z.object({\n /**\n * A discriminant, so an opened envelope announces which shape it is.\n *\n * Without it the reader would have to guess from whether the plaintext parses as JSON — and a\n * pasted credential that happens to be JSON (a service-account key, which several vendors issue\n * exactly that way) would be misread as a grant. A guess that is right almost always is the worst\n * kind here, because the failure is a malformed Authorization header on somebody else's account.\n */\n kind: z.literal(ProviderStoredCredentialKind.OAUTH2_GRANT),\n\n /** The token that actually goes on the wire. */\n accessToken: z.string().min(1),\n\n /**\n * Present when the vendor issues one. Absent is normal and permanent for vendors that do not —\n * Slack's bot tokens do not expire and have no refresh — so its absence must not read as an\n * incomplete grant.\n */\n refreshToken: z.string().min(1).optional(),\n\n /**\n * When the access token stops being accepted, as an ISO instant.\n *\n * Optional because a non-expiring token genuinely has none. A grant with a refresh token and no\n * expiry is refreshed only after the vendor rejects it, which is correct but slower than\n * refreshing ahead of a known deadline.\n */\n expiresAt: z.iso.datetime().optional(),\n\n /**\n * What the vendor actually GRANTED, which is not always what was asked for.\n *\n * Recorded because the difference is invisible until a call fails: a vendor may issue a token for\n * a subset of the requested scopes, and the resulting `missing_scope` arrives on an unrelated\n * operation weeks later. Holding the granted set lets that be answered from the row.\n */\n grantedScopes: z.array(z.string()).optional(),\n\n /**\n * The vendor's own identifier for the account this grant is on — a Slack team id, a Google sub, a\n * Microsoft tenant id.\n *\n * Not used for lookup and deliberately not part of the row's identity. It exists so a person\n * reading their connections can tell WHICH account they connected, which a provider ref cannot\n * answer for anyone who has two.\n */\n accountRef: z.string().optional(),\n});\n\nexport type ProviderOAuth2Grant = z.infer<typeof ProviderOAuth2GrantSchema>;\n\n/**\n * The marker that opens the sealed plaintext of a grant rather than a pasted credential.\n *\n * A prefix on the JSON rather than a field inside it, so the decision can be made without parsing —\n * the same reason the envelope carries a prefix. Parsing first would mean feeding an arbitrary\n * pasted credential to `JSON.parse` on every resolution.\n */\nexport const PROVIDER_OAUTH2_GRANT_PREFIX = 'wildo-oauth2-grant:';\n\n/** Whether an OPENED credential is a grant. Cheap, and does not parse. */\nexport function isProviderOAuth2GrantPlaintext(plaintext: string): boolean {\n return plaintext.startsWith(PROVIDER_OAUTH2_GRANT_PREFIX);\n}\n\n/** Render a grant for sealing. The inverse of {@link parseProviderOAuth2Grant}. */\nexport function serializeProviderOAuth2Grant(grant: ProviderOAuth2Grant): string {\n return `${PROVIDER_OAUTH2_GRANT_PREFIX}${JSON.stringify(grant)}`;\n}\n\n/**\n * Read a grant back, or `undefined` when the plaintext is an ordinary pasted credential.\n *\n * THROWS when the value announces itself as a grant and then does not parse or does not validate.\n * That is the same posture the envelope takes toward a value the write path could not have\n * produced: a credential which claims a shape it does not have is a fault worth failing on, never\n * one worth falling back from — falling back would put a JSON blob on the wire as a bearer token.\n */\nexport function parseProviderOAuth2Grant(plaintext: string): ProviderOAuth2Grant | undefined {\n if (!isProviderOAuth2GrantPlaintext(plaintext)) return undefined;\n const body = plaintext.slice(PROVIDER_OAUTH2_GRANT_PREFIX.length);\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n throw new Error(\n 'A stored provider credential announces itself as an OAuth2 grant and is not valid JSON. It was '\n + 'written by something other than the authorization exchange; reconnect the account.',\n );\n }\n const result = ProviderOAuth2GrantSchema.safeParse(parsed);\n if (!result.success) {\n throw new Error(\n 'A stored provider credential announces itself as an OAuth2 grant but does not match the grant '\n + 'shape. Reconnect the account rather than editing the row — the value on the wire would '\n + 'otherwise be a fragment of a token.',\n );\n }\n return result.data;\n}\n\n/**\n * Whether a grant should be refreshed BEFORE it is spent.\n *\n * The skew is what makes this useful rather than decorative: a token that expires in two seconds is\n * still \"valid\" and will have expired by the time the request reaches the vendor, so refreshing only\n * on expiry guarantees a population of calls that fail for a reason nothing recorded. Sixty seconds\n * is the industry's common floor and comfortably exceeds any plausible clock skew plus flight time.\n *\n * Returns false when there is no expiry — a non-expiring token is refreshed reactively, after the\n * vendor rejects it, because there is no deadline to act ahead of.\n */\nexport const PROVIDER_OAUTH2_REFRESH_SKEW_SECONDS = 60;\n\nexport function providerOAuth2GrantNeedsRefresh(grant: ProviderOAuth2Grant, now: Date = new Date()): boolean {\n if (grant.expiresAt === undefined) return false;\n const expiry = Date.parse(grant.expiresAt);\n if (Number.isNaN(expiry)) return true;\n return expiry - now.getTime() <= PROVIDER_OAUTH2_REFRESH_SKEW_SECONDS * 1000;\n}\n"]}
1
+ {"version":3,"file":"provider-credentials.shared.schemas.js","sourceRoot":"","sources":["../../../../src/security/connected-accounts/provider-credentials.shared.schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;GAOG;AACH,MAAM,CAAN,IAAY,iCAOX;AAPD,WAAY,iCAAiC;IAC3C,0FAA0F;IAC1F,gEAA2B,CAAA;IAC3B,gDAAgD;IAChD,oDAAe,CAAA;IACf,8EAA8E;IAC9E,wDAAmB,CAAA;AACrB,CAAC,EAPW,iCAAiC,KAAjC,iCAAiC,QAO5C;AAED;;;;;;;;;;;GAWG;AACH;;;;;;;;GAQG;AACH,MAAM,CAAN,IAAY,kCAmBX;AAnBD,WAAY,kCAAkC;IAC5C,yEAAyE;IACzE,yFAAmD,CAAA;IACnD;;;OAGG;IACH,uFAAiD,CAAA;IACjD;;;;;;;;;OASG;IACH,yEAAmC,CAAA;AACrC,CAAC,EAnBW,kCAAkC,KAAlC,kCAAkC,QAmB7C;AAED,6CAA6C;AAC7C,MAAM,CAAN,IAAY,gCAeX;AAfD,WAAY,gCAAgC;IAC1C,wDAAwD;IACxD,mFAA+C,CAAA;IAC/C,iGAAiG;IACjG,+EAA2C,CAAA;IAC3C,gEAAgE;IAChE,mEAA+B,CAAA;IAC/B;;;;;;OAMG;IACH,+DAA2B,CAAA;AAC7B,CAAC,EAfW,gCAAgC,KAAhC,gCAAgC,QAe3C;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gDAAgD,GAAG;IAC9D,gBAAgB;IAChB,aAAa;IACb,YAAY;CACJ,CAAC;AAEX,MAAM,CAAC,MAAM,oCAAoC,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3D,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,cAAc,EAAE;IAEtD;;;;OAIG;IACH,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,YAAY,EAAE,CAAC,cAAc,EAAE,CAAC,iBAAiB,EAAE;IAEnG;;;;;OAKG;IACH,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,cAAc,EAAE,CAAC,iBAAiB,EAAE;IAE1F;;;;;OAKG;IACH,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,cAAc,EAAE,CAAC,iBAAiB,EAAE;IAEzF;;;;;;;;;;;;;OAaG;IACH,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,EAAE;IAElD;;;OAGG;IACH,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,cAAc,EAAE;IAEjE,eAAe,EAAE,CAAC;SACf,IAAI,CAAC,iCAAiC,CAAC;SACvC,OAAO,CAAC,iCAAiC,CAAC,WAAW,CAAC;SACtD,WAAW,EAAE;SACb,cAAc,EAAE;IAEnB;;;;OAIG;IACH,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE,CAAC,iBAAiB,EAAE;IAEvF,eAAe,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE,CAAC,iBAAiB,EAAE;IAC5E,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,CAAC,iBAAiB,EAAE,CAAC,iBAAiB,EAAE;IAErF;;;;;;;;OAQG;IACH,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,CAAC,iBAAiB,EAAE,CAAC,iBAAiB,EAAE;IAE/F,mGAAmG;IACnG,WAAW,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE,CAAC,iBAAiB,EAAE;IAExE,6FAA6F;IAC7F;;;;;;;;;;;;;;;;;;;OAmBG;IACH,oBAAoB,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE;IAGrF,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAE3C,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;IACA;;;;;;;;;;;;OAYG;KACF,cAAc,CAAC,CAAC,GAAG,gDAAgD,CAAC,CAAC,CAAC;AAMzE,gFAAgF;AAChF,yBAAyB;AACzB,gFAAgF;AAEhF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,wCAAwC,GAAG;IACtD,QAAQ;IACR,aAAa;IACb,YAAY;CACJ,CAAC;AAEX;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC,MAAM,CAAC;IACnD,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,cAAc,EAAE;IAEtD;;;;OAIG;IACH,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,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,cAAc,EAAE,CAAC,iBAAiB,EAAE;IAE1F;;iDAE6C;IAC7C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,cAAc,EAAE,CAAC,iBAAiB,EAAE;IAEzF;;;;;;OAMG;IACH,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,EAAE;IAElD,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,cAAc,EAAE;IAEjE,eAAe,EAAE,CAAC;SACf,IAAI,CAAC,iCAAiC,CAAC;SACvC,OAAO,CAAC,iCAAiC,CAAC,WAAW,CAAC;SACtD,WAAW,EAAE;SACb,cAAc,EAAE;IAEnB;wCACoC;IACpC,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE,CAAC,iBAAiB,EAAE;IAEvF,eAAe,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE,CAAC,iBAAiB,EAAE;IAC5E,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,CAAC,iBAAiB,EAAE,CAAC,iBAAiB,EAAE;IAErF,mGAAmG;IACnG,WAAW,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE,CAAC,iBAAiB,EAAE;IAExE,2FAA2F;IAC3F;;;;;;;;;;;;;;;;;;;OAmBG;IACH,oBAAoB,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE;IAGrF,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAE3C,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;IACA;;;;;OAKG;KACF,cAAc,CAAC,CAAC,GAAG,wCAAwC,CAAC,CAAC,CAAC;AAKjE,iGAAiG;AACjG,gBAAgB;AAChB,EAAE;AACF,kGAAkG;AAClG,oFAAoF;AACpF,EAAE;AACF,oDAAoD;AACpD,EAAE;AACF,oGAAoG;AACpG,mGAAmG;AACnG,oGAAoG;AACpG,2EAA2E;AAC3E,EAAE;AACF,oGAAoG;AACpG,oGAAoG;AACpG,kGAAkG;AAClG,uFAAuF;AACvF,iGAAiG;AAEjG;;;;;;GAMG;AACH;;;;;;;;GAQG;AACH;;;;;;;;;;GAUG;AACH;;;;;;GAMG;AACH,MAAM,CAAN,IAAY,kBAQX;AARD,WAAY,kBAAkB;IAC5B,+FAA+F;IAC/F,6EAAuD,CAAA;IACvD;;;OAGG;IACH,yDAAmC,CAAA;AACrC,CAAC,EARW,kBAAkB,KAAlB,kBAAkB,QAQ7B;AAED,MAAM,CAAN,IAAY,6BAcX;AAdD,WAAY,6BAA6B;IACvC;;;;OAIG;IACH,gFAA+C,CAAA;IAC/C;;;;;OAKG;IACH,0FAAyD,CAAA;AAC3D,CAAC,EAdW,6BAA6B,KAA7B,6BAA6B,QAcxC;AAkBD,MAAM,CAAN,IAAY,4BAGX;AAHD,WAAY,4BAA4B;IACtC,wEAAwE;IACxE,6DAA6B,CAAA;AAC/B,CAAC,EAHW,4BAA4B,KAA5B,4BAA4B,QAGvC;AAED,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD;;;;;;;OAOG;IACH,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,4BAA4B,CAAC,YAAY,CAAC;IAE1D,gDAAgD;IAChD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAE9B;;;;OAIG;IACH,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAE1C;;;;;;OAMG;IACH,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAEtC;;;;;;OAMG;IACH,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IAE7C;;;;;;;OAOG;IACH,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAClC,CAAC,CAAC;AAIH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,qBAAqB,CAAC;AAElE,0EAA0E;AAC1E,MAAM,UAAU,8BAA8B,CAAC,SAAiB;IAC9D,OAAO,SAAS,CAAC,UAAU,CAAC,4BAA4B,CAAC,CAAC;AAC5D,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,4BAA4B,CAAC,KAA0B;IACrE,OAAO,GAAG,4BAA4B,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;AACnE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,wBAAwB,CAAC,SAAiB;IACxD,IAAI,CAAC,8BAA8B,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IACjE,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,4BAA4B,CAAC,MAAM,CAAC,CAAC;IAClE,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,iGAAiG;cAC/F,oFAAoF,CACvF,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,yBAAyB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC3D,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,gGAAgG;cAC9F,yFAAyF;cACzF,qCAAqC,CACxC,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,oCAAoC,GAAG,EAAE,CAAC;AAEvD,MAAM,UAAU,+BAA+B,CAAC,KAA0B,EAAE,MAAY,IAAI,IAAI,EAAE;IAChG,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAChD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC3C,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,OAAO,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,IAAI,oCAAoC,GAAG,IAAI,CAAC;AAC/E,CAAC","sourcesContent":["/**\n * Organization Provider Credentials — shared schemas.\n *\n * ## What this resource is, and what it is NOT\n *\n * It is an ORGANIZATION's OWN credential toward a third party: the Slack workspace token, the CRM\n * API key, the SMTP password that belongs to THAT tenant. The organization is the third-party\n * principal, and the credential is a service credential the tenant's administrator supplies.\n *\n * It is NOT a user's delegated OAuth grant. A delegated grant is a different object with a\n * different lifetime (a refresh loop, a revocation the USER can perform, a consent record) and it\n * lands as `connected accounts` beside this file — see issue #333. Merging the two would give one\n * row two owners and two revocation semantics.\n *\n * ## Why it has to exist\n *\n * Before this resource, every provider secret resolved from `process.env` through the\n * `SecretsContract`, so a credential was per-PROCESS and per-DEPLOYMENT. One application serving\n * many organizations therefore had ONE Slack token for all of them, and the failure was silent in\n * the worst direction: an operator sets one key and every tenant thereafter acts as the SAME\n * third-party principal, with nothing anywhere saying so.\n *\n * ## The value is sealed, and this file is where that is stated\n *\n * `secretValue` holds an AES-256-GCM envelope, never the plaintext an operator typed. The seal is\n * applied on the way in and opened only by the resolver — see\n * `provider-credential-envelope.backend.utils.ts` for the envelope and its key derivation. The\n * schema cannot enforce that (a string is a string), so the write path is what guarantees it and\n * the pins are what keep it guaranteed.\n */\n\nimport { z } from 'zod';\n\n/**\n * Whether the stored credential has been shown to work against the provider.\n *\n * A closed vocabulary rather than a boolean because \"we have never tried\" and \"we tried and it\n * failed\" are different states with different operator actions, and a boolean would merge them\n * into the same falsy answer. `UNVALIDATED` is the honest default: storing a credential proves\n * only that somebody typed one.\n */\nexport enum ProviderCredentialValidationState {\n /** Stored, never exercised against the provider. The state every credential starts in. */\n UNVALIDATED = 'unvalidated',\n /** The provider accepted it on its last use. */\n VALID = 'valid',\n /** The provider rejected it on its last use — the operator must rotate it. */\n INVALID = 'invalid',\n}\n\n/**\n * The organization's credential for one (provider, secret slug) pair.\n *\n * ## The scope identifier is TOP-LEVEL and stays that way\n *\n * `organizationId` is the only `organizationId`-named path in this schema, and nothing nested may\n * ever be named `organizationId` or `userId`. `buildContextualFilter` injects the scope FK by\n * matching that field name at EVERY schema path, so a nested key of the same name adds a phantom\n * exact-subdocument clause and the scoped read silently matches zero rows — a credential that\n * exists and cannot be resolved, which reads exactly like a credential that was never set.\n * `setByUserId` is deliberately spelled so it cannot be caught by that matcher.\n */\n/**\n * WHERE a resolved provider secret came from.\n *\n * The whole point of this slice is that the answer used to be unanswerable: every secret came from\n * `process.env`, so \"which principal did this tenant act as?\" had one answer for every tenant and\n * nothing recorded it. Making the source an explicit, closed value means an audit reader can see a\n * tenant falling back to the shared deployment credential — the exact condition the resource exists\n * to make visible — instead of having to infer it from an absence.\n */\nexport enum ProviderCredentialResolutionSource {\n /** The organization's own credential row. The tenant acted as itself. */\n ORGANIZATION_CREDENTIAL = 'organization_credential',\n /**\n * The deployment's env-projected `SecretsContract`. Legitimate — a single-tenant deployment, or a\n * provider the operator intends every tenant to share — but never silent.\n */\n DEPLOYMENT_ENVIRONMENT = 'deployment_environment',\n /**\n * A PERSON's own credential row. The application acted as that individual.\n *\n * This member has no sibling fallback, and that asymmetry is deliberate rather than an omission.\n * An organization with no credential of its own may legitimately fall through to the deployment's\n * — an operator can intend every tenant to share one integration. A person cannot: the vendor\n * attributes the act to whoever's token was spent, so acting for someone under the deployment's\n * principal would put the wrong name on the record that outlives us. A person who has connected\n * nothing gets a refusal, not a substitute.\n */\n USER_CREDENTIAL = 'user_credential',\n}\n\n/** Why a credential row stopped existing. */\nexport enum ProviderCredentialDeletionReason {\n /** An administrator of the owning tenant removed it. */\n ADMINISTRATOR_REVOKED = 'administrator_revoked',\n /** The owning organization was purged and the composition cascade removed it with the tenant. */\n ORGANIZATION_PURGED = 'organization_purged',\n /** The person whose credential it was removed it themselves. */\n OWNER_REVOKED = 'owner_revoked',\n /**\n * The owning user was erased and the composition cascade destroyed it with them.\n *\n * Distinct from `ORGANIZATION_PURGED` because this one is EVIDENCE: it is what an operator points\n * at when asked whether a subject-erasure request reached the person's third-party credentials.\n * Collapsing the two into a generic \"cascade\" would make that question unanswerable from the trail.\n */\n USER_ERASED = 'user_erased',\n}\n\n/**\n * The fields that IDENTIFY a credential within its tenant.\n *\n * One tenant holds at most one credential per (provider, slug). Exported rather than repeated so\n * the uniqueness contract, the resolver's lookup and the tests cannot drift apart — three copies\n * of a compound key is how two of them come to disagree about what identity means.\n */\nexport const ORGANIZATION_PROVIDER_CREDENTIAL_IDENTITY_FIELDS = [\n 'organizationId',\n 'providerRef',\n 'secretSlug',\n] as const;\n\nexport const OrganizationProviderCredentialSchema = z.object({\n _id: z.string().min(1).isPrimaryKey().isSummaryField(),\n\n /**\n * The tenant that owns this credential. Injected by the context machinery from the request\n * scope, never from a caller-supplied field — which is what makes the isolation structural\n * rather than a filter somebody has to remember to write.\n */\n organizationId: z.string().min(1).isDBIndexed().isForeignKey().isSummaryField().excludeFromUpdate(),\n\n /**\n * The provider this credential authenticates toward (`slack`, `stripe`, a generated package's\n * ref). An OPEN string, matching `ProviderRef`'s own openness — the whole point of the provider\n * work is that the set is not closed, so a closed enum here would refuse every generated\n * provider.\n */\n providerRef: z.string().min(1).max(200).isDBIndexed().isSummaryField().excludeFromUpdate(),\n\n /**\n * The slug in the provider's `secretsContract` that this value satisfies — the same identifier\n * the deployment's env projection carries, so the two resolution places name the same thing.\n * Immutable: re-pointing a stored secret at a different slug would silently hand one vendor\n * credential to a different vendor field.\n */\n secretSlug: z.string().min(1).max(200).isDBIndexed().isSummaryField().excludeFromUpdate(),\n\n /**\n * The credential, SEALED.\n *\n * `.isWriteOnlySecret()` is the framework's write-then-masked contract and is exactly right\n * here: the operator supplies and rotates the value, so it must stay in the CREATE/UPDATE\n * request DTO; the framework redacts it to a placeholder at the client boundary, so no read\n * ever returns it; and the backend keeps the stored content for its own resolution.\n *\n * `.isBackendOnly()` was rejected — it strips the field from the client DTO, so the operator's\n * typed value is dropped before it is ever stored and the surface silently accepts nothing.\n *\n * What is PERSISTED is the envelope, never the plaintext. The write path seals it; a value that\n * reaches persistence unsealed is a defect, not a tolerated legacy shape.\n */\n secretValue: z.string().min(1).isWriteOnlySecret(),\n\n /**\n * Whether this credential may be spent. An operator can park a credential without deleting it —\n * which matters during an incident, where deleting is not reversible and disabling is.\n */\n enabled: z.boolean().default(true).isDBIndexed().isSummaryField(),\n\n validationState: z\n .enum(ProviderCredentialValidationState)\n .default(ProviderCredentialValidationState.UNVALIDATED)\n .isDBIndexed()\n .isSummaryField(),\n\n /**\n * Why the last use failed, when it did. PROVIDER-supplied text about the CREDENTIAL's status —\n * never the credential. A resolver writing anything derived from `secretValue` here would defeat\n * every other precaution in this file, because this field IS client-readable.\n */\n validationError: z.string().max(500).optional().excludeFromCreate().excludeFromUpdate(),\n\n lastValidatedAt: z.date().optional().excludeFromCreate().excludeFromUpdate(),\n lastUsedAt: z.date().optional().isDBIndexed().excludeFromCreate().excludeFromUpdate(),\n\n /**\n * WHO set it — the acting user's id, recorded for the audit trail.\n *\n * Deliberately NOT a registered `USERS` relationship. Declaring that edge would put a CREDENTIAL\n * row on the Art. 15 subject-export graph, and a credential is precisely the class of row that\n * must never reach a data subject. The id is recorded because \"who set this\" is the first\n * question of any credential incident; the edge is withheld because the answer must not travel\n * with a subject export.\n */\n setByUserId: z.string().min(1).optional().isDBIndexed().excludeFromCreate().excludeFromUpdate(),\n\n /** When the stored VALUE last changed — distinct from `updatedAt`, which any field write moves. */\n secretSetAt: z.date().optional().excludeFromCreate().excludeFromUpdate(),\n\n /** Free-text operator note. Never a place for the value; enforced by the write-path pins. */\n /**\n * Answers for the `{placeholder}` holes this provider's OAuth2 endpoints carry — which cloud,\n * which directory, which region.\n *\n * On the ROW rather than only in the connect flow, because a REFRESH needs them again. The\n * authorization record that held them lives ten minutes; the token it produced is renewed for as\n * long as the connection lasts, and a templated token URL is still templated an hour later.\n * Without them here, every one of the 21 vendors whose endpoints carry a placeholder — Microsoft,\n * Azure, and everything regional — would connect successfully and then fail its first renewal with\n * `needs a value for 'cloud'`: the exact failure the placeholder machinery exists to prevent, one\n * layer up.\n *\n * NOT secret, and deliberately client-readable: a tenant id is an identifier a person needs to see\n * to recognise which account they connected. The secret half is the grant, and it is sealed.\n *\n * `.excludeFromUpdate()` — chosen at connect time, and they describe the ACCOUNT the grant is for.\n * Changing them under a live grant would point the refresh at a different directory than the one\n * that issued the token, failing at the vendor with nothing local explaining why. Reconnecting is\n * the honest way to change them.\n */\n connectionParameters: z.record(z.string(), z.string()).optional().excludeFromUpdate(),\n\n\n description: z.string().max(500).optional(),\n\n createdAt: z.date().default(() => new Date()).isDBIndexed().isSummaryField().excludeFromCreate().excludeFromUpdate(),\n updatedAt: z.date().default(() => new Date()).isDBIndexed().excludeFromCreate().excludeFromUpdate(),\n})\n /**\n * One credential per tenant per (provider, slug), enforced by a compound UNIQUE index rather\n * than by a read-then-write.\n *\n * The race it closes is not academic: two administrators saving a rotated Slack token in the\n * same minute would otherwise leave two rows, and the resolver would then pick one of them\n * arbitrarily — so half the tenant's outbound calls would carry the old credential and nobody\n * could tell which half.\n *\n * No `customMessageReference`: that option exists so an integrator can tell WHICH identity a\n * duplicate violated, and this resource declares exactly one. A dedicated reference here would\n * disambiguate nothing.\n */\n .businessKeySet([...ORGANIZATION_PROVIDER_CREDENTIAL_IDENTITY_FIELDS]);\n\nexport type OrganizationProviderCredential = z.infer<typeof OrganizationProviderCredentialSchema>;\n\n\n\n// =============================================================================\n// USER-OWNED CREDENTIALS\n// =============================================================================\n\n/**\n * The fields that IDENTIFY a credential within its OWNER.\n *\n * Exported per owner rather than shared, because the compound key differs in its first component and\n * a single constant would have to be assembled by each side — which is how two copies of a key come\n * to disagree about what identity means.\n */\nexport const USER_PROVIDER_CREDENTIAL_IDENTITY_FIELDS = [\n 'userId',\n 'providerRef',\n 'secretSlug',\n] as const;\n\n/**\n * A PERSON's own credential toward a third party — the key they authored for themselves.\n *\n * ## Why this is a separate resource and not a nullable column beside the organization's\n *\n * Wildo's tenancy is STRUCTURAL: the contextual filter injects the scope FK by matching a field name\n * at every schema path, so a resource belongs to exactly one primary scope. One table holding both a\n * nullable `organizationId` and a nullable `userId` would turn that structural guarantee into a\n * filter somebody has to remember to write, on the one resource where forgetting it discloses a\n * credential. Two resources, each scoped by construction, is the framework working as designed\n * rather than a duplication.\n *\n * ## Not a delegated OAuth grant, and the difference is not subtle\n *\n * This is a key the user PASTED: they hold an account with the vendor and chose to let this\n * application spend it. A delegated grant is the vendor minting a token because the user approved a\n * consent screen, and it carries a refresh loop, an expiry and a revocation the vendor also honours.\n * Merging them would give one row two lifecycles and two revocation semantics — see #333, which owns\n * the second.\n *\n * ## Only the holder may spend it\n *\n * Not an administrator of their organization, and not a platform operator. Consent to STORE a\n * personal key is not consent for somebody else to use it, and the vendor would record the act as\n * the holder's own. The authorization side of that is\n * `InitiatorMembershipConnectionTargetAuthorization`; this schema is what makes the row reachable\n * only through the owner's own scope.\n */\nexport const UserProviderCredentialSchema = z.object({\n _id: z.string().min(1).isPrimaryKey().isSummaryField(),\n\n /**\n * The person who owns this credential. Injected by the context machinery from the authenticated\n * scope, never from a caller-supplied field — the same structural isolation the organization-owned\n * sibling relies on, which is what makes \"another user's key\" unreachable rather than filtered.\n */\n userId: z.string().min(1).isDBIndexed().isForeignKey().isSummaryField().excludeFromUpdate(),\n\n /** As the organization-owned sibling: an OPEN string, because the provider set is not closed. */\n providerRef: z.string().min(1).max(200).isDBIndexed().isSummaryField().excludeFromUpdate(),\n\n /** The slug in the provider's `secretsContract` this value satisfies. Immutable, for the same\n * reason as the sibling: re-pointing a stored secret at a different slug would hand one vendor\n * credential to a different vendor field. */\n secretSlug: z.string().min(1).max(200).isDBIndexed().isSummaryField().excludeFromUpdate(),\n\n /**\n * The credential, SEALED — an AES-256-GCM envelope bound to this row's identity, never plaintext.\n *\n * `.isWriteOnlySecret()` for the same reason as the sibling: the holder supplies and rotates it, so\n * it must survive into the CREATE/UPDATE request DTO, and the framework masks it at the client\n * boundary so no read ever returns it.\n */\n secretValue: z.string().min(1).isWriteOnlySecret(),\n\n enabled: z.boolean().default(true).isDBIndexed().isSummaryField(),\n\n validationState: z\n .enum(ProviderCredentialValidationState)\n .default(ProviderCredentialValidationState.UNVALIDATED)\n .isDBIndexed()\n .isSummaryField(),\n\n /** Why the last use failed. PROVIDER text about the CREDENTIAL, never anything derived from it —\n * this field IS client-readable. */\n validationError: z.string().max(500).optional().excludeFromCreate().excludeFromUpdate(),\n\n lastValidatedAt: z.date().optional().excludeFromCreate().excludeFromUpdate(),\n lastUsedAt: z.date().optional().isDBIndexed().excludeFromCreate().excludeFromUpdate(),\n\n /** When the stored VALUE last changed — distinct from `updatedAt`, which any field write moves. */\n secretSetAt: z.date().optional().excludeFromCreate().excludeFromUpdate(),\n\n /** The holder's own note. Never a place for the value; enforced by the write-path pins. */\n /**\n * Answers for the `{placeholder}` holes this provider's OAuth2 endpoints carry — which cloud,\n * which directory, which region.\n *\n * On the ROW rather than only in the connect flow, because a REFRESH needs them again. The\n * authorization record that held them lives ten minutes; the token it produced is renewed for as\n * long as the connection lasts, and a templated token URL is still templated an hour later.\n * Without them here, every one of the 21 vendors whose endpoints carry a placeholder — Microsoft,\n * Azure, and everything regional — would connect successfully and then fail its first renewal with\n * `needs a value for 'cloud'`: the exact failure the placeholder machinery exists to prevent, one\n * layer up.\n *\n * NOT secret, and deliberately client-readable: a tenant id is an identifier a person needs to see\n * to recognise which account they connected. The secret half is the grant, and it is sealed.\n *\n * `.excludeFromUpdate()` — chosen at connect time, and they describe the ACCOUNT the grant is for.\n * Changing them under a live grant would point the refresh at a different directory than the one\n * that issued the token, failing at the vendor with nothing local explaining why. Reconnecting is\n * the honest way to change them.\n */\n connectionParameters: z.record(z.string(), z.string()).optional().excludeFromUpdate(),\n\n\n description: z.string().max(500).optional(),\n\n createdAt: z.date().default(() => new Date()).isDBIndexed().isSummaryField().excludeFromCreate().excludeFromUpdate(),\n updatedAt: z.date().default(() => new Date()).isDBIndexed().excludeFromCreate().excludeFromUpdate(),\n})\n /**\n * One credential per person per (provider, slug), enforced by a compound UNIQUE index rather than\n * a read-then-write — the same race the organization-owned sibling closes, and for the same\n * reason: two rows would leave the resolver picking one arbitrarily, so half the holder's outbound\n * calls would carry a rotated-away credential and nothing would say which half.\n */\n .businessKeySet([...USER_PROVIDER_CREDENTIAL_IDENTITY_FIELDS]);\n\nexport type UserProviderCredential = z.infer<typeof UserProviderCredentialSchema>;\n\n\n// ══════════════════════════════════════════════════════════════════════════════════════════════\n// OAUTH2 GRANTS\n//\n// A credential a vendor MINTS rather than one a person pastes. It rides in the same `secretValue`\n// field of the same two resources — sealed, as JSON — and that reuse is deliberate.\n//\n// ## Why the same rows rather than a third resource\n//\n// The identity is the same triple (owner, providerRef, secretSlug), the ownership semantics are the\n// same, the authorization is the same, the erasure is the same, and the resolver already routes by\n// scope. Only the PAYLOAD differs. A separate resource would duplicate every one of those and force\n// each consumer to ask \"which store?\" before it could ask anything useful.\n//\n// Note this is the OPPOSITE call from the one that split USER from ORGANIZATION, and the difference\n// is what makes both right: there the TENANCY differed, and tenancy in this framework is structural\n// — one table with a nullable owner would turn a structural guarantee into a filter somebody must\n// remember to write. Here nothing about ownership changes; a string becomes an object.\n// ══════════════════════════════════════════════════════════════════════════════════════════════\n\n/**\n * What an authorization exchange gives back, as it is stored.\n *\n * Sealed as JSON into `secretValue`, so `.isWriteOnlySecret()` keeps masking it at the client\n * boundary and the envelope keeps binding it to its row — both mechanisms work on a string and\n * neither needs to know the string is structured.\n */\n/**\n * What SHAPE a sealed credential holds, once opened.\n *\n * One member today and a named vocabulary anyway, because the day a second sealed payload exists —\n * a service-account key, a signed JWT assertion — the discriminant is what tells them apart, and a\n * bare literal is where per-member explanation cannot live. It is also the value a reader needs to\n * understand `PROVIDER_OAUTH2_GRANT_PREFIX`: the prefix is how the shape is recognised WITHOUT\n * parsing, and this is what it recognises.\n */\n/**\n * Why a provider cannot be connected HERE, even though the vendor is in the catalogue.\n *\n * \"Connectable\" is a property of the DEPLOYMENT and not of the vendor, and conflating the two put a\n * Connect button on a screen that could only ever fail. Asana supports OAuth2 perfectly well; this\n * application has simply never registered with Asana, and no amount of pressing the button changes\n * that.\n *\n * The two members lead to different actions by different people, which is the whole reason they are\n * distinguished rather than collapsed into a boolean.\n */\n/**\n * HOW a connection to a provider is established — the shape of the act, which decides the screen.\n *\n * A connect surface cannot be one form. Granting consent at a vendor and typing a key are different\n * acts with different inputs and different failure modes, and a screen that offered one button for\n * both would be wrong for whichever it was not built around.\n */\nexport enum ProviderAuthMethod {\n /** The authorization-code round trip: leave, consent at the vendor, come back with a grant. */\n OAUTH2_AUTHORIZATION_CODE = 'oauth2-authorization-code',\n /**\n * A value somebody holds and types — an API key, a personal access token. The fields are DECLARED\n * by the provider's secrets contract, so a screen names them rather than asking for a slug.\n */\n DECLARED_SECRET = 'declared-secret',\n}\n\nexport enum ProviderConnectabilityBlocker {\n /**\n * The vendor has no authorization flow in the catalogue: its credential is PASTED, not granted.\n * Nothing is missing and nothing is broken — this provider is authored on the credential screen\n * instead, and an application author is the one who acts.\n */\n NO_AUTHORIZATION_FLOW = 'no-authorization-flow',\n /**\n * The vendor has a flow and THIS DEPLOYMENT has not registered with it — no client id, or no client\n * secret. An OPERATOR acts: register an application with the vendor and set the two environment\n * variables the provider's contract names. Distinct from the above because the vendor is perfectly\n * connectable and the gap is ours.\n */\n APPLICATION_NOT_REGISTERED = 'application-not-registered',\n}\n\n/**\n * One secret slot a provider declares, as a SCREEN needs it — never the value.\n *\n * Exists so nothing is typed by hand. The slug names the field, the environment variable tells an\n * operator exactly what to set, and `configured` lets a missing one be REPORTED rather than\n * discovered by pressing a button that fails.\n */\nexport interface ProviderSecretSlotView {\n readonly slug: string;\n readonly envVarName: string;\n readonly required: boolean;\n readonly description: string;\n /** Whether the deployment supplies it. There is deliberately no field for the value. */\n readonly configured: boolean;\n}\n\nexport enum ProviderStoredCredentialKind {\n /** An OAuth2 grant: an access token, and what is needed to renew it. */\n OAUTH2_GRANT = 'oauth2-grant',\n}\n\nexport const ProviderOAuth2GrantSchema = z.object({\n /**\n * A discriminant, so an opened envelope announces which shape it is.\n *\n * Without it the reader would have to guess from whether the plaintext parses as JSON — and a\n * pasted credential that happens to be JSON (a service-account key, which several vendors issue\n * exactly that way) would be misread as a grant. A guess that is right almost always is the worst\n * kind here, because the failure is a malformed Authorization header on somebody else's account.\n */\n kind: z.literal(ProviderStoredCredentialKind.OAUTH2_GRANT),\n\n /** The token that actually goes on the wire. */\n accessToken: z.string().min(1),\n\n /**\n * Present when the vendor issues one. Absent is normal and permanent for vendors that do not —\n * Slack's bot tokens do not expire and have no refresh — so its absence must not read as an\n * incomplete grant.\n */\n refreshToken: z.string().min(1).optional(),\n\n /**\n * When the access token stops being accepted, as an ISO instant.\n *\n * Optional because a non-expiring token genuinely has none. A grant with a refresh token and no\n * expiry is refreshed only after the vendor rejects it, which is correct but slower than\n * refreshing ahead of a known deadline.\n */\n expiresAt: z.iso.datetime().optional(),\n\n /**\n * What the vendor actually GRANTED, which is not always what was asked for.\n *\n * Recorded because the difference is invisible until a call fails: a vendor may issue a token for\n * a subset of the requested scopes, and the resulting `missing_scope` arrives on an unrelated\n * operation weeks later. Holding the granted set lets that be answered from the row.\n */\n grantedScopes: z.array(z.string()).optional(),\n\n /**\n * The vendor's own identifier for the account this grant is on — a Slack team id, a Google sub, a\n * Microsoft tenant id.\n *\n * Not used for lookup and deliberately not part of the row's identity. It exists so a person\n * reading their connections can tell WHICH account they connected, which a provider ref cannot\n * answer for anyone who has two.\n */\n accountRef: z.string().optional(),\n});\n\nexport type ProviderOAuth2Grant = z.infer<typeof ProviderOAuth2GrantSchema>;\n\n/**\n * The marker that opens the sealed plaintext of a grant rather than a pasted credential.\n *\n * A prefix on the JSON rather than a field inside it, so the decision can be made without parsing —\n * the same reason the envelope carries a prefix. Parsing first would mean feeding an arbitrary\n * pasted credential to `JSON.parse` on every resolution.\n */\nexport const PROVIDER_OAUTH2_GRANT_PREFIX = 'wildo-oauth2-grant:';\n\n/** Whether an OPENED credential is a grant. Cheap, and does not parse. */\nexport function isProviderOAuth2GrantPlaintext(plaintext: string): boolean {\n return plaintext.startsWith(PROVIDER_OAUTH2_GRANT_PREFIX);\n}\n\n/** Render a grant for sealing. The inverse of {@link parseProviderOAuth2Grant}. */\nexport function serializeProviderOAuth2Grant(grant: ProviderOAuth2Grant): string {\n return `${PROVIDER_OAUTH2_GRANT_PREFIX}${JSON.stringify(grant)}`;\n}\n\n/**\n * Read a grant back, or `undefined` when the plaintext is an ordinary pasted credential.\n *\n * THROWS when the value announces itself as a grant and then does not parse or does not validate.\n * That is the same posture the envelope takes toward a value the write path could not have\n * produced: a credential which claims a shape it does not have is a fault worth failing on, never\n * one worth falling back from — falling back would put a JSON blob on the wire as a bearer token.\n */\nexport function parseProviderOAuth2Grant(plaintext: string): ProviderOAuth2Grant | undefined {\n if (!isProviderOAuth2GrantPlaintext(plaintext)) return undefined;\n const body = plaintext.slice(PROVIDER_OAUTH2_GRANT_PREFIX.length);\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n throw new Error(\n 'A stored provider credential announces itself as an OAuth2 grant and is not valid JSON. It was '\n + 'written by something other than the authorization exchange; reconnect the account.',\n );\n }\n const result = ProviderOAuth2GrantSchema.safeParse(parsed);\n if (!result.success) {\n throw new Error(\n 'A stored provider credential announces itself as an OAuth2 grant but does not match the grant '\n + 'shape. Reconnect the account rather than editing the row — the value on the wire would '\n + 'otherwise be a fragment of a token.',\n );\n }\n return result.data;\n}\n\n/**\n * Whether a grant should be refreshed BEFORE it is spent.\n *\n * The skew is what makes this useful rather than decorative: a token that expires in two seconds is\n * still \"valid\" and will have expired by the time the request reaches the vendor, so refreshing only\n * on expiry guarantees a population of calls that fail for a reason nothing recorded. Sixty seconds\n * is the industry's common floor and comfortably exceeds any plausible clock skew plus flight time.\n *\n * Returns false when there is no expiry — a non-expiring token is refreshed reactively, after the\n * vendor rejects it, because there is no deadline to act ahead of.\n */\nexport const PROVIDER_OAUTH2_REFRESH_SKEW_SECONDS = 60;\n\nexport function providerOAuth2GrantNeedsRefresh(grant: ProviderOAuth2Grant, now: Date = new Date()): boolean {\n if (grant.expiresAt === undefined) return false;\n const expiry = Date.parse(grant.expiresAt);\n if (Number.isNaN(expiry)) return true;\n return expiry - now.getTime() <= PROVIDER_OAUTH2_REFRESH_SKEW_SECONDS * 1000;\n}\n"]}