@wildo-ai/saas-backend-lib 1.1.2 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (853) hide show
  1. package/dist/esm/applications/services/worker-remote-client-factory.backend.service.d.ts.map +1 -1
  2. package/dist/esm/applications/services/worker-remote-client-factory.backend.service.js +19 -1
  3. package/dist/esm/applications/services/worker-remote-client-factory.backend.service.js.map +1 -1
  4. package/dist/esm/base-classes/models/manual-controllers.backend.definition.d.ts.map +1 -1
  5. package/dist/esm/base-classes/models/manual-controllers.backend.definition.js +4 -0
  6. package/dist/esm/base-classes/models/manual-controllers.backend.definition.js.map +1 -1
  7. package/dist/esm/base-classes/services/batches/child-lifecycle-teardown.batch.backend.service.d.ts +35 -0
  8. package/dist/esm/base-classes/services/batches/child-lifecycle-teardown.batch.backend.service.d.ts.map +1 -0
  9. package/dist/esm/base-classes/services/batches/child-lifecycle-teardown.batch.backend.service.js +111 -0
  10. package/dist/esm/base-classes/services/batches/child-lifecycle-teardown.batch.backend.service.js.map +1 -0
  11. package/dist/esm/base-classes/services/batches/credential-expiry-sweep.batch.backend.service.d.ts +50 -0
  12. package/dist/esm/base-classes/services/batches/credential-expiry-sweep.batch.backend.service.d.ts.map +1 -0
  13. package/dist/esm/base-classes/services/batches/credential-expiry-sweep.batch.backend.service.js +199 -0
  14. package/dist/esm/base-classes/services/batches/credential-expiry-sweep.batch.backend.service.js.map +1 -0
  15. package/dist/esm/base-classes/services/batches/engine-custom-batch-manifests.d.ts +111 -0
  16. package/dist/esm/base-classes/services/batches/engine-custom-batch-manifests.d.ts.map +1 -1
  17. package/dist/esm/base-classes/services/batches/engine-custom-batch-manifests.js +140 -0
  18. package/dist/esm/base-classes/services/batches/engine-custom-batch-manifests.js.map +1 -1
  19. package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.d.ts.map +1 -1
  20. package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.js +27 -6
  21. package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.js.map +1 -1
  22. package/dist/esm/base-classes/services/repositories/http-api/http-api-provider-access.backend.d.ts +124 -13
  23. package/dist/esm/base-classes/services/repositories/http-api/http-api-provider-access.backend.d.ts.map +1 -1
  24. package/dist/esm/base-classes/services/repositories/http-api/http-api-provider-access.backend.js +207 -21
  25. package/dist/esm/base-classes/services/repositories/http-api/http-api-provider-access.backend.js.map +1 -1
  26. package/dist/esm/base-classes/services/repositories/http-api/http-api-read-client.backend.d.ts +60 -8
  27. package/dist/esm/base-classes/services/repositories/http-api/http-api-read-client.backend.d.ts.map +1 -1
  28. package/dist/esm/base-classes/services/repositories/http-api/http-api-read-client.backend.js +174 -26
  29. package/dist/esm/base-classes/services/repositories/http-api/http-api-read-client.backend.js.map +1 -1
  30. package/dist/esm/base-classes/services/repositories/http-api/http-api-resource-repository.backend.service.d.ts +47 -4
  31. package/dist/esm/base-classes/services/repositories/http-api/http-api-resource-repository.backend.service.d.ts.map +1 -1
  32. package/dist/esm/base-classes/services/repositories/http-api/http-api-resource-repository.backend.service.js +96 -29
  33. package/dist/esm/base-classes/services/repositories/http-api/http-api-resource-repository.backend.service.js.map +1 -1
  34. package/dist/esm/base-classes/services/repositories/http-api/http-api-rest-operation-reference.backend.d.ts +55 -0
  35. package/dist/esm/base-classes/services/repositories/http-api/http-api-rest-operation-reference.backend.d.ts.map +1 -0
  36. package/dist/esm/base-classes/services/repositories/http-api/http-api-rest-operation-reference.backend.js +114 -0
  37. package/dist/esm/base-classes/services/repositories/http-api/http-api-rest-operation-reference.backend.js.map +1 -0
  38. package/dist/esm/base-classes/services/repositories/http-api/http-api-transport.backend.d.ts +89 -14
  39. package/dist/esm/base-classes/services/repositories/http-api/http-api-transport.backend.d.ts.map +1 -1
  40. package/dist/esm/base-classes/services/repositories/http-api/http-api-transport.backend.js +84 -11
  41. package/dist/esm/base-classes/services/repositories/http-api/http-api-transport.backend.js.map +1 -1
  42. package/dist/esm/base-classes/services/repositories/infrastructure-tier-contract.backend.d.ts.map +1 -1
  43. package/dist/esm/base-classes/services/repositories/infrastructure-tier-contract.backend.js +9 -1
  44. package/dist/esm/base-classes/services/repositories/infrastructure-tier-contract.backend.js.map +1 -1
  45. package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.d.ts +49 -0
  46. package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.d.ts.map +1 -1
  47. package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.js +171 -18
  48. package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.js.map +1 -1
  49. package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.d.ts.map +1 -1
  50. package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.js +23 -3
  51. package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.js.map +1 -1
  52. package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.d.ts.map +1 -1
  53. package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.js +20 -0
  54. package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.js.map +1 -1
  55. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-base.backend.service.d.ts +22 -0
  56. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-base.backend.service.d.ts.map +1 -1
  57. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-base.backend.service.js.map +1 -1
  58. package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.d.ts.map +1 -1
  59. package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.js +4 -1
  60. package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.js.map +1 -1
  61. package/dist/esm/base-classes/services/services/resource-status-transition.definitions.backend.d.ts +11 -0
  62. package/dist/esm/base-classes/services/services/resource-status-transition.definitions.backend.d.ts.map +1 -1
  63. package/dist/esm/base-classes/services/services/resource-status-transition.definitions.backend.js +39 -5
  64. package/dist/esm/base-classes/services/services/resource-status-transition.definitions.backend.js.map +1 -1
  65. package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.d.ts +181 -2
  66. package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.d.ts.map +1 -1
  67. package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js +529 -41
  68. package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js.map +1 -1
  69. package/dist/esm/base-classes/services/services/system-access.backend.service.d.ts +36 -3
  70. package/dist/esm/base-classes/services/services/system-access.backend.service.d.ts.map +1 -1
  71. package/dist/esm/base-classes/services/services/system-access.backend.service.js +70 -8
  72. package/dist/esm/base-classes/services/services/system-access.backend.service.js.map +1 -1
  73. package/dist/esm/billing/batches/billing-reconciliation.batch.backend.service.d.ts +28 -0
  74. package/dist/esm/billing/batches/billing-reconciliation.batch.backend.service.d.ts.map +1 -0
  75. package/dist/esm/billing/batches/billing-reconciliation.batch.backend.service.js +90 -0
  76. package/dist/esm/billing/batches/billing-reconciliation.batch.backend.service.js.map +1 -0
  77. package/dist/esm/billing/batches/usage-flush.batch.backend.service.d.ts +44 -0
  78. package/dist/esm/billing/batches/usage-flush.batch.backend.service.d.ts.map +1 -0
  79. package/dist/esm/billing/batches/usage-flush.batch.backend.service.js +99 -0
  80. package/dist/esm/billing/batches/usage-flush.batch.backend.service.js.map +1 -0
  81. package/dist/esm/billing/models/billing-provider-event-settlement.backend.schemas.d.ts +91 -0
  82. package/dist/esm/billing/models/billing-provider-event-settlement.backend.schemas.d.ts.map +1 -0
  83. package/dist/esm/billing/models/billing-provider-event-settlement.backend.schemas.js +152 -0
  84. package/dist/esm/billing/models/billing-provider-event-settlement.backend.schemas.js.map +1 -0
  85. package/dist/esm/billing/services/back-office/billing-reconciliation.backend.service.d.ts +186 -0
  86. package/dist/esm/billing/services/back-office/billing-reconciliation.backend.service.d.ts.map +1 -0
  87. package/dist/esm/billing/services/back-office/billing-reconciliation.backend.service.js +474 -0
  88. package/dist/esm/billing/services/back-office/billing-reconciliation.backend.service.js.map +1 -0
  89. package/dist/esm/billing/services/back-office/product-catalog-sync.backend.service.d.ts +100 -0
  90. package/dist/esm/billing/services/back-office/product-catalog-sync.backend.service.d.ts.map +1 -1
  91. package/dist/esm/billing/services/back-office/product-catalog-sync.backend.service.js +209 -6
  92. package/dist/esm/billing/services/back-office/product-catalog-sync.backend.service.js.map +1 -1
  93. package/dist/esm/billing/services/back-office/usage-metering.backend.service.d.ts +200 -4
  94. package/dist/esm/billing/services/back-office/usage-metering.backend.service.d.ts.map +1 -1
  95. package/dist/esm/billing/services/back-office/usage-metering.backend.service.js +593 -64
  96. package/dist/esm/billing/services/back-office/usage-metering.backend.service.js.map +1 -1
  97. package/dist/esm/billing/services/billing-adapter-registry.backend.d.ts +36 -0
  98. package/dist/esm/billing/services/billing-adapter-registry.backend.d.ts.map +1 -0
  99. package/dist/esm/billing/services/billing-adapter-registry.backend.js +83 -0
  100. package/dist/esm/billing/services/billing-adapter-registry.backend.js.map +1 -0
  101. package/dist/esm/billing/services/billing-checkout-metadata.backend.utils.d.ts +9 -0
  102. package/dist/esm/billing/services/billing-checkout-metadata.backend.utils.d.ts.map +1 -1
  103. package/dist/esm/billing/services/billing-checkout-metadata.backend.utils.js +11 -1
  104. package/dist/esm/billing/services/billing-checkout-metadata.backend.utils.js.map +1 -1
  105. package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.d.ts.map +1 -1
  106. package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.js +48 -7
  107. package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.js.map +1 -1
  108. package/dist/esm/billing/services/custom-impl/billing-custom-impl-utils.backend.d.ts +38 -1
  109. package/dist/esm/billing/services/custom-impl/billing-custom-impl-utils.backend.d.ts.map +1 -1
  110. package/dist/esm/billing/services/custom-impl/billing-custom-impl-utils.backend.js +67 -2
  111. package/dist/esm/billing/services/custom-impl/billing-custom-impl-utils.backend.js.map +1 -1
  112. package/dist/esm/billing/services/custom-impl/billing-custom-implementations.backend.d.ts +30 -1
  113. package/dist/esm/billing/services/custom-impl/billing-custom-implementations.backend.d.ts.map +1 -1
  114. package/dist/esm/billing/services/custom-impl/billing-custom-implementations.backend.js +43 -1
  115. package/dist/esm/billing/services/custom-impl/billing-custom-implementations.backend.js.map +1 -1
  116. package/dist/esm/billing/services/custom-impl/promotion.custom-ops.custom-impl.backend.service.d.ts +11 -3
  117. package/dist/esm/billing/services/custom-impl/promotion.custom-ops.custom-impl.backend.service.d.ts.map +1 -1
  118. package/dist/esm/billing/services/custom-impl/promotion.custom-ops.custom-impl.backend.service.js +30 -16
  119. package/dist/esm/billing/services/custom-impl/promotion.custom-ops.custom-impl.backend.service.js.map +1 -1
  120. package/dist/esm/billing/services/custom-impl/subscription.mutations.custom-impl.backend.service.d.ts.map +1 -1
  121. package/dist/esm/billing/services/custom-impl/subscription.mutations.custom-impl.backend.service.js +104 -25
  122. package/dist/esm/billing/services/custom-impl/subscription.mutations.custom-impl.backend.service.js.map +1 -1
  123. package/dist/esm/billing/services/stripe-standard-billing-provider.backend.service.d.ts +18 -1
  124. package/dist/esm/billing/services/stripe-standard-billing-provider.backend.service.d.ts.map +1 -1
  125. package/dist/esm/billing/services/stripe-standard-billing-provider.backend.service.js +106 -2
  126. package/dist/esm/billing/services/stripe-standard-billing-provider.backend.service.js.map +1 -1
  127. package/dist/esm/billing/services/webhooks/__tests__/settlement-ledger.test-double.d.ts +52 -0
  128. package/dist/esm/billing/services/webhooks/__tests__/settlement-ledger.test-double.d.ts.map +1 -0
  129. package/dist/esm/billing/services/webhooks/__tests__/settlement-ledger.test-double.js +74 -0
  130. package/dist/esm/billing/services/webhooks/__tests__/settlement-ledger.test-double.js.map +1 -0
  131. package/dist/esm/billing/services/webhooks/billing-webhook-event-router.backend.service.d.ts +104 -11
  132. package/dist/esm/billing/services/webhooks/billing-webhook-event-router.backend.service.d.ts.map +1 -1
  133. package/dist/esm/billing/services/webhooks/billing-webhook-event-router.backend.service.js +260 -26
  134. package/dist/esm/billing/services/webhooks/billing-webhook-event-router.backend.service.js.map +1 -1
  135. package/dist/esm/billing/testing/mock-billing-provider.d.ts +30 -1
  136. package/dist/esm/billing/testing/mock-billing-provider.d.ts.map +1 -1
  137. package/dist/esm/billing/testing/mock-billing-provider.js +25 -0
  138. package/dist/esm/billing/testing/mock-billing-provider.js.map +1 -1
  139. package/dist/esm/compliance/audit-trails/batches/audit-logs-archive.batch.backend.service.js +11 -4
  140. package/dist/esm/compliance/audit-trails/batches/audit-logs-archive.batch.backend.service.js.map +1 -1
  141. package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.d.ts +225 -13
  142. package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.d.ts.map +1 -1
  143. package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.js +340 -62
  144. package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.js.map +1 -1
  145. package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.d.ts +244 -7
  146. package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.d.ts.map +1 -1
  147. package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.js +386 -5
  148. package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.js.map +1 -1
  149. package/dist/esm/compliance/audit-trails/services/composite-audit-log-sink.backend.d.ts.map +1 -1
  150. package/dist/esm/compliance/audit-trails/services/composite-audit-log-sink.backend.js +7 -1
  151. package/dist/esm/compliance/audit-trails/services/composite-audit-log-sink.backend.js.map +1 -1
  152. package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.d.ts +6 -2
  153. package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.d.ts.map +1 -1
  154. package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.js +31 -9
  155. package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.js.map +1 -1
  156. package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.d.ts +42 -0
  157. package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.d.ts.map +1 -1
  158. package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.js +57 -1
  159. package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.js.map +1 -1
  160. package/dist/esm/compliance/audit-trails/services/utils/leased-value-cache.backend.utils.d.ts +110 -0
  161. package/dist/esm/compliance/audit-trails/services/utils/leased-value-cache.backend.utils.d.ts.map +1 -0
  162. package/dist/esm/compliance/audit-trails/services/utils/leased-value-cache.backend.utils.js +192 -0
  163. package/dist/esm/compliance/audit-trails/services/utils/leased-value-cache.backend.utils.js.map +1 -0
  164. package/dist/esm/compliance/audit-trails/services/utils/ocsf-activity-mapping.backend.utils.d.ts.map +1 -1
  165. package/dist/esm/compliance/audit-trails/services/utils/ocsf-activity-mapping.backend.utils.js +31 -0
  166. package/dist/esm/compliance/audit-trails/services/utils/ocsf-activity-mapping.backend.utils.js.map +1 -1
  167. package/dist/esm/config/bootstrap/application-runtime-profile.backend.d.ts +5 -0
  168. package/dist/esm/config/bootstrap/application-runtime-profile.backend.d.ts.map +1 -1
  169. package/dist/esm/config/bootstrap/application-runtime-profile.backend.js +6 -0
  170. package/dist/esm/config/bootstrap/application-runtime-profile.backend.js.map +1 -1
  171. package/dist/esm/config/models/app-config.backend.schemas.d.ts +142 -46
  172. package/dist/esm/config/models/app-config.backend.schemas.d.ts.map +1 -1
  173. package/dist/esm/config/models/app-config.backend.schemas.js +121 -12
  174. package/dist/esm/config/models/app-config.backend.schemas.js.map +1 -1
  175. package/dist/esm/config/models/provider-runtime-artifact.backend.schemas.d.ts +38 -15
  176. package/dist/esm/config/models/provider-runtime-artifact.backend.schemas.d.ts.map +1 -1
  177. package/dist/esm/config/models/provider-runtime-artifact.backend.schemas.js +17 -2
  178. package/dist/esm/config/models/provider-runtime-artifact.backend.schemas.js.map +1 -1
  179. package/dist/esm/config/services/app-configuration-loader.backend.service.d.ts +0 -1
  180. package/dist/esm/config/services/app-configuration-loader.backend.service.d.ts.map +1 -1
  181. package/dist/esm/config/services/app-configuration-loader.backend.service.js +68 -76
  182. package/dist/esm/config/services/app-configuration-loader.backend.service.js.map +1 -1
  183. package/dist/esm/config/services/app-configuration.backend.service.d.ts.map +1 -1
  184. package/dist/esm/config/services/app-configuration.backend.service.js +23 -1
  185. package/dist/esm/config/services/app-configuration.backend.service.js.map +1 -1
  186. package/dist/esm/config/services/app-configuration.backend.utils.d.ts +33 -0
  187. package/dist/esm/config/services/app-configuration.backend.utils.d.ts.map +1 -1
  188. package/dist/esm/config/services/app-configuration.backend.utils.js +39 -1
  189. package/dist/esm/config/services/app-configuration.backend.utils.js.map +1 -1
  190. package/dist/esm/config/services/application-startup-config-validator.backend.service.d.ts +25 -0
  191. package/dist/esm/config/services/application-startup-config-validator.backend.service.d.ts.map +1 -1
  192. package/dist/esm/config/services/application-startup-config-validator.backend.service.js +41 -1
  193. package/dist/esm/config/services/application-startup-config-validator.backend.service.js.map +1 -1
  194. package/dist/esm/databases/services/postgresql-schema-plan-diff.backend.d.ts.map +1 -1
  195. package/dist/esm/databases/services/postgresql-schema-plan-diff.backend.js +48 -0
  196. package/dist/esm/databases/services/postgresql-schema-plan-diff.backend.js.map +1 -1
  197. package/dist/esm/errors/services/error-builder.backend.service.d.ts +13 -1
  198. package/dist/esm/errors/services/error-builder.backend.service.d.ts.map +1 -1
  199. package/dist/esm/errors/services/error-builder.backend.service.js +13 -1
  200. package/dist/esm/errors/services/error-builder.backend.service.js.map +1 -1
  201. package/dist/esm/errors/services/error-handler.backend.service.d.ts +70 -7
  202. package/dist/esm/errors/services/error-handler.backend.service.d.ts.map +1 -1
  203. package/dist/esm/errors/services/error-handler.backend.service.js +129 -8
  204. package/dist/esm/errors/services/error-handler.backend.service.js.map +1 -1
  205. package/dist/esm/errors/services/rate-limit.backend.service.d.ts +66 -0
  206. package/dist/esm/errors/services/rate-limit.backend.service.d.ts.map +1 -1
  207. package/dist/esm/errors/services/rate-limit.backend.service.js +102 -25
  208. package/dist/esm/errors/services/rate-limit.backend.service.js.map +1 -1
  209. package/dist/esm/errors/utils/error-log-level-classification.backend.utils.d.ts +5 -0
  210. package/dist/esm/errors/utils/error-log-level-classification.backend.utils.d.ts.map +1 -1
  211. package/dist/esm/errors/utils/error-log-level-classification.backend.utils.js +25 -0
  212. package/dist/esm/errors/utils/error-log-level-classification.backend.utils.js.map +1 -1
  213. package/dist/esm/errors/utils/rate-limit-environment-relaxation.backend.utils.d.ts +33 -0
  214. package/dist/esm/errors/utils/rate-limit-environment-relaxation.backend.utils.d.ts.map +1 -1
  215. package/dist/esm/errors/utils/rate-limit-environment-relaxation.backend.utils.js +40 -0
  216. package/dist/esm/errors/utils/rate-limit-environment-relaxation.backend.utils.js.map +1 -1
  217. package/dist/esm/external-data/external-data-pipeline-run.backend.service.d.ts +59 -2
  218. package/dist/esm/external-data/external-data-pipeline-run.backend.service.d.ts.map +1 -1
  219. package/dist/esm/external-data/external-data-pipeline-run.backend.service.js +52 -17
  220. package/dist/esm/external-data/external-data-pipeline-run.backend.service.js.map +1 -1
  221. package/dist/esm/external-providers/models/provider-selection-resolution-evidence.backend.definitions.d.ts +4 -2
  222. package/dist/esm/external-providers/models/provider-selection-resolution-evidence.backend.definitions.d.ts.map +1 -1
  223. package/dist/esm/external-providers/models/provider-selection-resolution-evidence.backend.definitions.js.map +1 -1
  224. package/dist/esm/external-providers/operations/provider-operation-executor.backend.service.d.ts +256 -0
  225. package/dist/esm/external-providers/operations/provider-operation-executor.backend.service.d.ts.map +1 -0
  226. package/dist/esm/external-providers/operations/provider-operation-executor.backend.service.js +333 -0
  227. package/dist/esm/external-providers/operations/provider-operation-executor.backend.service.js.map +1 -0
  228. package/dist/esm/external-providers/operations/provider-operation-request.backend.d.ts +56 -0
  229. package/dist/esm/external-providers/operations/provider-operation-request.backend.d.ts.map +1 -0
  230. package/dist/esm/external-providers/operations/provider-operation-request.backend.js +211 -0
  231. package/dist/esm/external-providers/operations/provider-operation-request.backend.js.map +1 -0
  232. package/dist/esm/external-providers/operations/provider-request-signing.backend.d.ts +45 -0
  233. package/dist/esm/external-providers/operations/provider-request-signing.backend.d.ts.map +1 -0
  234. package/dist/esm/external-providers/operations/provider-request-signing.backend.js +216 -0
  235. package/dist/esm/external-providers/operations/provider-request-signing.backend.js.map +1 -0
  236. package/dist/esm/external-providers/operations/provider-rest-call-client.backend.d.ts +56 -0
  237. package/dist/esm/external-providers/operations/provider-rest-call-client.backend.d.ts.map +1 -0
  238. package/dist/esm/external-providers/operations/provider-rest-call-client.backend.js +78 -0
  239. package/dist/esm/external-providers/operations/provider-rest-call-client.backend.js.map +1 -0
  240. package/dist/esm/external-providers/services/__tests__/mock-external-providers-registry.service.d.ts +1 -1
  241. package/dist/esm/external-providers/services/__tests__/mock-external-providers-registry.service.d.ts.map +1 -1
  242. package/dist/esm/external-providers/services/__tests__/mock-external-providers-registry.service.js +2 -2
  243. package/dist/esm/external-providers/services/__tests__/mock-external-providers-registry.service.js.map +1 -1
  244. package/dist/esm/external-providers/services/backend-provider-loader.backend.service.d.ts +89 -0
  245. package/dist/esm/external-providers/services/backend-provider-loader.backend.service.d.ts.map +1 -0
  246. package/dist/esm/external-providers/services/backend-provider-loader.backend.service.js +164 -0
  247. package/dist/esm/external-providers/services/backend-provider-loader.backend.service.js.map +1 -0
  248. package/dist/esm/external-providers/services/backend-provider-registry.backend.service.d.ts +26 -27
  249. package/dist/esm/external-providers/services/backend-provider-registry.backend.service.d.ts.map +1 -1
  250. package/dist/esm/external-providers/services/backend-provider-registry.backend.service.js +50 -64
  251. package/dist/esm/external-providers/services/backend-provider-registry.backend.service.js.map +1 -1
  252. package/dist/esm/external-providers/services/document-extraction.backend.service.d.ts.map +1 -1
  253. package/dist/esm/external-providers/services/document-extraction.backend.service.js +3 -3
  254. package/dist/esm/external-providers/services/document-extraction.backend.service.js.map +1 -1
  255. package/dist/esm/external-providers/services/embeddings.backend.service.d.ts.map +1 -1
  256. package/dist/esm/external-providers/services/embeddings.backend.service.js +4 -4
  257. package/dist/esm/external-providers/services/embeddings.backend.service.js.map +1 -1
  258. package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts +292 -7
  259. package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts.map +1 -1
  260. package/dist/esm/external-providers/services/external-providers-registry.backend.service.js +533 -45
  261. package/dist/esm/external-providers/services/external-providers-registry.backend.service.js.map +1 -1
  262. package/dist/esm/external-providers/services/frontend-bootstrap.backend.service.d.ts.map +1 -1
  263. package/dist/esm/external-providers/services/frontend-bootstrap.backend.service.js +25 -2
  264. package/dist/esm/external-providers/services/frontend-bootstrap.backend.service.js.map +1 -1
  265. package/dist/esm/files/controllers/file.controller.d.ts.map +1 -1
  266. package/dist/esm/files/controllers/file.controller.js +21 -13
  267. package/dist/esm/files/controllers/file.controller.js.map +1 -1
  268. package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.d.ts.map +1 -1
  269. package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.js +39 -15
  270. package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.js.map +1 -1
  271. package/dist/esm/files/services/file-scanning.backend.service.d.ts +94 -9
  272. package/dist/esm/files/services/file-scanning.backend.service.d.ts.map +1 -1
  273. package/dist/esm/files/services/file-scanning.backend.service.js +197 -17
  274. package/dist/esm/files/services/file-scanning.backend.service.js.map +1 -1
  275. package/dist/esm/files/services/file-text-extraction.backend.service.d.ts +60 -1
  276. package/dist/esm/files/services/file-text-extraction.backend.service.d.ts.map +1 -1
  277. package/dist/esm/files/services/file-text-extraction.backend.service.js +167 -8
  278. package/dist/esm/files/services/file-text-extraction.backend.service.js.map +1 -1
  279. package/dist/esm/files/services/file-upload-grant.backend.service.d.ts +53 -2
  280. package/dist/esm/files/services/file-upload-grant.backend.service.d.ts.map +1 -1
  281. package/dist/esm/files/services/file-upload-grant.backend.service.js +127 -3
  282. package/dist/esm/files/services/file-upload-grant.backend.service.js.map +1 -1
  283. package/dist/esm/files/services/files.backend.service.d.ts +68 -0
  284. package/dist/esm/files/services/files.backend.service.d.ts.map +1 -1
  285. package/dist/esm/files/services/files.backend.service.js +175 -5
  286. package/dist/esm/files/services/files.backend.service.js.map +1 -1
  287. package/dist/esm/files/storage/application-storage-key.backend.utils.d.ts +109 -0
  288. package/dist/esm/files/storage/application-storage-key.backend.utils.d.ts.map +1 -0
  289. package/dist/esm/files/storage/application-storage-key.backend.utils.js +123 -0
  290. package/dist/esm/files/storage/application-storage-key.backend.utils.js.map +1 -0
  291. package/dist/esm/files/storage/file-storage-provider.types.d.ts +16 -10
  292. package/dist/esm/files/storage/file-storage-provider.types.d.ts.map +1 -1
  293. package/dist/esm/files/storage/file-storage-provider.types.js.map +1 -1
  294. package/dist/esm/files/storage/local-directory-storage-provider.backend.service.d.ts +67 -8
  295. package/dist/esm/files/storage/local-directory-storage-provider.backend.service.d.ts.map +1 -1
  296. package/dist/esm/files/storage/local-directory-storage-provider.backend.service.js +101 -28
  297. package/dist/esm/files/storage/local-directory-storage-provider.backend.service.js.map +1 -1
  298. package/dist/esm/files/storage/wildo-managed-storage-provider.backend.service.d.ts.map +1 -1
  299. package/dist/esm/files/storage/wildo-managed-storage-provider.backend.service.js +8 -55
  300. package/dist/esm/files/storage/wildo-managed-storage-provider.backend.service.js.map +1 -1
  301. package/dist/esm/files/utils/file-field-schema-path.backend.utils.d.ts.map +1 -1
  302. package/dist/esm/files/utils/file-field-schema-path.backend.utils.js +20 -0
  303. package/dist/esm/files/utils/file-field-schema-path.backend.utils.js.map +1 -1
  304. package/dist/esm/files/utils/office-document-text-extraction.backend.utils.d.ts +86 -0
  305. package/dist/esm/files/utils/office-document-text-extraction.backend.utils.d.ts.map +1 -0
  306. package/dist/esm/files/utils/office-document-text-extraction.backend.utils.js +288 -0
  307. package/dist/esm/files/utils/office-document-text-extraction.backend.utils.js.map +1 -0
  308. package/dist/esm/flows-actors/a2a/batches/a2a-abandoned-task-sweep.batch.backend.service.d.ts +15 -0
  309. package/dist/esm/flows-actors/a2a/batches/a2a-abandoned-task-sweep.batch.backend.service.d.ts.map +1 -1
  310. package/dist/esm/flows-actors/a2a/batches/a2a-abandoned-task-sweep.batch.backend.service.js +76 -5
  311. package/dist/esm/flows-actors/a2a/batches/a2a-abandoned-task-sweep.batch.backend.service.js.map +1 -1
  312. package/dist/esm/flows-actors/a2a/controllers/a2a.controller.d.ts.map +1 -1
  313. package/dist/esm/flows-actors/a2a/controllers/a2a.controller.js +6 -1
  314. package/dist/esm/flows-actors/a2a/controllers/a2a.controller.js.map +1 -1
  315. package/dist/esm/flows-actors/a2a/models/a2a.backend.schemas.d.ts +60 -0
  316. package/dist/esm/flows-actors/a2a/models/a2a.backend.schemas.d.ts.map +1 -1
  317. package/dist/esm/flows-actors/a2a/models/a2a.backend.schemas.js +63 -0
  318. package/dist/esm/flows-actors/a2a/models/a2a.backend.schemas.js.map +1 -1
  319. package/dist/esm/flows-actors/a2a/services/a2a-task-cancellation.backend.service.d.ts +74 -0
  320. package/dist/esm/flows-actors/a2a/services/a2a-task-cancellation.backend.service.d.ts.map +1 -1
  321. package/dist/esm/flows-actors/a2a/services/a2a-task-cancellation.backend.service.js +196 -40
  322. package/dist/esm/flows-actors/a2a/services/a2a-task-cancellation.backend.service.js.map +1 -1
  323. package/dist/esm/flows-actors/a2a/services/a2a-task.backend.service.d.ts +7 -1
  324. package/dist/esm/flows-actors/a2a/services/a2a-task.backend.service.d.ts.map +1 -1
  325. package/dist/esm/flows-actors/a2a/services/a2a-task.backend.service.js +53 -1
  326. package/dist/esm/flows-actors/a2a/services/a2a-task.backend.service.js.map +1 -1
  327. package/dist/esm/flows-actors/a2a/services/a2a-token-budget.backend.service.d.ts +18 -0
  328. package/dist/esm/flows-actors/a2a/services/a2a-token-budget.backend.service.d.ts.map +1 -1
  329. package/dist/esm/flows-actors/a2a/services/a2a-token-budget.backend.service.js +18 -0
  330. package/dist/esm/flows-actors/a2a/services/a2a-token-budget.backend.service.js.map +1 -1
  331. package/dist/esm/flows-actors/a2a/services/a2a.backend.service.d.ts +12 -7
  332. package/dist/esm/flows-actors/a2a/services/a2a.backend.service.d.ts.map +1 -1
  333. package/dist/esm/flows-actors/a2a/services/a2a.backend.service.js.map +1 -1
  334. package/dist/esm/flows-actors/models/agent-catalogs.backend.definitions.d.ts +0 -13
  335. package/dist/esm/flows-actors/models/agent-catalogs.backend.definitions.d.ts.map +1 -1
  336. package/dist/esm/flows-actors/models/agent-catalogs.backend.definitions.js +14 -22
  337. package/dist/esm/flows-actors/models/agent-catalogs.backend.definitions.js.map +1 -1
  338. package/dist/esm/flows-actors/models/core-facets.backend.definitions.d.ts +8 -3
  339. package/dist/esm/flows-actors/models/core-facets.backend.definitions.d.ts.map +1 -1
  340. package/dist/esm/flows-actors/models/core-facets.backend.definitions.js +25 -15
  341. package/dist/esm/flows-actors/models/core-facets.backend.definitions.js.map +1 -1
  342. package/dist/esm/flows-actors/models/flows-actors.backend.schemas.d.ts +13 -1
  343. package/dist/esm/flows-actors/models/flows-actors.backend.schemas.d.ts.map +1 -1
  344. package/dist/esm/flows-actors/models/flows-actors.backend.schemas.js.map +1 -1
  345. package/dist/esm/flows-actors/models/function-tools.backend.definitions.d.ts +88 -8
  346. package/dist/esm/flows-actors/models/function-tools.backend.definitions.d.ts.map +1 -1
  347. package/dist/esm/flows-actors/models/function-tools.backend.definitions.js +333 -31
  348. package/dist/esm/flows-actors/models/function-tools.backend.definitions.js.map +1 -1
  349. package/dist/esm/flows-actors/models/market-generation.actors-system.backend.definitions.d.ts.map +1 -1
  350. package/dist/esm/flows-actors/models/market-generation.actors-system.backend.definitions.js +4 -2
  351. package/dist/esm/flows-actors/models/market-generation.actors-system.backend.definitions.js.map +1 -1
  352. package/dist/esm/flows-actors/models/mcp-client.backend.definitions.d.ts +113 -0
  353. package/dist/esm/flows-actors/models/mcp-client.backend.definitions.d.ts.map +1 -0
  354. package/dist/esm/flows-actors/models/mcp-client.backend.definitions.js +62 -0
  355. package/dist/esm/flows-actors/models/mcp-client.backend.definitions.js.map +1 -0
  356. package/dist/esm/flows-actors/services/actors-system.backend.service.d.ts.map +1 -1
  357. package/dist/esm/flows-actors/services/actors-system.backend.service.js +0 -2
  358. package/dist/esm/flows-actors/services/actors-system.backend.service.js.map +1 -1
  359. package/dist/esm/flows-actors/services/agents.backend.service.d.ts +28 -1
  360. package/dist/esm/flows-actors/services/agents.backend.service.d.ts.map +1 -1
  361. package/dist/esm/flows-actors/services/agents.backend.service.js +204 -18
  362. package/dist/esm/flows-actors/services/agents.backend.service.js.map +1 -1
  363. package/dist/esm/flows-actors/services/conversational-execution.backend.service.d.ts +5 -1
  364. package/dist/esm/flows-actors/services/conversational-execution.backend.service.d.ts.map +1 -1
  365. package/dist/esm/flows-actors/services/conversational-execution.backend.service.js +79 -16
  366. package/dist/esm/flows-actors/services/conversational-execution.backend.service.js.map +1 -1
  367. package/dist/esm/flows-actors/services/flows-actors-registry.service.d.ts +34 -5
  368. package/dist/esm/flows-actors/services/flows-actors-registry.service.d.ts.map +1 -1
  369. package/dist/esm/flows-actors/services/flows-actors-registry.service.js +154 -20
  370. package/dist/esm/flows-actors/services/flows-actors-registry.service.js.map +1 -1
  371. package/dist/esm/flows-actors/services/flows.backend.services.d.ts.map +1 -1
  372. package/dist/esm/flows-actors/services/flows.backend.services.js +27 -23
  373. package/dist/esm/flows-actors/services/flows.backend.services.js.map +1 -1
  374. package/dist/esm/flows-actors/services/llm-observability-agent-call-trace-sink.backend.d.ts.map +1 -1
  375. package/dist/esm/flows-actors/services/llm-observability-agent-call-trace-sink.backend.js +7 -1
  376. package/dist/esm/flows-actors/services/llm-observability-agent-call-trace-sink.backend.js.map +1 -1
  377. package/dist/esm/flows-actors/services/mcp-client.backend.service.d.ts +90 -0
  378. package/dist/esm/flows-actors/services/mcp-client.backend.service.d.ts.map +1 -0
  379. package/dist/esm/flows-actors/services/mcp-client.backend.service.js +368 -0
  380. package/dist/esm/flows-actors/services/mcp-client.backend.service.js.map +1 -0
  381. package/dist/esm/flows-actors/services/prompt-compiler.backend.service.d.ts +9 -5
  382. package/dist/esm/flows-actors/services/prompt-compiler.backend.service.d.ts.map +1 -1
  383. package/dist/esm/flows-actors/services/prompt-compiler.backend.service.js +12 -17
  384. package/dist/esm/flows-actors/services/prompt-compiler.backend.service.js.map +1 -1
  385. package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.d.ts.map +1 -1
  386. package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.js +8 -4
  387. package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.js.map +1 -1
  388. package/dist/esm/flows-actors/utils/meta-workflow-canonical-json.backend.utils.d.ts +0 -207
  389. package/dist/esm/flows-actors/utils/meta-workflow-canonical-json.backend.utils.d.ts.map +1 -1
  390. package/dist/esm/flows-actors/utils/meta-workflow-canonical-json.backend.utils.js +8 -243
  391. package/dist/esm/flows-actors/utils/meta-workflow-canonical-json.backend.utils.js.map +1 -1
  392. package/dist/esm/flows-actors/utils/meta-workflow-structured-generation-plan.backend.utils.d.ts.map +1 -1
  393. package/dist/esm/flows-actors/utils/meta-workflow-structured-generation-plan.backend.utils.js.map +1 -1
  394. package/dist/esm/guidance/services/milestone-evaluator.backend.service.d.ts +9 -14
  395. package/dist/esm/guidance/services/milestone-evaluator.backend.service.d.ts.map +1 -1
  396. package/dist/esm/guidance/services/milestone-evaluator.backend.service.js +18 -89
  397. package/dist/esm/guidance/services/milestone-evaluator.backend.service.js.map +1 -1
  398. package/dist/esm/guidance/services/progression-state-store.backend.service.d.ts +86 -0
  399. package/dist/esm/guidance/services/progression-state-store.backend.service.d.ts.map +1 -0
  400. package/dist/esm/guidance/services/progression-state-store.backend.service.js +155 -0
  401. package/dist/esm/guidance/services/progression-state-store.backend.service.js.map +1 -0
  402. package/dist/esm/i18n/controllers/i18n-controller.backend.service.d.ts +10 -0
  403. package/dist/esm/i18n/controllers/i18n-controller.backend.service.d.ts.map +1 -1
  404. package/dist/esm/i18n/controllers/i18n-controller.backend.service.js +55 -5
  405. package/dist/esm/i18n/controllers/i18n-controller.backend.service.js.map +1 -1
  406. package/dist/esm/index.d.ts +11 -4
  407. package/dist/esm/index.d.ts.map +1 -1
  408. package/dist/esm/index.js +31 -4
  409. package/dist/esm/index.js.map +1 -1
  410. package/dist/esm/inject/models/container.d.ts.map +1 -1
  411. package/dist/esm/inject/models/container.js +78 -10
  412. package/dist/esm/inject/models/container.js.map +1 -1
  413. package/dist/esm/inject/models/service-types.d.ts +17 -3
  414. package/dist/esm/inject/models/service-types.d.ts.map +1 -1
  415. package/dist/esm/inject/models/service-types.js +19 -3
  416. package/dist/esm/inject/models/service-types.js.map +1 -1
  417. package/dist/esm/mcp/controllers/mcp.controller.d.ts.map +1 -1
  418. package/dist/esm/mcp/controllers/mcp.controller.js +20 -0
  419. package/dist/esm/mcp/controllers/mcp.controller.js.map +1 -1
  420. package/dist/esm/mcp/services/mcp-server.backend.service.d.ts +56 -1
  421. package/dist/esm/mcp/services/mcp-server.backend.service.d.ts.map +1 -1
  422. package/dist/esm/mcp/services/mcp-server.backend.service.js +107 -11
  423. package/dist/esm/mcp/services/mcp-server.backend.service.js.map +1 -1
  424. package/dist/esm/mcp/services/mcp-tool-adapter.backend.service.d.ts.map +1 -1
  425. package/dist/esm/mcp/services/mcp-tool-adapter.backend.service.js +22 -0
  426. package/dist/esm/mcp/services/mcp-tool-adapter.backend.service.js.map +1 -1
  427. package/dist/esm/monitoring/analytics/controllers/analytics.backend.controller.d.ts.map +1 -1
  428. package/dist/esm/monitoring/analytics/controllers/analytics.backend.controller.js +49 -4
  429. package/dist/esm/monitoring/analytics/controllers/analytics.backend.controller.js.map +1 -1
  430. package/dist/esm/monitoring/analytics/services/value-moment-definition-registry.backend.service.d.ts +66 -0
  431. package/dist/esm/monitoring/analytics/services/value-moment-definition-registry.backend.service.d.ts.map +1 -0
  432. package/dist/esm/monitoring/analytics/services/value-moment-definition-registry.backend.service.js +199 -0
  433. package/dist/esm/monitoring/analytics/services/value-moment-definition-registry.backend.service.js.map +1 -0
  434. package/dist/esm/monitoring/analytics/services/value-moment-engine.backend.service.d.ts +149 -13
  435. package/dist/esm/monitoring/analytics/services/value-moment-engine.backend.service.d.ts.map +1 -1
  436. package/dist/esm/monitoring/analytics/services/value-moment-engine.backend.service.js +411 -19
  437. package/dist/esm/monitoring/analytics/services/value-moment-engine.backend.service.js.map +1 -1
  438. package/dist/esm/monitoring/analytics/services/value-moment-handler-registry.backend.service.d.ts +11 -2
  439. package/dist/esm/monitoring/analytics/services/value-moment-handler-registry.backend.service.d.ts.map +1 -1
  440. package/dist/esm/monitoring/analytics/services/value-moment-handler-registry.backend.service.js.map +1 -1
  441. package/dist/esm/monitoring/logger/models/logger.backend.schemas.d.ts +28 -9
  442. package/dist/esm/monitoring/logger/models/logger.backend.schemas.d.ts.map +1 -1
  443. package/dist/esm/monitoring/logger/models/logger.backend.schemas.js +30 -10
  444. package/dist/esm/monitoring/logger/models/logger.backend.schemas.js.map +1 -1
  445. package/dist/esm/monitoring/logger/services/logger.service.d.ts +12 -0
  446. package/dist/esm/monitoring/logger/services/logger.service.d.ts.map +1 -1
  447. package/dist/esm/monitoring/logger/services/logger.service.js +52 -11
  448. package/dist/esm/monitoring/logger/services/logger.service.js.map +1 -1
  449. package/dist/esm/monitoring/logger/utils/log-severity-floor.backend.utils.d.ts +62 -0
  450. package/dist/esm/monitoring/logger/utils/log-severity-floor.backend.utils.d.ts.map +1 -0
  451. package/dist/esm/monitoring/logger/utils/log-severity-floor.backend.utils.js +78 -0
  452. package/dist/esm/monitoring/logger/utils/log-severity-floor.backend.utils.js.map +1 -0
  453. package/dist/esm/monitoring/observability/audit-observation-emission.backend.d.ts +309 -0
  454. package/dist/esm/monitoring/observability/audit-observation-emission.backend.d.ts.map +1 -0
  455. package/dist/esm/monitoring/observability/audit-observation-emission.backend.js +385 -0
  456. package/dist/esm/monitoring/observability/audit-observation-emission.backend.js.map +1 -0
  457. package/dist/esm/monitoring/observability/models/observability.backend.schemas.d.ts +1 -0
  458. package/dist/esm/monitoring/observability/models/observability.backend.schemas.d.ts.map +1 -1
  459. package/dist/esm/monitoring/observability/models/observability.backend.schemas.js.map +1 -1
  460. package/dist/esm/monitoring/observability/services/metrics.service.d.ts +21 -0
  461. package/dist/esm/monitoring/observability/services/metrics.service.d.ts.map +1 -1
  462. package/dist/esm/monitoring/observability/services/metrics.service.js +38 -0
  463. package/dist/esm/monitoring/observability/services/metrics.service.js.map +1 -1
  464. package/dist/esm/notifications/email/models/email-context-provider.interface.d.ts +0 -80
  465. package/dist/esm/notifications/email/models/email-context-provider.interface.d.ts.map +0 -1
  466. package/dist/esm/notifications/email/models/email-context-provider.interface.js +0 -25
  467. package/dist/esm/notifications/email/models/email-context-provider.interface.js.map +0 -1
  468. package/dist/esm/notifications/email/services/email-context-provider-registry.backend.service.d.ts +0 -49
  469. package/dist/esm/notifications/email/services/email-context-provider-registry.backend.service.d.ts.map +0 -1
  470. package/dist/esm/notifications/email/services/email-context-provider-registry.backend.service.js +0 -141
  471. package/dist/esm/notifications/email/services/email-context-provider-registry.backend.service.js.map +0 -1
  472. package/dist/esm/notifications/email/services/email-template-compiler.backend.service.d.ts +0 -37
  473. package/dist/esm/notifications/email/services/email-template-compiler.backend.service.d.ts.map +0 -1
  474. package/dist/esm/notifications/email/services/email-template-compiler.backend.service.js +0 -121
  475. package/dist/esm/notifications/email/services/email-template-compiler.backend.service.js.map +0 -1
  476. package/dist/esm/notifications/email/services/email-template-registry.backend.service.d.ts +66 -1
  477. package/dist/esm/notifications/email/services/email-template-registry.backend.service.d.ts.map +1 -1
  478. package/dist/esm/notifications/email/services/email-template-registry.backend.service.js +105 -10
  479. package/dist/esm/notifications/email/services/email-template-registry.backend.service.js.map +1 -1
  480. package/dist/esm/notifications/email/services/email-template-sandbox.backend.service.d.ts +0 -58
  481. package/dist/esm/notifications/email/services/email-template-sandbox.backend.service.d.ts.map +0 -1
  482. package/dist/esm/notifications/email/services/email-template-sandbox.backend.service.js +0 -223
  483. package/dist/esm/notifications/email/services/email-template-sandbox.backend.service.js.map +0 -1
  484. package/dist/esm/notifications/email/services/email-template-validator.backend.service.d.ts.map +1 -1
  485. package/dist/esm/notifications/email/services/email-template-validator.backend.service.js +10 -1
  486. package/dist/esm/notifications/email/services/email-template-validator.backend.service.js.map +1 -1
  487. package/dist/esm/notifications/email/services/email.backend.service.d.ts +60 -4
  488. package/dist/esm/notifications/email/services/email.backend.service.d.ts.map +1 -1
  489. package/dist/esm/notifications/email/services/email.backend.service.js +145 -43
  490. package/dist/esm/notifications/email/services/email.backend.service.js.map +1 -1
  491. package/dist/esm/notifications/email/utils/color-conversion.utils.d.ts +0 -1
  492. package/dist/esm/notifications/email/utils/color-conversion.utils.d.ts.map +1 -1
  493. package/dist/esm/notifications/email/utils/color-conversion.utils.js.map +1 -1
  494. package/dist/esm/notifications/services/notification-badge.backend.service.d.ts +142 -21
  495. package/dist/esm/notifications/services/notification-badge.backend.service.d.ts.map +1 -1
  496. package/dist/esm/notifications/services/notification-badge.backend.service.js +283 -58
  497. package/dist/esm/notifications/services/notification-badge.backend.service.js.map +1 -1
  498. package/dist/esm/notifications/services/notifications-dispatcher.backend.service.d.ts +99 -13
  499. package/dist/esm/notifications/services/notifications-dispatcher.backend.service.d.ts.map +1 -1
  500. package/dist/esm/notifications/services/notifications-dispatcher.backend.service.js +422 -66
  501. package/dist/esm/notifications/services/notifications-dispatcher.backend.service.js.map +1 -1
  502. package/dist/esm/notifications/sms/services/sms.backend.service.d.ts +2 -2
  503. package/dist/esm/notifications/sms/services/sms.backend.service.d.ts.map +1 -1
  504. package/dist/esm/notifications/sms/services/sms.backend.service.js +5 -5
  505. package/dist/esm/notifications/sms/services/sms.backend.service.js.map +1 -1
  506. package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.d.ts +117 -5
  507. package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.d.ts.map +1 -1
  508. package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.js +164 -6
  509. package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.js.map +1 -1
  510. package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.backend.service.d.ts +0 -6
  511. package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.backend.service.d.ts.map +1 -1
  512. package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.backend.service.js +46 -1
  513. package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.backend.service.js.map +1 -1
  514. package/dist/esm/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.d.ts.map +1 -1
  515. package/dist/esm/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.js +16 -6
  516. package/dist/esm/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.js.map +1 -1
  517. package/dist/esm/notifications/webhooks/outbound/services/webhook-config-test-endpoint.custom-impl.backend.service.d.ts.map +1 -1
  518. package/dist/esm/notifications/webhooks/outbound/services/webhook-config-test-endpoint.custom-impl.backend.service.js +12 -12
  519. package/dist/esm/notifications/webhooks/outbound/services/webhook-config-test-endpoint.custom-impl.backend.service.js.map +1 -1
  520. package/dist/esm/notifications/webhooks/services/webhook-handler.backend.service.d.ts +16 -0
  521. package/dist/esm/notifications/webhooks/services/webhook-handler.backend.service.d.ts.map +1 -1
  522. package/dist/esm/notifications/webhooks/services/webhook-handler.backend.service.js +18 -0
  523. package/dist/esm/notifications/webhooks/services/webhook-handler.backend.service.js.map +1 -1
  524. package/dist/esm/organizations/batches/organization-purge.batch.backend.service.d.ts +2 -2
  525. package/dist/esm/organizations/batches/organization-purge.batch.backend.service.js +2 -2
  526. package/dist/esm/organizations/batches/organization-purge.batch.backend.service.js.map +1 -1
  527. package/dist/esm/organizations/services/organization-custom-implementation.backend.service.d.ts.map +1 -1
  528. package/dist/esm/organizations/services/organization-custom-implementation.backend.service.js +63 -2
  529. package/dist/esm/organizations/services/organization-custom-implementation.backend.service.js.map +1 -1
  530. package/dist/esm/queue/adapters/in-memory-queue-adapter.backend.service.d.ts +66 -0
  531. package/dist/esm/queue/adapters/in-memory-queue-adapter.backend.service.d.ts.map +1 -0
  532. package/dist/esm/queue/adapters/in-memory-queue-adapter.backend.service.js +257 -0
  533. package/dist/esm/queue/adapters/in-memory-queue-adapter.backend.service.js.map +1 -0
  534. package/dist/esm/queue/adapters/queue-adapter.backend.binding.d.ts +12 -0
  535. package/dist/esm/queue/adapters/queue-adapter.backend.binding.d.ts.map +1 -0
  536. package/dist/esm/queue/adapters/queue-adapter.backend.binding.js +47 -0
  537. package/dist/esm/queue/adapters/queue-adapter.backend.binding.js.map +1 -0
  538. package/dist/esm/queue/adapters/queue-adapter.backend.interface.d.ts +87 -0
  539. package/dist/esm/queue/adapters/queue-adapter.backend.interface.d.ts.map +1 -0
  540. package/dist/esm/queue/adapters/queue-adapter.backend.interface.js +1 -0
  541. package/dist/esm/queue/adapters/queue-adapter.backend.interface.js.map +1 -0
  542. package/dist/esm/queue/adapters/queue-adapter.backend.options.d.ts +31 -0
  543. package/dist/esm/queue/adapters/queue-adapter.backend.options.d.ts.map +1 -0
  544. package/dist/esm/queue/adapters/queue-adapter.backend.options.js +13 -0
  545. package/dist/esm/queue/adapters/queue-adapter.backend.options.js.map +1 -0
  546. package/dist/esm/queue/adapters/rabbitmq-adapter.backend.service.d.ts +19 -25
  547. package/dist/esm/queue/adapters/rabbitmq-adapter.backend.service.d.ts.map +1 -1
  548. package/dist/esm/queue/adapters/rabbitmq-adapter.backend.service.js +33 -0
  549. package/dist/esm/queue/adapters/rabbitmq-adapter.backend.service.js.map +1 -1
  550. package/dist/esm/queue/domain-queue-consumer.backend.service.d.ts +2 -2
  551. package/dist/esm/queue/domain-queue-consumer.backend.service.d.ts.map +1 -1
  552. package/dist/esm/queue/domain-queue-consumer.backend.service.js +1 -4
  553. package/dist/esm/queue/domain-queue-consumer.backend.service.js.map +1 -1
  554. package/dist/esm/queue/job-consumer.backend.service.d.ts +2 -2
  555. package/dist/esm/queue/job-consumer.backend.service.d.ts.map +1 -1
  556. package/dist/esm/queue/job-consumer.backend.service.js +1 -4
  557. package/dist/esm/queue/job-consumer.backend.service.js.map +1 -1
  558. package/dist/esm/queue/job-executor.backend.service.d.ts +2 -2
  559. package/dist/esm/queue/job-executor.backend.service.d.ts.map +1 -1
  560. package/dist/esm/queue/job-executor.backend.service.js +1 -4
  561. package/dist/esm/queue/job-executor.backend.service.js.map +1 -1
  562. package/dist/esm/queue/queue-monitoring.backend.service.d.ts +8 -4
  563. package/dist/esm/queue/queue-monitoring.backend.service.d.ts.map +1 -1
  564. package/dist/esm/queue/queue-monitoring.backend.service.js +25 -17
  565. package/dist/esm/queue/queue-monitoring.backend.service.js.map +1 -1
  566. package/dist/esm/queue/queue-worker-initializer.backend.service.d.ts +16 -1
  567. package/dist/esm/queue/queue-worker-initializer.backend.service.d.ts.map +1 -1
  568. package/dist/esm/queue/queue-worker-initializer.backend.service.js +16 -1
  569. package/dist/esm/queue/queue-worker-initializer.backend.service.js.map +1 -1
  570. package/dist/esm/queue/queue.backend.service.d.ts +3 -3
  571. package/dist/esm/queue/queue.backend.service.d.ts.map +1 -1
  572. package/dist/esm/queue/queue.backend.service.js +26 -4
  573. package/dist/esm/queue/queue.backend.service.js.map +1 -1
  574. package/dist/esm/queue/worker-shutdown-manager.backend.service.d.ts +2 -2
  575. package/dist/esm/queue/worker-shutdown-manager.backend.service.d.ts.map +1 -1
  576. package/dist/esm/queue/worker-shutdown-manager.backend.service.js +18 -3
  577. package/dist/esm/queue/worker-shutdown-manager.backend.service.js.map +1 -1
  578. package/dist/esm/rag/utils/rag-chunking.backend.utils.d.ts +50 -25
  579. package/dist/esm/rag/utils/rag-chunking.backend.utils.d.ts.map +1 -1
  580. package/dist/esm/rag/utils/rag-chunking.backend.utils.js +147 -39
  581. package/dist/esm/rag/utils/rag-chunking.backend.utils.js.map +1 -1
  582. package/dist/esm/rag/utils/rag-context-assembly.backend.utils.d.ts +12 -3
  583. package/dist/esm/rag/utils/rag-context-assembly.backend.utils.d.ts.map +1 -1
  584. package/dist/esm/rag/utils/rag-context-assembly.backend.utils.js +12 -3
  585. package/dist/esm/rag/utils/rag-context-assembly.backend.utils.js.map +1 -1
  586. package/dist/esm/requests/service/websocket.service.d.ts +9 -0
  587. package/dist/esm/requests/service/websocket.service.d.ts.map +1 -1
  588. package/dist/esm/requests/service/websocket.service.js +32 -8
  589. package/dist/esm/requests/service/websocket.service.js.map +1 -1
  590. package/dist/esm/resources/models/custom-service-implementations.backend.definition.d.ts.map +1 -1
  591. package/dist/esm/resources/models/custom-service-implementations.backend.definition.js +14 -2
  592. package/dist/esm/resources/models/custom-service-implementations.backend.definition.js.map +1 -1
  593. package/dist/esm/resources/models/resources-operations.backend.definitions.d.ts.map +1 -1
  594. package/dist/esm/resources/models/resources-operations.backend.definitions.js +2 -0
  595. package/dist/esm/resources/models/resources-operations.backend.definitions.js.map +1 -1
  596. package/dist/esm/resources/models/resources-relationships.backend.definitions.d.ts.map +1 -1
  597. package/dist/esm/resources/models/resources-relationships.backend.definitions.js +14 -0
  598. package/dist/esm/resources/models/resources-relationships.backend.definitions.js.map +1 -1
  599. package/dist/esm/resources/models/resources-types.backend.schemas.d.ts +2 -1
  600. package/dist/esm/resources/models/resources-types.backend.schemas.d.ts.map +1 -1
  601. package/dist/esm/resources/models/resources-types.backend.schemas.js +8 -0
  602. package/dist/esm/resources/models/resources-types.backend.schemas.js.map +1 -1
  603. package/dist/esm/resources/services/resources-registry.backend.service.d.ts +60 -5
  604. package/dist/esm/resources/services/resources-registry.backend.service.d.ts.map +1 -1
  605. package/dist/esm/resources/services/resources-registry.backend.service.js +90 -6
  606. package/dist/esm/resources/services/resources-registry.backend.service.js.map +1 -1
  607. package/dist/esm/runtime/controllers/health-controller.backend.service.d.ts +36 -3
  608. package/dist/esm/runtime/controllers/health-controller.backend.service.d.ts.map +1 -1
  609. package/dist/esm/runtime/controllers/health-controller.backend.service.js +32 -10
  610. package/dist/esm/runtime/controllers/health-controller.backend.service.js.map +1 -1
  611. package/dist/esm/runtime/domain-module.backend.definitions.d.ts +24 -0
  612. package/dist/esm/runtime/domain-module.backend.definitions.d.ts.map +1 -1
  613. package/dist/esm/runtime/domain-module.backend.definitions.js +24 -0
  614. package/dist/esm/runtime/domain-module.backend.definitions.js.map +1 -1
  615. package/dist/esm/runtime/services/health-readiness-contributor.backend.interface.d.ts +51 -0
  616. package/dist/esm/runtime/services/health-readiness-contributor.backend.interface.d.ts.map +1 -1
  617. package/dist/esm/runtime/services/health-readiness-contributor.backend.interface.js.map +1 -1
  618. package/dist/esm/runtime/services/http-server.backend.service.d.ts +26 -0
  619. package/dist/esm/runtime/services/http-server.backend.service.d.ts.map +1 -1
  620. package/dist/esm/runtime/services/http-server.backend.service.js +181 -1
  621. package/dist/esm/runtime/services/http-server.backend.service.js.map +1 -1
  622. package/dist/esm/runtime/services/start-application.backend.service.d.ts +19 -1
  623. package/dist/esm/runtime/services/start-application.backend.service.d.ts.map +1 -1
  624. package/dist/esm/runtime/services/start-application.backend.service.js +261 -77
  625. package/dist/esm/runtime/services/start-application.backend.service.js.map +1 -1
  626. package/dist/esm/security/api-keys/api-keys.custom-impl.backend.service.d.ts +15 -0
  627. package/dist/esm/security/api-keys/api-keys.custom-impl.backend.service.d.ts.map +1 -1
  628. package/dist/esm/security/api-keys/api-keys.custom-impl.backend.service.js +28 -0
  629. package/dist/esm/security/api-keys/api-keys.custom-impl.backend.service.js.map +1 -1
  630. package/dist/esm/security/authentications/batches/anonymous-session-cleanup.batch.backend.service.d.ts +5 -1
  631. package/dist/esm/security/authentications/batches/anonymous-session-cleanup.batch.backend.service.d.ts.map +1 -1
  632. package/dist/esm/security/authentications/batches/anonymous-session-cleanup.batch.backend.service.js +24 -4
  633. package/dist/esm/security/authentications/batches/anonymous-session-cleanup.batch.backend.service.js.map +1 -1
  634. package/dist/esm/security/authentications/controllers/authentication-controller.backend.service.d.ts.map +1 -1
  635. package/dist/esm/security/authentications/controllers/authentication-controller.backend.service.js +29 -4
  636. package/dist/esm/security/authentications/controllers/authentication-controller.backend.service.js.map +1 -1
  637. package/dist/esm/security/authentications/controllers/oauth-provider-controller.backend.service.d.ts +114 -0
  638. package/dist/esm/security/authentications/controllers/oauth-provider-controller.backend.service.d.ts.map +1 -1
  639. package/dist/esm/security/authentications/controllers/oauth-provider-controller.backend.service.js +354 -3
  640. package/dist/esm/security/authentications/controllers/oauth-provider-controller.backend.service.js.map +1 -1
  641. package/dist/esm/security/authentications/models/cimd.backend.schemas.d.ts +1 -0
  642. package/dist/esm/security/authentications/models/cimd.backend.schemas.d.ts.map +1 -1
  643. package/dist/esm/security/authentications/models/cimd.backend.schemas.js +22 -0
  644. package/dist/esm/security/authentications/models/cimd.backend.schemas.js.map +1 -1
  645. package/dist/esm/security/authentications/models/oauth2-connection.backend.schemas.d.ts +15 -0
  646. package/dist/esm/security/authentications/models/oauth2-connection.backend.schemas.d.ts.map +1 -1
  647. package/dist/esm/security/authentications/models/oauth2-connection.backend.schemas.js.map +1 -1
  648. package/dist/esm/security/authentications/services/admin-config/auth-organization-configuration.service.d.ts +0 -2
  649. package/dist/esm/security/authentications/services/admin-config/auth-organization-configuration.service.d.ts.map +1 -1
  650. package/dist/esm/security/authentications/services/admin-config/auth-organization-configuration.service.js +23 -14
  651. package/dist/esm/security/authentications/services/admin-config/auth-organization-configuration.service.js.map +1 -1
  652. package/dist/esm/security/authentications/services/admin-config/domain-to-org-lookup.backend.service.d.ts +0 -1
  653. package/dist/esm/security/authentications/services/admin-config/domain-to-org-lookup.backend.service.d.ts.map +1 -1
  654. package/dist/esm/security/authentications/services/admin-config/domain-to-org-lookup.backend.service.js +15 -12
  655. package/dist/esm/security/authentications/services/admin-config/domain-to-org-lookup.backend.service.js.map +1 -1
  656. package/dist/esm/security/authentications/services/admin-config/domain-verification.backend.service.d.ts +113 -3
  657. package/dist/esm/security/authentications/services/admin-config/domain-verification.backend.service.d.ts.map +1 -1
  658. package/dist/esm/security/authentications/services/admin-config/domain-verification.backend.service.js +207 -30
  659. package/dist/esm/security/authentications/services/admin-config/domain-verification.backend.service.js.map +1 -1
  660. package/dist/esm/security/authentications/services/admin-config/enterprise-user-provisioning.backend.service.d.ts +95 -2
  661. package/dist/esm/security/authentications/services/admin-config/enterprise-user-provisioning.backend.service.d.ts.map +1 -1
  662. package/dist/esm/security/authentications/services/admin-config/enterprise-user-provisioning.backend.service.js +153 -9
  663. package/dist/esm/security/authentications/services/admin-config/enterprise-user-provisioning.backend.service.js.map +1 -1
  664. package/dist/esm/security/authentications/services/anonymous-session.backend.service.d.ts +190 -0
  665. package/dist/esm/security/authentications/services/anonymous-session.backend.service.d.ts.map +1 -1
  666. package/dist/esm/security/authentications/services/anonymous-session.backend.service.js +377 -53
  667. package/dist/esm/security/authentications/services/anonymous-session.backend.service.js.map +1 -1
  668. package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.d.ts.map +1 -1
  669. package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.js +68 -1
  670. package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.js.map +1 -1
  671. package/dist/esm/security/authentications/services/auth-methods/auth-registration.backend.service.d.ts +41 -0
  672. package/dist/esm/security/authentications/services/auth-methods/auth-registration.backend.service.d.ts.map +1 -1
  673. package/dist/esm/security/authentications/services/auth-methods/auth-registration.backend.service.js +202 -23
  674. package/dist/esm/security/authentications/services/auth-methods/auth-registration.backend.service.js.map +1 -1
  675. package/dist/esm/security/authentications/services/auth-methods/oauth2-authentication.backend.service.d.ts.map +1 -1
  676. package/dist/esm/security/authentications/services/auth-methods/oauth2-authentication.backend.service.js +42 -1
  677. package/dist/esm/security/authentications/services/auth-methods/oauth2-authentication.backend.service.js.map +1 -1
  678. package/dist/esm/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service.d.ts.map +1 -1
  679. package/dist/esm/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service.js +34 -4
  680. package/dist/esm/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service.js.map +1 -1
  681. package/dist/esm/security/authentications/services/auth-methods/webauthn.backend.service.d.ts +29 -5
  682. package/dist/esm/security/authentications/services/auth-methods/webauthn.backend.service.d.ts.map +1 -1
  683. package/dist/esm/security/authentications/services/auth-methods/webauthn.backend.service.js +77 -5
  684. package/dist/esm/security/authentications/services/auth-methods/webauthn.backend.service.js.map +1 -1
  685. package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.d.ts +17 -1
  686. package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.d.ts.map +1 -1
  687. package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.js +49 -17
  688. package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.js.map +1 -1
  689. package/dist/esm/security/authentications/services/authentication-orchestrator.backend.service.d.ts +43 -1
  690. package/dist/esm/security/authentications/services/authentication-orchestrator.backend.service.d.ts.map +1 -1
  691. package/dist/esm/security/authentications/services/authentication-orchestrator.backend.service.js +277 -97
  692. package/dist/esm/security/authentications/services/authentication-orchestrator.backend.service.js.map +1 -1
  693. package/dist/esm/security/authentications/services/cimd-client-metadata.backend.service.d.ts +28 -5
  694. package/dist/esm/security/authentications/services/cimd-client-metadata.backend.service.d.ts.map +1 -1
  695. package/dist/esm/security/authentications/services/cimd-client-metadata.backend.service.js +72 -12
  696. package/dist/esm/security/authentications/services/cimd-client-metadata.backend.service.js.map +1 -1
  697. package/dist/esm/security/authentications/services/custom-impls/auth-custom-implementations.backend.d.ts.map +1 -1
  698. package/dist/esm/security/authentications/services/custom-impls/auth-custom-implementations.backend.js +3 -0
  699. package/dist/esm/security/authentications/services/custom-impls/auth-custom-implementations.backend.js.map +1 -1
  700. package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.d.ts +28 -0
  701. package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.d.ts.map +1 -0
  702. package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.js +283 -0
  703. package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.js.map +1 -0
  704. package/dist/esm/security/authentications/services/custom-impls/sso-config.custom-impl.backend.service.d.ts +4 -3
  705. package/dist/esm/security/authentications/services/custom-impls/sso-config.custom-impl.backend.service.d.ts.map +1 -1
  706. package/dist/esm/security/authentications/services/custom-impls/sso-config.custom-impl.backend.service.js +4 -3
  707. package/dist/esm/security/authentications/services/custom-impls/sso-config.custom-impl.backend.service.js.map +1 -1
  708. package/dist/esm/security/authentications/services/oauth-provider-token.backend.service.d.ts +35 -0
  709. package/dist/esm/security/authentications/services/oauth-provider-token.backend.service.d.ts.map +1 -1
  710. package/dist/esm/security/authentications/services/oauth-provider-token.backend.service.js +111 -21
  711. package/dist/esm/security/authentications/services/oauth-provider-token.backend.service.js.map +1 -1
  712. package/dist/esm/security/authentications/services/oidc-authorization-code.backend.service.d.ts +14 -1
  713. package/dist/esm/security/authentications/services/oidc-authorization-code.backend.service.d.ts.map +1 -1
  714. package/dist/esm/security/authentications/services/oidc-authorization-code.backend.service.js +49 -8
  715. package/dist/esm/security/authentications/services/oidc-authorization-code.backend.service.js.map +1 -1
  716. package/dist/esm/security/authentications/services/utils/auth-policy-resolution.backend.utils.d.ts.map +1 -1
  717. package/dist/esm/security/authentications/services/utils/auth-policy-resolution.backend.utils.js +4 -0
  718. package/dist/esm/security/authentications/services/utils/auth-policy-resolution.backend.utils.js.map +1 -1
  719. package/dist/esm/security/authentications/services/utils/auth-user-lookup.backend.service.d.ts.map +1 -1
  720. package/dist/esm/security/authentications/services/utils/auth-user-lookup.backend.service.js +6 -0
  721. package/dist/esm/security/authentications/services/utils/auth-user-lookup.backend.service.js.map +1 -1
  722. package/dist/esm/security/authentications/services/utils/external-turn-rate-limit.backend.utils.d.ts +37 -1
  723. package/dist/esm/security/authentications/services/utils/external-turn-rate-limit.backend.utils.d.ts.map +1 -1
  724. package/dist/esm/security/authentications/services/utils/external-turn-rate-limit.backend.utils.js +51 -0
  725. package/dist/esm/security/authentications/services/utils/external-turn-rate-limit.backend.utils.js.map +1 -1
  726. package/dist/esm/security/authentications/utils/enterprise-sso-enforcement.backend.utils.d.ts +41 -0
  727. package/dist/esm/security/authentications/utils/enterprise-sso-enforcement.backend.utils.d.ts.map +1 -1
  728. package/dist/esm/security/authentications/utils/enterprise-sso-enforcement.backend.utils.js +45 -0
  729. package/dist/esm/security/authentications/utils/enterprise-sso-enforcement.backend.utils.js.map +1 -1
  730. package/dist/esm/security/authorizations/cross-tenant-read-observation.backend.d.ts +116 -0
  731. package/dist/esm/security/authorizations/cross-tenant-read-observation.backend.d.ts.map +1 -0
  732. package/dist/esm/security/authorizations/cross-tenant-read-observation.backend.js +162 -0
  733. package/dist/esm/security/authorizations/cross-tenant-read-observation.backend.js.map +1 -0
  734. package/dist/esm/security/authorizations/organization-owner-floor.backend.utils.d.ts +20 -20
  735. package/dist/esm/security/authorizations/organization-owner-floor.backend.utils.d.ts.map +1 -1
  736. package/dist/esm/security/authorizations/organization-owner-floor.backend.utils.js +27 -28
  737. package/dist/esm/security/authorizations/organization-owner-floor.backend.utils.js.map +1 -1
  738. package/dist/esm/security/authorizations/platform-access-grant-custom-implementation.backend.service.d.ts.map +1 -1
  739. package/dist/esm/security/authorizations/platform-access-grant-custom-implementation.backend.service.js +77 -3
  740. package/dist/esm/security/authorizations/platform-access-grant-custom-implementation.backend.service.js.map +1 -1
  741. package/dist/esm/security/authorizations/role-ceiling.backend.utils.d.ts +4 -0
  742. package/dist/esm/security/authorizations/role-ceiling.backend.utils.d.ts.map +1 -1
  743. package/dist/esm/security/authorizations/role-ceiling.backend.utils.js +4 -0
  744. package/dist/esm/security/authorizations/role-ceiling.backend.utils.js.map +1 -1
  745. package/dist/esm/security/authorizations/role-conferral.backend.utils.d.ts +93 -0
  746. package/dist/esm/security/authorizations/role-conferral.backend.utils.d.ts.map +1 -0
  747. package/dist/esm/security/authorizations/role-conferral.backend.utils.js +95 -0
  748. package/dist/esm/security/authorizations/role-conferral.backend.utils.js.map +1 -0
  749. package/dist/esm/security/authorizations/scope-root-collection-confinement.backend.d.ts +124 -1
  750. package/dist/esm/security/authorizations/scope-root-collection-confinement.backend.d.ts.map +1 -1
  751. package/dist/esm/security/authorizations/scope-root-collection-confinement.backend.js +142 -5
  752. package/dist/esm/security/authorizations/scope-root-collection-confinement.backend.js.map +1 -1
  753. package/dist/esm/security/authorizations/services/authorizations.backend.service.d.ts +74 -8
  754. package/dist/esm/security/authorizations/services/authorizations.backend.service.d.ts.map +1 -1
  755. package/dist/esm/security/authorizations/services/authorizations.backend.service.js +175 -19
  756. package/dist/esm/security/authorizations/services/authorizations.backend.service.js.map +1 -1
  757. package/dist/esm/security/authorizations/super-admin-floor.backend.utils.d.ts +6 -14
  758. package/dist/esm/security/authorizations/super-admin-floor.backend.utils.d.ts.map +1 -1
  759. package/dist/esm/security/authorizations/super-admin-floor.backend.utils.js +13 -22
  760. package/dist/esm/security/authorizations/super-admin-floor.backend.utils.js.map +1 -1
  761. package/dist/esm/security/connected-accounts/connection-target-authorization.backend.d.ts +60 -0
  762. package/dist/esm/security/connected-accounts/connection-target-authorization.backend.d.ts.map +1 -0
  763. package/dist/esm/security/connected-accounts/connection-target-authorization.backend.js +79 -0
  764. package/dist/esm/security/connected-accounts/connection-target-authorization.backend.js.map +1 -0
  765. package/dist/esm/security/connected-accounts/controllers/provider-connection.controller.backend.service.d.ts +161 -0
  766. package/dist/esm/security/connected-accounts/controllers/provider-connection.controller.backend.service.d.ts.map +1 -0
  767. package/dist/esm/security/connected-accounts/controllers/provider-connection.controller.backend.service.js +512 -0
  768. package/dist/esm/security/connected-accounts/controllers/provider-connection.controller.backend.service.js.map +1 -0
  769. package/dist/esm/security/connected-accounts/organization-provider-credential-resolver.port.d.ts +59 -0
  770. package/dist/esm/security/connected-accounts/organization-provider-credential-resolver.port.d.ts.map +1 -0
  771. package/dist/esm/security/connected-accounts/organization-provider-credential-resolver.port.js +22 -0
  772. package/dist/esm/security/connected-accounts/organization-provider-credential-resolver.port.js.map +1 -0
  773. package/dist/esm/security/connected-accounts/provider-oauth2-refresher.port.d.ts +44 -0
  774. package/dist/esm/security/connected-accounts/provider-oauth2-refresher.port.d.ts.map +1 -0
  775. package/dist/esm/security/connected-accounts/provider-oauth2-refresher.port.js +20 -0
  776. package/dist/esm/security/connected-accounts/provider-oauth2-refresher.port.js.map +1 -0
  777. package/dist/esm/security/connected-accounts/services/organization-provider-credential-store.backend.service.d.ts +191 -0
  778. package/dist/esm/security/connected-accounts/services/organization-provider-credential-store.backend.service.d.ts.map +1 -0
  779. package/dist/esm/security/connected-accounts/services/organization-provider-credential-store.backend.service.js +385 -0
  780. package/dist/esm/security/connected-accounts/services/organization-provider-credential-store.backend.service.js.map +1 -0
  781. package/dist/esm/security/connected-accounts/services/organization-provider-credentials.custom-impl.backend.service.d.ts +41 -0
  782. package/dist/esm/security/connected-accounts/services/organization-provider-credentials.custom-impl.backend.service.d.ts.map +1 -0
  783. package/dist/esm/security/connected-accounts/services/organization-provider-credentials.custom-impl.backend.service.js +358 -0
  784. package/dist/esm/security/connected-accounts/services/organization-provider-credentials.custom-impl.backend.service.js.map +1 -0
  785. package/dist/esm/security/connected-accounts/services/provider-oauth2-exchange.backend.d.ts +160 -0
  786. package/dist/esm/security/connected-accounts/services/provider-oauth2-exchange.backend.d.ts.map +1 -0
  787. package/dist/esm/security/connected-accounts/services/provider-oauth2-exchange.backend.js +266 -0
  788. package/dist/esm/security/connected-accounts/services/provider-oauth2-exchange.backend.js.map +1 -0
  789. package/dist/esm/security/connected-accounts/services/provider-oauth2-pending-authorization.backend.service.d.ts +111 -0
  790. package/dist/esm/security/connected-accounts/services/provider-oauth2-pending-authorization.backend.service.d.ts.map +1 -0
  791. package/dist/esm/security/connected-accounts/services/provider-oauth2-pending-authorization.backend.service.js +107 -0
  792. package/dist/esm/security/connected-accounts/services/provider-oauth2-pending-authorization.backend.service.js.map +1 -0
  793. package/dist/esm/security/connected-accounts/services/provider-oauth2-refresher.backend.service.d.ts +54 -0
  794. package/dist/esm/security/connected-accounts/services/provider-oauth2-refresher.backend.service.d.ts.map +1 -0
  795. package/dist/esm/security/connected-accounts/services/provider-oauth2-refresher.backend.service.js +153 -0
  796. package/dist/esm/security/connected-accounts/services/provider-oauth2-refresher.backend.service.js.map +1 -0
  797. package/dist/esm/security/connected-accounts/services/user-provider-credential-store.backend.service.d.ts +195 -0
  798. package/dist/esm/security/connected-accounts/services/user-provider-credential-store.backend.service.d.ts.map +1 -0
  799. package/dist/esm/security/connected-accounts/services/user-provider-credential-store.backend.service.js +387 -0
  800. package/dist/esm/security/connected-accounts/services/user-provider-credential-store.backend.service.js.map +1 -0
  801. package/dist/esm/security/connected-accounts/services/user-provider-credentials.custom-impl.backend.service.d.ts +45 -0
  802. package/dist/esm/security/connected-accounts/services/user-provider-credentials.custom-impl.backend.service.d.ts.map +1 -0
  803. package/dist/esm/security/connected-accounts/services/user-provider-credentials.custom-impl.backend.service.js +291 -0
  804. package/dist/esm/security/connected-accounts/services/user-provider-credentials.custom-impl.backend.service.js.map +1 -0
  805. package/dist/esm/security/connected-accounts/user-provider-credential-resolver.port.d.ts +62 -0
  806. package/dist/esm/security/connected-accounts/user-provider-credential-resolver.port.d.ts.map +1 -0
  807. package/dist/esm/security/connected-accounts/user-provider-credential-resolver.port.js +29 -0
  808. package/dist/esm/security/connected-accounts/user-provider-credential-resolver.port.js.map +1 -0
  809. package/dist/esm/security/connected-accounts/utils/provider-credential-envelope.backend.utils.d.ts +127 -0
  810. package/dist/esm/security/connected-accounts/utils/provider-credential-envelope.backend.utils.d.ts.map +1 -0
  811. package/dist/esm/security/connected-accounts/utils/provider-credential-envelope.backend.utils.js +277 -0
  812. package/dist/esm/security/connected-accounts/utils/provider-credential-envelope.backend.utils.js.map +1 -0
  813. package/dist/esm/security/connected-accounts/utils/stored-credential-value.backend.utils.d.ts +66 -0
  814. package/dist/esm/security/connected-accounts/utils/stored-credential-value.backend.utils.d.ts.map +1 -0
  815. package/dist/esm/security/connected-accounts/utils/stored-credential-value.backend.utils.js +75 -0
  816. package/dist/esm/security/connected-accounts/utils/stored-credential-value.backend.utils.js.map +1 -0
  817. package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.d.ts +21 -3
  818. package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.d.ts.map +1 -1
  819. package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.js +26 -16
  820. package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.js.map +1 -1
  821. package/dist/esm/security/credential-rotation-grace.backend.utils.d.ts +9 -4
  822. package/dist/esm/security/credential-rotation-grace.backend.utils.d.ts.map +1 -1
  823. package/dist/esm/security/credential-rotation-grace.backend.utils.js +9 -4
  824. package/dist/esm/security/credential-rotation-grace.backend.utils.js.map +1 -1
  825. package/dist/esm/security/oauth-clients/oauth-client-generation.backend.utils.d.ts +26 -0
  826. package/dist/esm/security/oauth-clients/oauth-client-generation.backend.utils.d.ts.map +1 -1
  827. package/dist/esm/security/oauth-clients/oauth-client-generation.backend.utils.js +43 -0
  828. package/dist/esm/security/oauth-clients/oauth-client-generation.backend.utils.js.map +1 -1
  829. package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.d.ts +8 -1
  830. package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.d.ts.map +1 -1
  831. package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.js +49 -0
  832. package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.js.map +1 -1
  833. package/dist/esm/security/scim/controllers/scim.backend.controller.d.ts.map +1 -1
  834. package/dist/esm/security/scim/controllers/scim.backend.controller.js +17 -5
  835. package/dist/esm/security/scim/controllers/scim.backend.controller.js.map +1 -1
  836. package/dist/esm/security/scim/models/scim-protocol.backend.schemas.d.ts +67 -29
  837. package/dist/esm/security/scim/models/scim-protocol.backend.schemas.d.ts.map +1 -1
  838. package/dist/esm/security/scim/models/scim-protocol.backend.schemas.js +47 -25
  839. package/dist/esm/security/scim/models/scim-protocol.backend.schemas.js.map +1 -1
  840. package/dist/esm/security/ssrf/outbound-target-guard.backend.utils.d.ts +10 -2
  841. package/dist/esm/security/ssrf/outbound-target-guard.backend.utils.d.ts.map +1 -1
  842. package/dist/esm/security/ssrf/outbound-target-guard.backend.utils.js +10 -2
  843. package/dist/esm/security/ssrf/outbound-target-guard.backend.utils.js.map +1 -1
  844. package/dist/esm/security/ssrf/pinned-outbound-fetch.backend.utils.d.ts +143 -0
  845. package/dist/esm/security/ssrf/pinned-outbound-fetch.backend.utils.d.ts.map +1 -0
  846. package/dist/esm/security/ssrf/pinned-outbound-fetch.backend.utils.js +258 -0
  847. package/dist/esm/security/ssrf/pinned-outbound-fetch.backend.utils.js.map +1 -0
  848. package/dist/esm/users/services/user-read-retained.custom-impl.backend.service.d.ts +39 -0
  849. package/dist/esm/users/services/user-read-retained.custom-impl.backend.service.d.ts.map +1 -0
  850. package/dist/esm/users/services/user-read-retained.custom-impl.backend.service.js +159 -0
  851. package/dist/esm/users/services/user-read-retained.custom-impl.backend.service.js.map +1 -0
  852. package/dist/tsconfig.build.tsbuildinfo +1 -1
  853. package/package.json +11 -9
@@ -1 +1 @@
1
- {"version":3,"file":"webhook-auto-controller.backend.service.js","sourceRoot":"","sources":["../../../../../../src/notifications/webhooks/controllers/webhook-auto-controller.backend.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Webhook Auto-Controller Backend Service\n *\n * Auto-registers webhook routes from provider registry definitions.\n * At startup, iterates all providers with WEBHOOK_ORIGINATOR protocol,\n * then iterates each provider's endpoints, and registers:\n * POST /webhooks/{providerRef}/{endpointKey}\n *\n * e.g., POST /webhooks/stripe/billing\n * POST /webhooks/google/calendar\n * POST /webhooks/google/drive\n *\n * This replaces manual per-provider webhook controllers (like BillingWebhookControllerBackendService).\n *\n * @see hook-protocol-webhook-callback.md\n */\n\nimport { injectable, inject } from 'inversify';\nimport express from 'express';\nimport type { Request, Response, NextFunction } from 'express';\nimport {\n ExternalProvider_ExchangeProtocol_Kind,\n type Hook_Endpoint,\n type WebhookCapabilityHandler,\n} from '@wildo-ai/external-connectors-models';\nimport { HttpMethod } from '@wildo-ai/saas-models';\n\nimport { SAAS_SERVICE_TYPES } from '~wildo-backend-lib/inject/models/service-types';\nimport type { LoggerService } from '~wildo-backend-lib/monitoring/logger/services/logger.service';\nimport type { ErrorBuilderBackendService } from '~wildo-backend-lib/errors/services/error-builder.backend.service';\nimport type { ErrorHandlerService } from '~wildo-backend-lib/errors/services/error-handler.backend.service';\nimport type { BackendProviderRegistryBackendService } from '~wildo-backend-lib/external-providers/services/backend-provider-registry.backend.service';\nimport type { ExternalProvidersRegistryBackendService } from '~wildo-backend-lib/external-providers/services/external-providers-registry.backend.service';\nimport { AbstractControllerBackendService } from '~wildo-backend-lib/base-classes/services/controllers/abstract-controller.backend.service';\nimport type { WebhookHandlerBackendService } from '~wildo-backend-lib/notifications/webhooks/services/webhook-handler.backend.service';\n\n@injectable()\nexport class WebhookAutoControllerBackendService extends AbstractControllerBackendService {\n\n /** Capability handlers keyed by capability string (e.g., 'billing') */\n private capabilityHandlers = new Map<string, WebhookCapabilityHandler>();\n\n private webhookHandler: WebhookHandlerBackendService | null = null;\n\n /**\n * Pre-loaded endpoint configurations per provider.\n * Populated during initialize() from first-class provider runtime contracts.\n * setupRoutes() reads from this cache (sync) to register routes.\n */\n private loadedEndpoints = new Map<string, Hook_Endpoint[]>();\n\n /** Routes recorded only after Express accepted their registration. */\n\n constructor(\n @inject(SAAS_SERVICE_TYPES.Logger) logger: LoggerService,\n @inject(SAAS_SERVICE_TYPES.ErrorBuilderService) errorBuilder: ErrorBuilderBackendService,\n @inject(SAAS_SERVICE_TYPES.ErrorHandlerService) errorHandler: ErrorHandlerService,\n @inject(SAAS_SERVICE_TYPES.BackendProviderRegistryService) private readonly backendProviderRegistry: BackendProviderRegistryBackendService,\n @inject(SAAS_SERVICE_TYPES.ExternalProvidersRegistryService) private readonly externalProvidersRegistry: ExternalProvidersRegistryBackendService,\n ) {\n super(logger, errorBuilder, errorHandler, 'WebhookAutoController');\n }\n\n // ════════════════════════════════════════════════════════════\n // Initialization\n // ════════════════════════════════════════════════════════════\n\n /**\n * Initialize with required dependencies, pre-load endpoint configs, AND\n * register the webhook routes.\n *\n * ── Why routes are registered HERE, not in `setupRoutes()` ──────────────\n *\n * `AbstractControllerBackendService` calls the abstract `setupRoutes()` hook\n * synchronously from *inside its own constructor* (`super(...)`). At that\n * point this controller has NOTHING to register:\n *\n * 1. The webhook handler is not injected via the constructor — it is\n * supplied to `initialize()` by `start-application` after the billing /\n * provider layers are wired.\n * 2. The route SET is data-dependent (one route per provider webhook\n * endpoint), and those endpoint contracts are only knowable after the\n * provider registries have been initialized (which happens later in the\n * startup sequence than DI construction).\n *\n * So `setupRoutes()` is a deliberate no-op (see its JSDoc) and the real,\n * data-dependent route registration runs here — the same lifecycle shape\n * `ControllerResourceBackendService` uses for its per-resource routes.\n *\n * `start-application` calls this BEFORE the controllers registry mounts the\n * router (via `getRouter()`), so the routes added here are present when the\n * master router mounts this controller's router by reference. Errors thrown\n * from webhook handlers propagate to the app-level error middleware\n * (`HttpServerBackendService`), so no router-scoped error handler is needed\n * after these routes.\n */\n public async initialize(\n webhookHandler: WebhookHandlerBackendService,\n ): Promise<void> {\n this.webhookHandler = webhookHandler;\n\n for (const provider of this.backendProviderRegistry.getProvidersWithProtocol(ExternalProvider_ExchangeProtocol_Kind.WEBHOOK_ORIGINATOR)) {\n const providerRef = provider.metadata.ref;\n try {\n if (\n !this.externalProvidersRegistry.isProviderEnabled(\n providerRef,\n ExternalProvider_ExchangeProtocol_Kind.WEBHOOK_ORIGINATOR,\n )\n ) {\n continue;\n }\n\n const config = this.externalProvidersRegistry.getProviderConfiguration(\n providerRef,\n ExternalProvider_ExchangeProtocol_Kind.WEBHOOK_ORIGINATOR,\n );\n // `config.endpoints` is `ReadonlyArray<Hook_Endpoint>` post the\n // 2026-05-06 webhook endpoint reshape: `Hook_Endpoint.displayName`\n // is now optional (matches the runtime emission) and the dead\n // extras (`providerRef` / `path` / `secretBinding`) were dropped\n // from `buildWebhookEndpoints`. The local cache is a\n // `Map<string, Hook_Endpoint[]>`, so we materialize a mutable\n // copy here — the cache was historically `Hook_Endpoint[]`\n // (mutable); preserving that semantics avoids touching every\n // downstream signature.\n const endpoints: Hook_Endpoint[] = [...(config?.endpoints ?? [])];\n if (endpoints.length > 0) {\n this.loadedEndpoints.set(providerRef, endpoints);\n this.logDebug(`Pre-loaded ${endpoints.length} webhook endpoint(s) for ${providerRef}`);\n } else {\n // Genuine contract fault (not the expected \"no webhook providers\"\n // case): the provider is ENABLED for WEBHOOK_ORIGINATOR yet exposes\n // zero endpoints, so it will silently never receive inbound webhooks\n // (e.g. Stripe would 404 on /webhooks/stripe/billing). Surface it\n // once, clearly — this is a mis-sequence, not steady-state noise.\n this.logger.warn(\n `WebhookAutoController: provider '${providerRef}' is enabled for WEBHOOK_ORIGINATOR but exposes no endpoints — no routes will be registered for it`,\n );\n }\n } catch (error) {\n this.logger.warn(`Failed to pre-load webhook protocol for ${providerRef}`, {\n error: (error as Error).message,\n });\n }\n }\n\n this.logDebug(`Webhook auto-controller initialized with ${this.loadedEndpoints.size} provider(s)`);\n\n // Register the routes now that the handler + endpoint contracts are known.\n this.registerWebhookRoutes();\n }\n\n /**\n * Register a capability handler for dispatching processed events.\n * Called at startup by capability modules (e.g., billing module).\n */\n registerCapabilityHandler(handler: WebhookCapabilityHandler): void {\n this.capabilityHandlers.set(handler.capability, handler);\n this.logDebug(`Registered webhook capability handler for ${handler.capability}`);\n }\n\n /**\n * Return the sanitized inbound-provider routes that this controller actually\n * registered. Provider configuration, signature material, endpoint payloads,\n * and handler metadata are intentionally absent.\n */\n\n // ════════════════════════════════════════════════════════════\n // Routes\n // ════════════════════════════════════════════════════════════\n\n /**\n * Required by `AbstractControllerBackendService`, which invokes this hook\n * synchronously from its constructor (`super(...)`). This controller\n * intentionally registers NOTHING here: its route set is data-dependent\n * (one route per provider webhook endpoint) and neither the webhook handler\n * nor the provider endpoint contracts exist at construction time. The real\n * registration happens in `initialize()` / `registerWebhookRoutes()` once\n * that data is available — see `initialize()`'s JSDoc for the full rationale.\n */\n protected setupRoutes(): void {\n // No-op by design — see JSDoc above and `registerWebhookRoutes()`.\n }\n\n /**\n * Register one Express route per pre-loaded provider webhook endpoint.\n * Invoked from `initialize()` after `webhookHandler` and `loadedEndpoints`\n * have been populated. Idempotent-safe against an empty cache; guards on the\n * handler so a mis-sequenced call fails visibly rather than registering dead\n * routes.\n */\n private registerWebhookRoutes(): void {\n if (!this.webhookHandler) {\n this.logger.warn('WebhookAutoController: initialize() ran without a webhook handler — no routes registered');\n return;\n }\n\n if (this.loadedEndpoints.size === 0) {\n this.logDebug('No webhook endpoints pre-loaded — no routes registered');\n return;\n }\n\n for (const [providerRef, endpoints] of this.loadedEndpoints) {\n for (const endpoint of endpoints) {\n const routePath = `/webhooks/${providerRef}/${endpoint.key}`;\n\n this.router.post(\n routePath,\n // Defense-in-depth for a future streaming mount. If this controller is\n // ever assigned the RAW_REQUEST_STREAM mount phase, this express.raw()\n // makes req.body the raw Buffer. Under the\n // current master-router mount it is an inert no-op: the global\n // express.json (HttpServerBackendService.setupBodyParsing) parses the\n // body first and sets req._body, so the signature-faithful bytes come\n // from req.rawBody — captured by that same express.json `verify` hook.\n // handleWebhookRequest reads rawBody first, then falls back to a Buffer\n // req.body for the streaming case.\n express.raw({ type: 'application/json' }),\n this.asyncHandler(async (req: Request, res: Response, _next: NextFunction) => {\n await this.handleWebhookRequest(providerRef, endpoint, req, res);\n }),\n );\n\n\n this.logger.info(`Webhook endpoint registered: POST ${routePath}`);\n }\n }\n }\n\n // ════════════════════════════════════════════════════════════\n // Handler\n // ════════════════════════════════════════════════════════════\n\n private async handleWebhookRequest(\n providerRef: string,\n endpoint: Hook_Endpoint,\n req: Request,\n res: Response,\n ): Promise<void> {\n if (!this.webhookHandler) {\n res.status(503).json({ error: 'Webhook handler not initialized' });\n return;\n }\n\n // Raw request bytes for signature verification. Order matters:\n // 1. req.rawBody — captured by the global express.json `verify` hook\n // (HttpServerBackendService.setupBodyParsing). This is the provider's\n // EXACT original payload and the ONLY byte-faithful source under the\n // current master-router mount, where global express.json parses the\n // body before this route runs (making the per-route express.raw() a\n // no-op, so req.body is a parsed object here).\n // 2. Buffer req.body — only populated if this controller is ever\n // streaming-mounted before body parsing (per-route express.raw() fires).\n // 3. string / JSON.stringify — last-resort fallbacks; JSON.stringify will\n // NOT byte-match the provider (key ordering / whitespace), so it exists\n // only to avoid a crash, never as a correctness path for signatures.\n const rawBody = Buffer.isBuffer(req.rawBody)\n ? req.rawBody.toString('utf-8')\n : Buffer.isBuffer(req.body)\n ? req.body.toString('utf-8')\n : typeof req.body === 'string'\n ? req.body\n : JSON.stringify(req.body);\n\n let result: Awaited<ReturnType<WebhookHandlerBackendService['processWebhook']>> | null = null;\n try {\n result = await this.webhookHandler.processWebhook({\n providerRef,\n endpointKey: endpoint.key,\n endpoint,\n rawBody,\n headers: req.headers as Record<string, string>,\n });\n\n // null = idempotent duplicate or unparseable event — already acknowledged\n if (!result) {\n res.status(200).json({ received: true });\n return;\n }\n\n // Dispatch to capability handler\n const handler = this.capabilityHandlers.get(endpoint.capability);\n if (handler) {\n await handler.handleEvent(result.executionContext, result.parsedEvent);\n } else {\n throw new Error(`No capability handler for ${endpoint.capability} on ${providerRef}/${endpoint.key}`);\n }\n\n await this.webhookHandler.markWebhookProcessed(result.idempotencyKey);\n res.status(200).json({ received: true });\n } catch (error) {\n const errorMessage = (error as Error).message ?? 'Unknown error';\n const errorType = (error as any)?.errorType;\n\n // Signature failure → 401\n if (errorType === 'AUTHORIZATION') {\n this.logDebug('Webhook signature verification failed', { providerRef, endpointKey: endpoint.key });\n res.status(401).json({ error: 'Invalid signature' });\n return;\n }\n\n // All other errors → 500 (trigger provider retry)\n this.logger.error('Webhook processing failed', {\n providerRef,\n endpointKey: endpoint.key,\n error: errorMessage,\n });\n await this.webhookHandler.releaseWebhookClaim(result?.idempotencyKey);\n res.status(500).json({ error: 'Processing failed' });\n }\n }\n}\n"]}
1
+ {"version":3,"file":"webhook-auto-controller.backend.service.js","sourceRoot":"","sources":["../../../../../../src/notifications/webhooks/controllers/webhook-auto-controller.backend.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Webhook Auto-Controller Backend Service\n *\n * Auto-registers webhook routes from provider registry definitions.\n * At startup, iterates all providers with WEBHOOK_ORIGINATOR protocol,\n * then iterates each provider's endpoints, and registers:\n * POST /webhooks/{providerRef}/{endpointKey}\n *\n * One provider declares the protocol today, and it declares one endpoint:\n * POST /webhooks/stripe/billing\n *\n * A second provider registers here the moment it declares `WEBHOOK_ORIGINATOR` with its own\n * `endpoints`; no edit to this controller is needed.\n *\n * This replaces manual per-provider webhook controllers (like BillingWebhookControllerBackendService).\n *\n * @see hook-protocol-webhook-callback.md\n */\n\nimport { injectable, inject } from 'inversify';\nimport express from 'express';\nimport type { Request, Response, NextFunction } from 'express';\nimport {\n ExternalProvider_ExchangeProtocol_Kind,\n type Hook_Endpoint,\n type WebhookCapabilityHandler,\n} from '@wildo-ai/external-connectors-models';\nimport { HttpMethod } from '@wildo-ai/saas-models';\n\nimport { SAAS_SERVICE_TYPES } from '~wildo-backend-lib/inject/models/service-types';\nimport type { LoggerService } from '~wildo-backend-lib/monitoring/logger/services/logger.service';\nimport type { ErrorBuilderBackendService } from '~wildo-backend-lib/errors/services/error-builder.backend.service';\nimport type { ErrorHandlerService } from '~wildo-backend-lib/errors/services/error-handler.backend.service';\nimport type { BackendProviderRegistryBackendService } from '~wildo-backend-lib/external-providers/services/backend-provider-registry.backend.service';\nimport type { ExternalProvidersRegistryBackendService } from '~wildo-backend-lib/external-providers/services/external-providers-registry.backend.service';\nimport { AbstractControllerBackendService } from '~wildo-backend-lib/base-classes/services/controllers/abstract-controller.backend.service';\nimport type { WebhookHandlerBackendService } from '~wildo-backend-lib/notifications/webhooks/services/webhook-handler.backend.service';\n\n/**\n * Why a declared webhook endpoint did NOT get an Express route.\n *\n * A closed vocabulary rather than a free string: each member names a DIFFERENT\n * missing registration, with a different remedy, and an operator reading the\n * startup log has to be able to tell them apart. The two are independent — an\n * endpoint can be missing either, or both.\n */\nexport enum WebhookRouteWithholdingReason {\n /**\n * No {@link WebhookCapabilityHandler} is registered for the endpoint's\n * `capability`. The route would reach `handleWebhookRequest`, complete\n * signature verification and idempotency claiming, then fail at dispatch.\n */\n NO_CAPABILITY_HANDLER = 'NO_CAPABILITY_HANDLER',\n /**\n * No `WebhookCapabilityAdapter` is registered for `providerRef:endpointKey`\n * on {@link WebhookHandlerBackendService}. The route would fail at the very\n * top of `processWebhook`, before signature verification.\n */\n NO_ENDPOINT_ADAPTER = 'NO_ENDPOINT_ADAPTER',\n}\n\n/** One declared endpoint whose route was deliberately not mounted, and why. */\nexport interface WebhookRouteWithholding {\n providerRef: string;\n endpointKey: string;\n capability: string;\n routePath: string;\n reasons: WebhookRouteWithholdingReason[];\n}\n\n@injectable()\nexport class WebhookAutoControllerBackendService extends AbstractControllerBackendService {\n\n /** Capability handlers keyed by capability string (e.g., 'billing') */\n private capabilityHandlers = new Map<string, WebhookCapabilityHandler>();\n\n private webhookHandler: WebhookHandlerBackendService | null = null;\n\n /**\n * Pre-loaded endpoint configurations per provider.\n * Populated during initialize() from first-class provider runtime contracts.\n * setupRoutes() reads from this cache (sync) to register routes.\n */\n private loadedEndpoints = new Map<string, Hook_Endpoint[]>();\n\n /** Route paths recorded only after Express accepted their registration. */\n private registeredRoutePaths: string[] = [];\n\n /**\n * Declared endpoints whose route was WITHHELD because the capability could\n * not be dispatched. Kept so the decision is inspectable after startup rather\n * than only visible in a log line that has already scrolled past.\n */\n private withheldRoutes: WebhookRouteWithholding[] = [];\n\n /**\n * Set once {@link registerWebhookRoutes} has run. The mount decision is taken\n * ONCE, from the registration state at that instant, so anything registered\n * afterwards cannot change which routes exist — see\n * {@link registerCapabilityHandler}, which refuses to let that be silent.\n */\n private routesRegistered = false;\n\n constructor(\n @inject(SAAS_SERVICE_TYPES.Logger) logger: LoggerService,\n @inject(SAAS_SERVICE_TYPES.ErrorBuilderService) errorBuilder: ErrorBuilderBackendService,\n @inject(SAAS_SERVICE_TYPES.ErrorHandlerService) errorHandler: ErrorHandlerService,\n @inject(SAAS_SERVICE_TYPES.BackendProviderRegistryService) private readonly backendProviderRegistry: BackendProviderRegistryBackendService,\n @inject(SAAS_SERVICE_TYPES.ExternalProvidersRegistryService) private readonly externalProvidersRegistry: ExternalProvidersRegistryBackendService,\n ) {\n super(logger, errorBuilder, errorHandler, 'WebhookAutoController');\n }\n\n // ════════════════════════════════════════════════════════════\n // Initialization\n // ════════════════════════════════════════════════════════════\n\n /**\n * Initialize with required dependencies, pre-load endpoint configs, AND\n * register the webhook routes.\n *\n * ── Why routes are registered HERE, not in `setupRoutes()` ──────────────\n *\n * `AbstractControllerBackendService` calls the abstract `setupRoutes()` hook\n * synchronously from *inside its own constructor* (`super(...)`). At that\n * point this controller has NOTHING to register:\n *\n * 1. The webhook handler is not injected via the constructor — it is\n * supplied to `initialize()` by `start-application` after the billing /\n * provider layers are wired.\n * 2. The route SET is data-dependent (one route per provider webhook\n * endpoint), and those endpoint contracts are only knowable after the\n * provider registries have been initialized (which happens later in the\n * startup sequence than DI construction).\n *\n * So `setupRoutes()` is a deliberate no-op (see its JSDoc) and the real,\n * data-dependent route registration runs here — the same lifecycle shape\n * `ControllerResourceBackendService` uses for its per-resource routes.\n *\n * `start-application` calls this BEFORE the controllers registry mounts the\n * router (via `getRouter()`), so the routes added here are present when the\n * master router mounts this controller's router by reference. Errors thrown\n * from webhook handlers propagate to the app-level error middleware\n * (`HttpServerBackendService`), so no router-scoped error handler is needed\n * after these routes.\n */\n public async initialize(\n webhookHandler: WebhookHandlerBackendService,\n ): Promise<void> {\n this.webhookHandler = webhookHandler;\n\n for (const provider of this.backendProviderRegistry.getProvidersWithProtocol(ExternalProvider_ExchangeProtocol_Kind.WEBHOOK_ORIGINATOR)) {\n const providerRef = provider.metadata.ref;\n try {\n if (\n !this.externalProvidersRegistry.isProviderEnabled(\n providerRef,\n ExternalProvider_ExchangeProtocol_Kind.WEBHOOK_ORIGINATOR,\n )\n ) {\n continue;\n }\n\n const config = this.externalProvidersRegistry.getProviderConfiguration(\n providerRef,\n ExternalProvider_ExchangeProtocol_Kind.WEBHOOK_ORIGINATOR,\n );\n // `config.endpoints` is `ReadonlyArray<Hook_Endpoint>` post the\n // 2026-05-06 webhook endpoint reshape: `Hook_Endpoint.displayName`\n // is now optional (matches the runtime emission) and the dead\n // extras (`providerRef` / `path` / `secretBinding`) were dropped\n // from `buildWebhookEndpoints`. The local cache is a\n // `Map<string, Hook_Endpoint[]>`, so we materialize a mutable\n // copy here — the cache was historically `Hook_Endpoint[]`\n // (mutable); preserving that semantics avoids touching every\n // downstream signature.\n const endpoints: Hook_Endpoint[] = [...(config?.endpoints ?? [])];\n if (endpoints.length > 0) {\n this.loadedEndpoints.set(providerRef, endpoints);\n this.logDebug(`Pre-loaded ${endpoints.length} webhook endpoint(s) for ${providerRef}`);\n } else {\n // Genuine contract fault (not the expected \"no webhook providers\"\n // case): the provider is ENABLED for WEBHOOK_ORIGINATOR yet exposes\n // zero endpoints, so it will silently never receive inbound webhooks\n // (e.g. Stripe would 404 on /webhooks/stripe/billing). Surface it\n // once, clearly — this is a mis-sequence, not steady-state noise.\n this.logger.warn(\n `WebhookAutoController: provider '${providerRef}' is enabled for WEBHOOK_ORIGINATOR but exposes no endpoints — no routes will be registered for it`,\n );\n }\n } catch (error) {\n this.logger.warn(`Failed to pre-load webhook protocol for ${providerRef}`, {\n error: (error as Error).message,\n });\n }\n }\n\n this.logDebug(`Webhook auto-controller initialized with ${this.loadedEndpoints.size} provider(s)`);\n\n // Register the routes now that the handler + endpoint contracts are known.\n this.registerWebhookRoutes();\n }\n\n /**\n * Register a capability handler for dispatching processed events.\n * Called at startup by capability modules (e.g., billing module).\n *\n * MUST be called before {@link initialize}. `start-application` satisfies this\n * ordering today — step 4.5 initializes capability modules (which register\n * here) and step 4.6 initializes this controller — and the guard below exists\n * so a future step inserted the other way round is LOUD instead of silent.\n *\n * The failure it catches is genuinely confusing without it: a late-registered\n * handler works perfectly at request time (the map is read per request), but\n * the route it would serve was already withheld at mount time, so the endpoint\n * answers 404 while a handler for it demonstrably exists.\n */\n registerCapabilityHandler(handler: WebhookCapabilityHandler): void {\n this.capabilityHandlers.set(handler.capability, handler);\n\n if (this.routesRegistered) {\n this.logger.error(\n `WebhookAutoController: capability handler for '${handler.capability}' was registered AFTER webhook routes were mounted. `\n + 'Route mounting is decided once, from the registrations present at that moment, so this handler cannot bring back any route '\n + 'that was withheld for a missing handler — those endpoints will keep answering 404. '\n + 'Register capability handlers before WebhookAutoControllerBackendService.initialize() runs.',\n {\n capability: handler.capability,\n withheldRoutes: this.withheldRoutes.map((withholding) => withholding.routePath),\n },\n );\n return;\n }\n\n this.logDebug(`Registered webhook capability handler for ${handler.capability}`);\n }\n\n /**\n * Return the sanitized inbound-provider routes that this controller actually\n * registered. Provider configuration, signature material, endpoint payloads,\n * and handler metadata are intentionally absent.\n */\n public getRegisteredWebhookRoutePaths(): ReadonlyArray<string> {\n return [...this.registeredRoutePaths];\n }\n\n /**\n * Return the declared endpoints whose route was deliberately NOT mounted,\n * with the reason. Carries no provider configuration or signature material —\n * only the route identity and which registration was missing.\n */\n public getWithheldWebhookRoutes(): ReadonlyArray<WebhookRouteWithholding> {\n return this.withheldRoutes.map((withholding) => ({ ...withholding, reasons: [...withholding.reasons] }));\n }\n\n // ════════════════════════════════════════════════════════════\n // Routes\n // ════════════════════════════════════════════════════════════\n\n /**\n * Required by `AbstractControllerBackendService`, which invokes this hook\n * synchronously from its constructor (`super(...)`). This controller\n * intentionally registers NOTHING here: its route set is data-dependent\n * (one route per provider webhook endpoint) and neither the webhook handler\n * nor the provider endpoint contracts exist at construction time. The real\n * registration happens in `initialize()` / `registerWebhookRoutes()` once\n * that data is available — see `initialize()`'s JSDoc for the full rationale.\n */\n protected setupRoutes(): void {\n // No-op by design — see JSDoc above and `registerWebhookRoutes()`.\n }\n\n /**\n * Register one Express route per pre-loaded provider webhook endpoint —\n * EXCEPT those whose capability cannot actually be dispatched.\n *\n * Invoked from `initialize()` after `webhookHandler` and `loadedEndpoints`\n * have been populated. Idempotent-safe against an empty cache; guards on the\n * handler so a mis-sequenced call fails visibly rather than registering dead\n * routes.\n *\n * ── Why an undispatchable endpoint is WITHHELD rather than mounted ────────\n *\n * A declared endpoint needs two registrations that this controller does not\n * own and cannot create: a `WebhookCapabilityAdapter` (verify + parse, on\n * `WebhookHandlerBackendService`) and a `WebhookCapabilityHandler` (dispatch,\n * here). Both are supplied by the capability module — for `billing`, inside\n * `start-application.initializeBillingServices`, which is deliberately\n * NON-FATAL: if it throws part-way, or if `billing.enabled` is false while the\n * provider is still enabled for `WEBHOOK_ORIGINATOR`, the application boots\n * with the provider's endpoint declared and neither registration present.\n *\n * Mounting a route in that state produces a 500 on every inbound delivery\n * (`No webhook adapter registered for ...`, or `No capability handler for ...`\n * below), and a 500 is precisely the answer that tells a vendor to RETRY — an\n * instruction that can never be satisfied, because no retry supplies a missing\n * startup registration. The endpoint therefore absorbs the vendor's full retry\n * schedule and eventually gets disabled on the vendor's side, while the only\n * local signal is a repeating error log.\n *\n * Not mounting says the true thing instead: this endpoint does not exist. The\n * vendor gets a 404 rather than a retry instruction, and the operator gets one\n * loud, remedy-naming error at startup — the moment the misconfiguration was\n * actually introduced.\n *\n * REJECTED — refusing at BOOT (throwing from here). It is the shape the rest of\n * the registry uses, and it is wrong at this site for three reasons. (1) It\n * would not even be loud: `start-application.initializeWebhookAutoController`\n * wraps `initialize()` in a non-fatal catch that downgrades a throw to a warn,\n * so the net effect would be a quieter log AND the loss of every OTHER\n * provider's working route. (2) It inverts a decision the engine already took\n * explicitly — billing initialization failure is documented as survivable\n * (\"the app can still run without billing\"); a failed optional subsystem must\n * not become a refusal to start. (3) `billing.enabled: false` beside a\n * registered Stripe provider is a COHERENT configuration, and refusing to boot\n * over it would be a false alarm. The check is per-endpoint, so a capability\n * that is wired keeps its route regardless of a sibling that is not.\n */\n private registerWebhookRoutes(): void {\n this.routesRegistered = true;\n\n if (!this.webhookHandler) {\n this.logger.warn('WebhookAutoController: initialize() ran without a webhook handler — no routes registered');\n return;\n }\n\n if (this.loadedEndpoints.size === 0) {\n this.logDebug('No webhook endpoints pre-loaded — no routes registered');\n return;\n }\n\n for (const [providerRef, endpoints] of this.loadedEndpoints) {\n for (const endpoint of endpoints) {\n const routePath = `/webhooks/${providerRef}/${endpoint.key}`;\n\n const withholding = this.assessRouteDispatchability(providerRef, endpoint, routePath);\n if (withholding) {\n this.withheldRoutes.push(withholding);\n this.logger.error(\n `WebhookAutoController: NOT registering POST ${routePath} — the endpoint is declared but cannot be dispatched `\n + `(${withholding.reasons.join(', ')}). A route mounted in this state can only ever answer 500, which instructs the `\n + 'vendor to retry an inbound event that no retry can make processable. Withholding the route so the vendor gets a '\n + '404 instead. Remedy: register the capability module that owns '\n + `'${endpoint.capability}' before WebhookAutoControllerBackendService.initialize() runs (for billing, check whether `\n + 'billing initialization was skipped or failed non-fatally earlier in startup), or disable the WEBHOOK_ORIGINATOR '\n + `protocol for provider '${providerRef}'.`,\n {\n providerRef,\n endpointKey: endpoint.key,\n capability: endpoint.capability,\n routePath,\n reasons: withholding.reasons,\n },\n );\n continue;\n }\n\n this.router.post(\n routePath,\n // Defense-in-depth for a future streaming mount. If this controller is\n // ever assigned the RAW_REQUEST_STREAM mount phase, this express.raw()\n // makes req.body the raw Buffer. Under the\n // current master-router mount it is an inert no-op: the global\n // express.json (HttpServerBackendService.setupBodyParsing) parses the\n // body first and sets req._body, so the signature-faithful bytes come\n // from req.rawBody — captured by that same express.json `verify` hook.\n // handleWebhookRequest reads rawBody first, then falls back to a Buffer\n // req.body for the streaming case.\n express.raw({ type: 'application/json' }),\n this.asyncHandler(async (req: Request, res: Response, _next: NextFunction) => {\n await this.handleWebhookRequest(providerRef, endpoint, req, res);\n }),\n );\n\n this.registeredRoutePaths.push(routePath);\n this.logger.info(`Webhook endpoint registered: POST ${routePath}`);\n }\n }\n }\n\n /**\n * Decide whether a declared endpoint can actually be served, and if not, say\n * which registration is missing.\n *\n * Returns `null` when the route is dispatchable. Both prerequisites are\n * evaluated (rather than short-circuiting on the first) so an operator gets\n * the WHOLE remedy in one log line instead of fixing one registration and\n * meeting the next on the following restart.\n */\n private assessRouteDispatchability(\n providerRef: string,\n endpoint: Hook_Endpoint,\n routePath: string,\n ): WebhookRouteWithholding | null {\n const reasons: WebhookRouteWithholdingReason[] = [];\n\n if (!this.capabilityHandlers.has(endpoint.capability)) {\n reasons.push(WebhookRouteWithholdingReason.NO_CAPABILITY_HANDLER);\n }\n if (!this.webhookHandler?.hasAdapter(providerRef, endpoint.key)) {\n reasons.push(WebhookRouteWithholdingReason.NO_ENDPOINT_ADAPTER);\n }\n\n if (reasons.length === 0) {\n return null;\n }\n return { providerRef, endpointKey: endpoint.key, capability: endpoint.capability, routePath, reasons };\n }\n\n // ════════════════════════════════════════════════════════════\n // Handler\n // ════════════════════════════════════════════════════════════\n\n private async handleWebhookRequest(\n providerRef: string,\n endpoint: Hook_Endpoint,\n req: Request,\n res: Response,\n ): Promise<void> {\n if (!this.webhookHandler) {\n res.status(503).json({ error: 'Webhook handler not initialized' });\n return;\n }\n\n // Raw request bytes for signature verification. Order matters:\n // 1. req.rawBody — captured by the global express.json `verify` hook\n // (HttpServerBackendService.setupBodyParsing). This is the provider's\n // EXACT original payload and the ONLY byte-faithful source under the\n // current master-router mount, where global express.json parses the\n // body before this route runs (making the per-route express.raw() a\n // no-op, so req.body is a parsed object here).\n // 2. Buffer req.body — only populated if this controller is ever\n // streaming-mounted before body parsing (per-route express.raw() fires).\n // 3. string / JSON.stringify — last-resort fallbacks; JSON.stringify will\n // NOT byte-match the provider (key ordering / whitespace), so it exists\n // only to avoid a crash, never as a correctness path for signatures.\n const rawBody = Buffer.isBuffer(req.rawBody)\n ? req.rawBody.toString('utf-8')\n : Buffer.isBuffer(req.body)\n ? req.body.toString('utf-8')\n : typeof req.body === 'string'\n ? req.body\n : JSON.stringify(req.body);\n\n let result: Awaited<ReturnType<WebhookHandlerBackendService['processWebhook']>> | null = null;\n try {\n result = await this.webhookHandler.processWebhook({\n providerRef,\n endpointKey: endpoint.key,\n endpoint,\n rawBody,\n headers: req.headers as Record<string, string>,\n });\n\n // null = idempotent duplicate or unparseable event — already acknowledged\n if (!result) {\n res.status(200).json({ received: true });\n return;\n }\n\n // Dispatch to capability handler.\n //\n // Defence in depth only: `registerWebhookRoutes` refuses to MOUNT a route\n // whose capability has no handler, so this branch is unreachable while that\n // gate holds — reaching it means the handler map was mutated after mounting\n // (which `registerCapabilityHandler` refuses to do silently). The throw is\n // kept rather than removed because the alternative — dispatching to\n // `undefined` — would 500 anyway, with no explanation.\n const handler = this.capabilityHandlers.get(endpoint.capability);\n if (handler) {\n await handler.handleEvent(result.executionContext, result.parsedEvent);\n } else {\n throw new Error(`No capability handler for ${endpoint.capability} on ${providerRef}/${endpoint.key}`);\n }\n\n await this.webhookHandler.markWebhookProcessed(result.idempotencyKey);\n res.status(200).json({ received: true });\n } catch (error) {\n const errorMessage = (error as Error).message ?? 'Unknown error';\n const errorType = (error as any)?.errorType;\n\n // Signature failure → 401\n if (errorType === 'AUTHORIZATION') {\n this.logDebug('Webhook signature verification failed', { providerRef, endpointKey: endpoint.key });\n res.status(401).json({ error: 'Invalid signature' });\n return;\n }\n\n // All other errors → 500 (trigger provider retry)\n this.logger.error('Webhook processing failed', {\n providerRef,\n endpointKey: endpoint.key,\n error: errorMessage,\n });\n await this.webhookHandler.releaseWebhookClaim(result?.idempotencyKey);\n res.status(500).json({ error: 'Processing failed' });\n }\n }\n}\n"]}
@@ -30,12 +30,6 @@
30
30
  import { z } from 'zod';
31
31
  import { AuthScopeType } from '@wildo-ai/saas-models';
32
32
  import { type BatchesCronjobsCustomExecution_Service } from '../../../../base-classes/services/batches/batches-cronjobs-custom-execution.service';
33
- /**
34
- * The dispatcher writes the row first, then enqueues this lightweight
35
- * payload. Keeping the payload minimal (id + scope) makes the worker
36
- * resilient to queue / DB race conditions: re-reading the row is the
37
- * source of truth.
38
- */
39
33
  export declare const M2MWebhookDeliveryBatchInputSchema: z.ZodObject<{
40
34
  scope: z.ZodObject<{
41
35
  type: z.ZodEnum<typeof AuthScopeType>;
@@ -1 +1 @@
1
- {"version":3,"file":"m2m-webhook-delivery.batch.backend.service.d.ts","sourceRoot":"","sources":["../../../../../../../src/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.backend.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,aAAa,EAEd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAEL,KAAK,sCAAsC,EAC5C,MAAM,4FAA4F,CAAC;AAmBpG;;;;;GAKG;AACH,eAAO,MAAM,kCAAkC;;;;;;iBAM7C,CAAC;AAEH,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kCAAkC,CAAC,CAAC;AAE9F,eAAO,MAAM,mCAAmC;;;;;;;;;;;;iBAiB9C,CAAC;AAEH,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mCAAmC,CAAC,CAAC;AAMhG,eAAO,MAAM,8BAA8B,EAAE,sCAAsC,CACjF,OAAO,kCAAkC,EACzC,OAAO,mCAAmC,CAwU1C,CAAC"}
1
+ {"version":3,"file":"m2m-webhook-delivery.batch.backend.service.d.ts","sourceRoot":"","sources":["../../../../../../../src/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.backend.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,aAAa,EAId,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAEL,KAAK,sCAAsC,EAC5C,MAAM,4FAA4F,CAAC;AAmDpG,eAAO,MAAM,kCAAkC;;;;;;iBAM7C,CAAC;AAEH,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kCAAkC,CAAC,CAAC;AAE9F,eAAO,MAAM,mCAAmC;;;;;;;;;;;;iBAiB9C,CAAC;AAEH,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mCAAmC,CAAC,CAAC;AAMhG,eAAO,MAAM,8BAA8B,EAAE,sCAAsC,CACjF,OAAO,kCAAkC,EACzC,OAAO,mCAAmC,CA8V1C,CAAC"}
@@ -28,7 +28,7 @@
28
28
  * (precedent: same pattern for an event-triggered custom batch).
29
29
  */
30
30
  import { z } from 'zod';
31
- import { AuthScopeType, M2M_WEBHOOK_DELIVERY_CONTRACT, } from '@wildo-ai/saas-models';
31
+ import { AuthScopeType, M2M_WEBHOOK_DELIVERY_CONTRACT, webhookEndpointDestinationHost, webhookEndpointTransportIsPlaintext, } from '@wildo-ai/saas-models';
32
32
  import { createCustomBatchExecutionService, } from '../../../../base-classes/services/batches/batches-cronjobs-custom-execution.service.js';
33
33
  import { ENGINE_M2M_WEBHOOK_DELIVERY_BATCH_MANIFEST } from '../../../../base-classes/services/batches/engine-custom-batch-manifests.js';
34
34
  import { describeCaughtError, projectCaughtErrorLogFields } from '../../../../errors/utils/error-log-level-classification.backend.utils.js';
@@ -45,6 +45,31 @@ import { M2M_WEBHOOK_BODY_HASH_ALGORITHM, sendSignedWebhookRequest } from '../m2
45
45
  * resilient to queue / DB race conditions: re-reading the row is the
46
46
  * source of truth.
47
47
  */
48
+ /**
49
+ * Endpoints already warned about in this process, so a permanently-plaintext destination costs one
50
+ * line rather than one per delivery (#492).
51
+ *
52
+ * ## Why the warning is HERE, and why it is once
53
+ *
54
+ * Plaintext endpoints are ADMITTED — a commercial accommodation recorded on
55
+ * `WebhookEndpointSchema.url` — and the cost of admitting them is that the decision becomes
56
+ * invisible. The obvious place to say so is the moment an endpoint is SAVED, and that place does
57
+ * not exist: `webhookConfig` declares CREATE and UPDATE `REPOSITORY_ONLY` with no admin route, and
58
+ * the only writer that exists (data seeding) reaches the row through `upsertByBusinessKey`, a raw
59
+ * repository call that no operation-pipeline hook observes. A postfix handler there would have been
60
+ * a mechanism nothing runs — the shape this whole review exists to remove.
61
+ *
62
+ * The delivery IS the exposure, so this is where it can be stated truthfully: every POST over
63
+ * `http://` puts the signature JWT on the wire in the clear, readable and replayable by anyone on
64
+ * the path until it expires.
65
+ *
66
+ * Once per endpoint per process, because a webhook configuration is stable: a WARN on every
67
+ * delivery would be a line an operator learns to filter, and a filtered warning is the same as no
68
+ * warning. The set is bounded by the endpoint population and is deliberately NOT time-based — the
69
+ * fact does not become news again after an hour, it becomes news again when the process restarts
70
+ * and re-reads a configuration somebody may have changed.
71
+ */
72
+ const PLAINTEXT_ENDPOINTS_ALREADY_WARNED = new Set();
48
73
  export const M2MWebhookDeliveryBatchInputSchema = z.object({
49
74
  scope: z.object({
50
75
  type: z.enum(AuthScopeType),
@@ -253,6 +278,26 @@ export const m2mWebhookDeliveryBatchService = createCustomBatchExecutionService(
253
278
  // connectivity test must exercise THIS transport, not a parallel one,
254
279
  // or a green test would prove nothing about real deliveries.
255
280
  const bodyBytes = typeof row.payload === 'string' ? row.payload : JSON.stringify(row.payload);
281
+ if (webhookEndpointTransportIsPlaintext(row.httpUrl)) {
282
+ const warnedKey = `${input.scope.type}:${input.scope.id}:${row.endpointId}`;
283
+ if (!PLAINTEXT_ENDPOINTS_ALREADY_WARNED.has(warnedKey)) {
284
+ PLAINTEXT_ENDPOINTS_ALREADY_WARNED.add(warnedKey);
285
+ // NOT debug. The whole point is that an operator meets this without going looking, and
286
+ // `AbstractControllerBackendService` disables the debug channel — the same trap that made a
287
+ // readiness breakdown unreachable in #498.
288
+ logger.warn('Webhook endpoint is plaintext: the delivery signature is sent in the clear', {
289
+ scopeType: input.scope.type,
290
+ scopeId: input.scope.id,
291
+ endpointId: row.endpointId,
292
+ // Host only, never the URL — a customer endpoint's path routinely carries a per-tenant
293
+ // token, and this line reaches the ordinary log stream.
294
+ destinationHost: webhookEndpointDestinationHost(row.httpUrl),
295
+ exposure: 'The signature JWT is readable on the network path and replayable against this '
296
+ + 'endpoint until it expires, so an observer of one delivery can forge the next.',
297
+ remedy: 'Reconfigure this endpoint with an https:// URL.',
298
+ });
299
+ }
300
+ }
256
301
  const { responseStatus, responseBodyTruncated, networkError } = await sendSignedWebhookRequest({
257
302
  url: row.httpUrl,
258
303
  body: bodyBytes,
@@ -1 +1 @@
1
- {"version":3,"file":"m2m-webhook-delivery.batch.backend.service.js","sourceRoot":"","sources":["../../../../../../../src/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.backend.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * M2M Webhook Delivery Batch Worker\n *\n * Event-triggered custom batch — one job per delivery row enqueued by\n * `M2MWebhookDispatcherBackendService.enqueueDelivery`. The worker:\n * 1. Re-reads the row from `M2MWebhookDeliveryLog` (ground truth —\n * we never trust in-flight queue state for the body or signature).\n * 2. Marks it `IN_FLIGHT` (incrementing `attemptCount`).\n * 3. Builds the JWT signature with `JwtPrivateKeys.APPLICATION_WEBHOOK`.\n * 4. POSTs the body with a 30s `AbortController` timeout.\n * 5. Classifies the response and records the terminal/intermediate\n * transition on the row.\n *\n * Status classification (D6):\n * - 2xx → DELIVERED (terminal success).\n * - 4xx, excluding 408 / 429 → FAILED (terminal — non-retryable).\n * - 408 / 429 / 5xx / network → mark failed attempt; if\n * `attemptCount >= MAX_ATTEMPTS`,\n * transition to FAILED.\n *\n * Custom batches are factory-created rather than constructor-injected. This\n * batch therefore declares its exact services through `resolveDependencies`;\n * the executor resolves them lazily for each invocation and `doHandle`\n * receives only the typed named result.\n *\n * @see m2m-webhook-organization-delivery.md — Phase 3 / Step 10\n * @see notifications/email/services/email-batch-send.batch.backend.service.ts\n * (precedent: same pattern for an event-triggered custom batch).\n */\n\nimport { z } from 'zod';\nimport {\n AuthScopeType,\n M2M_WEBHOOK_DELIVERY_CONTRACT,\n} from '@wildo-ai/saas-models';\nimport {\n createCustomBatchExecutionService,\n type BatchesCronjobsCustomExecution_Service,\n} from '~wildo-backend-lib/base-classes/services/batches/batches-cronjobs-custom-execution.service';\nimport { ENGINE_M2M_WEBHOOK_DELIVERY_BATCH_MANIFEST } from '~wildo-backend-lib/base-classes/services/batches/engine-custom-batch-manifests';\nimport { describeCaughtError, projectCaughtErrorLogFields } from '~wildo-backend-lib/errors/utils/error-log-level-classification.backend.utils';\nimport { SAAS_SERVICE_TYPES } from '~wildo-backend-lib/inject/models/service-types';\nimport type { JwtBackendService } from '~wildo-backend-lib/security/jwt/services/jwt.backend.service';\nimport { JwtPrivateKeys } from '~wildo-backend-lib/security/authentications/models/jwt.backend.schemas';\nimport type { MetricsService } from '~wildo-backend-lib/monitoring/observability/services/metrics.service';\nimport type { M2MWebhookDeliveryLogRepository } from '~wildo-backend-lib/notifications/webhooks/outbound/services/m2m-webhook-delivery-log.repository';\nimport {\n MAX_ATTEMPTS,\n classifyResponseStatus,\n computeNextAttemptAt,\n} from './m2m-webhook-delivery.batch.utils';\nimport { M2M_WEBHOOK_BODY_HASH_ALGORITHM, sendSignedWebhookRequest } from '../m2m-webhook-signed-request.backend.utils';\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Input / Output schemas\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * The dispatcher writes the row first, then enqueues this lightweight\n * payload. Keeping the payload minimal (id + scope) makes the worker\n * resilient to queue / DB race conditions: re-reading the row is the\n * source of truth.\n */\nexport const M2MWebhookDeliveryBatchInputSchema = z.object({\n scope: z.object({\n type: z.enum(AuthScopeType),\n id: z.string().min(1),\n }),\n deliveryLogId: z.string().min(1),\n});\n\nexport type M2MWebhookDeliveryBatchInput = z.infer<typeof M2MWebhookDeliveryBatchInputSchema>;\n\nexport const M2MWebhookDeliveryBatchOutputSchema = z.object({\n deliveryLogId: z.string(),\n /**\n * High-level outcome string. Stored only in the worker output for\n * cron / log inspection; the persisted truth lives on the row's\n * `status` field.\n */\n outcome: z.enum([\n 'delivered',\n 'retry_scheduled',\n 'failed_terminal',\n 'skipped_missing_row',\n 'skipped_already_leased',\n ]),\n attemptCount: z.number().int().nonnegative(),\n responseStatus: z.number().int().optional(),\n durationMs: z.number().int().nonnegative(),\n});\n\nexport type M2MWebhookDeliveryBatchOutput = z.infer<typeof M2MWebhookDeliveryBatchOutputSchema>;\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Batch Service\n// ═══════════════════════════════════════════════════════════════════════════\n\nexport const m2mWebhookDeliveryBatchService: BatchesCronjobsCustomExecution_Service<\n typeof M2MWebhookDeliveryBatchInputSchema,\n typeof M2MWebhookDeliveryBatchOutputSchema\n> = createCustomBatchExecutionService({\n input: M2MWebhookDeliveryBatchInputSchema,\n output: M2MWebhookDeliveryBatchOutputSchema,\n batchCronjob_Context: {\n // Anchored on the `APPLICATION` primary scope rather than a fake\n // `ORGANIZATION_M2M_WEBHOOK_DELIVERY_LOG` operation: an event-triggered\n // polymorphic worker has no honest \"primary\" resource (each enqueued\n // row carries its own `scope: { type, id }` and routes to either\n // `ORGANIZATION_M2M_WEBHOOK_DELIVERY_LOG` or\n // `APPLICATION_M2M_WEBHOOK_DELIVERY_LOG` via\n // `resolveDeliveryLogResourceType` in\n // `m2m-webhook-delivery-log.repository.ts`).\n //\n // The bootstrap path inside\n // `ExecutionContextCreatorBackendService.createForInternalCustomBatch`\n // resolves an `APPLICATION.READ` operation, populates the application\n // id, then swaps in `notifications:m2m-webhook-delivery` via\n // `withOperation()`. Audit trails surface the honest batch identity\n // and authorization runs against `APP_ADMIN_SUPER_ADMIN @ APPLICATION`\n // (see `createInternalSystemRoles()`), exactly as before, but without\n // pretending the worker mutates the org-variant log on every job —\n // including for app-scoped deliveries where that anchor was a\n // flat-out lie. Per-row resource-type resolution (org vs app) stays\n // inside the worker and is driven off the per-row `input.scope.type`.\n kind: ENGINE_M2M_WEBHOOK_DELIVERY_BATCH_MANIFEST.kind,\n operationIdentifier: ENGINE_M2M_WEBHOOK_DELIVERY_BATCH_MANIFEST.operationIdentifier,\n primaryScope: ENGINE_M2M_WEBHOOK_DELIVERY_BATCH_MANIFEST.primaryScope,\n },\n resolveDependencies: ({ get }) => ({\n repository: get<M2MWebhookDeliveryLogRepository>(\n SAAS_SERVICE_TYPES.M2MWebhookDeliveryLogRepository,\n ),\n jwtService: get<JwtBackendService>(SAAS_SERVICE_TYPES.JwtBackendService),\n metricsService: get<MetricsService>(SAAS_SERVICE_TYPES.MetricsService),\n }),\n doHandle: async (input, { logger, executionContext, dependencies }) => {\n const startedAt = Date.now();\n const logDebug = logger.debugByType('M2MWebhookDeliveryBatch');\n const {\n repository: repo,\n jwtService,\n metricsService,\n } = dependencies;\n\n /**\n * Single funnel for every `doHandle` return-point. Mirrors the\n * batch output back to the caller while firing the Phase 5 /\n * Step 17 outcome counter exactly once per worker invocation.\n *\n * Kept inline (not extracted to a module-level helper) because it\n * closes over `metricsService` and `input.scope.type` — lifting it\n * would need re-threading both via parameters on every call site\n * and would dilute the fire-exactly-once contract this funnel\n * enforces.\n *\n * Metric emission is error-isolated for the same reason the audit\n * helper swallows its failures: observability MUST NEVER fail the\n * main flow. By the time `recordAndReturn` runs, the row has\n * already been persisted with the correct terminal/intermediate\n * status — letting an OpenTelemetry exporter glitch abort the\n * batch invocation here would leave the custom-batch runner\n * reporting the run as failed even though the real delivery\n * completed and the truth-source row reflects success.\n */\n const recordAndReturn = (\n output: M2MWebhookDeliveryBatchOutput,\n ): M2MWebhookDeliveryBatchOutput => {\n try {\n metricsService.recordM2MWebhookDeliveryOutcome({\n scope: input.scope.type,\n outcome: output.outcome,\n });\n } catch (error) {\n logger.warn('Failed to record M2M webhook delivery outcome metric', {\n deliveryLogId: input.deliveryLogId,\n scopeType: input.scope.type,\n scopeId: input.scope.id,\n outcome: output.outcome,\n ...projectCaughtErrorLogFields(error),\n });\n }\n return output;\n };\n\n // ── Load the row (ground truth) ────────────────────────────\n const row = await repo.read(input.scope, executionContext, input.deliveryLogId);\n if (!row) {\n // Possible if the row was purged between enqueue and worker\n // execution (admin `PURGE_OLD`). Quiet skip — there is nothing\n // to deliver and no caller to surface the absence to.\n logger.warn('Webhook delivery row not found; skipping', {\n deliveryLogId: input.deliveryLogId,\n scopeType: input.scope.type,\n scopeId: input.scope.id,\n });\n return recordAndReturn({\n deliveryLogId: input.deliveryLogId,\n outcome: 'skipped_missing_row',\n attemptCount: 0,\n durationMs: Date.now() - startedAt,\n });\n }\n\n const nextAttemptCount = (row.attemptCount ?? 0) + 1;\n\n // ── Lease the row (atomic CAS) ─────────────────────────────\n // `markInFlight` is a compare-and-swap on `status: PENDING`. If\n // another worker already leased the row (cron retry sweep + queue\n // redelivery race), the CAS returns false and we exit cleanly —\n // double-POSTs and double-counted attempts would corrupt the\n // retry budget and the consumer's idempotency guarantees.\n const leased = await repo.markInFlight(\n input.scope,\n executionContext,\n input.deliveryLogId,\n nextAttemptCount,\n );\n if (!leased) {\n logger.warn('Webhook delivery row already leased by another worker; skipping', {\n deliveryLogId: input.deliveryLogId,\n scopeType: input.scope.type,\n scopeId: input.scope.id,\n endpointId: row.endpointId,\n httpUrl: row.httpUrl,\n signatureJti: row.signatureJti,\n currentStatus: row.status,\n });\n return recordAndReturn({\n deliveryLogId: input.deliveryLogId,\n outcome: 'skipped_already_leased',\n attemptCount: row.attemptCount ?? 0,\n durationMs: Date.now() - startedAt,\n });\n }\n\n // ── Build the JWT signature (D5: claims-JWT) ───────────────\n // The body itself is NOT in the JWT — only its sha256 hash. This\n // keeps the header small (some HTTP intermediaries cap header\n // size) and lets consumers verify integrity independently of the\n // raw body bytes (which they can re-hash).\n const claims = {\n // `jti` is the consumer-facing dedup key. It is stable across\n // every retry of THIS delivery row (same value re-signed each\n // attempt) and unique across rows. Consumers MUST dedup on\n // `jti` — the rest of the token (`iat`, `exp`, signature) is\n // refreshed per attempt and so cannot serve as a replay marker.\n // See `m2m-webhook-dispatcher.backend.service.ts` (`signatureJti`\n // creation site) for the full consumer-contract JSDoc.\n // Claim NAMES come from the published receiver contract so the customer\n // documentation and this signing site cannot drift apart.\n [M2M_WEBHOOK_DELIVERY_CONTRACT.signatureClaims.deliveryId]: row.signatureJti,\n [M2M_WEBHOOK_DELIVERY_CONTRACT.signatureClaims.bodyHash]: row.payloadHash,\n [M2M_WEBHOOK_DELIVERY_CONTRACT.signatureClaims.bodyHashAlgorithm]: M2M_WEBHOOK_BODY_HASH_ALGORITHM,\n [M2M_WEBHOOK_DELIVERY_CONTRACT.signatureClaims.eventChannel]: row.channel,\n [M2M_WEBHOOK_DELIVERY_CONTRACT.signatureClaims.resourceIdentifier]: row.resourceIdentifier,\n [M2M_WEBHOOK_DELIVERY_CONTRACT.signatureClaims.operationIdentifier]: row.operationIdentifier,\n // `iss`, `iat`, `exp`, `aud`, `kid` defaults come from\n // `JwtPrivateKeySignOptions[APPLICATION_WEBHOOK]`. We don't\n // override them here — the consumer-facing contract is the\n // signing options table, not this call site.\n };\n\n let signature: string;\n try {\n signature = await jwtService.sign(claims, JwtPrivateKeys.APPLICATION_WEBHOOK);\n } catch (error) {\n // Signing failure is a configuration problem (missing key) —\n // re-trying won't help until the operator fixes secrets, so we\n // mark the row as terminally failed and let admin RETRY pick it\n // up after the fix.\n const reason = describeCaughtError(error);\n logger.error('Failed to sign webhook payload — marking delivery FAILED', {\n deliveryLogId: input.deliveryLogId,\n scopeType: input.scope.type,\n scopeId: input.scope.id,\n endpointId: row.endpointId,\n httpUrl: row.httpUrl,\n signatureJti: row.signatureJti,\n attempt: nextAttemptCount,\n error,\n });\n await repo.markFinallyFailed(input.scope, executionContext, input.deliveryLogId, {\n failureReason: `JWT signing failed: ${reason}`,\n });\n return recordAndReturn({\n deliveryLogId: input.deliveryLogId,\n outcome: 'failed_terminal',\n attemptCount: nextAttemptCount,\n durationMs: Date.now() - startedAt,\n });\n }\n\n // ── POST the body ──────────────────────────────────────────\n // Shared with the `webhookConfig.testEndpoint` probe (see\n // `../m2m-webhook-signed-request.backend.utils`). The admin-facing\n // connectivity test must exercise THIS transport, not a parallel one,\n // or a green test would prove nothing about real deliveries.\n const bodyBytes =\n typeof row.payload === 'string' ? row.payload : JSON.stringify(row.payload);\n const { responseStatus, responseBodyTruncated, networkError } = await sendSignedWebhookRequest({\n url: row.httpUrl,\n body: bodyBytes,\n signature,\n });\n\n // Job-level duration: spans the row re-read and lease as well as the POST,\n // so it stays the batch's own measurement rather than the transport's.\n const durationMs = Date.now() - startedAt;\n\n // ── Classify + persist transition ──────────────────────────\n if (responseStatus !== undefined) {\n const verdict = classifyResponseStatus(responseStatus);\n\n if (verdict === 'delivered') {\n await repo.markDelivered(input.scope, executionContext, input.deliveryLogId, {\n responseStatus,\n responseBodyTruncated,\n });\n logDebug('Webhook delivered', {\n deliveryLogId: input.deliveryLogId,\n scopeType: input.scope.type,\n scopeId: input.scope.id,\n endpointId: row.endpointId,\n httpUrl: row.httpUrl,\n signatureJti: row.signatureJti,\n httpStatus: responseStatus,\n durationMs,\n attempt: nextAttemptCount,\n });\n return recordAndReturn({\n deliveryLogId: input.deliveryLogId,\n outcome: 'delivered',\n attemptCount: nextAttemptCount,\n responseStatus,\n durationMs,\n });\n }\n\n if (verdict === 'fatal') {\n await repo.markFinallyFailed(input.scope, executionContext, input.deliveryLogId, {\n responseStatus,\n responseBodyTruncated,\n failureReason: `non-retryable HTTP status ${responseStatus}`,\n });\n logger.warn('Webhook delivery failed (non-retryable)', {\n deliveryLogId: input.deliveryLogId,\n scopeType: input.scope.type,\n scopeId: input.scope.id,\n endpointId: row.endpointId,\n httpUrl: row.httpUrl,\n signatureJti: row.signatureJti,\n httpStatus: responseStatus,\n durationMs,\n attempt: nextAttemptCount,\n });\n return recordAndReturn({\n deliveryLogId: input.deliveryLogId,\n outcome: 'failed_terminal',\n attemptCount: nextAttemptCount,\n responseStatus,\n durationMs,\n });\n }\n\n // verdict === 'retry' — fall through to the retry branch below.\n }\n\n // Retryable failure (5xx, 408, 429, network/timeout). Decide\n // between scheduling another attempt and giving up.\n const failureReason =\n networkError ?? `retryable HTTP status ${responseStatus ?? 'unknown'}`;\n\n if (nextAttemptCount >= MAX_ATTEMPTS) {\n await repo.markFinallyFailed(input.scope, executionContext, input.deliveryLogId, {\n responseStatus,\n responseBodyTruncated,\n failureReason: `${failureReason} (retry cap ${MAX_ATTEMPTS} reached)`,\n });\n logger.warn('Webhook delivery failed (retry cap reached)', {\n deliveryLogId: input.deliveryLogId,\n scopeType: input.scope.type,\n scopeId: input.scope.id,\n endpointId: row.endpointId,\n httpUrl: row.httpUrl,\n signatureJti: row.signatureJti,\n httpStatus: responseStatus,\n durationMs,\n attempt: nextAttemptCount,\n failureReason,\n });\n return recordAndReturn({\n deliveryLogId: input.deliveryLogId,\n outcome: 'failed_terminal',\n attemptCount: nextAttemptCount,\n responseStatus,\n durationMs,\n });\n }\n\n const nextAttemptAt = computeNextAttemptAt(nextAttemptCount);\n await repo.markFailedAttempt(input.scope, executionContext, input.deliveryLogId, {\n responseStatus,\n responseBodyTruncated,\n failureReason,\n nextAttemptAt,\n });\n logDebug('Webhook delivery retry scheduled', {\n deliveryLogId: input.deliveryLogId,\n scopeType: input.scope.type,\n scopeId: input.scope.id,\n endpointId: row.endpointId,\n httpUrl: row.httpUrl,\n signatureJti: row.signatureJti,\n httpStatus: responseStatus,\n durationMs,\n attempt: nextAttemptCount,\n nextAttemptAt: nextAttemptAt.toISOString(),\n failureReason,\n });\n return recordAndReturn({\n deliveryLogId: input.deliveryLogId,\n outcome: 'retry_scheduled',\n attemptCount: nextAttemptCount,\n responseStatus,\n durationMs,\n });\n },\n});\n\n// Batch reference identifier lives in the declarative manifest registry\n// (`engine-custom-batch-manifests`); import `M2M_WEBHOOK_DELIVERY_BATCH_REF`\n// from there to keep a single source of truth across runtime wiring,\n// queue dispatch, and specification cross-validation.\n"]}
1
+ {"version":3,"file":"m2m-webhook-delivery.batch.backend.service.js","sourceRoot":"","sources":["../../../../../../../src/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.backend.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * M2M Webhook Delivery Batch Worker\n *\n * Event-triggered custom batch — one job per delivery row enqueued by\n * `M2MWebhookDispatcherBackendService.enqueueDelivery`. The worker:\n * 1. Re-reads the row from `M2MWebhookDeliveryLog` (ground truth —\n * we never trust in-flight queue state for the body or signature).\n * 2. Marks it `IN_FLIGHT` (incrementing `attemptCount`).\n * 3. Builds the JWT signature with `JwtPrivateKeys.APPLICATION_WEBHOOK`.\n * 4. POSTs the body with a 30s `AbortController` timeout.\n * 5. Classifies the response and records the terminal/intermediate\n * transition on the row.\n *\n * Status classification (D6):\n * - 2xx → DELIVERED (terminal success).\n * - 4xx, excluding 408 / 429 → FAILED (terminal — non-retryable).\n * - 408 / 429 / 5xx / network → mark failed attempt; if\n * `attemptCount >= MAX_ATTEMPTS`,\n * transition to FAILED.\n *\n * Custom batches are factory-created rather than constructor-injected. This\n * batch therefore declares its exact services through `resolveDependencies`;\n * the executor resolves them lazily for each invocation and `doHandle`\n * receives only the typed named result.\n *\n * @see m2m-webhook-organization-delivery.md — Phase 3 / Step 10\n * @see notifications/email/services/email-batch-send.batch.backend.service.ts\n * (precedent: same pattern for an event-triggered custom batch).\n */\n\nimport { z } from 'zod';\nimport {\n AuthScopeType,\n M2M_WEBHOOK_DELIVERY_CONTRACT,\n webhookEndpointDestinationHost,\n webhookEndpointTransportIsPlaintext,\n} from '@wildo-ai/saas-models';\nimport {\n createCustomBatchExecutionService,\n type BatchesCronjobsCustomExecution_Service,\n} from '~wildo-backend-lib/base-classes/services/batches/batches-cronjobs-custom-execution.service';\nimport { ENGINE_M2M_WEBHOOK_DELIVERY_BATCH_MANIFEST } from '~wildo-backend-lib/base-classes/services/batches/engine-custom-batch-manifests';\nimport { describeCaughtError, projectCaughtErrorLogFields } from '~wildo-backend-lib/errors/utils/error-log-level-classification.backend.utils';\nimport { SAAS_SERVICE_TYPES } from '~wildo-backend-lib/inject/models/service-types';\nimport type { JwtBackendService } from '~wildo-backend-lib/security/jwt/services/jwt.backend.service';\nimport { JwtPrivateKeys } from '~wildo-backend-lib/security/authentications/models/jwt.backend.schemas';\nimport type { MetricsService } from '~wildo-backend-lib/monitoring/observability/services/metrics.service';\nimport type { M2MWebhookDeliveryLogRepository } from '~wildo-backend-lib/notifications/webhooks/outbound/services/m2m-webhook-delivery-log.repository';\nimport {\n MAX_ATTEMPTS,\n classifyResponseStatus,\n computeNextAttemptAt,\n} from './m2m-webhook-delivery.batch.utils';\nimport { M2M_WEBHOOK_BODY_HASH_ALGORITHM, sendSignedWebhookRequest } from '../m2m-webhook-signed-request.backend.utils';\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Input / Output schemas\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * The dispatcher writes the row first, then enqueues this lightweight\n * payload. Keeping the payload minimal (id + scope) makes the worker\n * resilient to queue / DB race conditions: re-reading the row is the\n * source of truth.\n */\n/**\n * Endpoints already warned about in this process, so a permanently-plaintext destination costs one\n * line rather than one per delivery (#492).\n *\n * ## Why the warning is HERE, and why it is once\n *\n * Plaintext endpoints are ADMITTED — a commercial accommodation recorded on\n * `WebhookEndpointSchema.url` — and the cost of admitting them is that the decision becomes\n * invisible. The obvious place to say so is the moment an endpoint is SAVED, and that place does\n * not exist: `webhookConfig` declares CREATE and UPDATE `REPOSITORY_ONLY` with no admin route, and\n * the only writer that exists (data seeding) reaches the row through `upsertByBusinessKey`, a raw\n * repository call that no operation-pipeline hook observes. A postfix handler there would have been\n * a mechanism nothing runs — the shape this whole review exists to remove.\n *\n * The delivery IS the exposure, so this is where it can be stated truthfully: every POST over\n * `http://` puts the signature JWT on the wire in the clear, readable and replayable by anyone on\n * the path until it expires.\n *\n * Once per endpoint per process, because a webhook configuration is stable: a WARN on every\n * delivery would be a line an operator learns to filter, and a filtered warning is the same as no\n * warning. The set is bounded by the endpoint population and is deliberately NOT time-based — the\n * fact does not become news again after an hour, it becomes news again when the process restarts\n * and re-reads a configuration somebody may have changed.\n */\nconst PLAINTEXT_ENDPOINTS_ALREADY_WARNED = new Set<string>();\n\nexport const M2MWebhookDeliveryBatchInputSchema = z.object({\n scope: z.object({\n type: z.enum(AuthScopeType),\n id: z.string().min(1),\n }),\n deliveryLogId: z.string().min(1),\n});\n\nexport type M2MWebhookDeliveryBatchInput = z.infer<typeof M2MWebhookDeliveryBatchInputSchema>;\n\nexport const M2MWebhookDeliveryBatchOutputSchema = z.object({\n deliveryLogId: z.string(),\n /**\n * High-level outcome string. Stored only in the worker output for\n * cron / log inspection; the persisted truth lives on the row's\n * `status` field.\n */\n outcome: z.enum([\n 'delivered',\n 'retry_scheduled',\n 'failed_terminal',\n 'skipped_missing_row',\n 'skipped_already_leased',\n ]),\n attemptCount: z.number().int().nonnegative(),\n responseStatus: z.number().int().optional(),\n durationMs: z.number().int().nonnegative(),\n});\n\nexport type M2MWebhookDeliveryBatchOutput = z.infer<typeof M2MWebhookDeliveryBatchOutputSchema>;\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Batch Service\n// ═══════════════════════════════════════════════════════════════════════════\n\nexport const m2mWebhookDeliveryBatchService: BatchesCronjobsCustomExecution_Service<\n typeof M2MWebhookDeliveryBatchInputSchema,\n typeof M2MWebhookDeliveryBatchOutputSchema\n> = createCustomBatchExecutionService({\n input: M2MWebhookDeliveryBatchInputSchema,\n output: M2MWebhookDeliveryBatchOutputSchema,\n batchCronjob_Context: {\n // Anchored on the `APPLICATION` primary scope rather than a fake\n // `ORGANIZATION_M2M_WEBHOOK_DELIVERY_LOG` operation: an event-triggered\n // polymorphic worker has no honest \"primary\" resource (each enqueued\n // row carries its own `scope: { type, id }` and routes to either\n // `ORGANIZATION_M2M_WEBHOOK_DELIVERY_LOG` or\n // `APPLICATION_M2M_WEBHOOK_DELIVERY_LOG` via\n // `resolveDeliveryLogResourceType` in\n // `m2m-webhook-delivery-log.repository.ts`).\n //\n // The bootstrap path inside\n // `ExecutionContextCreatorBackendService.createForInternalCustomBatch`\n // resolves an `APPLICATION.READ` operation, populates the application\n // id, then swaps in `notifications:m2m-webhook-delivery` via\n // `withOperation()`. Audit trails surface the honest batch identity\n // and authorization runs against `APP_ADMIN_SUPER_ADMIN @ APPLICATION`\n // (see `createInternalSystemRoles()`), exactly as before, but without\n // pretending the worker mutates the org-variant log on every job —\n // including for app-scoped deliveries where that anchor was a\n // flat-out lie. Per-row resource-type resolution (org vs app) stays\n // inside the worker and is driven off the per-row `input.scope.type`.\n kind: ENGINE_M2M_WEBHOOK_DELIVERY_BATCH_MANIFEST.kind,\n operationIdentifier: ENGINE_M2M_WEBHOOK_DELIVERY_BATCH_MANIFEST.operationIdentifier,\n primaryScope: ENGINE_M2M_WEBHOOK_DELIVERY_BATCH_MANIFEST.primaryScope,\n },\n resolveDependencies: ({ get }) => ({\n repository: get<M2MWebhookDeliveryLogRepository>(\n SAAS_SERVICE_TYPES.M2MWebhookDeliveryLogRepository,\n ),\n jwtService: get<JwtBackendService>(SAAS_SERVICE_TYPES.JwtBackendService),\n metricsService: get<MetricsService>(SAAS_SERVICE_TYPES.MetricsService),\n }),\n doHandle: async (input, { logger, executionContext, dependencies }) => {\n const startedAt = Date.now();\n const logDebug = logger.debugByType('M2MWebhookDeliveryBatch');\n const {\n repository: repo,\n jwtService,\n metricsService,\n } = dependencies;\n\n /**\n * Single funnel for every `doHandle` return-point. Mirrors the\n * batch output back to the caller while firing the Phase 5 /\n * Step 17 outcome counter exactly once per worker invocation.\n *\n * Kept inline (not extracted to a module-level helper) because it\n * closes over `metricsService` and `input.scope.type` — lifting it\n * would need re-threading both via parameters on every call site\n * and would dilute the fire-exactly-once contract this funnel\n * enforces.\n *\n * Metric emission is error-isolated for the same reason the audit\n * helper swallows its failures: observability MUST NEVER fail the\n * main flow. By the time `recordAndReturn` runs, the row has\n * already been persisted with the correct terminal/intermediate\n * status — letting an OpenTelemetry exporter glitch abort the\n * batch invocation here would leave the custom-batch runner\n * reporting the run as failed even though the real delivery\n * completed and the truth-source row reflects success.\n */\n const recordAndReturn = (\n output: M2MWebhookDeliveryBatchOutput,\n ): M2MWebhookDeliveryBatchOutput => {\n try {\n metricsService.recordM2MWebhookDeliveryOutcome({\n scope: input.scope.type,\n outcome: output.outcome,\n });\n } catch (error) {\n logger.warn('Failed to record M2M webhook delivery outcome metric', {\n deliveryLogId: input.deliveryLogId,\n scopeType: input.scope.type,\n scopeId: input.scope.id,\n outcome: output.outcome,\n ...projectCaughtErrorLogFields(error),\n });\n }\n return output;\n };\n\n // ── Load the row (ground truth) ────────────────────────────\n const row = await repo.read(input.scope, executionContext, input.deliveryLogId);\n if (!row) {\n // Possible if the row was purged between enqueue and worker\n // execution (admin `PURGE_OLD`). Quiet skip — there is nothing\n // to deliver and no caller to surface the absence to.\n logger.warn('Webhook delivery row not found; skipping', {\n deliveryLogId: input.deliveryLogId,\n scopeType: input.scope.type,\n scopeId: input.scope.id,\n });\n return recordAndReturn({\n deliveryLogId: input.deliveryLogId,\n outcome: 'skipped_missing_row',\n attemptCount: 0,\n durationMs: Date.now() - startedAt,\n });\n }\n\n const nextAttemptCount = (row.attemptCount ?? 0) + 1;\n\n // ── Lease the row (atomic CAS) ─────────────────────────────\n // `markInFlight` is a compare-and-swap on `status: PENDING`. If\n // another worker already leased the row (cron retry sweep + queue\n // redelivery race), the CAS returns false and we exit cleanly —\n // double-POSTs and double-counted attempts would corrupt the\n // retry budget and the consumer's idempotency guarantees.\n const leased = await repo.markInFlight(\n input.scope,\n executionContext,\n input.deliveryLogId,\n nextAttemptCount,\n );\n if (!leased) {\n logger.warn('Webhook delivery row already leased by another worker; skipping', {\n deliveryLogId: input.deliveryLogId,\n scopeType: input.scope.type,\n scopeId: input.scope.id,\n endpointId: row.endpointId,\n httpUrl: row.httpUrl,\n signatureJti: row.signatureJti,\n currentStatus: row.status,\n });\n return recordAndReturn({\n deliveryLogId: input.deliveryLogId,\n outcome: 'skipped_already_leased',\n attemptCount: row.attemptCount ?? 0,\n durationMs: Date.now() - startedAt,\n });\n }\n\n // ── Build the JWT signature (D5: claims-JWT) ───────────────\n // The body itself is NOT in the JWT — only its sha256 hash. This\n // keeps the header small (some HTTP intermediaries cap header\n // size) and lets consumers verify integrity independently of the\n // raw body bytes (which they can re-hash).\n const claims = {\n // `jti` is the consumer-facing dedup key. It is stable across\n // every retry of THIS delivery row (same value re-signed each\n // attempt) and unique across rows. Consumers MUST dedup on\n // `jti` — the rest of the token (`iat`, `exp`, signature) is\n // refreshed per attempt and so cannot serve as a replay marker.\n // See `m2m-webhook-dispatcher.backend.service.ts` (`signatureJti`\n // creation site) for the full consumer-contract JSDoc.\n // Claim NAMES come from the published receiver contract so the customer\n // documentation and this signing site cannot drift apart.\n [M2M_WEBHOOK_DELIVERY_CONTRACT.signatureClaims.deliveryId]: row.signatureJti,\n [M2M_WEBHOOK_DELIVERY_CONTRACT.signatureClaims.bodyHash]: row.payloadHash,\n [M2M_WEBHOOK_DELIVERY_CONTRACT.signatureClaims.bodyHashAlgorithm]: M2M_WEBHOOK_BODY_HASH_ALGORITHM,\n [M2M_WEBHOOK_DELIVERY_CONTRACT.signatureClaims.eventChannel]: row.channel,\n [M2M_WEBHOOK_DELIVERY_CONTRACT.signatureClaims.resourceIdentifier]: row.resourceIdentifier,\n [M2M_WEBHOOK_DELIVERY_CONTRACT.signatureClaims.operationIdentifier]: row.operationIdentifier,\n // `iss`, `iat`, `exp`, `aud`, `kid` defaults come from\n // `JwtPrivateKeySignOptions[APPLICATION_WEBHOOK]`. We don't\n // override them here — the consumer-facing contract is the\n // signing options table, not this call site.\n };\n\n let signature: string;\n try {\n signature = await jwtService.sign(claims, JwtPrivateKeys.APPLICATION_WEBHOOK);\n } catch (error) {\n // Signing failure is a configuration problem (missing key) —\n // re-trying won't help until the operator fixes secrets, so we\n // mark the row as terminally failed and let admin RETRY pick it\n // up after the fix.\n const reason = describeCaughtError(error);\n logger.error('Failed to sign webhook payload — marking delivery FAILED', {\n deliveryLogId: input.deliveryLogId,\n scopeType: input.scope.type,\n scopeId: input.scope.id,\n endpointId: row.endpointId,\n httpUrl: row.httpUrl,\n signatureJti: row.signatureJti,\n attempt: nextAttemptCount,\n error,\n });\n await repo.markFinallyFailed(input.scope, executionContext, input.deliveryLogId, {\n failureReason: `JWT signing failed: ${reason}`,\n });\n return recordAndReturn({\n deliveryLogId: input.deliveryLogId,\n outcome: 'failed_terminal',\n attemptCount: nextAttemptCount,\n durationMs: Date.now() - startedAt,\n });\n }\n\n // ── POST the body ──────────────────────────────────────────\n // Shared with the `webhookConfig.testEndpoint` probe (see\n // `../m2m-webhook-signed-request.backend.utils`). The admin-facing\n // connectivity test must exercise THIS transport, not a parallel one,\n // or a green test would prove nothing about real deliveries.\n const bodyBytes =\n typeof row.payload === 'string' ? row.payload : JSON.stringify(row.payload);\n\n if (webhookEndpointTransportIsPlaintext(row.httpUrl)) {\n const warnedKey = `${input.scope.type}:${input.scope.id}:${row.endpointId}`;\n if (!PLAINTEXT_ENDPOINTS_ALREADY_WARNED.has(warnedKey)) {\n PLAINTEXT_ENDPOINTS_ALREADY_WARNED.add(warnedKey);\n // NOT debug. The whole point is that an operator meets this without going looking, and\n // `AbstractControllerBackendService` disables the debug channel — the same trap that made a\n // readiness breakdown unreachable in #498.\n logger.warn('Webhook endpoint is plaintext: the delivery signature is sent in the clear', {\n scopeType: input.scope.type,\n scopeId: input.scope.id,\n endpointId: row.endpointId,\n // Host only, never the URL — a customer endpoint's path routinely carries a per-tenant\n // token, and this line reaches the ordinary log stream.\n destinationHost: webhookEndpointDestinationHost(row.httpUrl),\n exposure: 'The signature JWT is readable on the network path and replayable against this '\n + 'endpoint until it expires, so an observer of one delivery can forge the next.',\n remedy: 'Reconfigure this endpoint with an https:// URL.',\n });\n }\n }\n\n const { responseStatus, responseBodyTruncated, networkError } = await sendSignedWebhookRequest({\n url: row.httpUrl,\n body: bodyBytes,\n signature,\n });\n\n // Job-level duration: spans the row re-read and lease as well as the POST,\n // so it stays the batch's own measurement rather than the transport's.\n const durationMs = Date.now() - startedAt;\n\n // ── Classify + persist transition ──────────────────────────\n if (responseStatus !== undefined) {\n const verdict = classifyResponseStatus(responseStatus);\n\n if (verdict === 'delivered') {\n await repo.markDelivered(input.scope, executionContext, input.deliveryLogId, {\n responseStatus,\n responseBodyTruncated,\n });\n logDebug('Webhook delivered', {\n deliveryLogId: input.deliveryLogId,\n scopeType: input.scope.type,\n scopeId: input.scope.id,\n endpointId: row.endpointId,\n httpUrl: row.httpUrl,\n signatureJti: row.signatureJti,\n httpStatus: responseStatus,\n durationMs,\n attempt: nextAttemptCount,\n });\n return recordAndReturn({\n deliveryLogId: input.deliveryLogId,\n outcome: 'delivered',\n attemptCount: nextAttemptCount,\n responseStatus,\n durationMs,\n });\n }\n\n if (verdict === 'fatal') {\n await repo.markFinallyFailed(input.scope, executionContext, input.deliveryLogId, {\n responseStatus,\n responseBodyTruncated,\n failureReason: `non-retryable HTTP status ${responseStatus}`,\n });\n logger.warn('Webhook delivery failed (non-retryable)', {\n deliveryLogId: input.deliveryLogId,\n scopeType: input.scope.type,\n scopeId: input.scope.id,\n endpointId: row.endpointId,\n httpUrl: row.httpUrl,\n signatureJti: row.signatureJti,\n httpStatus: responseStatus,\n durationMs,\n attempt: nextAttemptCount,\n });\n return recordAndReturn({\n deliveryLogId: input.deliveryLogId,\n outcome: 'failed_terminal',\n attemptCount: nextAttemptCount,\n responseStatus,\n durationMs,\n });\n }\n\n // verdict === 'retry' — fall through to the retry branch below.\n }\n\n // Retryable failure (5xx, 408, 429, network/timeout). Decide\n // between scheduling another attempt and giving up.\n const failureReason =\n networkError ?? `retryable HTTP status ${responseStatus ?? 'unknown'}`;\n\n if (nextAttemptCount >= MAX_ATTEMPTS) {\n await repo.markFinallyFailed(input.scope, executionContext, input.deliveryLogId, {\n responseStatus,\n responseBodyTruncated,\n failureReason: `${failureReason} (retry cap ${MAX_ATTEMPTS} reached)`,\n });\n logger.warn('Webhook delivery failed (retry cap reached)', {\n deliveryLogId: input.deliveryLogId,\n scopeType: input.scope.type,\n scopeId: input.scope.id,\n endpointId: row.endpointId,\n httpUrl: row.httpUrl,\n signatureJti: row.signatureJti,\n httpStatus: responseStatus,\n durationMs,\n attempt: nextAttemptCount,\n failureReason,\n });\n return recordAndReturn({\n deliveryLogId: input.deliveryLogId,\n outcome: 'failed_terminal',\n attemptCount: nextAttemptCount,\n responseStatus,\n durationMs,\n });\n }\n\n const nextAttemptAt = computeNextAttemptAt(nextAttemptCount);\n await repo.markFailedAttempt(input.scope, executionContext, input.deliveryLogId, {\n responseStatus,\n responseBodyTruncated,\n failureReason,\n nextAttemptAt,\n });\n logDebug('Webhook delivery retry scheduled', {\n deliveryLogId: input.deliveryLogId,\n scopeType: input.scope.type,\n scopeId: input.scope.id,\n endpointId: row.endpointId,\n httpUrl: row.httpUrl,\n signatureJti: row.signatureJti,\n httpStatus: responseStatus,\n durationMs,\n attempt: nextAttemptCount,\n nextAttemptAt: nextAttemptAt.toISOString(),\n failureReason,\n });\n return recordAndReturn({\n deliveryLogId: input.deliveryLogId,\n outcome: 'retry_scheduled',\n attemptCount: nextAttemptCount,\n responseStatus,\n durationMs,\n });\n },\n});\n\n// Batch reference identifier lives in the declarative manifest registry\n// (`engine-custom-batch-manifests`); import `M2M_WEBHOOK_DELIVERY_BATCH_REF`\n// from there to keep a single source of truth across runtime wiring,\n// queue dispatch, and specification cross-validation.\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"m2m-webhook-signed-request.backend.utils.d.ts","sourceRoot":"","sources":["../../../../../../src/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,6BAA6B,EAAmB,MAAM,uBAAuB,CAAC;AAkEvF,8EAA8E;AAC9E,eAAO,MAAM,+BAA+B,EAAE,OAAO,6BAA6B,CAAC,iBAAmE,CAAC;AAEvJ;;;;;;;;GAQG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACvC,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0FAA0F;IAC1F,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAuCF;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAAC,MAAM,EAAE;IACrD,gCAAgC;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAsEtC"}
1
+ {"version":3,"file":"m2m-webhook-signed-request.backend.utils.d.ts","sourceRoot":"","sources":["../../../../../../src/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,6BAA6B,EAAmB,MAAM,uBAAuB,CAAC;AA4EvF,8EAA8E;AAC9E,eAAO,MAAM,+BAA+B,EAAE,OAAO,6BAA6B,CAAC,iBAAmE,CAAC;AAEvJ;;;;;;;;GAQG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACvC,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0FAA0F;IAC1F,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAuCF;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAAC,MAAM,EAAE;IACrD,gCAAgC;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAsEtC"}
@@ -29,12 +29,22 @@ import { REQUEST_TIMEOUT_MS, WEBHOOK_USER_AGENT, truncateBody, } from './batches
29
29
  /**
30
30
  * Schemes an outbound webhook delivery may use.
31
31
  *
32
- * `http:` is admitted, and that is a DEFERRED decision rather than an endorsement. The A2A sibling
33
- * requires HTTPS unconditionally, and the same argument applies here — the signature JWT in transit
34
- * is a credential. But `WebhookEndpointSchema.url` is a bare `z.url()`, so plaintext endpoints are
35
- * authorable today and may already be authored; refusing them here would silently stop deliveries for
36
- * tenants whose configuration was accepted by the framework. Tightening this is a product decision
37
- * with a migration, not a hardening pass.
32
+ * `http:` is admitted. DECIDED 2026-09-08 (#492): keep admitting it, and document the exposure where
33
+ * a customer authors the endpoint — which is now done, on `WebhookEndpointSchema.url`.
34
+ *
35
+ * This is a COMMERCIAL accommodation, not a security assessment, and the distinction is the whole
36
+ * point of writing it down. The A2A sibling requires HTTPS unconditionally and the same argument
37
+ * applies here — the signature JWT in transit is a credential, readable on the path and replayable
38
+ * until it expires, so an observer of one delivery can forge the next. What was chosen is not to break
39
+ * endpoints that a previous version of the framework accepted.
40
+ *
41
+ * The two options NOT taken, either of which is the better security answer: require HTTPS with a
42
+ * migration that identifies and notifies existing plaintext endpoints, or require it for new endpoints
43
+ * and grandfather existing ones behind an explicit acknowledgement. The second is the one to revisit
44
+ * first — it stops the plaintext population growing without breaking anyone today.
45
+ *
46
+ * Reopen on an observed interception, or on a customer compliance requirement. Do not reopen it as a
47
+ * tidy-up: the asymmetry with the A2A caller is deliberate and is recorded at both sites.
38
48
  */
39
49
  const M2M_WEBHOOK_ADMITTED_PROTOCOLS = ['https:', 'http:'];
40
50
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"m2m-webhook-signed-request.backend.utils.js","sourceRoot":"","sources":["../../../../../../src/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The single outbound-transport primitive for M2M webhooks.\n *\n * Every signed request Wildo emits to a customer endpoint goes through\n * {@link sendSignedWebhookRequest} — the retry worker's real deliveries AND the\n * `webhookConfig.testEndpoint` synthetic probe. Two call sites, one implementation, on\n * purpose: a probe that reached the endpoint through a *different* code path would\n * validate that path rather than the delivery path, which is precisely the reassurance an\n * admin is asking for when they press \"test\". Timeout, User-Agent, signature header name,\n * and body-truncation behaviour are therefore not re-decided per caller.\n *\n * Scope boundary — this module owns the WIRE, nothing else. It does not sign (callers hold\n * their own claims), does not classify (see `classifyResponseStatus`), does not persist,\n * and never throws on a transport failure: an unreachable endpoint is data the caller must\n * report, not an exception. The only way to get an exception out of here is to pass\n * something that is not a valid request.\n *\n * The tunables come from `./batches/m2m-webhook-delivery.batch.utils`, which is\n * deliberately import-free so its pure-decision tests load without the DI graph. They are\n * left there rather than moved up here precisely to preserve that property — this module\n * performs I/O and would drag `@wildo-ai/saas-models` into those tests.\n *\n * @see batches/m2m-webhook-delivery.batch.backend.service.ts — real deliveries.\n * @see services/webhook-config-test-endpoint.custom-impl.backend.service.ts — synthetic probe.\n */\n\nimport { M2M_WEBHOOK_DELIVERY_CONTRACT, WildoHeaderKeys } from '@wildo-ai/saas-models';\nimport {\n OutboundTargetRejection,\n classifyOutboundTargetUrl,\n} from '~wildo-backend-lib/security/ssrf/outbound-target-guard.backend.utils';\nimport {\n REQUEST_TIMEOUT_MS,\n WEBHOOK_USER_AGENT,\n truncateBody,\n} from './batches/m2m-webhook-delivery.batch.utils';\n\n/**\n * Schemes an outbound webhook delivery may use.\n *\n * `http:` is admitted, and that is a DEFERRED decision rather than an endorsement. The A2A sibling\n * requires HTTPS unconditionally, and the same argument applies here — the signature JWT in transit\n * is a credential. But `WebhookEndpointSchema.url` is a bare `z.url()`, so plaintext endpoints are\n * authorable today and may already be authored; refusing them here would silently stop deliveries for\n * tenants whose configuration was accepted by the framework. Tightening this is a product decision\n * with a migration, not a hardening pass.\n */\nconst M2M_WEBHOOK_ADMITTED_PROTOCOLS = ['https:', 'http:'] as const;\n\n/**\n * Refuse a destination that would turn this server into a request-forgery tool.\n *\n * ## Why the guard is HERE and not on the schema\n *\n * `WebhookEndpointSchema.url` validates shape (`z.url()`) and nothing else, so an admin could author\n * `http://169.254.169.254/latest/meta-data/` and the engine would POST signed payloads to the cloud\n * instance-metadata service — then capture the answer into the delivery log as\n * `responseBodyTruncated`. That makes it a READ primitive, not a blind SSRF, and\n * `webhookConfig.testEndpoint` is a low-friction oracle for it.\n *\n * A schema refine would leave two holes this placement does not have: it would not cover endpoints\n * ALREADY STORED before the refine existed, and it would not cover the A2A push-delivery worker,\n * which reaches this same primitive with a URL its own (separate) guard validated at configuration\n * time. Putting the check at the wire makes it unbypassable for every caller — present and future —\n * which is what `.claude/rules/invariant-call-site-enumeration.md` means by preferring one\n * chokepoint over N hand-applied predicates.\n *\n * ## What it cannot do\n *\n * An ordinary hostname is not resolved, so `hook.attacker.test` with an A record of `169.254.169.254`\n * still passes. That residual is inherited from the shared classifier and is stated there; closing it\n * needs either a resolving check (a check-then-connect, still open to rebinding) or egress-path\n * enforcement. It is a deliberate open item, not an oversight.\n */\nfunction refuseUnsafeWebhookTarget(url: string): string | undefined {\n const rejection = classifyOutboundTargetUrl(url, { admittedProtocols: M2M_WEBHOOK_ADMITTED_PROTOCOLS });\n switch (rejection) {\n case undefined:\n return undefined;\n case OutboundTargetRejection.NOT_ABSOLUTE_ADMITTED_SCHEME:\n return 'refused: endpoint is not an absolute http(s) URL';\n case OutboundTargetRejection.CREDENTIALS_IN_URL:\n // Credentials in the URL would be replayed on every delivery and would land in any log or\n // delivery row that records the target.\n return 'refused: endpoint URL carries embedded credentials';\n case OutboundTargetRejection.PRIVATE_OR_RESERVED_ADDRESS:\n return 'refused: endpoint resolves to a private, loopback, link-local or otherwise reserved address';\n case OutboundTargetRejection.RESERVED_SPECIAL_USE_HOSTNAME:\n return 'refused: endpoint uses a reserved special-use hostname';\n }\n}\n\n/** Consumer-facing digest algorithm carried in every outbound webhook JWT. */\nexport const M2M_WEBHOOK_BODY_HASH_ALGORITHM: typeof M2M_WEBHOOK_DELIVERY_CONTRACT.bodyHashAlgorithm = M2M_WEBHOOK_DELIVERY_CONTRACT.bodyHashAlgorithm;\n\n/**\n * Outcome of one attempt at the wire level.\n *\n * `responseStatus` and `networkError` are mutually exclusive and exhaustive: either the\n * endpoint produced an HTTP response or it did not. Callers classify from there — this\n * type deliberately carries no verdict of its own, because \"429 is retryable\" is a\n * delivery-policy question and \"429 means the endpoint is reachable\" is a probe question,\n * and the same status answers both differently.\n */\nexport type SignedWebhookRequestResult = {\n /** Set when the endpoint answered, whatever the status. */\n responseStatus?: number;\n /** Best-effort capture of the consumer's response body, truncated on a UTF-8 boundary. */\n responseBodyTruncated?: string;\n /** Set when no HTTP response was obtained (DNS/TLS/connection failure, or timeout). */\n networkError?: string;\n /** Wall-clock duration of this attempt alone, excluding any caller-side work. */\n durationMs: number;\n};\n\n/**\n * Render a `fetch` rejection into something an operator can act on.\n *\n * Node's `fetch` (undici) rejects with a flat `TypeError: fetch failed` and buries the actual\n * cause — `ECONNREFUSED`, `ENOTFOUND`, `EHOSTUNREACH`, a TLS failure — one or more levels down in\n * `error.cause`. Reporting only `error.message` tells an admin their endpoint failed without\n * telling them whether the hostname is wrong, the port is closed, or the certificate is bad; for a\n * diagnostic whose entire job is to explain a failure, that is barely better than the silent\n * success this operation used to return. So walk the cause chain and append what it names.\n *\n * `AggregateError` (emitted when every resolved address fails, e.g. happy-eyeballs against a dead\n * host) carries its detail in `errors[]` rather than `cause`, so that shape is unwrapped too.\n * Depth-capped and de-duplicated: the chain is attacker-adjacent input in the sense that a hostile\n * endpoint controls how deep it goes, and a repeated message adds nothing.\n */\nfunction describeFetchFailure(error: unknown): string {\n if (!(error instanceof Error)) return String(error);\n\n const parts: string[] = [];\n const seen = new Set<string>();\n let current: unknown = error;\n\n for (let depth = 0; depth < 4 && current instanceof Error; depth += 1) {\n // `code` is where Node puts the actionable token (ECONNREFUSED, …); the message often repeats it.\n const code = (current as NodeJS.ErrnoException).code;\n const label = code && !current.message.includes(code) ? `${current.message} (${code})` : current.message;\n if (label && !seen.has(label)) {\n seen.add(label);\n parts.push(label);\n }\n const aggregated = current instanceof AggregateError ? current.errors?.[0] : undefined;\n current = aggregated ?? (current as { cause?: unknown }).cause;\n }\n\n return parts.join(': ') || 'fetch failed';\n}\n\n/**\n * POST a pre-signed body to a webhook endpoint under a hard timeout.\n *\n * Never throws for a transport failure — a refused connection, a DNS miss and a timeout\n * all come back as `networkError`. A timeout is reported with its budget spelled out\n * because \"timed out\" alone sends an operator hunting for the wrong thing.\n *\n * Body capture is best-effort: a consumer that returns an unreadable body still produced a\n * valid status, and losing the body must not turn a successful attempt into a failed one.\n */\nexport async function sendSignedWebhookRequest(params: {\n /** Absolute destination URL. */\n url: string;\n /** Exact bytes to send — already the string whose hash the caller signed. */\n body: string;\n /**\n * Value for the `X-Webhook-Signature` header. Omit when the caller authenticates by another\n * mechanism and supplies its own {@link headers} — see below.\n */\n signature?: string;\n /**\n * Caller-supplied headers, MERGED OVER the defaults.\n *\n * Added for the A2A push-notification worker, which authenticates with the CLIENT's declared\n * scheme (`Authorization: {scheme} {credentials}`) and sends `application/a2a+json` rather than\n * Wildo's own ES256 signature and `application/json`.\n *\n * Widening this primitive instead of writing a second POST is deliberate, and follows the module\n * header's own claim to own THE WIRE: timeout, abort handling, failure description and body\n * truncation are the parts that are easy to get subtly wrong and expensive to have two of. What\n * varies between callers is authentication and media type — which are exactly the two things a\n * caller is in a position to decide. Purely additive: `signature` stays optional-by-absence for\n * the two existing M2M call sites, whose behaviour is byte-for-byte unchanged.\n */\n headers?: Record<string, string>;\n}): Promise<SignedWebhookRequestResult> {\n const startedAt = Date.now();\n\n // Refused BEFORE any timer or connection: a target the guard rejects must produce no DNS lookup,\n // no socket, and no signed body on the wire. Reported as `networkError` rather than thrown, because\n // this module's contract is that a destination problem is DATA the caller reports — the probe\n // surfaces it to the admin as UNREACHABLE and the delivery worker records it on the attempt row.\n const refusal = refuseUnsafeWebhookTarget(params.url);\n if (refusal) {\n return { networkError: refusal, durationMs: Date.now() - startedAt };\n }\n\n const abort = new AbortController();\n const timer = setTimeout(() => abort.abort(), REQUEST_TIMEOUT_MS);\n\n let responseStatus: number | undefined;\n let responseBodyTruncated: string | undefined;\n let networkError: string | undefined;\n\n try {\n const response = await fetch(params.url, {\n method: 'POST',\n signal: abort.signal,\n /**\n * A redirect is REPORTED, never followed.\n *\n * Following one re-points the request at a target the guard above never saw, which is the\n * guard's most obvious bypass — an admin authors a public URL that 302s to\n * `http://169.254.169.254/`. It also silently defeats a decision this subsystem had ALREADY\n * taken and could not enforce: `classifyResponseStatus` classifies 3xx as `fatal` and\n * `resolveProbeOutcome` classifies it as REJECTED (\"webhooks must not redirect, and a\n * CDN/proxy redirect on a wrong URL is one of the most common real misconfigurations an admin\n * uses this probe to find\") — but with `fetch`'s default follow behaviour neither of those\n * branches could ever execute, because a 3xx never reached them.\n *\n * `'manual'` rather than `'error'` on purpose: `'error'` would surface as an opaque network\n * failure, whereas `'manual'` hands back the 3xx status so both classifiers see the redirect\n * and tell the admin exactly what their endpoint did.\n */\n redirect: 'manual',\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': WEBHOOK_USER_AGENT,\n ...(params.signature ? { [WildoHeaderKeys.X_WEBHOOK_SIGNATURE]: params.signature } : {}),\n ...params.headers,\n },\n body: params.body,\n });\n responseStatus = response.status;\n try {\n const text = await response.text();\n responseBodyTruncated = text ? truncateBody(text) : undefined;\n } catch {\n // Best-effort body capture — never fail the attempt on a non-readable body.\n responseBodyTruncated = undefined;\n }\n } catch (error) {\n networkError = abort.signal.aborted\n ? `request timed out after ${REQUEST_TIMEOUT_MS}ms`\n : describeFetchFailure(error);\n } finally {\n clearTimeout(timer);\n }\n\n return {\n responseStatus,\n responseBodyTruncated,\n networkError,\n durationMs: Date.now() - startedAt,\n };\n}\n"]}
1
+ {"version":3,"file":"m2m-webhook-signed-request.backend.utils.js","sourceRoot":"","sources":["../../../../../../src/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The single outbound-transport primitive for M2M webhooks.\n *\n * Every signed request Wildo emits to a customer endpoint goes through\n * {@link sendSignedWebhookRequest} — the retry worker's real deliveries AND the\n * `webhookConfig.testEndpoint` synthetic probe. Two call sites, one implementation, on\n * purpose: a probe that reached the endpoint through a *different* code path would\n * validate that path rather than the delivery path, which is precisely the reassurance an\n * admin is asking for when they press \"test\". Timeout, User-Agent, signature header name,\n * and body-truncation behaviour are therefore not re-decided per caller.\n *\n * Scope boundary — this module owns the WIRE, nothing else. It does not sign (callers hold\n * their own claims), does not classify (see `classifyResponseStatus`), does not persist,\n * and never throws on a transport failure: an unreachable endpoint is data the caller must\n * report, not an exception. The only way to get an exception out of here is to pass\n * something that is not a valid request.\n *\n * The tunables come from `./batches/m2m-webhook-delivery.batch.utils`, which is\n * deliberately import-free so its pure-decision tests load without the DI graph. They are\n * left there rather than moved up here precisely to preserve that property — this module\n * performs I/O and would drag `@wildo-ai/saas-models` into those tests.\n *\n * @see batches/m2m-webhook-delivery.batch.backend.service.ts — real deliveries.\n * @see services/webhook-config-test-endpoint.custom-impl.backend.service.ts — synthetic probe.\n */\n\nimport { M2M_WEBHOOK_DELIVERY_CONTRACT, WildoHeaderKeys } from '@wildo-ai/saas-models';\nimport {\n OutboundTargetRejection,\n classifyOutboundTargetUrl,\n} from '~wildo-backend-lib/security/ssrf/outbound-target-guard.backend.utils';\nimport {\n REQUEST_TIMEOUT_MS,\n WEBHOOK_USER_AGENT,\n truncateBody,\n} from './batches/m2m-webhook-delivery.batch.utils';\n\n/**\n * Schemes an outbound webhook delivery may use.\n *\n * `http:` is admitted. DECIDED 2026-09-08 (#492): keep admitting it, and document the exposure where\n * a customer authors the endpoint — which is now done, on `WebhookEndpointSchema.url`.\n *\n * This is a COMMERCIAL accommodation, not a security assessment, and the distinction is the whole\n * point of writing it down. The A2A sibling requires HTTPS unconditionally and the same argument\n * applies here — the signature JWT in transit is a credential, readable on the path and replayable\n * until it expires, so an observer of one delivery can forge the next. What was chosen is not to break\n * endpoints that a previous version of the framework accepted.\n *\n * The two options NOT taken, either of which is the better security answer: require HTTPS with a\n * migration that identifies and notifies existing plaintext endpoints, or require it for new endpoints\n * and grandfather existing ones behind an explicit acknowledgement. The second is the one to revisit\n * first — it stops the plaintext population growing without breaking anyone today.\n *\n * Reopen on an observed interception, or on a customer compliance requirement. Do not reopen it as a\n * tidy-up: the asymmetry with the A2A caller is deliberate and is recorded at both sites.\n */\nconst M2M_WEBHOOK_ADMITTED_PROTOCOLS = ['https:', 'http:'] as const;\n\n/**\n * Refuse a destination that would turn this server into a request-forgery tool.\n *\n * ## Why the guard is HERE and not on the schema\n *\n * `WebhookEndpointSchema.url` validates shape (`z.url()`) and nothing else, so an admin could author\n * `http://169.254.169.254/latest/meta-data/` and the engine would POST signed payloads to the cloud\n * instance-metadata service — then capture the answer into the delivery log as\n * `responseBodyTruncated`. That makes it a READ primitive, not a blind SSRF, and\n * `webhookConfig.testEndpoint` is a low-friction oracle for it.\n *\n * A schema refine would leave two holes this placement does not have: it would not cover endpoints\n * ALREADY STORED before the refine existed, and it would not cover the A2A push-delivery worker,\n * which reaches this same primitive with a URL its own (separate) guard validated at configuration\n * time. Putting the check at the wire makes it unbypassable for every caller — present and future —\n * which is what `.claude/rules/invariant-call-site-enumeration.md` means by preferring one\n * chokepoint over N hand-applied predicates.\n *\n * ## What it cannot do\n *\n * An ordinary hostname is not resolved, so `hook.attacker.test` with an A record of `169.254.169.254`\n * still passes. That residual is inherited from the shared classifier and is stated there; closing it\n * needs either a resolving check (a check-then-connect, still open to rebinding) or egress-path\n * enforcement. It is a deliberate open item, not an oversight.\n */\nfunction refuseUnsafeWebhookTarget(url: string): string | undefined {\n const rejection = classifyOutboundTargetUrl(url, { admittedProtocols: M2M_WEBHOOK_ADMITTED_PROTOCOLS });\n switch (rejection) {\n case undefined:\n return undefined;\n case OutboundTargetRejection.NOT_ABSOLUTE_ADMITTED_SCHEME:\n return 'refused: endpoint is not an absolute http(s) URL';\n case OutboundTargetRejection.CREDENTIALS_IN_URL:\n // Credentials in the URL would be replayed on every delivery and would land in any log or\n // delivery row that records the target.\n return 'refused: endpoint URL carries embedded credentials';\n case OutboundTargetRejection.PRIVATE_OR_RESERVED_ADDRESS:\n return 'refused: endpoint resolves to a private, loopback, link-local or otherwise reserved address';\n case OutboundTargetRejection.RESERVED_SPECIAL_USE_HOSTNAME:\n return 'refused: endpoint uses a reserved special-use hostname';\n }\n}\n\n/** Consumer-facing digest algorithm carried in every outbound webhook JWT. */\nexport const M2M_WEBHOOK_BODY_HASH_ALGORITHM: typeof M2M_WEBHOOK_DELIVERY_CONTRACT.bodyHashAlgorithm = M2M_WEBHOOK_DELIVERY_CONTRACT.bodyHashAlgorithm;\n\n/**\n * Outcome of one attempt at the wire level.\n *\n * `responseStatus` and `networkError` are mutually exclusive and exhaustive: either the\n * endpoint produced an HTTP response or it did not. Callers classify from there — this\n * type deliberately carries no verdict of its own, because \"429 is retryable\" is a\n * delivery-policy question and \"429 means the endpoint is reachable\" is a probe question,\n * and the same status answers both differently.\n */\nexport type SignedWebhookRequestResult = {\n /** Set when the endpoint answered, whatever the status. */\n responseStatus?: number;\n /** Best-effort capture of the consumer's response body, truncated on a UTF-8 boundary. */\n responseBodyTruncated?: string;\n /** Set when no HTTP response was obtained (DNS/TLS/connection failure, or timeout). */\n networkError?: string;\n /** Wall-clock duration of this attempt alone, excluding any caller-side work. */\n durationMs: number;\n};\n\n/**\n * Render a `fetch` rejection into something an operator can act on.\n *\n * Node's `fetch` (undici) rejects with a flat `TypeError: fetch failed` and buries the actual\n * cause — `ECONNREFUSED`, `ENOTFOUND`, `EHOSTUNREACH`, a TLS failure — one or more levels down in\n * `error.cause`. Reporting only `error.message` tells an admin their endpoint failed without\n * telling them whether the hostname is wrong, the port is closed, or the certificate is bad; for a\n * diagnostic whose entire job is to explain a failure, that is barely better than the silent\n * success this operation used to return. So walk the cause chain and append what it names.\n *\n * `AggregateError` (emitted when every resolved address fails, e.g. happy-eyeballs against a dead\n * host) carries its detail in `errors[]` rather than `cause`, so that shape is unwrapped too.\n * Depth-capped and de-duplicated: the chain is attacker-adjacent input in the sense that a hostile\n * endpoint controls how deep it goes, and a repeated message adds nothing.\n */\nfunction describeFetchFailure(error: unknown): string {\n if (!(error instanceof Error)) return String(error);\n\n const parts: string[] = [];\n const seen = new Set<string>();\n let current: unknown = error;\n\n for (let depth = 0; depth < 4 && current instanceof Error; depth += 1) {\n // `code` is where Node puts the actionable token (ECONNREFUSED, …); the message often repeats it.\n const code = (current as NodeJS.ErrnoException).code;\n const label = code && !current.message.includes(code) ? `${current.message} (${code})` : current.message;\n if (label && !seen.has(label)) {\n seen.add(label);\n parts.push(label);\n }\n const aggregated = current instanceof AggregateError ? current.errors?.[0] : undefined;\n current = aggregated ?? (current as { cause?: unknown }).cause;\n }\n\n return parts.join(': ') || 'fetch failed';\n}\n\n/**\n * POST a pre-signed body to a webhook endpoint under a hard timeout.\n *\n * Never throws for a transport failure — a refused connection, a DNS miss and a timeout\n * all come back as `networkError`. A timeout is reported with its budget spelled out\n * because \"timed out\" alone sends an operator hunting for the wrong thing.\n *\n * Body capture is best-effort: a consumer that returns an unreadable body still produced a\n * valid status, and losing the body must not turn a successful attempt into a failed one.\n */\nexport async function sendSignedWebhookRequest(params: {\n /** Absolute destination URL. */\n url: string;\n /** Exact bytes to send — already the string whose hash the caller signed. */\n body: string;\n /**\n * Value for the `X-Webhook-Signature` header. Omit when the caller authenticates by another\n * mechanism and supplies its own {@link headers} — see below.\n */\n signature?: string;\n /**\n * Caller-supplied headers, MERGED OVER the defaults.\n *\n * Added for the A2A push-notification worker, which authenticates with the CLIENT's declared\n * scheme (`Authorization: {scheme} {credentials}`) and sends `application/a2a+json` rather than\n * Wildo's own ES256 signature and `application/json`.\n *\n * Widening this primitive instead of writing a second POST is deliberate, and follows the module\n * header's own claim to own THE WIRE: timeout, abort handling, failure description and body\n * truncation are the parts that are easy to get subtly wrong and expensive to have two of. What\n * varies between callers is authentication and media type — which are exactly the two things a\n * caller is in a position to decide. Purely additive: `signature` stays optional-by-absence for\n * the two existing M2M call sites, whose behaviour is byte-for-byte unchanged.\n */\n headers?: Record<string, string>;\n}): Promise<SignedWebhookRequestResult> {\n const startedAt = Date.now();\n\n // Refused BEFORE any timer or connection: a target the guard rejects must produce no DNS lookup,\n // no socket, and no signed body on the wire. Reported as `networkError` rather than thrown, because\n // this module's contract is that a destination problem is DATA the caller reports — the probe\n // surfaces it to the admin as UNREACHABLE and the delivery worker records it on the attempt row.\n const refusal = refuseUnsafeWebhookTarget(params.url);\n if (refusal) {\n return { networkError: refusal, durationMs: Date.now() - startedAt };\n }\n\n const abort = new AbortController();\n const timer = setTimeout(() => abort.abort(), REQUEST_TIMEOUT_MS);\n\n let responseStatus: number | undefined;\n let responseBodyTruncated: string | undefined;\n let networkError: string | undefined;\n\n try {\n const response = await fetch(params.url, {\n method: 'POST',\n signal: abort.signal,\n /**\n * A redirect is REPORTED, never followed.\n *\n * Following one re-points the request at a target the guard above never saw, which is the\n * guard's most obvious bypass — an admin authors a public URL that 302s to\n * `http://169.254.169.254/`. It also silently defeats a decision this subsystem had ALREADY\n * taken and could not enforce: `classifyResponseStatus` classifies 3xx as `fatal` and\n * `resolveProbeOutcome` classifies it as REJECTED (\"webhooks must not redirect, and a\n * CDN/proxy redirect on a wrong URL is one of the most common real misconfigurations an admin\n * uses this probe to find\") — but with `fetch`'s default follow behaviour neither of those\n * branches could ever execute, because a 3xx never reached them.\n *\n * `'manual'` rather than `'error'` on purpose: `'error'` would surface as an opaque network\n * failure, whereas `'manual'` hands back the 3xx status so both classifiers see the redirect\n * and tell the admin exactly what their endpoint did.\n */\n redirect: 'manual',\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': WEBHOOK_USER_AGENT,\n ...(params.signature ? { [WildoHeaderKeys.X_WEBHOOK_SIGNATURE]: params.signature } : {}),\n ...params.headers,\n },\n body: params.body,\n });\n responseStatus = response.status;\n try {\n const text = await response.text();\n responseBodyTruncated = text ? truncateBody(text) : undefined;\n } catch {\n // Best-effort body capture — never fail the attempt on a non-readable body.\n responseBodyTruncated = undefined;\n }\n } catch (error) {\n networkError = abort.signal.aborted\n ? `request timed out after ${REQUEST_TIMEOUT_MS}ms`\n : describeFetchFailure(error);\n } finally {\n clearTimeout(timer);\n }\n\n return {\n responseStatus,\n responseBodyTruncated,\n networkError,\n durationMs: Date.now() - startedAt,\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"webhook-config-test-endpoint.custom-impl.backend.service.d.ts","sourceRoot":"","sources":["../../../../../../../src/notifications/webhooks/outbound/services/webhook-config-test-endpoint.custom-impl.backend.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAGH,OAAO,EAWL,2BAA2B,EAK5B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAEL,KAAK,0CAA0C,EAChD,MAAM,4GAA4G,CAAC;AAiDpH;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,2BAA2B,CAKnG;AAED,wBAAgB,wCAAwC,IAAI,0CAA0C,EAAE,CAgMvG"}
1
+ {"version":3,"file":"webhook-config-test-endpoint.custom-impl.backend.service.d.ts","sourceRoot":"","sources":["../../../../../../../src/notifications/webhooks/outbound/services/webhook-config-test-endpoint.custom-impl.backend.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAGH,OAAO,EAWL,2BAA2B,EAO5B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAEL,KAAK,0CAA0C,EAChD,MAAM,4GAA4G,CAAC;AAyCpH;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,2BAA2B,CAKnG;AAED,wBAAgB,wCAAwC,IAAI,0CAA0C,EAAE,CAyMvG"}
@@ -38,7 +38,7 @@
38
38
  * @see m2m-webhook-delivery-log.custom-impl.backend.service.ts — sibling REPLACE impls.
39
39
  */
40
40
  import { createHash, randomUUID } from 'node:crypto';
41
- import { AuthScopeType, CoreAuditableEventType, CoreM2MNotificationChannel, CoreResourceType, ErrorCustomMessageReference, ErrorType, ResourceOperationRiskLevel, ResourceOperationVariantType, WebhookConfig_Operations, WebhookConfig_TestEndpointRequestDto, WebhookEndpointProbeOutcome, M2M_WEBHOOK_DELIVERY_CONTRACT, } from '@wildo-ai/saas-models';
41
+ import { AuthScopeType, CoreAuditableEventType, CoreM2MNotificationChannel, CoreResourceType, ErrorCustomMessageReference, ErrorType, ResourceOperationRiskLevel, ResourceOperationVariantType, WebhookConfig_Operations, WebhookConfig_TestEndpointRequestDto, WebhookEndpointProbeOutcome, webhookEndpointDestinationHost, webhookEndpointTransportIsPlaintext, M2M_WEBHOOK_DELIVERY_CONTRACT, } from '@wildo-ai/saas-models';
42
42
  import { createResourceCustomServiceImplementation, } from '../../../../base-classes/services/services/resource-operation-custom-implementation.factory.backend.js';
43
43
  import { describeCaughtError } from '../../../../errors/utils/error-log-level-classification.backend.utils.js';
44
44
  import { relaxAbuseThrottleMaxForEnvironment } from '../../../../errors/utils/rate-limit-environment-relaxation.backend.utils.js';
@@ -71,15 +71,6 @@ const WEBHOOK_CONFIG_VARIANTS = [
71
71
  */
72
72
  const PROBE_RATE_LIMIT_WINDOW_SECONDS = 60;
73
73
  const PROBE_RATE_LIMIT_MAX_PER_WINDOW = 5;
74
- /** Host-only projection for the audit trail — see the audit schema for why the path is withheld. */
75
- function extractHost(url) {
76
- try {
77
- return new URL(url).host;
78
- }
79
- catch {
80
- return 'unparseable';
81
- }
82
- }
83
74
  /**
84
75
  * Map a transport result onto the reported verdict.
85
76
  *
@@ -217,6 +208,10 @@ export function createWebhookConfigTestEndpointFactories() {
217
208
  const notSent = {
218
209
  endpointId,
219
210
  url: endpoint.url,
211
+ // Reported even though nothing left the platform: the scheme is a property of the
212
+ // STORED destination, not of this attempt, so an admin fixing a signing fault is
213
+ // still told what the endpoint will cost them once it works (#492).
214
+ transportIsPlaintext: webhookEndpointTransportIsPlaintext(endpoint.url),
220
215
  outcome: WebhookEndpointProbeOutcome.NOT_SENT,
221
216
  failureReason,
222
217
  durationMs: 0,
@@ -234,9 +229,13 @@ export function createWebhookConfigTestEndpointFactories() {
234
229
  // ── Send ──────────────────────────────────────────────────
235
230
  const result = await sendSignedWebhookRequest({ url: endpoint.url, body, signature });
236
231
  const outcome = resolveProbeOutcome(result.responseStatus);
232
+ const transportIsPlaintext = webhookEndpointTransportIsPlaintext(endpoint.url);
237
233
  utils.logger.info('Webhook endpoint test dispatched', {
238
234
  scopeType, scopeId, endpointId,
239
- destinationHost: extractHost(endpoint.url),
235
+ destinationHost: webhookEndpointDestinationHost(endpoint.url),
236
+ // A probe is the moment an operator is looking at ONE endpoint, so it is also the
237
+ // cheapest moment to notice the signature JWT is going out in the clear (#492).
238
+ transportIsPlaintext,
240
239
  outcome,
241
240
  responseStatus: result.responseStatus,
242
241
  durationMs: result.durationMs,
@@ -253,6 +252,7 @@ export function createWebhookConfigTestEndpointFactories() {
253
252
  return {
254
253
  endpointId,
255
254
  url: endpoint.url,
255
+ transportIsPlaintext,
256
256
  outcome,
257
257
  responseStatus: result.responseStatus,
258
258
  responseBodyTruncated: result.responseBodyTruncated,
@@ -297,7 +297,7 @@ async function recordProbeAudit(container, executionContext, data) {
297
297
  // over it — an unattributable egress probe is itself the thing worth noticing.
298
298
  dispatchedBy: actorUserId ?? 'unattributed',
299
299
  endpointId: data.endpointId,
300
- destinationHost: extractHost(data.url),
300
+ destinationHost: webhookEndpointDestinationHost(data.url),
301
301
  outcome: data.outcome,
302
302
  responseStatus: data.responseStatus,
303
303
  durationMs: data.durationMs,