@wildo-ai/saas-backend-lib 1.1.12 → 1.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/dist/esm/base-classes/models/manual-controllers.backend.definition.d.ts.map +1 -1
  2. package/dist/esm/base-classes/models/manual-controllers.backend.definition.js +2 -0
  3. package/dist/esm/base-classes/models/manual-controllers.backend.definition.js.map +1 -1
  4. package/dist/esm/base-classes/services/repositories/stored-field-omission.backend.d.ts +4 -0
  5. package/dist/esm/base-classes/services/repositories/stored-field-omission.backend.d.ts.map +1 -1
  6. package/dist/esm/base-classes/services/repositories/stored-field-omission.backend.js +20 -5
  7. package/dist/esm/base-classes/services/repositories/stored-field-omission.backend.js.map +1 -1
  8. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.d.ts +3 -0
  9. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.d.ts.map +1 -1
  10. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.js +10 -1
  11. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.js.map +1 -1
  12. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.d.ts +22 -0
  13. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.d.ts.map +1 -1
  14. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.js +25 -1
  15. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.js.map +1 -1
  16. package/dist/esm/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.d.ts +38 -3
  17. package/dist/esm/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.d.ts.map +1 -1
  18. package/dist/esm/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.js +68 -5
  19. package/dist/esm/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.js.map +1 -1
  20. package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.d.ts +2 -2
  21. package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.d.ts.map +1 -1
  22. package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.js +6 -3
  23. package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.js.map +1 -1
  24. package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.d.ts +83 -0
  25. package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.d.ts.map +1 -1
  26. package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js +217 -14
  27. package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js.map +1 -1
  28. package/dist/esm/compliance/approval-seals/approval-seal-currency.backend.d.ts +32 -0
  29. package/dist/esm/compliance/approval-seals/approval-seal-currency.backend.d.ts.map +1 -0
  30. package/dist/esm/compliance/approval-seals/approval-seal-currency.backend.js +36 -0
  31. package/dist/esm/compliance/approval-seals/approval-seal-currency.backend.js.map +1 -0
  32. package/dist/esm/compliance/approval-seals/approval-seal-on-record.backend.d.ts +38 -0
  33. package/dist/esm/compliance/approval-seals/approval-seal-on-record.backend.d.ts.map +1 -0
  34. package/dist/esm/compliance/approval-seals/approval-seal-on-record.backend.js +83 -0
  35. package/dist/esm/compliance/approval-seals/approval-seal-on-record.backend.js.map +1 -0
  36. package/dist/esm/compliance/approval-seals/approval-seal-presentation-read.backend.d.ts +36 -0
  37. package/dist/esm/compliance/approval-seals/approval-seal-presentation-read.backend.d.ts.map +1 -0
  38. package/dist/esm/compliance/approval-seals/approval-seal-presentation-read.backend.js +51 -0
  39. package/dist/esm/compliance/approval-seals/approval-seal-presentation-read.backend.js.map +1 -0
  40. package/dist/esm/compliance/approval-seals/approval-seal-relay-store.backend.d.ts +46 -0
  41. package/dist/esm/compliance/approval-seals/approval-seal-relay-store.backend.d.ts.map +1 -1
  42. package/dist/esm/compliance/approval-seals/approval-seal-relay-store.backend.js +68 -0
  43. package/dist/esm/compliance/approval-seals/approval-seal-relay-store.backend.js.map +1 -1
  44. package/dist/esm/compliance/approval-seals/approval-seal-store.backend.d.ts +27 -0
  45. package/dist/esm/compliance/approval-seals/approval-seal-store.backend.d.ts.map +1 -1
  46. package/dist/esm/compliance/approval-seals/approval-seal-store.backend.js +42 -3
  47. package/dist/esm/compliance/approval-seals/approval-seal-store.backend.js.map +1 -1
  48. package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.contracts.d.ts +26 -1
  49. package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.contracts.d.ts.map +1 -1
  50. package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.contracts.js +10 -0
  51. package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.contracts.js.map +1 -1
  52. package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.controller.d.ts +10 -1
  53. package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.controller.d.ts.map +1 -1
  54. package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.controller.js +60 -28
  55. package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.controller.js.map +1 -1
  56. package/dist/esm/compliance/approval-seals/approval-seals-on-record.backend.controller.d.ts +90 -0
  57. package/dist/esm/compliance/approval-seals/approval-seals-on-record.backend.controller.d.ts.map +1 -0
  58. package/dist/esm/compliance/approval-seals/approval-seals-on-record.backend.controller.js +373 -0
  59. package/dist/esm/compliance/approval-seals/approval-seals-on-record.backend.controller.js.map +1 -0
  60. package/dist/esm/compliance/approval-seals/decision-presentation.backend.d.ts +29 -2
  61. package/dist/esm/compliance/approval-seals/decision-presentation.backend.d.ts.map +1 -1
  62. package/dist/esm/compliance/approval-seals/decision-presentation.backend.js +40 -3
  63. package/dist/esm/compliance/approval-seals/decision-presentation.backend.js.map +1 -1
  64. package/dist/esm/compliance/electronic-signatures/pdf-signature-structure.backend.d.ts.map +1 -1
  65. package/dist/esm/compliance/electronic-signatures/pdf-signature-structure.backend.js +34 -6
  66. package/dist/esm/compliance/electronic-signatures/pdf-signature-structure.backend.js.map +1 -1
  67. package/dist/esm/compliance/electronic-signatures/signature-request-evidence-files.backend.d.ts +30 -6
  68. package/dist/esm/compliance/electronic-signatures/signature-request-evidence-files.backend.d.ts.map +1 -1
  69. package/dist/esm/compliance/electronic-signatures/signature-request-evidence-files.backend.js +67 -22
  70. package/dist/esm/compliance/electronic-signatures/signature-request-evidence-files.backend.js.map +1 -1
  71. package/dist/esm/compliance/electronic-signatures/signature-request-poll.batch.backend.service.d.ts.map +1 -1
  72. package/dist/esm/compliance/electronic-signatures/signature-request-poll.batch.backend.service.js +18 -1
  73. package/dist/esm/compliance/electronic-signatures/signature-request-poll.batch.backend.service.js.map +1 -1
  74. package/dist/esm/compliance/electronic-signatures/signature-requests.backend.service.d.ts +66 -1
  75. package/dist/esm/compliance/electronic-signatures/signature-requests.backend.service.d.ts.map +1 -1
  76. package/dist/esm/compliance/electronic-signatures/signature-requests.backend.service.js +161 -14
  77. package/dist/esm/compliance/electronic-signatures/signature-requests.backend.service.js.map +1 -1
  78. package/dist/esm/compliance/electronic-signatures/signed-document-validation.backend.d.ts +47 -0
  79. package/dist/esm/compliance/electronic-signatures/signed-document-validation.backend.d.ts.map +1 -1
  80. package/dist/esm/compliance/electronic-signatures/signed-document-validation.backend.js.map +1 -1
  81. package/dist/esm/external-providers/services/content-safety.backend.service.d.ts +27 -2
  82. package/dist/esm/external-providers/services/content-safety.backend.service.d.ts.map +1 -1
  83. package/dist/esm/external-providers/services/content-safety.backend.service.js +46 -1
  84. package/dist/esm/external-providers/services/content-safety.backend.service.js.map +1 -1
  85. package/dist/esm/external-providers/services/embeddings.backend.service.d.ts.map +1 -1
  86. package/dist/esm/external-providers/services/embeddings.backend.service.js +2 -0
  87. package/dist/esm/external-providers/services/embeddings.backend.service.js.map +1 -1
  88. package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts +11 -0
  89. package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts.map +1 -1
  90. package/dist/esm/external-providers/services/external-providers-registry.backend.service.js +23 -0
  91. package/dist/esm/external-providers/services/external-providers-registry.backend.service.js.map +1 -1
  92. package/dist/esm/external-providers/services/provider-service-account-token.backend.d.ts +19 -1
  93. package/dist/esm/external-providers/services/provider-service-account-token.backend.d.ts.map +1 -1
  94. package/dist/esm/external-providers/services/provider-service-account-token.backend.js +41 -1
  95. package/dist/esm/external-providers/services/provider-service-account-token.backend.js.map +1 -1
  96. package/dist/esm/files/utils/file-parent-read-context.backend.d.ts +27 -2
  97. package/dist/esm/files/utils/file-parent-read-context.backend.d.ts.map +1 -1
  98. package/dist/esm/files/utils/file-parent-read-context.backend.js +23 -4
  99. package/dist/esm/files/utils/file-parent-read-context.backend.js.map +1 -1
  100. package/dist/esm/flows-actors/content-guardrails/classifier-availability.backend.utils.d.ts +26 -0
  101. package/dist/esm/flows-actors/content-guardrails/classifier-availability.backend.utils.d.ts.map +1 -1
  102. package/dist/esm/flows-actors/content-guardrails/classifier-availability.backend.utils.js +100 -8
  103. package/dist/esm/flows-actors/content-guardrails/classifier-availability.backend.utils.js.map +1 -1
  104. package/dist/esm/flows-actors/content-guardrails/record-owner-policy.backend.d.ts +3 -1
  105. package/dist/esm/flows-actors/content-guardrails/record-owner-policy.backend.d.ts.map +1 -1
  106. package/dist/esm/flows-actors/content-guardrails/record-owner-policy.backend.js +8 -2
  107. package/dist/esm/flows-actors/content-guardrails/record-owner-policy.backend.js.map +1 -1
  108. package/dist/esm/flows-actors/models/function-tools.backend.definitions.d.ts +43 -0
  109. package/dist/esm/flows-actors/models/function-tools.backend.definitions.d.ts.map +1 -1
  110. package/dist/esm/flows-actors/models/function-tools.backend.definitions.js +37 -0
  111. package/dist/esm/flows-actors/models/function-tools.backend.definitions.js.map +1 -1
  112. package/dist/esm/flows-actors/services/agent-work-decisions.backend.service.d.ts +7 -0
  113. package/dist/esm/flows-actors/services/agent-work-decisions.backend.service.d.ts.map +1 -1
  114. package/dist/esm/flows-actors/services/agent-work-decisions.backend.service.js +8 -3
  115. package/dist/esm/flows-actors/services/agent-work-decisions.backend.service.js.map +1 -1
  116. package/dist/esm/flows-actors/services/agents.backend.service.d.ts +31 -6
  117. package/dist/esm/flows-actors/services/agents.backend.service.d.ts.map +1 -1
  118. package/dist/esm/flows-actors/services/agents.backend.service.js +78 -30
  119. package/dist/esm/flows-actors/services/agents.backend.service.js.map +1 -1
  120. package/dist/esm/flows-actors/services/autonomous-agent-turn.backend.service.d.ts.map +1 -1
  121. package/dist/esm/flows-actors/services/autonomous-agent-turn.backend.service.js +4 -0
  122. package/dist/esm/flows-actors/services/autonomous-agent-turn.backend.service.js.map +1 -1
  123. package/dist/esm/flows-actors/services/conversational-execution.backend.service.d.ts +28 -2
  124. package/dist/esm/flows-actors/services/conversational-execution.backend.service.d.ts.map +1 -1
  125. package/dist/esm/flows-actors/services/conversational-execution.backend.service.js +132 -22
  126. package/dist/esm/flows-actors/services/conversational-execution.backend.service.js.map +1 -1
  127. package/dist/esm/flows-actors/services/flow-actor-executions.custom-impl.backend.service.d.ts.map +1 -1
  128. package/dist/esm/flows-actors/services/flow-actor-executions.custom-impl.backend.service.js +12 -8
  129. package/dist/esm/flows-actors/services/flow-actor-executions.custom-impl.backend.service.js.map +1 -1
  130. package/dist/esm/flows-actors/services/flows-actors-registry.service.d.ts +5 -0
  131. package/dist/esm/flows-actors/services/flows-actors-registry.service.d.ts.map +1 -1
  132. package/dist/esm/flows-actors/services/flows-actors-registry.service.js +18 -2
  133. package/dist/esm/flows-actors/services/flows-actors-registry.service.js.map +1 -1
  134. package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.d.ts +33 -0
  135. package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.d.ts.map +1 -1
  136. package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.js +58 -0
  137. package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.js.map +1 -1
  138. package/dist/esm/inbound/services/inbound-delivery-dispatch.backend.service.d.ts +12 -1
  139. package/dist/esm/inbound/services/inbound-delivery-dispatch.backend.service.d.ts.map +1 -1
  140. package/dist/esm/inbound/services/inbound-delivery-dispatch.backend.service.js +23 -4
  141. package/dist/esm/inbound/services/inbound-delivery-dispatch.backend.service.js.map +1 -1
  142. package/dist/esm/inbound/services/inbound-delivery-receiver.backend.service.d.ts +12 -1
  143. package/dist/esm/inbound/services/inbound-delivery-receiver.backend.service.d.ts.map +1 -1
  144. package/dist/esm/inbound/services/inbound-delivery-receiver.backend.service.js +55 -17
  145. package/dist/esm/inbound/services/inbound-delivery-receiver.backend.service.js.map +1 -1
  146. package/dist/esm/inbound/services/inbound-delivery-store.backend.service.d.ts +22 -1
  147. package/dist/esm/inbound/services/inbound-delivery-store.backend.service.d.ts.map +1 -1
  148. package/dist/esm/inbound/services/inbound-delivery-store.backend.service.js +52 -9
  149. package/dist/esm/inbound/services/inbound-delivery-store.backend.service.js.map +1 -1
  150. package/dist/esm/inbound/services/inbound-delivery-stored-body.backend.service.d.ts +79 -0
  151. package/dist/esm/inbound/services/inbound-delivery-stored-body.backend.service.d.ts.map +1 -0
  152. package/dist/esm/inbound/services/inbound-delivery-stored-body.backend.service.js +211 -0
  153. package/dist/esm/inbound/services/inbound-delivery-stored-body.backend.service.js.map +1 -0
  154. package/dist/esm/inbound/services/inbound-delivery-subject-erasure-severance.backend.d.ts +2 -2
  155. package/dist/esm/inbound/services/inbound-delivery-subject-erasure-severance.backend.d.ts.map +1 -1
  156. package/dist/esm/inbound/services/inbound-delivery-subject-erasure-severance.backend.js +9 -1
  157. package/dist/esm/inbound/services/inbound-delivery-subject-erasure-severance.backend.js.map +1 -1
  158. package/dist/esm/index.d.ts +1 -0
  159. package/dist/esm/index.d.ts.map +1 -1
  160. package/dist/esm/index.js +1 -0
  161. package/dist/esm/index.js.map +1 -1
  162. package/dist/esm/inject/models/container.d.ts.map +1 -1
  163. package/dist/esm/inject/models/container.js +6 -0
  164. package/dist/esm/inject/models/container.js.map +1 -1
  165. package/dist/esm/inject/models/service-types.d.ts +5 -0
  166. package/dist/esm/inject/models/service-types.d.ts.map +1 -1
  167. package/dist/esm/inject/models/service-types.js +3 -0
  168. package/dist/esm/inject/models/service-types.js.map +1 -1
  169. package/dist/esm/monitoring/observability/models/observability.backend.schemas.d.ts +5 -0
  170. package/dist/esm/monitoring/observability/models/observability.backend.schemas.d.ts.map +1 -1
  171. package/dist/esm/monitoring/observability/models/observability.backend.schemas.js.map +1 -1
  172. package/dist/esm/monitoring/observability/services/metrics.service.d.ts +34 -1
  173. package/dist/esm/monitoring/observability/services/metrics.service.d.ts.map +1 -1
  174. package/dist/esm/monitoring/observability/services/metrics.service.js +49 -0
  175. package/dist/esm/monitoring/observability/services/metrics.service.js.map +1 -1
  176. package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.d.ts +6 -1
  177. package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.d.ts.map +1 -1
  178. package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.js +15 -4
  179. package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.js.map +1 -1
  180. package/dist/esm/notifications/webhooks/outbound/services/m2m-webhook-delivery-log.custom-impl.backend.service.d.ts.map +1 -1
  181. package/dist/esm/notifications/webhooks/outbound/services/m2m-webhook-delivery-log.custom-impl.backend.service.js +3 -1
  182. package/dist/esm/notifications/webhooks/outbound/services/m2m-webhook-delivery-log.custom-impl.backend.service.js.map +1 -1
  183. package/dist/esm/runtime/services/http-server.backend.service.d.ts +3 -1
  184. package/dist/esm/runtime/services/http-server.backend.service.d.ts.map +1 -1
  185. package/dist/esm/runtime/services/http-server.backend.service.js +11 -3
  186. package/dist/esm/runtime/services/http-server.backend.service.js.map +1 -1
  187. package/dist/esm/runtime/services/utils/inbound-endpoint-raw-body.backend.utils.d.ts +22 -0
  188. package/dist/esm/runtime/services/utils/inbound-endpoint-raw-body.backend.utils.d.ts.map +1 -1
  189. package/dist/esm/runtime/services/utils/inbound-endpoint-raw-body.backend.utils.js +54 -0
  190. package/dist/esm/runtime/services/utils/inbound-endpoint-raw-body.backend.utils.js.map +1 -1
  191. package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.d.ts +51 -0
  192. package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.d.ts.map +1 -1
  193. package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.js +87 -15
  194. package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.js.map +1 -1
  195. package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.d.ts.map +1 -1
  196. package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.js +5 -2
  197. package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.js.map +1 -1
  198. package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.d.ts.map +1 -1
  199. package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.js +65 -24
  200. package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.js.map +1 -1
  201. package/dist/esm/security/authorizations/super-admin-floor.backend.utils.d.ts +64 -1
  202. package/dist/esm/security/authorizations/super-admin-floor.backend.utils.d.ts.map +1 -1
  203. package/dist/esm/security/authorizations/super-admin-floor.backend.utils.js +84 -2
  204. package/dist/esm/security/authorizations/super-admin-floor.backend.utils.js.map +1 -1
  205. package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.d.ts +14 -0
  206. package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.d.ts.map +1 -1
  207. package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.js +13 -5
  208. package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.js.map +1 -1
  209. package/dist/esm/users/services/anonymous-consent.custom-impl.backend.service.d.ts.map +1 -1
  210. package/dist/esm/users/services/anonymous-consent.custom-impl.backend.service.js +6 -2
  211. package/dist/esm/users/services/anonymous-consent.custom-impl.backend.service.js.map +1 -1
  212. package/dist/esm/users/services/user-force-password-reset.custom-impl.backend.service.d.ts +7 -0
  213. package/dist/esm/users/services/user-force-password-reset.custom-impl.backend.service.d.ts.map +1 -1
  214. package/dist/esm/users/services/user-force-password-reset.custom-impl.backend.service.js +65 -20
  215. package/dist/esm/users/services/user-force-password-reset.custom-impl.backend.service.js.map +1 -1
  216. package/dist/esm/users/services/user-role-administration.custom-impl.backend.service.d.ts.map +1 -1
  217. package/dist/esm/users/services/user-role-administration.custom-impl.backend.service.js +11 -4
  218. package/dist/esm/users/services/user-role-administration.custom-impl.backend.service.js.map +1 -1
  219. package/dist/esm/users/services/user-self-custom-implementations.backend.d.ts.map +1 -1
  220. package/dist/esm/users/services/user-self-custom-implementations.backend.js +4 -2
  221. package/dist/esm/users/services/user-self-custom-implementations.backend.js.map +1 -1
  222. package/dist/esm/users/services/user-super-admin-floor.custom-impl.backend.service.d.ts.map +1 -1
  223. package/dist/esm/users/services/user-super-admin-floor.custom-impl.backend.service.js +16 -0
  224. package/dist/esm/users/services/user-super-admin-floor.custom-impl.backend.service.js.map +1 -1
  225. package/dist/tsconfig.build.tsbuildinfo +1 -1
  226. package/package.json +10 -10
@@ -1,4 +1,8 @@
1
- import { CoreResourceOperation, CoreResourceType, isApiCallOperation, ResourceOperation_CustomServiceImplementationMode, ResourceOperationVariantType, ResourcesConfig_OperationPathUtils, } from '@wildo-ai/saas-models';
1
+ import { BULK_OPERATION_DEFAULT_MAX_SELECTION, CoreResourceOperation, CoreResourceType, isApiCallOperation, ResourceOperation_CustomServiceImplementationMode, ResourceOperationVariantType, ResourcesConfig_OperationPathUtils, } from '@wildo-ai/saas-models';
2
+ // entrypoint-closure-waiver: `resource-operation-audit-emission.backend.utils` is published only by `./assurance-derivations`
3
+ // and was ALREADY in the root closure (`services-registry-handler.backend.service`, root-exported, imports it), so this
4
+ // edge adds no reachability. Only `.shouldEmit` is read, inside `classifyPlainAuditedWriteDurability`; no exported
5
+ // declaration of this file names a type from that module, so a root-only consumer has nothing to name (#2297).
2
6
  import { resolveResourceOperationAuditDecision } from './resource-operation-audit-emission.backend.utils.js';
3
7
  import { ResourcePersistenceParticipantCoupling } from '../../../databases/services/resource-persistence-unit-of-work.backend.service.js';
4
8
  import { BackendResourceType } from '../../../resources/models/resources-types.backend.schemas.js';
@@ -115,6 +119,12 @@ export var PlainAuditedWriteDurability;
115
119
  * A write with custom implementations is included when EVERY registration declares its hooks
116
120
  * `RUNS_INSIDE_TRANSACTION` (wave 3): each was read, and does nothing outside the database before the commit
117
121
  * (`ResourceCustomServiceImplementationHookTransactionPosture`).
122
+ *
123
+ * A multi-row UPDATE_MANY / DELETE_MANY is included once its rows per transaction are BOUNDED by
124
+ * {@link MULTI_ROW_WRITE_ROWS_PER_TRANSACTION} (wave 4): the framework performs a hook-less core one in chunks of at most
125
+ * that many rows, each chunk its own transactional attempt with its own audit row
126
+ * ({@link isFrameworkChunkedMultiRowWrite}); a registration that performs the write itself is included when it declares
127
+ * how many rows one attempt writes (`maximumRowsWrittenPerAttempt`), within the same bound.
118
128
  */
119
129
  PlainAuditedWriteDurability["TRANSACTION_FOR_AUDIT_ROW"] = "transaction_for_audit_row";
120
130
  /**
@@ -137,9 +147,12 @@ export var PlainAuditedWriteDurability;
137
147
  */
138
148
  PlainAuditedWriteDurability["BEST_EFFORT_OVERRIDE_ALL"] = "best_effort_override_all";
139
149
  /**
140
- * A multi-row write (`CREATE_MANY`, `UPDATE_MANY`, `DELETE_MANY`) that is not a bounded synchronous bulk operation
141
- * (those are already transactional). Its selection has no ceiling, so one transaction could hold an unbounded number
142
- * of rows and outlive the store's transaction limits (MongoDB aborts a transaction after 60 seconds by default).
150
+ * A multi-row write (`CREATE_MANY`, `UPDATE_MANY`, `DELETE_MANY`) whose rows per transaction nothing bounds: not a
151
+ * synchronous bulk operation (bounded by its request, and already transactional), not a hook-less core UPDATE_MANY /
152
+ * DELETE_MANY the framework chunks, and not a registration that declares how many rows it writes. One transaction could
153
+ * hold an unbounded number of rows and outlive the store's transaction limits (MongoDB aborts a transaction after 60
154
+ * seconds by default). Since wave 4 its members are the writes whose selection a HOOK decides (a purge selecting its own
155
+ * population), which a framework bound cannot reach, and `CREATE_MANY`.
143
156
  */
144
157
  PlainAuditedWriteDurability["BEST_EFFORT_UNBOUNDED_MULTI_ROW"] = "best_effort_unbounded_multi_row";
145
158
  /**
@@ -189,14 +202,64 @@ export function classifyPlainAuditedWriteDurability(operation, registrations) {
189
202
  // Wave 2: a single-row DELETE, cascade included (see TRANSACTION_FOR_AUDIT_ROW for why its cascade stays in the database).
190
203
  case CoreResourceOperation.DELETE:
191
204
  return PlainAuditedWriteDurability.TRANSACTION_FOR_AUDIT_ROW;
192
- case CoreResourceOperation.CREATE_MANY:
205
+ // Wave 4: a multi-row write joins once its rows per transaction are bounded (see MULTI_ROW_WRITE_ROWS_PER_TRANSACTION).
193
206
  case CoreResourceOperation.UPDATE_MANY:
194
207
  case CoreResourceOperation.DELETE_MANY:
208
+ return multiRowWriteIsBoundedPerTransaction(operation, registrations)
209
+ ? PlainAuditedWriteDurability.TRANSACTION_FOR_AUDIT_ROW
210
+ : PlainAuditedWriteDurability.BEST_EFFORT_UNBOUNDED_MULTI_ROW;
211
+ case CoreResourceOperation.CREATE_MANY:
195
212
  return PlainAuditedWriteDurability.BEST_EFFORT_UNBOUNDED_MULTI_ROW;
196
213
  default:
197
214
  return PlainAuditedWriteDurability.BEST_EFFORT_NOT_YET_REVIEWED;
198
215
  }
199
216
  }
217
+ /**
218
+ * The most rows one transactional attempt of a multi-row write may hold (#2297 wave 4): 100, the bound a synchronous bulk
219
+ * operation already enforces on its request (`BULK_OPERATION_DEFAULT_MAX_SELECTION`), and so the one bound the framework
220
+ * already holds a synchronous multi-row transaction to. Decided by this repository's own principle (one bound for one
221
+ * concern) rather than by a new number:
222
+ * - MongoDB aborts a transaction that runs a minute; spec-cite: MongoDB Manual, "Production Considerations", Runtime Limit
223
+ * (https://www.mongodb.com/docs/manual/core/transactions-production-consideration/, quoted: "By default, a transaction
224
+ * must have a runtime of less than one minute."). Removing 10,000 rows' targets was measured at 19 s (MongoDB) and 37 s
225
+ * (PostgreSQL) in one transaction (#2864), so 100 rows is two orders of magnitude inside the limit.
226
+ * - it is NOT what makes a bulk write's guards complete, and must not be read as such: the RESTRICT and legal-hold refusals
227
+ * and the pre-hook snapshots read EVERY target (`loadBulkTargetResources`, a listing with no paging options, which both
228
+ * adapters answer whole), whatever the chunk size, including a nested write the chunking never splits (#3698).
229
+ * Above it, the write is performed in CHUNKS, each its own transaction and its own audit row naming its rows, which is how
230
+ * the framework's own sweeps already delete (`resource-retention-sweep`, `retention-class-sweep`); rejected: refusing a
231
+ * selection above the bound, which would break every internal caller that removes a population (a transposition, a
232
+ * cascade of a large tenant) for a limit that only exists to keep one transaction short.
233
+ */
234
+ export const MULTI_ROW_WRITE_ROWS_PER_TRANSACTION = BULK_OPERATION_DEFAULT_MAX_SELECTION;
235
+ /**
236
+ * Whether the FRAMEWORK performs this multi-row write itself and can therefore chunk it (#2297 wave 4): the core
237
+ * `UPDATE_MANY` / `DELETE_MANY` operation itself (not a custom verb borrowing it), answering the core response (no
238
+ * `customResponseDto`, so chunk answers merge: rows concatenate, deleted ids concatenate and their counts add), with no
239
+ * custom registration (nothing but the framework reads the selection it rewrites per chunk), and not a synchronous bulk
240
+ * operation (bounded by its request already). `ServiceResourceBackendService.doOperation` chunks exactly these.
241
+ */
242
+ export function isFrameworkChunkedMultiRowWrite(operation, registrations) {
243
+ const identifier = operation.operationIdentifier;
244
+ if (identifier !== CoreResourceOperation.UPDATE_MANY && identifier !== CoreResourceOperation.DELETE_MANY)
245
+ return false;
246
+ if (operation.hasCustomResponseDto === true)
247
+ return false;
248
+ if (operation.isBulkOperation === true)
249
+ return false;
250
+ return registrations.length === 0;
251
+ }
252
+ /**
253
+ * Whether one transactional attempt of this multi-row write holds at most {@link MULTI_ROW_WRITE_ROWS_PER_TRANSACTION} rows:
254
+ * the framework chunks it ({@link isFrameworkChunkedMultiRowWrite}), or a registration that REPLACES the core write declares
255
+ * how many rows one attempt writes (`maximumRowsWrittenPerAttempt`, refused at registration above the bound).
256
+ */
257
+ function multiRowWriteIsBoundedPerTransaction(operation, registrations) {
258
+ if (isFrameworkChunkedMultiRowWrite(operation, registrations))
259
+ return true;
260
+ return registrations.some((registration) => registration.maximumRowsWrittenPerAttempt !== undefined
261
+ && registration.implementation.getPlaceholders().includes(ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS));
262
+ }
200
263
  /**
201
264
  * Whether a registration's hooks may run in the transaction kept for the audit row (#2297 wave 3): it declares so, or it is
202
265
  * `transactionalCore` (its hooks run in a transaction already).
@@ -1 +1 @@
1
- {"version":3,"file":"resource-operation-transaction-persistence.backend.utils.js","sourceRoot":"","sources":["../../../../../src/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n CoreResourceOperation,\n CoreResourceType,\n isApiCallOperation,\n PersistenceAdapter,\n ResourceOperation_CustomServiceImplementationMode,\n ResourceOperationVariantType,\n ResourcesConfig_OperationPathUtils,\n type TokenGenerationConfig,\n type ResourceConfiguration_Operation,\n} from '@wildo-ai/saas-models';\n\nimport type {\n ResourcePersistenceUnitOfWorkBackendService,\n ResourcePersistenceUnitOfWorkRequest,\n} from '~wildo-backend-lib/databases/services/resource-persistence-unit-of-work.backend.service';\nimport { resolveResourceOperationAuditDecision } from './resource-operation-audit-emission.backend.utils';\nimport { ResourcePersistenceParticipantCoupling } from '~wildo-backend-lib/databases/services/resource-persistence-unit-of-work.backend.service';\nimport { BackendResourceType } from '~wildo-backend-lib/resources/models/resources-types.backend.schemas';\nimport { isReadShapedOperation } from '@wildo-ai/saas-models';\nimport { externalDataOutboundChangeOwed } from '~wildo-backend-lib/external-data/external-data-outbound-change-recording.backend';\nimport type { ExternalDataPipelineDeclaration } from '@wildo-ai/saas-models/external-data';\nimport type { z } from 'zod';\nimport { createAllocatedDocumentSequenceFieldsOf } from '~wildo-backend-lib/document-sequences/services/document-sequence-allocation.backend';\nimport type {\n ResourceOperationCustomImplementationRegistration,\n} from './resource-operation-custom-implementation-registry.backend.service';\nimport { commitOutcomeResolverReadsCommitReceipt } from './resource-operation-commit-receipt.backend.utils';\nimport { ResourceCustomServiceImplementationHookTransactionPosture } from './resource-operation-custom-implementation.factory.backend';\n\n/**\n * How the FILES resource participates in one resource write.\n *\n * File work is not one thing, and collapsing it into one was what forced the\n * service layer to answer the question with hardcoded adapter comparisons: a write\n * may carry file metadata, or a generated document that must be committed with the\n * row. Both commit with the row since #3328 (one transactional store per application).\n */\nexport enum ResourceWriteFileParticipation {\n /** The resource declares no file fields. FILES is not part of the boundary. */\n NONE = 'NONE',\n /**\n * File METADATA is written alongside the row, in the row's transaction.\n *\n * ATOMIC, like a generated document, since #3328: an application uses one\n * transactional store, so FILES always shares the row's, and the service layer\n * no longer has a separately-committed path to fall back to. It used to be\n * COMPENSATABLE (a resource on another adapter wrote its file metadata in FILES'\n * own transaction, once, after or beside the row). Kept distinct from\n * {@link ATOMIC_MATERIALIZATION} because the two are different facts about the\n * write, even though both now commit with the row.\n */\n METADATA = 'METADATA',\n /**\n * A generated document (a PDF materialization) must land in the SAME commit as\n * the row that references it.\n *\n * Not splittable: a row committed pointing at a document whose metadata never\n * committed is a dangling reference, so a cross-adapter boundary here must be\n * refused rather than degraded.\n */\n ATOMIC_MATERIALIZATION = 'ATOMIC_MATERIALIZATION',\n}\n\n/**\n * Declare the persistence boundary of one resource WRITE.\n *\n * This is the declaration the service layer never had. `executeResourceTransaction`\n * opens a transaction on the writing resource's adapter and then performs nested\n * and file work inside it, but nothing described WHO was in that boundary — so\n * every site that needed to know whether file work could join the transaction\n * asked `adapter === MONGODB` instead, which is correct only for as long as FILES\n * stays on MongoDB. Declaring the participants moves that question to the single\n * authority that already owns it.\n *\n * Everything here is derivable from the resource registry alone (file-field\n * presence and generated-PDF fields are schema-derived), so the same declaration\n * is available to startup validation as it is at runtime.\n */\nexport function createResourceWritePersistenceRequest(options: {\n readonly resourceType: string;\n readonly fileParticipation: ResourceWriteFileParticipation;\n readonly nestedResourceTypes?: readonly string[];\n}): ResourcePersistenceUnitOfWorkRequest {\n const participants: Record<string, ResourcePersistenceUnitOfWorkRequest['participants'][string]> = {\n // Shorthand: the writing resource is ATOMIC by definition — it IS the boundary.\n operationResource: options.resourceType,\n };\n\n (options.nestedResourceTypes ?? []).forEach((nestedResourceType, nestedIndex) => {\n // Nested mutations commit with the parent or not at all; a nested row that\n // survived a rolled-back parent is an orphan.\n participants[`nested[${nestedIndex}](${nestedResourceType})`] = nestedResourceType;\n });\n\n if (options.fileParticipation !== ResourceWriteFileParticipation.NONE) {\n // Both kinds commit with the row (#3328): there is no store FILES could sit on apart from the row's.\n participants.fileMetadata = {\n resourceType: CoreResourceType.FILES,\n coupling: ResourcePersistenceParticipantCoupling.ATOMIC,\n };\n }\n\n return Object.freeze({\n boundary: `resource-write:${options.resourceType}`,\n participants: Object.freeze(participants),\n });\n}\n\n/**\n * Canonical transaction contract for one resource-operation pipeline.\n *\n * Startup validation and runtime execution must both consume this resolver.\n * Otherwise an authored participant can be checked under one adapter set at\n * boot and executed under a broader, incompatible set on the first request.\n */\nexport interface ResourceOperationTransactionPersistenceContract {\n readonly request?: ResourcePersistenceUnitOfWorkRequest;\n readonly transactionRequired: boolean;\n readonly tokenGeneration: TokenGenerationConfig | undefined;\n readonly transactionalRegistrationLabels: readonly string[];\n readonly overrideAllRegistrationLabels: readonly string[];\n /**\n * Whether each root-owned attempt writes a commit receipt (#2870): set when a transactional registration's\n * commit-outcome resolver reads one ({@link commitOutcomeResolverReadsCommitReceipt}). The receipts resource is then a\n * participant of the transaction, so startup proves it shares the operation's adapter and the receipt commits with the\n * attempt's writes. Absent on a contract that needs no transaction.\n */\n readonly writesCommitReceipt?: boolean;\n /**\n * Whether an attempt of this operation can be CAPTURED (#2886): a transactional registration declares the post-commit\n * effect outbox as a participant ({@link POST_COMMIT_EFFECT_CAPTURE_PARTICIPANTS}), so startup proves the outbox shares the\n * operation's adapter and its rows commit with the attempt. A caller's `postCommitEffectCaptureRequested` is refused on a\n * contract without it. Absent on a contract that needs no transaction.\n */\n readonly capturesPostCommitEffects?: boolean;\n /**\n * Whether the ONLY reason this operation is transactional is its audit row (#2297): a plain audited write\n * ({@link PlainAuditedWriteDurability.TRANSACTION_FOR_AUDIT_ROW}) in a process where its attempt can be captured. The\n * transaction exists so the automatic capture can keep the row in the post-commit effect outbox. Absent otherwise.\n */\n readonly transactionForAuditRow?: boolean;\n}\n\n/**\n * What a PLAIN audited write does to keep its `RESOURCE_OPERATION_PERFORMED` row through a crash (#2297).\n *\n * A transactional operation keeps the row: its attempt is captured automatically and the outbox relay writes a leftover\n * row once. A write that no other rule makes transactional used to stay best effort, because the row is written after\n * the commit and a process that dies in between loses it. Each member below is one answer, per operation, to \"may the\n * framework open a transaction around this write so the row is kept?\". The answer is decided from the operation and its\n * custom registrations alone, so startup and runtime cannot disagree about it.\n *\n * Only {@link TRANSACTION_FOR_AUDIT_ROW} changes behaviour. Every other member is a reason the write stays best effort,\n * named so the boot coverage, a test failure and the tracker can say WHY rather than only that it does. The best-effort\n * members are reviewed in waves (#2297), so a member may move to the durable side once its reason is answered.\n */\nexport enum PlainAuditedWriteDurability {\n /**\n * A single-row CREATE, UPDATE or DELETE (including a custom operation that behaves as one), reached through the framework\n * pipeline (`API_CALL`, `INTERNAL_CALL`), with NO custom implementation registered. A write judged by an\n * `enabledCondition` is included: inside the transaction its row is re-read and the condition judged again, and a lost\n * race still answers the CONFLICT #2543 pins (a refusal on a row that no longer holds what the request was admitted on\n * is classified as that race). For a hook-less write nothing but the\n * framework's own core runs inside the transaction, and that core already runs inside one for every transactional\n * operation, so the transaction adds no new kind of work to it; no hook can call a provider, which refuses to run inside\n * a transaction (`assertOutsideTransaction`). The framework makes the write transactional when its attempt can be captured.\n *\n * A DELETE's cascade stays inside the database, which is what lets it in (wave 2, reviewed 2026-11-10): the service's\n * single-row delete already ran its repository write, its `onParentDelete` cascade and its file handling inside a\n * transaction of its own (`executeResourceTransaction`), which the transactional core's now replaces. Children are\n * deleted (or scrubbed) through their RAW repositories, so no child hook runs; a deferred (LAZY) edge's job is collected\n * and published by the cascade's entry inside that transaction (#2634); a linked file is soft-deleted or unlinked, and\n * its stored object is removed later by the files cleanup batch (`hardDeleteFile`), never inline, so no object-storage\n * call is made inside the transaction; the RAG chunk removal is a post-commit effect. A cascade child on a read-through\n * (HTTP_API) resource refuses inside any transaction, which is why such a cascade is refused already, before this.\n *\n * A write with custom implementations is included when EVERY registration declares its hooks\n * `RUNS_INSIDE_TRANSACTION` (wave 3): each was read, and does nothing outside the database before the commit\n * (`ResourceCustomServiceImplementationHookTransactionPosture`).\n */\n TRANSACTION_FOR_AUDIT_ROW = 'transaction_for_audit_row',\n /**\n * A custom implementation (PREFIX, BETWEEN, POSTFIX, …) is registered and has not declared whether its hooks may run\n * inside a transaction (`hookTransactionPosture`). Making the write transactional would run them there, and nothing\n * says whether a hook calls a provider, so it stays best effort until the registration is reviewed.\n */\n BEST_EFFORT_CUSTOM_IMPLEMENTATION = 'best_effort_custom_implementation',\n /**\n * A registration was reviewed and declares `STAYS_OUTSIDE_TRANSACTION`: a hook's answer depends on an effect outside the\n * database (a provider call, an audit row that must exist before the operation answers, a queue publish that decides\n * what is written), so the hooks must not run in a transaction and the row stays best effort. The reason is written at\n * the declaration.\n */\n BEST_EFFORT_HOOK_OUTSIDE_TRANSACTION = 'best_effort_hook_outside_transaction',\n /**\n * An `OVERRIDE_ALL` implementation owns the write. That mode replaces the framework's pipeline and returns before its\n * transaction (startup refuses a transaction-requiring operation that uses it), so the framework can never open one\n * here. Permanently best effort at the top level; durable only when nested in a captured caller's transaction.\n */\n BEST_EFFORT_OVERRIDE_ALL = 'best_effort_override_all',\n /**\n * A multi-row write (`CREATE_MANY`, `UPDATE_MANY`, `DELETE_MANY`) that is not a bounded synchronous bulk operation\n * (those are already transactional). Its selection has no ceiling, so one transaction could hold an unbounded number\n * of rows and outlive the store's transaction limits (MongoDB aborts a transaction after 60 seconds by default).\n */\n BEST_EFFORT_UNBOUNDED_MULTI_ROW = 'best_effort_unbounded_multi_row',\n /**\n * Another verb, or a scheduled variant (`CRON_JOB`, `BATCH_JOB`), that no wave has reviewed yet.\n */\n BEST_EFFORT_NOT_YET_REVIEWED = 'best_effort_not_yet_reviewed',\n /**\n * `REPOSITORY_ONLY`: the framework pipeline refuses this variant, so no operation-level audit row is written through it\n * at all, and there is no attempt to make transactional.\n */\n NOT_REACHED_THROUGH_PIPELINE = 'not_reached_through_pipeline',\n}\n\n/**\n * Classify one write the framework audits by its declaration alone (the risk floor, or\n * `auditableEvent.auditBelowRiskFloor`) into {@link PlainAuditedWriteDurability} (#2297). Answers `undefined` for an\n * operation that owes no row by declaration (read-shaped, or below the floor with no opt-in): a row that only runtime\n * evidence calls for (a decided agent write, a representative's write) is not known before the write starts, so it stays\n * best effort.\n *\n * It does not say whether the write is transactional for another reason (a token, a bulk selection, a transactional\n * registration): {@link resolveResourceOperationTransactionPersistenceContract} asks this only of a write nothing else\n * makes transactional.\n */\nexport function classifyPlainAuditedWriteDurability(\n operation: ResourceConfiguration_Operation<any, any, any>,\n registrations: readonly ResourceOperationCustomImplementationRegistration[],\n): PlainAuditedWriteDurability | undefined {\n if (!resolveResourceOperationAuditDecision(operation).shouldEmit) return undefined;\n const variantType = (operation as { variantType?: ResourceOperationVariantType }).variantType;\n if (variantType === ResourceOperationVariantType.REPOSITORY_ONLY) return PlainAuditedWriteDurability.NOT_REACHED_THROUGH_PIPELINE;\n if (registrations.some((registration) => registration.implementation.getPlaceholders().includes(ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL))) {\n return PlainAuditedWriteDurability.BEST_EFFORT_OVERRIDE_ALL;\n }\n // Wave 3: a registration's hooks run in the transaction only when it says they may; one that must not decides for the write.\n if (registrations.some((registration) => registration.hookTransactionPosture === ResourceCustomServiceImplementationHookTransactionPosture.STAYS_OUTSIDE_TRANSACTION)) {\n return PlainAuditedWriteDurability.BEST_EFFORT_HOOK_OUTSIDE_TRANSACTION;\n }\n if (!registrations.every(hooksMayRunInsideTransaction)) return PlainAuditedWriteDurability.BEST_EFFORT_CUSTOM_IMPLEMENTATION;\n if (variantType !== ResourceOperationVariantType.API_CALL && variantType !== ResourceOperationVariantType.INTERNAL_CALL) {\n return PlainAuditedWriteDurability.BEST_EFFORT_NOT_YET_REVIEWED;\n }\n // The verb the write path performs: a custom operation borrows a core one (`resourceOperationLike`), a core operation is its verb.\n const operationLike = (operation as { resourceOperationLike?: unknown }).resourceOperationLike ?? operation.operationIdentifier;\n switch (operationLike) {\n case CoreResourceOperation.CREATE:\n case CoreResourceOperation.UPDATE:\n // Wave 2: a single-row DELETE, cascade included (see TRANSACTION_FOR_AUDIT_ROW for why its cascade stays in the database).\n case CoreResourceOperation.DELETE:\n return PlainAuditedWriteDurability.TRANSACTION_FOR_AUDIT_ROW;\n case CoreResourceOperation.CREATE_MANY:\n case CoreResourceOperation.UPDATE_MANY:\n case CoreResourceOperation.DELETE_MANY:\n return PlainAuditedWriteDurability.BEST_EFFORT_UNBOUNDED_MULTI_ROW;\n default:\n return PlainAuditedWriteDurability.BEST_EFFORT_NOT_YET_REVIEWED;\n }\n}\n\n/**\n * Whether a registration's hooks may run in the transaction kept for the audit row (#2297 wave 3): it declares so, or it is\n * `transactionalCore` (its hooks run in a transaction already).\n */\nfunction hooksMayRunInsideTransaction(registration: ResourceOperationCustomImplementationRegistration): boolean {\n return registration.transactionalCore\n || registration.hookTransactionPosture === ResourceCustomServiceImplementationHookTransactionPosture.RUNS_INSIDE_TRANSACTION;\n}\n\n/**\n * What the process can do for a resource's writes, asked by both callers of\n * {@link resolveResourceOperationTransactionPersistenceContract} (startup validation and `doOperation`) through the same\n * function so the two cannot disagree (#2297).\n */\nexport interface ResourceOperationTransactionPersistenceEnvironment {\n /**\n * Whether an attempt on this operation's resource could keep its audit row: the post-commit effect outbox is a\n * registered resource on the SAME native transactional adapter. Read only for a\n * {@link PlainAuditedWriteDurability.TRANSACTION_FOR_AUDIT_ROW} write, so a process without the outbox (a platform\n * service) or a resource on HTTP_API / INTROSPECTION never gets a transaction it could not use. Build it with\n * {@link auditRowCaptureAvailableThrough}.\n */\n readonly auditRowCaptureAvailable?: () => boolean;\n}\n\n/**\n * The one answer to {@link ResourceOperationTransactionPersistenceEnvironment.auditRowCaptureAvailable} (#2297): the unit\n * of work assesses a boundary made of the resource and the post-commit effect outbox, without opening anything. It is\n * compatible exactly when both resolve to one native adapter whose database service is present. A unit of work that is\n * missing or cannot answer gives `false`, so the write stays as it was.\n */\nexport function auditRowCaptureAvailableThrough(\n unitOfWork: Pick<ResourcePersistenceUnitOfWorkBackendService, 'assessCompatibility'> | undefined,\n resourceType: string,\n): boolean {\n if (typeof unitOfWork?.assessCompatibility !== 'function') return false;\n try {\n return unitOfWork.assessCompatibility({\n boundary: `audit-row-capture:${resourceType}`,\n participants: {\n operationResource: resourceType,\n postCommitEffectOutbox: BackendResourceType.POST_COMMIT_EFFECT_OUTBOX,\n },\n }).compatible === true;\n } catch {\n return false;\n }\n}\n\n/**\n * The participant a transactional registration declares when its operation's attempts may be captured (#2886): spread into\n * its `transactionParticipants`. Declared on the verbs the sweeps dispatch with `postCommitEffectCaptureRequested`; the\n * declaration, not the request, is what startup validates, so a verb is proved capturable before any sweep asks.\n */\nexport const POST_COMMIT_EFFECT_CAPTURE_PARTICIPANTS: Readonly<Record<string, string>> = Object.freeze({\n postCommitEffectOutbox: BackendResourceType.POST_COMMIT_EFFECT_OUTBOX,\n});\n\nfunction getOperationTokenGeneration(\n operation: ResourceConfiguration_Operation<any, any, any>,\n): TokenGenerationConfig | undefined {\n if (\n isApiCallOperation(operation)\n ) {\n return operation.tokenGeneration;\n }\n return undefined;\n}\n\n/**\n * Resolve every resource that participates in the framework-owned atomic core\n * phase. The operation resource is implicit; custom implementations declare\n * their additional resources by semantic role, and every framework-owned token\n * effect contributes the consumable-token participant automatically.\n *\n * Token authentication and revocation are transaction triggers in their own\n * right. Validation-before-mutation followed by consumption-after-mutation is\n * not an atomic use: concurrent requests could both mutate before one loses the\n * token compare-and-set, and a process loss could persist the mutation while\n * leaving the token reusable. Startup and runtime therefore assess the same\n * resource-plus-token boundary even when no custom implementation requested a\n * transaction.\n */\nexport function resolveResourceOperationTransactionPersistenceContract(\n operation: ResourceConfiguration_Operation<any, any, any>,\n registrations: readonly ResourceOperationCustomImplementationRegistration[],\n /**\n * The operation resource's own declarations, when the caller holds them (#1690). Only `externalDataPipeline` is read:\n * a write that creates or changes rows of an OUTBOUND pipeline's destination records a marker for its system of\n * record, and that marker must commit with the change — so the write is transactional, with the markers as a\n * participant. Optional so a caller that cannot name the resource keeps today's contract.\n */\n resourceDeclarations?: {\n readonly externalDataPipeline?: Pick<ExternalDataPipelineDeclaration, 'direction'>;\n /**\n * The resource's main schema (#2509): a create on a resource with a CREATE-allocated `.documentSequence(...)` field\n * takes its number from a counter that must commit with the row, so that create is transactional, with the\n * counters as a participant.\n */\n readonly mainSchema?: z.ZodTypeAny;\n },\n /** What the process can do for this resource's writes (#2297). Omitted, no write is made transactional for its audit row. */\n environment?: ResourceOperationTransactionPersistenceEnvironment,\n): ResourceOperationTransactionPersistenceContract {\n const transactionalRegistrations = registrations.filter(\n (registration) => registration.transactionalCore,\n );\n const tokenGeneration = getOperationTokenGeneration(operation);\n const transactionallyGeneratesTokens = tokenGeneration !== undefined;\n const transactionallyConsumesTokens =\n 'tokenAuthentication' in operation\n && operation.tokenAuthentication !== undefined;\n const transactionallyRevokesTokens =\n 'tokenRevocation' in operation\n && operation.tokenRevocation !== undefined;\n const tokenCoupled =\n transactionallyGeneratesTokens\n || transactionallyConsumesTokens\n || transactionallyRevokesTokens;\n /**\n * A BULK MUTATION is transactional, whatever else it declares.\n *\n * A synchronous batch is atomic — spec-cite: Google AIP-234, \"Batch update\"\n * (https://google.aip.dev/234, quoted: \"Synchronous batch update must be atomic.\") — and the\n * whole action lane's design rests on that split: the synchronous form is all-or-nothing, and the\n * asynchronous form is the one allowed to partially succeed, which is why it reports per item.\n *\n * It was never true here. Measured 2026-09-22: nothing in this resolver mentioned bulk, so an\n * ordinary `UPDATE_MANY` / `DELETE_MANY` ran with no transaction. On PostgreSQL it survived by\n * accident — one `UPDATE … WHERE _id IN (…)` statement is atomic because it is one statement —\n * while on MongoDB a multi-document `updateMany` with no session leaves a partial write when it\n * fails part-way. The guarantee therefore held on one adapter, by coincidence, and not on the\n * other: two adapters disagreeing about what a refused batch means.\n *\n * READ-shaped bulk operations are excluded because there is nothing to make atomic; the cost is\n * bounded by the batch maximum a synchronous bulk already enforces\n * (`BULK_OPERATION_DEFAULT_MAX_SELECTION`, 100 rows), which is a small transaction on either\n * engine. Above that ceiling the work belongs to the background lane, which runs row by row and\n * is deliberately NOT atomic — there, partial success is the contract.\n */\n // `isBulkOperation` lives on the URL-bearing variants; a cron operation has no such field, which\n // is why this reads it defensively rather than narrowing the union at every call.\n const bulkMutation = ('isBulkOperation' in operation && operation.isBulkOperation === true)\n && !isReadShapedOperation(operation)\n // …unless an OVERRIDE_ALL implementation owns the write. That mode replaces this entire\n // pipeline and returns before the framework's transaction, so demanding one would be a promise\n // the framework cannot keep — and startup REFUSES a transaction-requiring operation that uses\n // it, which for a bulk operation would turn a guarantee into a boot failure for an application\n // that legitimately owns its own bulk persistence. Token coupling keeps its refusal, because\n // there the framework's own token effect really would be fictitious.\n && !registrations.some((registration) => registration.implementation.getPlaceholders().includes(\n ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL,\n ));\n /*\n * #1690 — an OUTBOUND pipeline's change marker. The effective verb is the core operation a custom operation borrows\n * (`resourceOperationLike`), as the write path reads it; a core operation's identifier IS its verb. Not under\n * OVERRIDE_ALL, for the bulk rule's reason: that mode replaces the pipeline that records the marker.\n */\n const operationLike = (operation as { resourceOperationLike?: unknown }).resourceOperationLike ?? operation.operationIdentifier;\n const recordsOutboundChange = externalDataOutboundChangeOwed(resourceDeclarations, operationLike)\n && !registrations.some((registration) => registration.implementation.getPlaceholders().includes(\n ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL,\n ));\n /*\n * #2509 — a document number is gapless only when its counter's increment commits or rolls back WITH the row, so a\n * create that numbers a row is transactional. Not under OVERRIDE_ALL, for the bulk rule's reason: that mode replaces\n * the repository create that allocates.\n */\n const allocatesDocumentNumbers = (operationLike === CoreResourceOperation.CREATE || operationLike === CoreResourceOperation.CREATE_MANY)\n && resourceDeclarations?.mainSchema !== undefined\n && createAllocatedDocumentSequenceFieldsOf(resourceDeclarations.mainSchema).length > 0\n && !registrations.some((registration) => registration.implementation.getPlaceholders().includes(\n ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL,\n ));\n const transactionalForAnotherReason = tokenCoupled || bulkMutation || recordsOutboundChange || allocatesDocumentNumbers || transactionalRegistrations.length > 0;\n /*\n * #2297 — a plain audited write keeps its audit row through a crash only when its attempt is captured, and an attempt\n * exists only inside a transaction. So a write nothing else makes transactional is made transactional for its row when\n * it is classified safe to wrap (PlainAuditedWriteDurability.TRANSACTION_FOR_AUDIT_ROW) AND the process can capture it\n * (the outbox shares the resource's native adapter). Without both, the write runs exactly as before: a transaction that\n * nothing could capture would buy nothing.\n */\n const transactionForAuditRow = !transactionalForAnotherReason\n && classifyPlainAuditedWriteDurability(operation, registrations) === PlainAuditedWriteDurability.TRANSACTION_FOR_AUDIT_ROW\n && environment?.auditRowCaptureAvailable?.() === true;\n const transactionRequired = transactionalForAnotherReason || transactionForAuditRow;\n const overrideAllRegistrationLabels = registrations\n .filter((registration) =>\n registration.implementation.getPlaceholders().includes(\n ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL,\n ))\n .map((registration) => registration.debugLabel)\n .sort();\n const transactionalRegistrationLabels = transactionalRegistrations\n .map((registration) => registration.debugLabel)\n .sort();\n\n if (!transactionRequired) {\n return Object.freeze({\n transactionRequired: false,\n tokenGeneration,\n transactionalRegistrationLabels: Object.freeze(\n transactionalRegistrationLabels,\n ),\n overrideAllRegistrationLabels: Object.freeze(\n overrideAllRegistrationLabels,\n ),\n });\n }\n\n const participants: Record<string, string> = {\n operationResource: String(operation.resourceIdentifier),\n };\n transactionalRegistrations.forEach((registration, registrationIndex) => {\n Object.entries(registration.transactionParticipants ?? {})\n .forEach(([participantName, resourceType]) => {\n participants[\n `custom[${registrationIndex}](${registration.debugLabel}).${participantName}`\n ] = resourceType;\n });\n });\n if (tokenCoupled) {\n participants.consumableToken = BackendResourceType.CONSUMABLE_TOKENS;\n }\n if (recordsOutboundChange) {\n participants.externalDataOutboundChange = BackendResourceType.EXTERNAL_DATA_OUTBOUND_CHANGES;\n }\n if (allocatesDocumentNumbers) {\n participants.documentSequenceCounter = BackendResourceType.DOCUMENT_SEQUENCE_COUNTERS;\n }\n // #2870 — a resolver that proves a commit by its receipt needs the receipt written in the same transaction, on the same\n // adapter. Not under OVERRIDE_ALL: startup already refuses a transactional registration in that mode.\n const writesCommitReceipt = transactionalRegistrations.some(\n (registration) => commitOutcomeResolverReadsCommitReceipt(registration.transactionalCoreCommitOutcomeResolver),\n );\n if (writesCommitReceipt) {\n participants.commitReceipt = BackendResourceType.TRANSACTIONAL_COMMIT_RECEIPTS;\n }\n // #2886 — capture is available when a registration declared the outbox, wherever in its participants it named it.\n const capturesPostCommitEffects = Object.values(participants).includes(BackendResourceType.POST_COMMIT_EFFECT_OUTBOX);\n\n const operationPathKey = ResourcesConfig_OperationPathUtils.createOperationPathKeyFromOperation(operation);\n const request: ResourcePersistenceUnitOfWorkRequest = Object.freeze({\n boundary: `resource-operation-transaction:${operationPathKey}`,\n participants: Object.freeze(participants),\n /**\n * NO adapter requirement.\n *\n * This used to pin every token-coupled operation to MongoDB, because consumable-token\n * persistence reached the MongoDB driver directly. That is no longer true: the token service\n * writes through the adapter-neutral repositories plane, so a token-coupled transaction resolves\n * to whichever adapter its participants share.\n *\n * What this unblocks concretely: `organizationMembers | create · revoke · resend` are\n * token-coupled (invitation issue / revoke / re-issue). On a PostgreSQL platform their\n * participants resolve to POSTGRESQL while this pinned MONGODB, producing\n * REQUIRED_ADAPTER_MISMATCH ×3 at boot — which is what stopped `platform-module-registry` from\n * starting.\n */\n });\n\n return Object.freeze({\n request,\n transactionRequired: true,\n writesCommitReceipt,\n capturesPostCommitEffects,\n ...(transactionForAuditRow ? { transactionForAuditRow: true } : {}),\n tokenGeneration,\n transactionalRegistrationLabels: Object.freeze(\n transactionalRegistrationLabels,\n ),\n overrideAllRegistrationLabels: Object.freeze(\n overrideAllRegistrationLabels,\n ),\n });\n}\n"]}
1
+ {"version":3,"file":"resource-operation-transaction-persistence.backend.utils.js","sourceRoot":"","sources":["../../../../../src/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BULK_OPERATION_DEFAULT_MAX_SELECTION,\n CoreResourceOperation,\n CoreResourceType,\n isApiCallOperation,\n PersistenceAdapter,\n ResourceOperation_CustomServiceImplementationMode,\n ResourceOperationVariantType,\n ResourcesConfig_OperationPathUtils,\n type TokenGenerationConfig,\n type ResourceConfiguration_Operation,\n} from '@wildo-ai/saas-models';\n\nimport type {\n ResourcePersistenceUnitOfWorkBackendService,\n ResourcePersistenceUnitOfWorkRequest,\n} from '~wildo-backend-lib/databases/services/resource-persistence-unit-of-work.backend.service';\n// entrypoint-closure-waiver: `resource-operation-audit-emission.backend.utils` is published only by `./assurance-derivations`\n// and was ALREADY in the root closure (`services-registry-handler.backend.service`, root-exported, imports it), so this\n// edge adds no reachability. Only `.shouldEmit` is read, inside `classifyPlainAuditedWriteDurability`; no exported\n// declaration of this file names a type from that module, so a root-only consumer has nothing to name (#2297).\nimport { resolveResourceOperationAuditDecision } from './resource-operation-audit-emission.backend.utils';\nimport { ResourcePersistenceParticipantCoupling } from '~wildo-backend-lib/databases/services/resource-persistence-unit-of-work.backend.service';\nimport { BackendResourceType } from '~wildo-backend-lib/resources/models/resources-types.backend.schemas';\nimport { isReadShapedOperation } from '@wildo-ai/saas-models';\nimport { externalDataOutboundChangeOwed } from '~wildo-backend-lib/external-data/external-data-outbound-change-recording.backend';\nimport type { ExternalDataPipelineDeclaration } from '@wildo-ai/saas-models/external-data';\nimport type { z } from 'zod';\nimport { createAllocatedDocumentSequenceFieldsOf } from '~wildo-backend-lib/document-sequences/services/document-sequence-allocation.backend';\nimport type {\n ResourceOperationCustomImplementationRegistration,\n} from './resource-operation-custom-implementation-registry.backend.service';\nimport { commitOutcomeResolverReadsCommitReceipt } from './resource-operation-commit-receipt.backend.utils';\nimport { ResourceCustomServiceImplementationHookTransactionPosture } from './resource-operation-custom-implementation.factory.backend';\n\n/**\n * How the FILES resource participates in one resource write.\n *\n * File work is not one thing, and collapsing it into one was what forced the\n * service layer to answer the question with hardcoded adapter comparisons: a write\n * may carry file metadata, or a generated document that must be committed with the\n * row. Both commit with the row since #3328 (one transactional store per application).\n */\nexport enum ResourceWriteFileParticipation {\n /** The resource declares no file fields. FILES is not part of the boundary. */\n NONE = 'NONE',\n /**\n * File METADATA is written alongside the row, in the row's transaction.\n *\n * ATOMIC, like a generated document, since #3328: an application uses one\n * transactional store, so FILES always shares the row's, and the service layer\n * no longer has a separately-committed path to fall back to. It used to be\n * COMPENSATABLE (a resource on another adapter wrote its file metadata in FILES'\n * own transaction, once, after or beside the row). Kept distinct from\n * {@link ATOMIC_MATERIALIZATION} because the two are different facts about the\n * write, even though both now commit with the row.\n */\n METADATA = 'METADATA',\n /**\n * A generated document (a PDF materialization) must land in the SAME commit as\n * the row that references it.\n *\n * Not splittable: a row committed pointing at a document whose metadata never\n * committed is a dangling reference, so a cross-adapter boundary here must be\n * refused rather than degraded.\n */\n ATOMIC_MATERIALIZATION = 'ATOMIC_MATERIALIZATION',\n}\n\n/**\n * Declare the persistence boundary of one resource WRITE.\n *\n * This is the declaration the service layer never had. `executeResourceTransaction`\n * opens a transaction on the writing resource's adapter and then performs nested\n * and file work inside it, but nothing described WHO was in that boundary — so\n * every site that needed to know whether file work could join the transaction\n * asked `adapter === MONGODB` instead, which is correct only for as long as FILES\n * stays on MongoDB. Declaring the participants moves that question to the single\n * authority that already owns it.\n *\n * Everything here is derivable from the resource registry alone (file-field\n * presence and generated-PDF fields are schema-derived), so the same declaration\n * is available to startup validation as it is at runtime.\n */\nexport function createResourceWritePersistenceRequest(options: {\n readonly resourceType: string;\n readonly fileParticipation: ResourceWriteFileParticipation;\n readonly nestedResourceTypes?: readonly string[];\n}): ResourcePersistenceUnitOfWorkRequest {\n const participants: Record<string, ResourcePersistenceUnitOfWorkRequest['participants'][string]> = {\n // Shorthand: the writing resource is ATOMIC by definition — it IS the boundary.\n operationResource: options.resourceType,\n };\n\n (options.nestedResourceTypes ?? []).forEach((nestedResourceType, nestedIndex) => {\n // Nested mutations commit with the parent or not at all; a nested row that\n // survived a rolled-back parent is an orphan.\n participants[`nested[${nestedIndex}](${nestedResourceType})`] = nestedResourceType;\n });\n\n if (options.fileParticipation !== ResourceWriteFileParticipation.NONE) {\n // Both kinds commit with the row (#3328): there is no store FILES could sit on apart from the row's.\n participants.fileMetadata = {\n resourceType: CoreResourceType.FILES,\n coupling: ResourcePersistenceParticipantCoupling.ATOMIC,\n };\n }\n\n return Object.freeze({\n boundary: `resource-write:${options.resourceType}`,\n participants: Object.freeze(participants),\n });\n}\n\n/**\n * Canonical transaction contract for one resource-operation pipeline.\n *\n * Startup validation and runtime execution must both consume this resolver.\n * Otherwise an authored participant can be checked under one adapter set at\n * boot and executed under a broader, incompatible set on the first request.\n */\nexport interface ResourceOperationTransactionPersistenceContract {\n readonly request?: ResourcePersistenceUnitOfWorkRequest;\n readonly transactionRequired: boolean;\n readonly tokenGeneration: TokenGenerationConfig | undefined;\n readonly transactionalRegistrationLabels: readonly string[];\n readonly overrideAllRegistrationLabels: readonly string[];\n /**\n * Whether each root-owned attempt writes a commit receipt (#2870): set when a transactional registration's\n * commit-outcome resolver reads one ({@link commitOutcomeResolverReadsCommitReceipt}). The receipts resource is then a\n * participant of the transaction, so startup proves it shares the operation's adapter and the receipt commits with the\n * attempt's writes. Absent on a contract that needs no transaction.\n */\n readonly writesCommitReceipt?: boolean;\n /**\n * Whether an attempt of this operation can be CAPTURED (#2886): a transactional registration declares the post-commit\n * effect outbox as a participant ({@link POST_COMMIT_EFFECT_CAPTURE_PARTICIPANTS}), so startup proves the outbox shares the\n * operation's adapter and its rows commit with the attempt. A caller's `postCommitEffectCaptureRequested` is refused on a\n * contract without it. Absent on a contract that needs no transaction.\n */\n readonly capturesPostCommitEffects?: boolean;\n /**\n * Whether the ONLY reason this operation is transactional is its audit row (#2297): a plain audited write\n * ({@link PlainAuditedWriteDurability.TRANSACTION_FOR_AUDIT_ROW}) in a process where its attempt can be captured. The\n * transaction exists so the automatic capture can keep the row in the post-commit effect outbox. Absent otherwise.\n */\n readonly transactionForAuditRow?: boolean;\n}\n\n/**\n * What a PLAIN audited write does to keep its `RESOURCE_OPERATION_PERFORMED` row through a crash (#2297).\n *\n * A transactional operation keeps the row: its attempt is captured automatically and the outbox relay writes a leftover\n * row once. A write that no other rule makes transactional used to stay best effort, because the row is written after\n * the commit and a process that dies in between loses it. Each member below is one answer, per operation, to \"may the\n * framework open a transaction around this write so the row is kept?\". The answer is decided from the operation and its\n * custom registrations alone, so startup and runtime cannot disagree about it.\n *\n * Only {@link TRANSACTION_FOR_AUDIT_ROW} changes behaviour. Every other member is a reason the write stays best effort,\n * named so the boot coverage, a test failure and the tracker can say WHY rather than only that it does. The best-effort\n * members are reviewed in waves (#2297), so a member may move to the durable side once its reason is answered.\n */\nexport enum PlainAuditedWriteDurability {\n /**\n * A single-row CREATE, UPDATE or DELETE (including a custom operation that behaves as one), reached through the framework\n * pipeline (`API_CALL`, `INTERNAL_CALL`), with NO custom implementation registered. A write judged by an\n * `enabledCondition` is included: inside the transaction its row is re-read and the condition judged again, and a lost\n * race still answers the CONFLICT #2543 pins (a refusal on a row that no longer holds what the request was admitted on\n * is classified as that race). For a hook-less write nothing but the\n * framework's own core runs inside the transaction, and that core already runs inside one for every transactional\n * operation, so the transaction adds no new kind of work to it; no hook can call a provider, which refuses to run inside\n * a transaction (`assertOutsideTransaction`). The framework makes the write transactional when its attempt can be captured.\n *\n * A DELETE's cascade stays inside the database, which is what lets it in (wave 2, reviewed 2026-11-10): the service's\n * single-row delete already ran its repository write, its `onParentDelete` cascade and its file handling inside a\n * transaction of its own (`executeResourceTransaction`), which the transactional core's now replaces. Children are\n * deleted (or scrubbed) through their RAW repositories, so no child hook runs; a deferred (LAZY) edge's job is collected\n * and published by the cascade's entry inside that transaction (#2634); a linked file is soft-deleted or unlinked, and\n * its stored object is removed later by the files cleanup batch (`hardDeleteFile`), never inline, so no object-storage\n * call is made inside the transaction; the RAG chunk removal is a post-commit effect. A cascade child on a read-through\n * (HTTP_API) resource refuses inside any transaction, which is why such a cascade is refused already, before this.\n *\n * A write with custom implementations is included when EVERY registration declares its hooks\n * `RUNS_INSIDE_TRANSACTION` (wave 3): each was read, and does nothing outside the database before the commit\n * (`ResourceCustomServiceImplementationHookTransactionPosture`).\n *\n * A multi-row UPDATE_MANY / DELETE_MANY is included once its rows per transaction are BOUNDED by\n * {@link MULTI_ROW_WRITE_ROWS_PER_TRANSACTION} (wave 4): the framework performs a hook-less core one in chunks of at most\n * that many rows, each chunk its own transactional attempt with its own audit row\n * ({@link isFrameworkChunkedMultiRowWrite}); a registration that performs the write itself is included when it declares\n * how many rows one attempt writes (`maximumRowsWrittenPerAttempt`), within the same bound.\n */\n TRANSACTION_FOR_AUDIT_ROW = 'transaction_for_audit_row',\n /**\n * A custom implementation (PREFIX, BETWEEN, POSTFIX, …) is registered and has not declared whether its hooks may run\n * inside a transaction (`hookTransactionPosture`). Making the write transactional would run them there, and nothing\n * says whether a hook calls a provider, so it stays best effort until the registration is reviewed.\n */\n BEST_EFFORT_CUSTOM_IMPLEMENTATION = 'best_effort_custom_implementation',\n /**\n * A registration was reviewed and declares `STAYS_OUTSIDE_TRANSACTION`: a hook's answer depends on an effect outside the\n * database (a provider call, an audit row that must exist before the operation answers, a queue publish that decides\n * what is written), so the hooks must not run in a transaction and the row stays best effort. The reason is written at\n * the declaration.\n */\n BEST_EFFORT_HOOK_OUTSIDE_TRANSACTION = 'best_effort_hook_outside_transaction',\n /**\n * An `OVERRIDE_ALL` implementation owns the write. That mode replaces the framework's pipeline and returns before its\n * transaction (startup refuses a transaction-requiring operation that uses it), so the framework can never open one\n * here. Permanently best effort at the top level; durable only when nested in a captured caller's transaction.\n */\n BEST_EFFORT_OVERRIDE_ALL = 'best_effort_override_all',\n /**\n * A multi-row write (`CREATE_MANY`, `UPDATE_MANY`, `DELETE_MANY`) whose rows per transaction nothing bounds: not a\n * synchronous bulk operation (bounded by its request, and already transactional), not a hook-less core UPDATE_MANY /\n * DELETE_MANY the framework chunks, and not a registration that declares how many rows it writes. One transaction could\n * hold an unbounded number of rows and outlive the store's transaction limits (MongoDB aborts a transaction after 60\n * seconds by default). Since wave 4 its members are the writes whose selection a HOOK decides (a purge selecting its own\n * population), which a framework bound cannot reach, and `CREATE_MANY`.\n */\n BEST_EFFORT_UNBOUNDED_MULTI_ROW = 'best_effort_unbounded_multi_row',\n /**\n * Another verb, or a scheduled variant (`CRON_JOB`, `BATCH_JOB`), that no wave has reviewed yet.\n */\n BEST_EFFORT_NOT_YET_REVIEWED = 'best_effort_not_yet_reviewed',\n /**\n * `REPOSITORY_ONLY`: the framework pipeline refuses this variant, so no operation-level audit row is written through it\n * at all, and there is no attempt to make transactional.\n */\n NOT_REACHED_THROUGH_PIPELINE = 'not_reached_through_pipeline',\n}\n\n/**\n * Classify one write the framework audits by its declaration alone (the risk floor, or\n * `auditableEvent.auditBelowRiskFloor`) into {@link PlainAuditedWriteDurability} (#2297). Answers `undefined` for an\n * operation that owes no row by declaration (read-shaped, or below the floor with no opt-in): a row that only runtime\n * evidence calls for (a decided agent write, a representative's write) is not known before the write starts, so it stays\n * best effort.\n *\n * It does not say whether the write is transactional for another reason (a token, a bulk selection, a transactional\n * registration): {@link resolveResourceOperationTransactionPersistenceContract} asks this only of a write nothing else\n * makes transactional.\n */\nexport function classifyPlainAuditedWriteDurability(\n operation: ResourceConfiguration_Operation<any, any, any>,\n registrations: readonly ResourceOperationCustomImplementationRegistration[],\n): PlainAuditedWriteDurability | undefined {\n if (!resolveResourceOperationAuditDecision(operation).shouldEmit) return undefined;\n const variantType = (operation as { variantType?: ResourceOperationVariantType }).variantType;\n if (variantType === ResourceOperationVariantType.REPOSITORY_ONLY) return PlainAuditedWriteDurability.NOT_REACHED_THROUGH_PIPELINE;\n if (registrations.some((registration) => registration.implementation.getPlaceholders().includes(ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL))) {\n return PlainAuditedWriteDurability.BEST_EFFORT_OVERRIDE_ALL;\n }\n // Wave 3: a registration's hooks run in the transaction only when it says they may; one that must not decides for the write.\n if (registrations.some((registration) => registration.hookTransactionPosture === ResourceCustomServiceImplementationHookTransactionPosture.STAYS_OUTSIDE_TRANSACTION)) {\n return PlainAuditedWriteDurability.BEST_EFFORT_HOOK_OUTSIDE_TRANSACTION;\n }\n if (!registrations.every(hooksMayRunInsideTransaction)) return PlainAuditedWriteDurability.BEST_EFFORT_CUSTOM_IMPLEMENTATION;\n if (variantType !== ResourceOperationVariantType.API_CALL && variantType !== ResourceOperationVariantType.INTERNAL_CALL) {\n return PlainAuditedWriteDurability.BEST_EFFORT_NOT_YET_REVIEWED;\n }\n // The verb the write path performs: a custom operation borrows a core one (`resourceOperationLike`), a core operation is its verb.\n const operationLike = (operation as { resourceOperationLike?: unknown }).resourceOperationLike ?? operation.operationIdentifier;\n switch (operationLike) {\n case CoreResourceOperation.CREATE:\n case CoreResourceOperation.UPDATE:\n // Wave 2: a single-row DELETE, cascade included (see TRANSACTION_FOR_AUDIT_ROW for why its cascade stays in the database).\n case CoreResourceOperation.DELETE:\n return PlainAuditedWriteDurability.TRANSACTION_FOR_AUDIT_ROW;\n // Wave 4: a multi-row write joins once its rows per transaction are bounded (see MULTI_ROW_WRITE_ROWS_PER_TRANSACTION).\n case CoreResourceOperation.UPDATE_MANY:\n case CoreResourceOperation.DELETE_MANY:\n return multiRowWriteIsBoundedPerTransaction(operation, registrations)\n ? PlainAuditedWriteDurability.TRANSACTION_FOR_AUDIT_ROW\n : PlainAuditedWriteDurability.BEST_EFFORT_UNBOUNDED_MULTI_ROW;\n case CoreResourceOperation.CREATE_MANY:\n return PlainAuditedWriteDurability.BEST_EFFORT_UNBOUNDED_MULTI_ROW;\n default:\n return PlainAuditedWriteDurability.BEST_EFFORT_NOT_YET_REVIEWED;\n }\n}\n\n/**\n * The most rows one transactional attempt of a multi-row write may hold (#2297 wave 4): 100, the bound a synchronous bulk\n * operation already enforces on its request (`BULK_OPERATION_DEFAULT_MAX_SELECTION`), and so the one bound the framework\n * already holds a synchronous multi-row transaction to. Decided by this repository's own principle (one bound for one\n * concern) rather than by a new number:\n * - MongoDB aborts a transaction that runs a minute; spec-cite: MongoDB Manual, \"Production Considerations\", Runtime Limit\n * (https://www.mongodb.com/docs/manual/core/transactions-production-consideration/, quoted: \"By default, a transaction\n * must have a runtime of less than one minute.\"). Removing 10,000 rows' targets was measured at 19 s (MongoDB) and 37 s\n * (PostgreSQL) in one transaction (#2864), so 100 rows is two orders of magnitude inside the limit.\n * - it is NOT what makes a bulk write's guards complete, and must not be read as such: the RESTRICT and legal-hold refusals\n * and the pre-hook snapshots read EVERY target (`loadBulkTargetResources`, a listing with no paging options, which both\n * adapters answer whole), whatever the chunk size, including a nested write the chunking never splits (#3698).\n * Above it, the write is performed in CHUNKS, each its own transaction and its own audit row naming its rows, which is how\n * the framework's own sweeps already delete (`resource-retention-sweep`, `retention-class-sweep`); rejected: refusing a\n * selection above the bound, which would break every internal caller that removes a population (a transposition, a\n * cascade of a large tenant) for a limit that only exists to keep one transaction short.\n */\nexport const MULTI_ROW_WRITE_ROWS_PER_TRANSACTION: number = BULK_OPERATION_DEFAULT_MAX_SELECTION;\n\n/**\n * Whether the FRAMEWORK performs this multi-row write itself and can therefore chunk it (#2297 wave 4): the core\n * `UPDATE_MANY` / `DELETE_MANY` operation itself (not a custom verb borrowing it), answering the core response (no\n * `customResponseDto`, so chunk answers merge: rows concatenate, deleted ids concatenate and their counts add), with no\n * custom registration (nothing but the framework reads the selection it rewrites per chunk), and not a synchronous bulk\n * operation (bounded by its request already). `ServiceResourceBackendService.doOperation` chunks exactly these.\n */\nexport function isFrameworkChunkedMultiRowWrite(\n operation: ResourceConfiguration_Operation<any, any, any>,\n registrations: readonly ResourceOperationCustomImplementationRegistration[],\n): boolean {\n const identifier = operation.operationIdentifier as unknown;\n if (identifier !== CoreResourceOperation.UPDATE_MANY && identifier !== CoreResourceOperation.DELETE_MANY) return false;\n if ((operation as { hasCustomResponseDto?: boolean }).hasCustomResponseDto === true) return false;\n if ((operation as { isBulkOperation?: boolean }).isBulkOperation === true) return false;\n return registrations.length === 0;\n}\n\n/**\n * Whether one transactional attempt of this multi-row write holds at most {@link MULTI_ROW_WRITE_ROWS_PER_TRANSACTION} rows:\n * the framework chunks it ({@link isFrameworkChunkedMultiRowWrite}), or a registration that REPLACES the core write declares\n * how many rows one attempt writes (`maximumRowsWrittenPerAttempt`, refused at registration above the bound).\n */\nfunction multiRowWriteIsBoundedPerTransaction(\n operation: ResourceConfiguration_Operation<any, any, any>,\n registrations: readonly ResourceOperationCustomImplementationRegistration[],\n): boolean {\n if (isFrameworkChunkedMultiRowWrite(operation, registrations)) return true;\n return registrations.some((registration) =>\n registration.maximumRowsWrittenPerAttempt !== undefined\n && registration.implementation.getPlaceholders().includes(ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS));\n}\n\n/**\n * Whether a registration's hooks may run in the transaction kept for the audit row (#2297 wave 3): it declares so, or it is\n * `transactionalCore` (its hooks run in a transaction already).\n */\nfunction hooksMayRunInsideTransaction(registration: ResourceOperationCustomImplementationRegistration): boolean {\n return registration.transactionalCore\n || registration.hookTransactionPosture === ResourceCustomServiceImplementationHookTransactionPosture.RUNS_INSIDE_TRANSACTION;\n}\n\n/**\n * What the process can do for a resource's writes, asked by both callers of\n * {@link resolveResourceOperationTransactionPersistenceContract} (startup validation and `doOperation`) through the same\n * function so the two cannot disagree (#2297).\n */\nexport interface ResourceOperationTransactionPersistenceEnvironment {\n /**\n * Whether an attempt on this operation's resource could keep its audit row: the post-commit effect outbox is a\n * registered resource on the SAME native transactional adapter. Read only for a\n * {@link PlainAuditedWriteDurability.TRANSACTION_FOR_AUDIT_ROW} write, so a process without the outbox (a platform\n * service) or a resource on HTTP_API / INTROSPECTION never gets a transaction it could not use. Build it with\n * {@link auditRowCaptureAvailableThrough}.\n */\n readonly auditRowCaptureAvailable?: () => boolean;\n}\n\n/**\n * The one answer to {@link ResourceOperationTransactionPersistenceEnvironment.auditRowCaptureAvailable} (#2297): the unit\n * of work assesses a boundary made of the resource and the post-commit effect outbox, without opening anything. It is\n * compatible exactly when both resolve to one native adapter whose database service is present. A unit of work that is\n * missing or cannot answer gives `false`, so the write stays as it was.\n */\nexport function auditRowCaptureAvailableThrough(\n unitOfWork: Pick<ResourcePersistenceUnitOfWorkBackendService, 'assessCompatibility'> | undefined,\n resourceType: string,\n): boolean {\n if (typeof unitOfWork?.assessCompatibility !== 'function') return false;\n try {\n return unitOfWork.assessCompatibility({\n boundary: `audit-row-capture:${resourceType}`,\n participants: {\n operationResource: resourceType,\n postCommitEffectOutbox: BackendResourceType.POST_COMMIT_EFFECT_OUTBOX,\n },\n }).compatible === true;\n } catch {\n return false;\n }\n}\n\n/**\n * The participant a transactional registration declares when its operation's attempts may be captured (#2886): spread into\n * its `transactionParticipants`. Declared on the verbs the sweeps dispatch with `postCommitEffectCaptureRequested`; the\n * declaration, not the request, is what startup validates, so a verb is proved capturable before any sweep asks.\n */\nexport const POST_COMMIT_EFFECT_CAPTURE_PARTICIPANTS: Readonly<Record<string, string>> = Object.freeze({\n postCommitEffectOutbox: BackendResourceType.POST_COMMIT_EFFECT_OUTBOX,\n});\n\nfunction getOperationTokenGeneration(\n operation: ResourceConfiguration_Operation<any, any, any>,\n): TokenGenerationConfig | undefined {\n if (\n isApiCallOperation(operation)\n ) {\n return operation.tokenGeneration;\n }\n return undefined;\n}\n\n/**\n * Resolve every resource that participates in the framework-owned atomic core\n * phase. The operation resource is implicit; custom implementations declare\n * their additional resources by semantic role, and every framework-owned token\n * effect contributes the consumable-token participant automatically.\n *\n * Token authentication and revocation are transaction triggers in their own\n * right. Validation-before-mutation followed by consumption-after-mutation is\n * not an atomic use: concurrent requests could both mutate before one loses the\n * token compare-and-set, and a process loss could persist the mutation while\n * leaving the token reusable. Startup and runtime therefore assess the same\n * resource-plus-token boundary even when no custom implementation requested a\n * transaction.\n */\nexport function resolveResourceOperationTransactionPersistenceContract(\n operation: ResourceConfiguration_Operation<any, any, any>,\n registrations: readonly ResourceOperationCustomImplementationRegistration[],\n /**\n * The operation resource's own declarations, when the caller holds them (#1690). Only `externalDataPipeline` is read:\n * a write that creates or changes rows of an OUTBOUND pipeline's destination records a marker for its system of\n * record, and that marker must commit with the change — so the write is transactional, with the markers as a\n * participant. Optional so a caller that cannot name the resource keeps today's contract.\n */\n resourceDeclarations?: {\n readonly externalDataPipeline?: Pick<ExternalDataPipelineDeclaration, 'direction'>;\n /**\n * The resource's main schema (#2509): a create on a resource with a CREATE-allocated `.documentSequence(...)` field\n * takes its number from a counter that must commit with the row, so that create is transactional, with the\n * counters as a participant.\n */\n readonly mainSchema?: z.ZodTypeAny;\n },\n /** What the process can do for this resource's writes (#2297). Omitted, no write is made transactional for its audit row. */\n environment?: ResourceOperationTransactionPersistenceEnvironment,\n): ResourceOperationTransactionPersistenceContract {\n const transactionalRegistrations = registrations.filter(\n (registration) => registration.transactionalCore,\n );\n const tokenGeneration = getOperationTokenGeneration(operation);\n const transactionallyGeneratesTokens = tokenGeneration !== undefined;\n const transactionallyConsumesTokens =\n 'tokenAuthentication' in operation\n && operation.tokenAuthentication !== undefined;\n const transactionallyRevokesTokens =\n 'tokenRevocation' in operation\n && operation.tokenRevocation !== undefined;\n const tokenCoupled =\n transactionallyGeneratesTokens\n || transactionallyConsumesTokens\n || transactionallyRevokesTokens;\n /**\n * A BULK MUTATION is transactional, whatever else it declares.\n *\n * A synchronous batch is atomic — spec-cite: Google AIP-234, \"Batch update\"\n * (https://google.aip.dev/234, quoted: \"Synchronous batch update must be atomic.\") — and the\n * whole action lane's design rests on that split: the synchronous form is all-or-nothing, and the\n * asynchronous form is the one allowed to partially succeed, which is why it reports per item.\n *\n * It was never true here. Measured 2026-09-22: nothing in this resolver mentioned bulk, so an\n * ordinary `UPDATE_MANY` / `DELETE_MANY` ran with no transaction. On PostgreSQL it survived by\n * accident — one `UPDATE … WHERE _id IN (…)` statement is atomic because it is one statement —\n * while on MongoDB a multi-document `updateMany` with no session leaves a partial write when it\n * fails part-way. The guarantee therefore held on one adapter, by coincidence, and not on the\n * other: two adapters disagreeing about what a refused batch means.\n *\n * READ-shaped bulk operations are excluded because there is nothing to make atomic; the cost is\n * bounded by the batch maximum a synchronous bulk already enforces\n * (`BULK_OPERATION_DEFAULT_MAX_SELECTION`, 100 rows), which is a small transaction on either\n * engine. Above that ceiling the work belongs to the background lane, which runs row by row and\n * is deliberately NOT atomic — there, partial success is the contract.\n */\n // `isBulkOperation` lives on the URL-bearing variants; a cron operation has no such field, which\n // is why this reads it defensively rather than narrowing the union at every call.\n const bulkMutation = ('isBulkOperation' in operation && operation.isBulkOperation === true)\n && !isReadShapedOperation(operation)\n // …unless an OVERRIDE_ALL implementation owns the write. That mode replaces this entire\n // pipeline and returns before the framework's transaction, so demanding one would be a promise\n // the framework cannot keep — and startup REFUSES a transaction-requiring operation that uses\n // it, which for a bulk operation would turn a guarantee into a boot failure for an application\n // that legitimately owns its own bulk persistence. Token coupling keeps its refusal, because\n // there the framework's own token effect really would be fictitious.\n && !registrations.some((registration) => registration.implementation.getPlaceholders().includes(\n ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL,\n ));\n /*\n * #1690 — an OUTBOUND pipeline's change marker. The effective verb is the core operation a custom operation borrows\n * (`resourceOperationLike`), as the write path reads it; a core operation's identifier IS its verb. Not under\n * OVERRIDE_ALL, for the bulk rule's reason: that mode replaces the pipeline that records the marker.\n */\n const operationLike = (operation as { resourceOperationLike?: unknown }).resourceOperationLike ?? operation.operationIdentifier;\n const recordsOutboundChange = externalDataOutboundChangeOwed(resourceDeclarations, operationLike)\n && !registrations.some((registration) => registration.implementation.getPlaceholders().includes(\n ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL,\n ));\n /*\n * #2509 — a document number is gapless only when its counter's increment commits or rolls back WITH the row, so a\n * create that numbers a row is transactional. Not under OVERRIDE_ALL, for the bulk rule's reason: that mode replaces\n * the repository create that allocates.\n */\n const allocatesDocumentNumbers = (operationLike === CoreResourceOperation.CREATE || operationLike === CoreResourceOperation.CREATE_MANY)\n && resourceDeclarations?.mainSchema !== undefined\n && createAllocatedDocumentSequenceFieldsOf(resourceDeclarations.mainSchema).length > 0\n && !registrations.some((registration) => registration.implementation.getPlaceholders().includes(\n ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL,\n ));\n const transactionalForAnotherReason = tokenCoupled || bulkMutation || recordsOutboundChange || allocatesDocumentNumbers || transactionalRegistrations.length > 0;\n /*\n * #2297 — a plain audited write keeps its audit row through a crash only when its attempt is captured, and an attempt\n * exists only inside a transaction. So a write nothing else makes transactional is made transactional for its row when\n * it is classified safe to wrap (PlainAuditedWriteDurability.TRANSACTION_FOR_AUDIT_ROW) AND the process can capture it\n * (the outbox shares the resource's native adapter). Without both, the write runs exactly as before: a transaction that\n * nothing could capture would buy nothing.\n */\n const transactionForAuditRow = !transactionalForAnotherReason\n && classifyPlainAuditedWriteDurability(operation, registrations) === PlainAuditedWriteDurability.TRANSACTION_FOR_AUDIT_ROW\n && environment?.auditRowCaptureAvailable?.() === true;\n const transactionRequired = transactionalForAnotherReason || transactionForAuditRow;\n const overrideAllRegistrationLabels = registrations\n .filter((registration) =>\n registration.implementation.getPlaceholders().includes(\n ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL,\n ))\n .map((registration) => registration.debugLabel)\n .sort();\n const transactionalRegistrationLabels = transactionalRegistrations\n .map((registration) => registration.debugLabel)\n .sort();\n\n if (!transactionRequired) {\n return Object.freeze({\n transactionRequired: false,\n tokenGeneration,\n transactionalRegistrationLabels: Object.freeze(\n transactionalRegistrationLabels,\n ),\n overrideAllRegistrationLabels: Object.freeze(\n overrideAllRegistrationLabels,\n ),\n });\n }\n\n const participants: Record<string, string> = {\n operationResource: String(operation.resourceIdentifier),\n };\n transactionalRegistrations.forEach((registration, registrationIndex) => {\n Object.entries(registration.transactionParticipants ?? {})\n .forEach(([participantName, resourceType]) => {\n participants[\n `custom[${registrationIndex}](${registration.debugLabel}).${participantName}`\n ] = resourceType;\n });\n });\n if (tokenCoupled) {\n participants.consumableToken = BackendResourceType.CONSUMABLE_TOKENS;\n }\n if (recordsOutboundChange) {\n participants.externalDataOutboundChange = BackendResourceType.EXTERNAL_DATA_OUTBOUND_CHANGES;\n }\n if (allocatesDocumentNumbers) {\n participants.documentSequenceCounter = BackendResourceType.DOCUMENT_SEQUENCE_COUNTERS;\n }\n // #2870 — a resolver that proves a commit by its receipt needs the receipt written in the same transaction, on the same\n // adapter. Not under OVERRIDE_ALL: startup already refuses a transactional registration in that mode.\n const writesCommitReceipt = transactionalRegistrations.some(\n (registration) => commitOutcomeResolverReadsCommitReceipt(registration.transactionalCoreCommitOutcomeResolver),\n );\n if (writesCommitReceipt) {\n participants.commitReceipt = BackendResourceType.TRANSACTIONAL_COMMIT_RECEIPTS;\n }\n // #2886 — capture is available when a registration declared the outbox, wherever in its participants it named it.\n const capturesPostCommitEffects = Object.values(participants).includes(BackendResourceType.POST_COMMIT_EFFECT_OUTBOX);\n\n const operationPathKey = ResourcesConfig_OperationPathUtils.createOperationPathKeyFromOperation(operation);\n const request: ResourcePersistenceUnitOfWorkRequest = Object.freeze({\n boundary: `resource-operation-transaction:${operationPathKey}`,\n participants: Object.freeze(participants),\n /**\n * NO adapter requirement.\n *\n * This used to pin every token-coupled operation to MongoDB, because consumable-token\n * persistence reached the MongoDB driver directly. That is no longer true: the token service\n * writes through the adapter-neutral repositories plane, so a token-coupled transaction resolves\n * to whichever adapter its participants share.\n *\n * What this unblocks concretely: `organizationMembers | create · revoke · resend` are\n * token-coupled (invitation issue / revoke / re-issue). On a PostgreSQL platform their\n * participants resolve to POSTGRESQL while this pinned MONGODB, producing\n * REQUIRED_ADAPTER_MISMATCH ×3 at boot — which is what stopped `platform-module-registry` from\n * starting.\n */\n });\n\n return Object.freeze({\n request,\n transactionRequired: true,\n writesCommitReceipt,\n capturesPostCommitEffects,\n ...(transactionForAuditRow ? { transactionForAuditRow: true } : {}),\n tokenGeneration,\n transactionalRegistrationLabels: Object.freeze(\n transactionalRegistrationLabels,\n ),\n overrideAllRegistrationLabels: Object.freeze(\n overrideAllRegistrationLabels,\n ),\n });\n}\n"]}
@@ -365,11 +365,11 @@ export declare function assertStatusTransitionPreservesOrganizationOwnerFloor(pa
365
365
  /**
366
366
  * Every resource this definition's transactional core touches beyond its own: what `resolveLandingStatus` reads, and
367
367
  * the organization-owner floor's reads and serialization write when a floor guard forwards the transaction to it
368
- * (the stranding report on USERS / USER_SELF, the owner floor on ORGANIZATION_MEMBERS).
368
+ * (the stranding report on USERS / USER_SELF, the owner floor on ORGANIZATION_MEMBERS), and the super-administrator
369
+ * floor's APPLICATION serialization write and USERS measurement on USERS / USER_SELF (#3670).
369
370
  *
370
371
  * Derived from the same governed-resource predicates that decide which guards run, so a definition that gains a
371
372
  * floor gains its participants with it. The operation's own resource is left out, since the framework includes it.
372
- * The super-admin floor forwards no transaction, so it adds none.
373
373
  */
374
374
  export declare function resolveStatusTransitionTransactionParticipants(definition: Pick<ResourceStatusTransitionDefinition, 'resourceIdentifier' | 'landingStatusTransactionParticipants' | 'capturesPostCommitEffects'>): Readonly<Record<string, string>>;
375
375
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"resource-status-transition.custom-impl.backend.service.d.ts","sourceRoot":"","sources":["../../../../../src/base-classes/services/services/resource-status-transition.custom-impl.backend.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resource-status-transition.custom-impl.backend.service.d.ts","sourceRoot":"","sources":["../../../../../src/base-classes/services/services/resource-status-transition.custom-impl.backend.service.ts"],"names":[],"mappings":"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"}
@@ -89,7 +89,7 @@
89
89
  */
90
90
  import { AdministrativeContinuityBreachDetection, CoreAuditableEventType, CoreResourceType, ErrorCustomMessageReference, ErrorType, ExecutionContext_ExecutionType, ResourceOperationVariantType, } from '@wildo-ai/saas-models';
91
91
  import { createResourceCustomServiceImplementation, } from '../../../base-classes/services/services/resource-operation-custom-implementation.factory.backend.js';
92
- import { assertSuperAdminFloorPreservedForTransition, createSuperAdminConferralResolver, isSuperAdminFloorGovernedSubjectResource, } from '../../../security/authorizations/super-admin-floor.backend.utils.js';
92
+ import { assertSuperAdminFloorPreservedForTransition, createSuperAdminConferralResolver, isSuperAdminFloorGovernedSubjectResource, SUPER_ADMIN_FLOOR_TRANSACTION_PARTICIPANTS, } from '../../../security/authorizations/super-admin-floor.backend.utils.js';
93
93
  import { assertOrganizationOwnerFloorPreservedForTransition, createOrganizationOwnerConferralResolver, createOrganizationOwnerFloorPopulationContext, isOrganizationOwnerFloorAuthorityBearingResource, isOrganizationOwnerFloorGovernedSubjectResource, reportOrganizationsStrandedByUserDeactivation, isAdministrativelyUsableOwnerUserStatus, membershipTransitionCouldReduceOwners, ORGANIZATION_OWNER_FLOOR_TRANSACTION_PARTICIPANTS, } from '../../../security/authorizations/organization-owner-floor.backend.utils.js';
94
94
  import { deriveDeterministicAuditEventId } from '../../../compliance/audit-trails/services/audit-logs.backend.service.js';
95
95
  import { SAAS_SERVICE_TYPES } from '../../../inject/models/service-types.js';
@@ -361,6 +361,8 @@ export async function assertStatusTransitionPreservesSuperAdminFloor(params) {
361
361
  errorBuilder: utils.errorBuilder,
362
362
  conferringRoles,
363
363
  operationIdentifier: definition.operationIdentifier,
364
+ // #3670: the transition's own transaction: the floor serializes concurrent reductions only inside it.
365
+ transaction: utils.serviceOptions?.transaction,
364
366
  });
365
367
  }
366
368
  /**
@@ -562,17 +564,18 @@ function resolveStatusTransitionFloorGuards(definition, container) {
562
564
  /**
563
565
  * Every resource this definition's transactional core touches beyond its own: what `resolveLandingStatus` reads, and
564
566
  * the organization-owner floor's reads and serialization write when a floor guard forwards the transaction to it
565
- * (the stranding report on USERS / USER_SELF, the owner floor on ORGANIZATION_MEMBERS).
567
+ * (the stranding report on USERS / USER_SELF, the owner floor on ORGANIZATION_MEMBERS), and the super-administrator
568
+ * floor's APPLICATION serialization write and USERS measurement on USERS / USER_SELF (#3670).
566
569
  *
567
570
  * Derived from the same governed-resource predicates that decide which guards run, so a definition that gains a
568
571
  * floor gains its participants with it. The operation's own resource is left out, since the framework includes it.
569
- * The super-admin floor forwards no transaction, so it adds none.
570
572
  */
571
573
  export function resolveStatusTransitionTransactionParticipants(definition) {
572
574
  const forwardsTransactionToOwnerFloor = isOrganizationOwnerFloorGovernedSubjectResource(definition.resourceIdentifier)
573
575
  || isOrganizationOwnerFloorAuthorityBearingResource(definition.resourceIdentifier);
574
576
  const participants = {
575
577
  ...(forwardsTransactionToOwnerFloor ? ORGANIZATION_OWNER_FLOOR_TRANSACTION_PARTICIPANTS : {}),
578
+ ...(isSuperAdminFloorGovernedSubjectResource(definition.resourceIdentifier) ? SUPER_ADMIN_FLOOR_TRANSACTION_PARTICIPANTS : {}),
576
579
  ...(definition.landingStatusTransactionParticipants ?? {}),
577
580
  // #2886: a verb whose attempts a caller captures keeps its kept effects in the post-commit effect outbox.
578
581
  ...(definition.capturesPostCommitEffects ? POST_COMMIT_EFFECT_CAPTURE_PARTICIPANTS : {}),