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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/dist/esm/base-classes/models/manual-controllers.backend.definition.d.ts.map +1 -1
  2. package/dist/esm/base-classes/models/manual-controllers.backend.definition.js +2 -0
  3. package/dist/esm/base-classes/models/manual-controllers.backend.definition.js.map +1 -1
  4. package/dist/esm/base-classes/services/repositories/stored-field-omission.backend.d.ts +4 -0
  5. package/dist/esm/base-classes/services/repositories/stored-field-omission.backend.d.ts.map +1 -1
  6. package/dist/esm/base-classes/services/repositories/stored-field-omission.backend.js +20 -5
  7. package/dist/esm/base-classes/services/repositories/stored-field-omission.backend.js.map +1 -1
  8. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.d.ts +3 -0
  9. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.d.ts.map +1 -1
  10. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.js +10 -1
  11. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.js.map +1 -1
  12. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.d.ts +22 -0
  13. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.d.ts.map +1 -1
  14. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.js +25 -1
  15. package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.js.map +1 -1
  16. package/dist/esm/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.d.ts +38 -3
  17. package/dist/esm/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.d.ts.map +1 -1
  18. package/dist/esm/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.js +68 -5
  19. package/dist/esm/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.js.map +1 -1
  20. package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.d.ts +2 -2
  21. package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.d.ts.map +1 -1
  22. package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.js +6 -3
  23. package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.js.map +1 -1
  24. package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.d.ts +83 -0
  25. package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.d.ts.map +1 -1
  26. package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js +217 -14
  27. package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js.map +1 -1
  28. package/dist/esm/compliance/approval-seals/approval-seal-currency.backend.d.ts +32 -0
  29. package/dist/esm/compliance/approval-seals/approval-seal-currency.backend.d.ts.map +1 -0
  30. package/dist/esm/compliance/approval-seals/approval-seal-currency.backend.js +36 -0
  31. package/dist/esm/compliance/approval-seals/approval-seal-currency.backend.js.map +1 -0
  32. package/dist/esm/compliance/approval-seals/approval-seal-on-record.backend.d.ts +38 -0
  33. package/dist/esm/compliance/approval-seals/approval-seal-on-record.backend.d.ts.map +1 -0
  34. package/dist/esm/compliance/approval-seals/approval-seal-on-record.backend.js +83 -0
  35. package/dist/esm/compliance/approval-seals/approval-seal-on-record.backend.js.map +1 -0
  36. package/dist/esm/compliance/approval-seals/approval-seal-presentation-read.backend.d.ts +36 -0
  37. package/dist/esm/compliance/approval-seals/approval-seal-presentation-read.backend.d.ts.map +1 -0
  38. package/dist/esm/compliance/approval-seals/approval-seal-presentation-read.backend.js +51 -0
  39. package/dist/esm/compliance/approval-seals/approval-seal-presentation-read.backend.js.map +1 -0
  40. package/dist/esm/compliance/approval-seals/approval-seal-relay-store.backend.d.ts +46 -0
  41. package/dist/esm/compliance/approval-seals/approval-seal-relay-store.backend.d.ts.map +1 -1
  42. package/dist/esm/compliance/approval-seals/approval-seal-relay-store.backend.js +68 -0
  43. package/dist/esm/compliance/approval-seals/approval-seal-relay-store.backend.js.map +1 -1
  44. package/dist/esm/compliance/approval-seals/approval-seal-store.backend.d.ts +27 -0
  45. package/dist/esm/compliance/approval-seals/approval-seal-store.backend.d.ts.map +1 -1
  46. package/dist/esm/compliance/approval-seals/approval-seal-store.backend.js +42 -3
  47. package/dist/esm/compliance/approval-seals/approval-seal-store.backend.js.map +1 -1
  48. package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.contracts.d.ts +26 -1
  49. package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.contracts.d.ts.map +1 -1
  50. package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.contracts.js +10 -0
  51. package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.contracts.js.map +1 -1
  52. package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.controller.d.ts +10 -1
  53. package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.controller.d.ts.map +1 -1
  54. package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.controller.js +60 -28
  55. package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.controller.js.map +1 -1
  56. package/dist/esm/compliance/approval-seals/approval-seals-on-record.backend.controller.d.ts +90 -0
  57. package/dist/esm/compliance/approval-seals/approval-seals-on-record.backend.controller.d.ts.map +1 -0
  58. package/dist/esm/compliance/approval-seals/approval-seals-on-record.backend.controller.js +373 -0
  59. package/dist/esm/compliance/approval-seals/approval-seals-on-record.backend.controller.js.map +1 -0
  60. package/dist/esm/compliance/approval-seals/decision-presentation.backend.d.ts +29 -2
  61. package/dist/esm/compliance/approval-seals/decision-presentation.backend.d.ts.map +1 -1
  62. package/dist/esm/compliance/approval-seals/decision-presentation.backend.js +40 -3
  63. package/dist/esm/compliance/approval-seals/decision-presentation.backend.js.map +1 -1
  64. package/dist/esm/compliance/electronic-signatures/pdf-signature-structure.backend.d.ts.map +1 -1
  65. package/dist/esm/compliance/electronic-signatures/pdf-signature-structure.backend.js +34 -6
  66. package/dist/esm/compliance/electronic-signatures/pdf-signature-structure.backend.js.map +1 -1
  67. package/dist/esm/compliance/electronic-signatures/signature-request-evidence-files.backend.d.ts +30 -6
  68. package/dist/esm/compliance/electronic-signatures/signature-request-evidence-files.backend.d.ts.map +1 -1
  69. package/dist/esm/compliance/electronic-signatures/signature-request-evidence-files.backend.js +67 -22
  70. package/dist/esm/compliance/electronic-signatures/signature-request-evidence-files.backend.js.map +1 -1
  71. package/dist/esm/compliance/electronic-signatures/signature-request-poll.batch.backend.service.d.ts.map +1 -1
  72. package/dist/esm/compliance/electronic-signatures/signature-request-poll.batch.backend.service.js +18 -1
  73. package/dist/esm/compliance/electronic-signatures/signature-request-poll.batch.backend.service.js.map +1 -1
  74. package/dist/esm/compliance/electronic-signatures/signature-requests.backend.service.d.ts +66 -1
  75. package/dist/esm/compliance/electronic-signatures/signature-requests.backend.service.d.ts.map +1 -1
  76. package/dist/esm/compliance/electronic-signatures/signature-requests.backend.service.js +161 -14
  77. package/dist/esm/compliance/electronic-signatures/signature-requests.backend.service.js.map +1 -1
  78. package/dist/esm/compliance/electronic-signatures/signed-document-validation.backend.d.ts +47 -0
  79. package/dist/esm/compliance/electronic-signatures/signed-document-validation.backend.d.ts.map +1 -1
  80. package/dist/esm/compliance/electronic-signatures/signed-document-validation.backend.js.map +1 -1
  81. package/dist/esm/external-providers/services/content-safety.backend.service.d.ts +27 -2
  82. package/dist/esm/external-providers/services/content-safety.backend.service.d.ts.map +1 -1
  83. package/dist/esm/external-providers/services/content-safety.backend.service.js +46 -1
  84. package/dist/esm/external-providers/services/content-safety.backend.service.js.map +1 -1
  85. package/dist/esm/external-providers/services/embeddings.backend.service.d.ts.map +1 -1
  86. package/dist/esm/external-providers/services/embeddings.backend.service.js +2 -0
  87. package/dist/esm/external-providers/services/embeddings.backend.service.js.map +1 -1
  88. package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts +11 -0
  89. package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts.map +1 -1
  90. package/dist/esm/external-providers/services/external-providers-registry.backend.service.js +23 -0
  91. package/dist/esm/external-providers/services/external-providers-registry.backend.service.js.map +1 -1
  92. package/dist/esm/external-providers/services/provider-service-account-token.backend.d.ts +19 -1
  93. package/dist/esm/external-providers/services/provider-service-account-token.backend.d.ts.map +1 -1
  94. package/dist/esm/external-providers/services/provider-service-account-token.backend.js +41 -1
  95. package/dist/esm/external-providers/services/provider-service-account-token.backend.js.map +1 -1
  96. package/dist/esm/files/utils/file-parent-read-context.backend.d.ts +27 -2
  97. package/dist/esm/files/utils/file-parent-read-context.backend.d.ts.map +1 -1
  98. package/dist/esm/files/utils/file-parent-read-context.backend.js +23 -4
  99. package/dist/esm/files/utils/file-parent-read-context.backend.js.map +1 -1
  100. package/dist/esm/flows-actors/content-guardrails/classifier-availability.backend.utils.d.ts +26 -0
  101. package/dist/esm/flows-actors/content-guardrails/classifier-availability.backend.utils.d.ts.map +1 -1
  102. package/dist/esm/flows-actors/content-guardrails/classifier-availability.backend.utils.js +100 -8
  103. package/dist/esm/flows-actors/content-guardrails/classifier-availability.backend.utils.js.map +1 -1
  104. package/dist/esm/flows-actors/content-guardrails/record-owner-policy.backend.d.ts +3 -1
  105. package/dist/esm/flows-actors/content-guardrails/record-owner-policy.backend.d.ts.map +1 -1
  106. package/dist/esm/flows-actors/content-guardrails/record-owner-policy.backend.js +8 -2
  107. package/dist/esm/flows-actors/content-guardrails/record-owner-policy.backend.js.map +1 -1
  108. package/dist/esm/flows-actors/models/function-tools.backend.definitions.d.ts +43 -0
  109. package/dist/esm/flows-actors/models/function-tools.backend.definitions.d.ts.map +1 -1
  110. package/dist/esm/flows-actors/models/function-tools.backend.definitions.js +37 -0
  111. package/dist/esm/flows-actors/models/function-tools.backend.definitions.js.map +1 -1
  112. package/dist/esm/flows-actors/services/agent-work-decisions.backend.service.d.ts +7 -0
  113. package/dist/esm/flows-actors/services/agent-work-decisions.backend.service.d.ts.map +1 -1
  114. package/dist/esm/flows-actors/services/agent-work-decisions.backend.service.js +8 -3
  115. package/dist/esm/flows-actors/services/agent-work-decisions.backend.service.js.map +1 -1
  116. package/dist/esm/flows-actors/services/agents.backend.service.d.ts +31 -6
  117. package/dist/esm/flows-actors/services/agents.backend.service.d.ts.map +1 -1
  118. package/dist/esm/flows-actors/services/agents.backend.service.js +78 -30
  119. package/dist/esm/flows-actors/services/agents.backend.service.js.map +1 -1
  120. package/dist/esm/flows-actors/services/autonomous-agent-turn.backend.service.d.ts.map +1 -1
  121. package/dist/esm/flows-actors/services/autonomous-agent-turn.backend.service.js +4 -0
  122. package/dist/esm/flows-actors/services/autonomous-agent-turn.backend.service.js.map +1 -1
  123. package/dist/esm/flows-actors/services/conversational-execution.backend.service.d.ts +28 -2
  124. package/dist/esm/flows-actors/services/conversational-execution.backend.service.d.ts.map +1 -1
  125. package/dist/esm/flows-actors/services/conversational-execution.backend.service.js +132 -22
  126. package/dist/esm/flows-actors/services/conversational-execution.backend.service.js.map +1 -1
  127. package/dist/esm/flows-actors/services/flow-actor-executions.custom-impl.backend.service.d.ts.map +1 -1
  128. package/dist/esm/flows-actors/services/flow-actor-executions.custom-impl.backend.service.js +12 -8
  129. package/dist/esm/flows-actors/services/flow-actor-executions.custom-impl.backend.service.js.map +1 -1
  130. package/dist/esm/flows-actors/services/flows-actors-registry.service.d.ts +5 -0
  131. package/dist/esm/flows-actors/services/flows-actors-registry.service.d.ts.map +1 -1
  132. package/dist/esm/flows-actors/services/flows-actors-registry.service.js +18 -2
  133. package/dist/esm/flows-actors/services/flows-actors-registry.service.js.map +1 -1
  134. package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.d.ts +33 -0
  135. package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.d.ts.map +1 -1
  136. package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.js +58 -0
  137. package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.js.map +1 -1
  138. package/dist/esm/inbound/services/inbound-delivery-dispatch.backend.service.d.ts +12 -1
  139. package/dist/esm/inbound/services/inbound-delivery-dispatch.backend.service.d.ts.map +1 -1
  140. package/dist/esm/inbound/services/inbound-delivery-dispatch.backend.service.js +23 -4
  141. package/dist/esm/inbound/services/inbound-delivery-dispatch.backend.service.js.map +1 -1
  142. package/dist/esm/inbound/services/inbound-delivery-receiver.backend.service.d.ts +12 -1
  143. package/dist/esm/inbound/services/inbound-delivery-receiver.backend.service.d.ts.map +1 -1
  144. package/dist/esm/inbound/services/inbound-delivery-receiver.backend.service.js +55 -17
  145. package/dist/esm/inbound/services/inbound-delivery-receiver.backend.service.js.map +1 -1
  146. package/dist/esm/inbound/services/inbound-delivery-store.backend.service.d.ts +22 -1
  147. package/dist/esm/inbound/services/inbound-delivery-store.backend.service.d.ts.map +1 -1
  148. package/dist/esm/inbound/services/inbound-delivery-store.backend.service.js +52 -9
  149. package/dist/esm/inbound/services/inbound-delivery-store.backend.service.js.map +1 -1
  150. package/dist/esm/inbound/services/inbound-delivery-stored-body.backend.service.d.ts +79 -0
  151. package/dist/esm/inbound/services/inbound-delivery-stored-body.backend.service.d.ts.map +1 -0
  152. package/dist/esm/inbound/services/inbound-delivery-stored-body.backend.service.js +211 -0
  153. package/dist/esm/inbound/services/inbound-delivery-stored-body.backend.service.js.map +1 -0
  154. package/dist/esm/inbound/services/inbound-delivery-subject-erasure-severance.backend.d.ts +2 -2
  155. package/dist/esm/inbound/services/inbound-delivery-subject-erasure-severance.backend.d.ts.map +1 -1
  156. package/dist/esm/inbound/services/inbound-delivery-subject-erasure-severance.backend.js +9 -1
  157. package/dist/esm/inbound/services/inbound-delivery-subject-erasure-severance.backend.js.map +1 -1
  158. package/dist/esm/index.d.ts +1 -0
  159. package/dist/esm/index.d.ts.map +1 -1
  160. package/dist/esm/index.js +1 -0
  161. package/dist/esm/index.js.map +1 -1
  162. package/dist/esm/inject/models/container.d.ts.map +1 -1
  163. package/dist/esm/inject/models/container.js +6 -0
  164. package/dist/esm/inject/models/container.js.map +1 -1
  165. package/dist/esm/inject/models/service-types.d.ts +5 -0
  166. package/dist/esm/inject/models/service-types.d.ts.map +1 -1
  167. package/dist/esm/inject/models/service-types.js +3 -0
  168. package/dist/esm/inject/models/service-types.js.map +1 -1
  169. package/dist/esm/monitoring/observability/models/observability.backend.schemas.d.ts +5 -0
  170. package/dist/esm/monitoring/observability/models/observability.backend.schemas.d.ts.map +1 -1
  171. package/dist/esm/monitoring/observability/models/observability.backend.schemas.js.map +1 -1
  172. package/dist/esm/monitoring/observability/services/metrics.service.d.ts +34 -1
  173. package/dist/esm/monitoring/observability/services/metrics.service.d.ts.map +1 -1
  174. package/dist/esm/monitoring/observability/services/metrics.service.js +49 -0
  175. package/dist/esm/monitoring/observability/services/metrics.service.js.map +1 -1
  176. package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.d.ts +6 -1
  177. package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.d.ts.map +1 -1
  178. package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.js +15 -4
  179. package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.js.map +1 -1
  180. package/dist/esm/notifications/webhooks/outbound/services/m2m-webhook-delivery-log.custom-impl.backend.service.d.ts.map +1 -1
  181. package/dist/esm/notifications/webhooks/outbound/services/m2m-webhook-delivery-log.custom-impl.backend.service.js +3 -1
  182. package/dist/esm/notifications/webhooks/outbound/services/m2m-webhook-delivery-log.custom-impl.backend.service.js.map +1 -1
  183. package/dist/esm/runtime/services/http-server.backend.service.d.ts +3 -1
  184. package/dist/esm/runtime/services/http-server.backend.service.d.ts.map +1 -1
  185. package/dist/esm/runtime/services/http-server.backend.service.js +11 -3
  186. package/dist/esm/runtime/services/http-server.backend.service.js.map +1 -1
  187. package/dist/esm/runtime/services/utils/inbound-endpoint-raw-body.backend.utils.d.ts +22 -0
  188. package/dist/esm/runtime/services/utils/inbound-endpoint-raw-body.backend.utils.d.ts.map +1 -1
  189. package/dist/esm/runtime/services/utils/inbound-endpoint-raw-body.backend.utils.js +54 -0
  190. package/dist/esm/runtime/services/utils/inbound-endpoint-raw-body.backend.utils.js.map +1 -1
  191. package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.d.ts +51 -0
  192. package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.d.ts.map +1 -1
  193. package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.js +87 -15
  194. package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.js.map +1 -1
  195. package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.d.ts.map +1 -1
  196. package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.js +5 -2
  197. package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.js.map +1 -1
  198. package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.d.ts.map +1 -1
  199. package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.js +65 -24
  200. package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.js.map +1 -1
  201. package/dist/esm/security/authorizations/super-admin-floor.backend.utils.d.ts +64 -1
  202. package/dist/esm/security/authorizations/super-admin-floor.backend.utils.d.ts.map +1 -1
  203. package/dist/esm/security/authorizations/super-admin-floor.backend.utils.js +84 -2
  204. package/dist/esm/security/authorizations/super-admin-floor.backend.utils.js.map +1 -1
  205. package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.d.ts +14 -0
  206. package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.d.ts.map +1 -1
  207. package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.js +13 -5
  208. package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.js.map +1 -1
  209. package/dist/esm/users/services/anonymous-consent.custom-impl.backend.service.d.ts.map +1 -1
  210. package/dist/esm/users/services/anonymous-consent.custom-impl.backend.service.js +6 -2
  211. package/dist/esm/users/services/anonymous-consent.custom-impl.backend.service.js.map +1 -1
  212. package/dist/esm/users/services/user-force-password-reset.custom-impl.backend.service.d.ts +7 -0
  213. package/dist/esm/users/services/user-force-password-reset.custom-impl.backend.service.d.ts.map +1 -1
  214. package/dist/esm/users/services/user-force-password-reset.custom-impl.backend.service.js +65 -20
  215. package/dist/esm/users/services/user-force-password-reset.custom-impl.backend.service.js.map +1 -1
  216. package/dist/esm/users/services/user-role-administration.custom-impl.backend.service.d.ts.map +1 -1
  217. package/dist/esm/users/services/user-role-administration.custom-impl.backend.service.js +11 -4
  218. package/dist/esm/users/services/user-role-administration.custom-impl.backend.service.js.map +1 -1
  219. package/dist/esm/users/services/user-self-custom-implementations.backend.d.ts.map +1 -1
  220. package/dist/esm/users/services/user-self-custom-implementations.backend.js +4 -2
  221. package/dist/esm/users/services/user-self-custom-implementations.backend.js.map +1 -1
  222. package/dist/esm/users/services/user-super-admin-floor.custom-impl.backend.service.d.ts.map +1 -1
  223. package/dist/esm/users/services/user-super-admin-floor.custom-impl.backend.service.js +16 -0
  224. package/dist/esm/users/services/user-super-admin-floor.custom-impl.backend.service.js.map +1 -1
  225. package/dist/tsconfig.build.tsbuildinfo +1 -1
  226. package/package.json +10 -10
@@ -20,8 +20,17 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
20
20
  *
21
21
  * The order is the approval seal relay's: write the files UNLINKED, move the request (the move names them), then link
22
22
  * them. A move that is lost (another re-read moved the request first) discards the files at once; they are unlinked in
23
- * any case, so the files cleanup removes them. A link that fails leaves the request naming a file the cleanup will
24
- * remove: logged at error, as the relay does for its manifested copy.
23
+ * any case, so the files cleanup removes them.
24
+ *
25
+ * A link that does not happen at once is NOT lost. The signed document is scanned where a scanner runs, and a file is
26
+ * not linkable while its scan is in flight (`FILE_LINKABLE_STATUSES` leaves `SCANNING` out), so with a scanner the first
27
+ * link of a signed document is refused nearly every time. The link therefore answers what happened
28
+ * ({@link SignatureRequestEvidenceLinkOutcome}) instead of retrying blindly, and the signature-request poll links every
29
+ * evidence file of a recently SIGNED request that is not linked yet (`linkPendingEvidence`), for longer than the files
30
+ * cleanup waits before it removes an unlinked file. Only a file that can never be this request's (gone, infected,
31
+ * quarantined, failed, or linked elsewhere) is LOST, and that is logged at error and counted.
32
+ * (Until 2026-11-12 the link was tried three times in a row and then logged as lost: with a scanner, every signed
33
+ * document was lost.)
25
34
  *
26
35
  * Scanning: the signed document's bytes come from the vendor. Where the application runs a scanner, they are scanned
27
36
  * before anything may serve them; where it runs none, they are kept unscanned rather than not kept, because the evidence
@@ -29,12 +38,37 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
29
38
  * (a signature, its field and appearance, a DSS) before anything is written.
30
39
  */
31
40
  import { inject, injectable, optional } from 'inversify';
32
- import { CORE_APP_ROLES, CoreResourceOperation, CoreResourceType, FileDerivationRole, ResourcePrimaryScope } from '@wildo-ai/saas-models';
41
+ import { CORE_APP_ROLES, CoreResourceOperation, CoreResourceType, FILE_LINKABLE_STATUSES, FileDerivationRole, FileStatus, ResourcePrimaryScope } from '@wildo-ai/saas-models';
33
42
  import { SAAS_SERVICE_TYPES } from '../../inject/models/service-types.js';
34
43
  import { ServerProducedFileScan, writeServerProducedFile } from '../../files/services/server-produced-file-writer.backend.js';
35
44
  import { describeCaughtError } from '../../errors/utils/error-log-level-classification.backend.utils.js';
36
- /** How many times linking an evidence file to its SIGNED request is tried before it is logged as lost. */
37
- export const EVIDENCE_LINK_ATTEMPTS = 3;
45
+ /**
46
+ * What one link of an evidence file to its SIGNED request did. Total over the file's states: the caller decides from it
47
+ * whether a later poll must try again.
48
+ */
49
+ export var SignatureRequestEvidenceLinkOutcome;
50
+ (function (SignatureRequestEvidenceLinkOutcome) {
51
+ /** Linked now. */
52
+ SignatureRequestEvidenceLinkOutcome["LINKED"] = "linked";
53
+ /** Already linked to this request and field (a later poll's link, or an earlier one that succeeded). */
54
+ SignatureRequestEvidenceLinkOutcome["ALREADY_LINKED"] = "already_linked";
55
+ /** Not linkable yet: its scan (or its upload) has not ended. A later poll links it. */
56
+ SignatureRequestEvidenceLinkOutcome["NOT_YET_LINKABLE"] = "not_yet_linkable";
57
+ /** The link failed for a reason that may pass (the store could not be read or written). A later poll tries again. */
58
+ SignatureRequestEvidenceLinkOutcome["FAILED"] = "failed";
59
+ /**
60
+ * It can never be this request's: gone, or in a state no link leaves (infected, quarantined, failed, deleted, orphaned),
61
+ * or linked to another record. The request names evidence that is not kept.
62
+ */
63
+ SignatureRequestEvidenceLinkOutcome["LOST"] = "lost";
64
+ })(SignatureRequestEvidenceLinkOutcome || (SignatureRequestEvidenceLinkOutcome = {}));
65
+ /** The outcomes a later poll must link again. */
66
+ export const SIGNATURE_EVIDENCE_LINK_RETRIED = new Set([
67
+ SignatureRequestEvidenceLinkOutcome.NOT_YET_LINKABLE,
68
+ SignatureRequestEvidenceLinkOutcome.FAILED,
69
+ ]);
70
+ /** File states whose link is only waiting: a scan in flight, an upload not finished. */
71
+ const EVIDENCE_FILE_STATES_AWAITING_LINK = new Set([FileStatus.SCANNING, FileStatus.PENDING]);
38
72
  /** The request's two evidence fields. */
39
73
  export var SignatureRequestEvidenceField;
40
74
  (function (SignatureRequestEvidenceField) {
@@ -49,12 +83,14 @@ let SignatureRequestEvidenceFilesBackendService = class SignatureRequestEvidence
49
83
  fileWriter;
50
84
  files;
51
85
  contexts;
86
+ repositories;
52
87
  resources;
53
- constructor(logger, fileWriter, files, contexts, resources) {
88
+ constructor(logger, fileWriter, files, contexts, repositories, resources) {
54
89
  this.logger = logger;
55
90
  this.fileWriter = fileWriter;
56
91
  this.files = files;
57
92
  this.contexts = contexts;
93
+ this.repositories = repositories;
58
94
  this.resources = resources;
59
95
  }
60
96
  async write(input) {
@@ -76,21 +112,29 @@ let SignatureRequestEvidenceFilesBackendService = class SignatureRequestEvidence
76
112
  return written.fileId;
77
113
  }
78
114
  async link(fileId, request, field) {
79
- // A few attempts: a request already SIGNED names this file, and an unlinked file is the cleanup's, so a link that
80
- // fails for good loses evidence that cannot be produced again (stated residual: no later run re-links it).
81
- let lastError;
82
- for (let attempt = 0; attempt < EVIDENCE_LINK_ATTEMPTS; attempt += 1) {
83
- try {
84
- await this.files.linkFileToResource(fileId, CoreResourceType.SIGNATURE_REQUESTS, String(request._id), field, await this.internalContext(), undefined, request);
85
- return;
86
- }
87
- catch (error) {
88
- lastError = error;
115
+ const requestId = String(request._id);
116
+ try {
117
+ const file = await this.repositories.readUnscopedByKey(CoreResourceType.FILES, { _id: fileId });
118
+ if (!file?.status)
119
+ return SignatureRequestEvidenceLinkOutcome.LOST;
120
+ if (file.status === FileStatus.LINKED) {
121
+ const ours = file.linkedResourceType === CoreResourceType.SIGNATURE_REQUESTS && String(file.linkedResourceId) === requestId && file.linkedFieldName === field;
122
+ return ours ? SignatureRequestEvidenceLinkOutcome.ALREADY_LINKED : SignatureRequestEvidenceLinkOutcome.LOST;
89
123
  }
124
+ if (EVIDENCE_FILE_STATES_AWAITING_LINK.has(file.status))
125
+ return SignatureRequestEvidenceLinkOutcome.NOT_YET_LINKABLE;
126
+ if (!FILE_LINKABLE_STATUSES.has(file.status))
127
+ return SignatureRequestEvidenceLinkOutcome.LOST;
128
+ await this.files.linkFileToResource(fileId, CoreResourceType.SIGNATURE_REQUESTS, requestId, field, await this.internalContext(), undefined, request);
129
+ return SignatureRequestEvidenceLinkOutcome.LINKED;
130
+ }
131
+ catch (error) {
132
+ // A file whose scan began between the read and the link, or a store that did not answer: the next poll tries again.
133
+ this.logger.warn('[signature-requests] An evidence file could not be linked to its signature request now; the poll tries again', {
134
+ signatureRequestId: requestId, fileId, field, error: describeCaughtError(error),
135
+ });
136
+ return SignatureRequestEvidenceLinkOutcome.FAILED;
90
137
  }
91
- this.logger.error('[signature-requests] An evidence file could not be linked to its signature request; the files cleanup will remove it and the request will name a file that is gone', {
92
- signatureRequestId: String(request._id), fileId, field, attempts: EVIDENCE_LINK_ATTEMPTS, error: describeCaughtError(lastError),
93
- });
94
138
  }
95
139
  async discard(fileId) {
96
140
  try {
@@ -118,9 +162,10 @@ SignatureRequestEvidenceFilesBackendService = __decorate([
118
162
  __param(1, inject(SAAS_SERVICE_TYPES.ServerProducedFileWriterDependencies)),
119
163
  __param(2, inject(SAAS_SERVICE_TYPES.FilesBackendService)),
120
164
  __param(3, inject(SAAS_SERVICE_TYPES.ExecutionContextCreatorBackendService)),
121
- __param(4, inject(SAAS_SERVICE_TYPES.ResourceRegistryService)),
122
- __param(4, optional()),
123
- __metadata("design:paramtypes", [Object, Object, Object, Object, Object])
165
+ __param(4, inject(SAAS_SERVICE_TYPES.RepositoriesRegistryHandlerService)),
166
+ __param(5, inject(SAAS_SERVICE_TYPES.ResourceRegistryService)),
167
+ __param(5, optional()),
168
+ __metadata("design:paramtypes", [Object, Object, Object, Object, Object, Object])
124
169
  ], SignatureRequestEvidenceFilesBackendService);
125
170
  export { SignatureRequestEvidenceFilesBackendService };
126
171
  //# sourceMappingURL=signature-request-evidence-files.backend.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"signature-request-evidence-files.backend.js","sourceRoot":"","sources":["../../../../src/compliance/electronic-signatures/signature-request-evidence-files.backend.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * # Where a SIGNED request keeps its evidence (#2293)\n *\n * Two files of the request's own, written when the signed document validates and named in the SAME write that makes the\n * request SIGNED: the signed document the vendor returned (`signedDocument`, derived from the original as a\n * `VENDOR_SIGNED_COPY`) and the validation's evidence (`validationEvidence`, JSON). They go with the request, so with the\n * deliverable's record (#2924), and its holds keep them (#2902).\n *\n * The order is the approval seal relay's: write the files UNLINKED, move the request (the move names them), then link\n * them. A move that is lost (another re-read moved the request first) discards the files at once; they are unlinked in\n * any case, so the files cleanup removes them. A link that fails leaves the request naming a file the cleanup will\n * remove: logged at error, as the relay does for its manifested copy.\n *\n * Scanning: the signed document's bytes come from the vendor. Where the application runs a scanner, they are scanned\n * before anything may serve them; where it runs none, they are kept unscanned rather than not kept, because the evidence\n * of a signature cannot be produced again. What the vendor appended was confined by the structure check of the validator\n * (a signature, its field and appearance, a DSS) before anything is written.\n */\nimport { inject, injectable, optional } from 'inversify';\nimport { CORE_APP_ROLES, CoreResourceOperation, CoreResourceType, FileDerivationRole, ResourcePrimaryScope, type ResourceType } 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 { FilesBackendService } from '~wildo-backend-lib/files/services/files.backend.service';\nimport type { ExecutionContextCreatorBackendService } from '~wildo-backend-lib/runtime/services/execution-context-creator.backend.service';\nimport type { ResourcesRegistryBackendService } from '~wildo-backend-lib/resources/services/resources-registry.backend.service';\nimport { ServerProducedFileScan, writeServerProducedFile, type ServerProducedFileWriterDependencies } from '~wildo-backend-lib/files/services/server-produced-file-writer.backend';\nimport { describeCaughtError } from '~wildo-backend-lib/errors/utils/error-log-level-classification.backend.utils';\n\n/** How many times linking an evidence file to its SIGNED request is tried before it is logged as lost. */\nexport const EVIDENCE_LINK_ATTEMPTS = 3;\n\n/** The request's two evidence fields. */\nexport enum SignatureRequestEvidenceField {\n /** The signed document the vendor returned. */\n SIGNED_DOCUMENT = 'signedDocument',\n /** The validation's evidence, as JSON. */\n VALIDATION_EVIDENCE = 'validationEvidence',\n}\n\n/** What the signature-request service asks of the evidence store. A port, so a unit test holds its files in memory. */\nexport interface SignatureRequestEvidenceFiles {\n /** Write one evidence file of the request, unlinked; answers its id. Throws when it cannot be written. */\n write(input: {\n readonly request: Readonly<Record<string, unknown>>;\n readonly field: SignatureRequestEvidenceField;\n readonly bytes: Uint8Array;\n readonly mimeType: string;\n readonly filename: string;\n }): Promise<string>;\n /** Link a file the request names to it, so the teardown and the holds find it. Never throws. */\n link(fileId: string, request: Readonly<Record<string, unknown>>, field: SignatureRequestEvidenceField): Promise<void>;\n /** Delete a file whose request move was lost. Never throws: an unlinked file is the cleanup's otherwise. */\n discard(fileId: string): Promise<void>;\n}\n\n/** The engine's evidence store: the server-produced file writer and the files service. */\n@injectable()\nexport class SignatureRequestEvidenceFilesBackendService implements SignatureRequestEvidenceFiles {\n constructor(\n @inject(SAAS_SERVICE_TYPES.Logger) private readonly logger: Pick<LoggerService, 'error' | 'warn'>,\n @inject(SAAS_SERVICE_TYPES.ServerProducedFileWriterDependencies) private readonly fileWriter: ServerProducedFileWriterDependencies,\n @inject(SAAS_SERVICE_TYPES.FilesBackendService) private readonly files: Pick<FilesBackendService, 'linkFileToResource' | 'deleteDetachedFile'>,\n @inject(SAAS_SERVICE_TYPES.ExecutionContextCreatorBackendService) private readonly contexts: Pick<ExecutionContextCreatorBackendService, 'createForInternalOperation'>,\n @inject(SAAS_SERVICE_TYPES.ResourceRegistryService) @optional() private readonly resources?: Pick<ResourcesRegistryBackendService, 'getServiceOperationPathDefault'>,\n ) {}\n\n async write(input: Parameters<SignatureRequestEvidenceFiles['write']>[0]): Promise<string> {\n const signedDocument = input.field === SignatureRequestEvidenceField.SIGNED_DOCUMENT;\n const originalFileId = typeof input.request.originalFileId === 'string' ? input.request.originalFileId : undefined;\n const written = await writeServerProducedFile(this.fileWriter, {\n resourceType: CoreResourceType.SIGNATURE_REQUESTS as ResourceType,\n fieldName: input.field,\n bytes: Buffer.from(input.bytes),\n mimeType: input.mimeType,\n filename: input.filename,\n scopeOwnerRow: input.request,\n executionContext: await this.internalContext(),\n // The vendor's bytes are scanned where a scanner runs; the engine's own JSON is not (see the module header).\n scan: signedDocument && this.fileWriter.fileScanning ? ServerProducedFileScan.REQUIRED : ServerProducedFileScan.NONE,\n ...(signedDocument && originalFileId ? { derivedFrom: { fileId: originalFileId, role: FileDerivationRole.VENDOR_SIGNED_COPY } } : {}),\n describedAs: signedDocument ? 'vendor-signed document' : 'signature validation evidence',\n });\n return written.fileId;\n }\n\n async link(fileId: string, request: Readonly<Record<string, unknown>>, field: SignatureRequestEvidenceField): Promise<void> {\n // A few attempts: a request already SIGNED names this file, and an unlinked file is the cleanup's, so a link that\n // fails for good loses evidence that cannot be produced again (stated residual: no later run re-links it).\n let lastError: unknown;\n for (let attempt = 0; attempt < EVIDENCE_LINK_ATTEMPTS; attempt += 1) {\n try {\n await this.files.linkFileToResource(fileId, CoreResourceType.SIGNATURE_REQUESTS as ResourceType, String(request._id), field, await this.internalContext(), undefined, request as Record<string, unknown>);\n return;\n } catch (error) {\n lastError = error;\n }\n }\n this.logger.error('[signature-requests] An evidence file could not be linked to its signature request; the files cleanup will remove it and the request will name a file that is gone', {\n signatureRequestId: String(request._id), fileId, field, attempts: EVIDENCE_LINK_ATTEMPTS, error: describeCaughtError(lastError),\n });\n }\n\n async discard(fileId: string): Promise<void> {\n try {\n await this.files.deleteDetachedFile(fileId, await this.internalContext());\n } catch (error) {\n this.logger.warn('[signature-requests] An evidence file whose request move was lost could not be deleted now; it is unlinked, so the files cleanup removes it', {\n fileId, error: describeCaughtError(error),\n });\n }\n }\n\n /** The application's own context for these files, as a super-administrator would act (the relay's). */\n private internalContext() {\n return this.contexts.createForInternalOperation({\n operation: this.resources?.getServiceOperationPathDefault(CoreResourceType.SIGNATURE_REQUESTS, CoreResourceOperation.READ),\n contextResourcesFieldIdentifier: new Map(),\n initiatorIds: null,\n initiatorRoles: [{ roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN], relatedPrimaryScope: ResourcePrimaryScope.APPLICATION }],\n } as never);\n }\n}\n"]}
1
+ {"version":3,"file":"signature-request-evidence-files.backend.js","sourceRoot":"","sources":["../../../../src/compliance/electronic-signatures/signature-request-evidence-files.backend.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * # Where a SIGNED request keeps its evidence (#2293)\n *\n * Two files of the request's own, written when the signed document validates and named in the SAME write that makes the\n * request SIGNED: the signed document the vendor returned (`signedDocument`, derived from the original as a\n * `VENDOR_SIGNED_COPY`) and the validation's evidence (`validationEvidence`, JSON). They go with the request, so with the\n * deliverable's record (#2924), and its holds keep them (#2902).\n *\n * The order is the approval seal relay's: write the files UNLINKED, move the request (the move names them), then link\n * them. A move that is lost (another re-read moved the request first) discards the files at once; they are unlinked in\n * any case, so the files cleanup removes them.\n *\n * A link that does not happen at once is NOT lost. The signed document is scanned where a scanner runs, and a file is\n * not linkable while its scan is in flight (`FILE_LINKABLE_STATUSES` leaves `SCANNING` out), so with a scanner the first\n * link of a signed document is refused nearly every time. The link therefore answers what happened\n * ({@link SignatureRequestEvidenceLinkOutcome}) instead of retrying blindly, and the signature-request poll links every\n * evidence file of a recently SIGNED request that is not linked yet (`linkPendingEvidence`), for longer than the files\n * cleanup waits before it removes an unlinked file. Only a file that can never be this request's (gone, infected,\n * quarantined, failed, or linked elsewhere) is LOST, and that is logged at error and counted.\n * (Until 2026-11-12 the link was tried three times in a row and then logged as lost: with a scanner, every signed\n * document was lost.)\n *\n * Scanning: the signed document's bytes come from the vendor. Where the application runs a scanner, they are scanned\n * before anything may serve them; where it runs none, they are kept unscanned rather than not kept, because the evidence\n * of a signature cannot be produced again. What the vendor appended was confined by the structure check of the validator\n * (a signature, its field and appearance, a DSS) before anything is written.\n */\nimport { inject, injectable, optional } from 'inversify';\nimport { CORE_APP_ROLES, CoreResourceOperation, CoreResourceType, FILE_LINKABLE_STATUSES, FileDerivationRole, FileStatus, ResourcePrimaryScope, type ResourceType } 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 { FilesBackendService } from '~wildo-backend-lib/files/services/files.backend.service';\nimport type { ExecutionContextCreatorBackendService } from '~wildo-backend-lib/runtime/services/execution-context-creator.backend.service';\nimport type { RepositoriesRegistryHandlerBackendService } from '~wildo-backend-lib/base-classes/services/repositories/repositories-registry-handler.backend.service';\nimport type { ResourcesRegistryBackendService } from '~wildo-backend-lib/resources/services/resources-registry.backend.service';\nimport { ServerProducedFileScan, writeServerProducedFile, type ServerProducedFileWriterDependencies } from '~wildo-backend-lib/files/services/server-produced-file-writer.backend';\nimport { describeCaughtError } from '~wildo-backend-lib/errors/utils/error-log-level-classification.backend.utils';\n\n/**\n * What one link of an evidence file to its SIGNED request did. Total over the file's states: the caller decides from it\n * whether a later poll must try again.\n */\nexport enum SignatureRequestEvidenceLinkOutcome {\n /** Linked now. */\n LINKED = 'linked',\n /** Already linked to this request and field (a later poll's link, or an earlier one that succeeded). */\n ALREADY_LINKED = 'already_linked',\n /** Not linkable yet: its scan (or its upload) has not ended. A later poll links it. */\n NOT_YET_LINKABLE = 'not_yet_linkable',\n /** The link failed for a reason that may pass (the store could not be read or written). A later poll tries again. */\n FAILED = 'failed',\n /**\n * It can never be this request's: gone, or in a state no link leaves (infected, quarantined, failed, deleted, orphaned),\n * or linked to another record. The request names evidence that is not kept.\n */\n LOST = 'lost',\n}\n\n/** The outcomes a later poll must link again. */\nexport const SIGNATURE_EVIDENCE_LINK_RETRIED: ReadonlySet<SignatureRequestEvidenceLinkOutcome> = new Set([\n SignatureRequestEvidenceLinkOutcome.NOT_YET_LINKABLE,\n SignatureRequestEvidenceLinkOutcome.FAILED,\n]);\n\n/** File states whose link is only waiting: a scan in flight, an upload not finished. */\nconst EVIDENCE_FILE_STATES_AWAITING_LINK: ReadonlySet<FileStatus> = new Set([FileStatus.SCANNING, FileStatus.PENDING]);\n\n/** The request's two evidence fields. */\nexport enum SignatureRequestEvidenceField {\n /** The signed document the vendor returned. */\n SIGNED_DOCUMENT = 'signedDocument',\n /** The validation's evidence, as JSON. */\n VALIDATION_EVIDENCE = 'validationEvidence',\n}\n\n/** What the signature-request service asks of the evidence store. A port, so a unit test holds its files in memory. */\nexport interface SignatureRequestEvidenceFiles {\n /** Write one evidence file of the request, unlinked; answers its id. Throws when it cannot be written. */\n write(input: {\n readonly request: Readonly<Record<string, unknown>>;\n readonly field: SignatureRequestEvidenceField;\n readonly bytes: Uint8Array;\n readonly mimeType: string;\n readonly filename: string;\n }): Promise<string>;\n /** Link a file the request names to it, so the teardown and the holds find it, and answer what happened. Never throws. */\n link(fileId: string, request: Readonly<Record<string, unknown>>, field: SignatureRequestEvidenceField): Promise<SignatureRequestEvidenceLinkOutcome>;\n /** Delete a file whose request move was lost. Never throws: an unlinked file is the cleanup's otherwise. */\n discard(fileId: string): Promise<void>;\n}\n\n/** The engine's evidence store: the server-produced file writer and the files service. */\n@injectable()\nexport class SignatureRequestEvidenceFilesBackendService implements SignatureRequestEvidenceFiles {\n constructor(\n @inject(SAAS_SERVICE_TYPES.Logger) private readonly logger: Pick<LoggerService, 'warn'>,\n @inject(SAAS_SERVICE_TYPES.ServerProducedFileWriterDependencies) private readonly fileWriter: ServerProducedFileWriterDependencies,\n @inject(SAAS_SERVICE_TYPES.FilesBackendService) private readonly files: Pick<FilesBackendService, 'linkFileToResource' | 'deleteDetachedFile'>,\n @inject(SAAS_SERVICE_TYPES.ExecutionContextCreatorBackendService) private readonly contexts: Pick<ExecutionContextCreatorBackendService, 'createForInternalOperation'>,\n /** The file's state, read as the inbound-email receiver reads its stored files: the infrastructure read, no access check. */\n @inject(SAAS_SERVICE_TYPES.RepositoriesRegistryHandlerService) private readonly repositories: Pick<RepositoriesRegistryHandlerBackendService, 'readUnscopedByKey'>,\n @inject(SAAS_SERVICE_TYPES.ResourceRegistryService) @optional() private readonly resources?: Pick<ResourcesRegistryBackendService, 'getServiceOperationPathDefault'>,\n ) {}\n\n async write(input: Parameters<SignatureRequestEvidenceFiles['write']>[0]): Promise<string> {\n const signedDocument = input.field === SignatureRequestEvidenceField.SIGNED_DOCUMENT;\n const originalFileId = typeof input.request.originalFileId === 'string' ? input.request.originalFileId : undefined;\n const written = await writeServerProducedFile(this.fileWriter, {\n resourceType: CoreResourceType.SIGNATURE_REQUESTS as ResourceType,\n fieldName: input.field,\n bytes: Buffer.from(input.bytes),\n mimeType: input.mimeType,\n filename: input.filename,\n scopeOwnerRow: input.request,\n executionContext: await this.internalContext(),\n // The vendor's bytes are scanned where a scanner runs; the engine's own JSON is not (see the module header).\n scan: signedDocument && this.fileWriter.fileScanning ? ServerProducedFileScan.REQUIRED : ServerProducedFileScan.NONE,\n ...(signedDocument && originalFileId ? { derivedFrom: { fileId: originalFileId, role: FileDerivationRole.VENDOR_SIGNED_COPY } } : {}),\n describedAs: signedDocument ? 'vendor-signed document' : 'signature validation evidence',\n });\n return written.fileId;\n }\n\n async link(fileId: string, request: Readonly<Record<string, unknown>>, field: SignatureRequestEvidenceField): Promise<SignatureRequestEvidenceLinkOutcome> {\n const requestId = String(request._id);\n try {\n const file = await this.repositories.readUnscopedByKey<{ status?: FileStatus; linkedResourceType?: string; linkedResourceId?: unknown; linkedFieldName?: string }>(\n CoreResourceType.FILES, { _id: fileId },\n );\n if (!file?.status) return SignatureRequestEvidenceLinkOutcome.LOST;\n if (file.status === FileStatus.LINKED) {\n const ours = file.linkedResourceType === CoreResourceType.SIGNATURE_REQUESTS && String(file.linkedResourceId) === requestId && file.linkedFieldName === field;\n return ours ? SignatureRequestEvidenceLinkOutcome.ALREADY_LINKED : SignatureRequestEvidenceLinkOutcome.LOST;\n }\n if (EVIDENCE_FILE_STATES_AWAITING_LINK.has(file.status)) return SignatureRequestEvidenceLinkOutcome.NOT_YET_LINKABLE;\n if (!FILE_LINKABLE_STATUSES.has(file.status)) return SignatureRequestEvidenceLinkOutcome.LOST;\n await this.files.linkFileToResource(fileId, CoreResourceType.SIGNATURE_REQUESTS as ResourceType, requestId, field, await this.internalContext(), undefined, request as Record<string, unknown>);\n return SignatureRequestEvidenceLinkOutcome.LINKED;\n } catch (error) {\n // A file whose scan began between the read and the link, or a store that did not answer: the next poll tries again.\n this.logger.warn('[signature-requests] An evidence file could not be linked to its signature request now; the poll tries again', {\n signatureRequestId: requestId, fileId, field, error: describeCaughtError(error),\n });\n return SignatureRequestEvidenceLinkOutcome.FAILED;\n }\n }\n\n async discard(fileId: string): Promise<void> {\n try {\n await this.files.deleteDetachedFile(fileId, await this.internalContext());\n } catch (error) {\n this.logger.warn('[signature-requests] An evidence file whose request move was lost could not be deleted now; it is unlinked, so the files cleanup removes it', {\n fileId, error: describeCaughtError(error),\n });\n }\n }\n\n /** The application's own context for these files, as a super-administrator would act (the relay's). */\n private internalContext() {\n return this.contexts.createForInternalOperation({\n operation: this.resources?.getServiceOperationPathDefault(CoreResourceType.SIGNATURE_REQUESTS, CoreResourceOperation.READ),\n contextResourcesFieldIdentifier: new Map(),\n initiatorIds: null,\n initiatorRoles: [{ roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN], relatedPrimaryScope: ResourcePrimaryScope.APPLICATION }],\n } as never);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"signature-request-poll.batch.backend.service.d.ts","sourceRoot":"","sources":["../../../../src/compliance/electronic-signatures/signature-request-poll.batch.backend.service.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,iCAAiC,EAAE,MAAM,4FAA4F,CAAC;AA8B/I,wBAAgB,+BAA+B,IAAI,UAAU,CAAC,OAAO,iCAAiC,CAAC,CAqBtG"}
1
+ {"version":3,"file":"signature-request-poll.batch.backend.service.d.ts","sourceRoot":"","sources":["../../../../src/compliance/electronic-signatures/signature-request-poll.batch.backend.service.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,iCAAiC,EAAE,MAAM,4FAA4F,CAAC;AAsC/I,wBAAgB,+BAA+B,IAAI,UAAU,CAAC,OAAO,iCAAiC,CAAC,CA0BtG"}
@@ -9,6 +9,10 @@
9
9
  * It also SENDS the deliverables approved since the last run whose tool declares an electronic signature
10
10
  * (`SignatureRequestTriggerBackendService`), before re-reading, so a request sent this run is read on the next.
11
11
  *
12
+ * Then it LINKS the evidence files of the requests SIGNED in the last two days that are not linked yet
13
+ * (`linkPendingEvidence`): a signed document is scanned on write where a scanner runs, and a file is not linkable until
14
+ * its scan ends, so its link is usually this run's work rather than the re-read's.
15
+ *
12
16
  * This output is the run's durable record: a steady `notRead` means a vendor is down or a provider answers unusably, and a
13
17
  * steady `deferredByBudget` means the bounds are too small for the open population.
14
18
  */
@@ -36,6 +40,14 @@ const SignatureRequestPollOutputSchema = z.strictObject({
36
40
  dispatchSent: Count,
37
41
  /** Deliverables whose sending was refused this run; each is logged. */
38
42
  dispatchRefused: Count,
43
+ /** SIGNED requests of the last two days whose evidence files were looked at. */
44
+ evidenceExamined: Count,
45
+ /** Evidence files linked this run. */
46
+ evidenceLinked: Count,
47
+ /** Evidence files not linkable yet (scan in flight) or whose link failed for now: the next run tries again. */
48
+ evidenceLinkPending: Count,
49
+ /** Evidence files that can never be linked: a SIGNED request names evidence nothing keeps. Each is logged once. */
50
+ evidenceLost: Count,
39
51
  durationMs: Count,
40
52
  });
41
53
  export function createSignatureRequestPollBatch() {
@@ -56,7 +68,12 @@ export function createSignatureRequestPollBatch() {
56
68
  const startTime = Date.now();
57
69
  const dispatch = await dependencies.trigger.sendSealedDeliverables();
58
70
  const report = await dependencies.signatureRequests.pollOpenRequests();
59
- return { ...report, dispatchExamined: dispatch.examined, dispatchSent: dispatch.sent, dispatchRefused: dispatch.refused, durationMs: Date.now() - startTime };
71
+ const evidence = await dependencies.signatureRequests.linkPendingEvidence();
72
+ return {
73
+ ...report, dispatchExamined: dispatch.examined, dispatchSent: dispatch.sent, dispatchRefused: dispatch.refused,
74
+ evidenceExamined: evidence.examined, evidenceLinked: evidence.linked, evidenceLinkPending: evidence.pending, evidenceLost: evidence.lost,
75
+ durationMs: Date.now() - startTime,
76
+ };
60
77
  },
61
78
  });
62
79
  }
@@ -1 +1 @@
1
- {"version":3,"file":"signature-request-poll.batch.backend.service.js","sourceRoot":"","sources":["../../../../src/compliance/electronic-signatures/signature-request-poll.batch.backend.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iCAAiC,EAAE,MAAM,4FAA4F,CAAC;AAC/I,OAAO,EAAE,4CAA4C,EAAE,MAAM,gFAAgF,CAAC;AAC9I,OAAO,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAC;AAIpF,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAEtC,MAAM,gCAAgC,GAAG,CAAC,CAAC,YAAY,CAAC;IACtD,sCAAsC;IACtC,QAAQ,EAAE,KAAK;IACf,kCAAkC;IAClC,KAAK,EAAE,KAAK;IACZ,oHAAoH;IACpH,SAAS,EAAE,KAAK;IAChB,qFAAqF;IACrF,OAAO,EAAE,KAAK;IACd,4CAA4C;IAC5C,QAAQ,EAAE,KAAK;IACf,kFAAkF;IAClF,gBAAgB,EAAE,KAAK;IACvB,uFAAuF;IACvF,gBAAgB,EAAE,KAAK;IACvB,gDAAgD;IAChD,YAAY,EAAE,KAAK;IACnB,uEAAuE;IACvE,eAAe,EAAE,KAAK;IACtB,UAAU,EAAE,KAAK;CAClB,CAAC,CAAC;AAEH,MAAM,UAAU,+BAA+B;IAC7C,OAAO,iCAAiC,CAAC;QACvC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACnB,MAAM,EAAE,gCAAgC;QACxC,oBAAoB,EAAE;YACpB,IAAI,EAAE,4CAA4C,CAAC,IAAI;YACvD,kBAAkB,EAAE,4CAA4C,CAAC,kBAAkB;YACnF,mBAAmB,EAAE,4CAA4C,CAAC,mBAAmB;YACrF,iBAAiB,EAAE,4CAA4C,CAAC,cAAc;SAC/E;QACD,mBAAmB,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;YACjC,iBAAiB,EAAE,GAAG,CAAkC,kBAAkB,CAAC,wBAAwB,CAAC;YACpG,OAAO,EAAE,GAAG,CAAwC,kBAAkB,CAAC,8BAA8B,CAAC;SACvG,CAAC;QACF,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE;YAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC7B,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,sBAAsB,EAAE,CAAC;YACrE,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,iBAAiB,CAAC,gBAAgB,EAAE,CAAC;YACvE,OAAO,EAAE,GAAG,MAAM,EAAE,gBAAgB,EAAE,QAAQ,CAAC,QAAQ,EAAE,YAAY,EAAE,QAAQ,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC;QAChK,CAAC;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * Signature Request Poll — the scheduled re-read of open signature requests (#2293).\n *\n * A vendor's notification only triggers a re-read (#2909), and a vendor that notifies nothing, or a notification lost on\n * the way, would leave a request open for ever. This batch re-reads the open requests every five minutes, oldest move\n * first, within a per-tenant and per-provider bound (`DEFAULT_SIGNATURE_REQUEST_POLL_BOUNDS`), so one tenant or one vendor\n * cannot use the run up.\n *\n * It also SENDS the deliverables approved since the last run whose tool declares an electronic signature\n * (`SignatureRequestTriggerBackendService`), before re-reading, so a request sent this run is read on the next.\n *\n * This output is the run's durable record: a steady `notRead` means a vendor is down or a provider answers unusably, and a\n * steady `deferredByBudget` means the bounds are too small for the open population.\n */\nimport { z } from 'zod';\nimport { createCustomBatchExecutionService } from '~wildo-backend-lib/base-classes/services/batches/batches-cronjobs-custom-execution.service';\nimport { ENGINE_SIGNATURE_REQUEST_POLL_BATCH_MANIFEST } from '~wildo-backend-lib/base-classes/services/batches/engine-custom-batch-manifests';\nimport { SAAS_SERVICE_TYPES } from '~wildo-backend-lib/inject/models/service-types';\nimport type { SignatureRequestsBackendService } from './signature-requests.backend.service';\nimport type { SignatureRequestTriggerBackendService } from './signature-request-trigger.backend.service';\n\nconst Count = z.number().int().min(0);\n\nconst SignatureRequestPollOutputSchema = z.strictObject({\n /** Open requests re-read this run. */\n examined: Count,\n /** Requests whose state moved. */\n moved: Count,\n /** Requests the vendor's answer left where they were (including a complete one whose evidence did not validate). */\n unchanged: Count,\n /** Requests whose vendor could not be read, or answered unusably; each is logged. */\n notRead: Count,\n /** Requests another re-read moved first. */\n lostRace: Count,\n /** Open requests left for a later run by the per-tenant or per-provider bound. */\n deferredByBudget: Count,\n /** Sealed approvals whose tool declares a signature, examined for sending this run. */\n dispatchExamined: Count,\n /** Deliverables sent for signature this run. */\n dispatchSent: Count,\n /** Deliverables whose sending was refused this run; each is logged. */\n dispatchRefused: Count,\n durationMs: Count,\n});\n\nexport function createSignatureRequestPollBatch(): ReturnType<typeof createCustomBatchExecutionService> {\n return createCustomBatchExecutionService({\n input: z.object({}),\n output: SignatureRequestPollOutputSchema,\n batchCronjob_Context: {\n kind: ENGINE_SIGNATURE_REQUEST_POLL_BATCH_MANIFEST.kind,\n resourceIdentifier: ENGINE_SIGNATURE_REQUEST_POLL_BATCH_MANIFEST.resourceIdentifier,\n operationIdentifier: ENGINE_SIGNATURE_REQUEST_POLL_BATCH_MANIFEST.operationIdentifier,\n cronJobExpression: ENGINE_SIGNATURE_REQUEST_POLL_BATCH_MANIFEST.cronExpression,\n },\n resolveDependencies: ({ get }) => ({\n signatureRequests: get<SignatureRequestsBackendService>(SAAS_SERVICE_TYPES.SignatureRequestsService),\n trigger: get<SignatureRequestTriggerBackendService>(SAAS_SERVICE_TYPES.SignatureRequestTriggerService),\n }),\n doHandle: async (_input, { dependencies }) => {\n const startTime = Date.now();\n const dispatch = await dependencies.trigger.sendSealedDeliverables();\n const report = await dependencies.signatureRequests.pollOpenRequests();\n return { ...report, dispatchExamined: dispatch.examined, dispatchSent: dispatch.sent, dispatchRefused: dispatch.refused, durationMs: Date.now() - startTime };\n },\n });\n}\n"]}
1
+ {"version":3,"file":"signature-request-poll.batch.backend.service.js","sourceRoot":"","sources":["../../../../src/compliance/electronic-signatures/signature-request-poll.batch.backend.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iCAAiC,EAAE,MAAM,4FAA4F,CAAC;AAC/I,OAAO,EAAE,4CAA4C,EAAE,MAAM,gFAAgF,CAAC;AAC9I,OAAO,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAC;AAIpF,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAEtC,MAAM,gCAAgC,GAAG,CAAC,CAAC,YAAY,CAAC;IACtD,sCAAsC;IACtC,QAAQ,EAAE,KAAK;IACf,kCAAkC;IAClC,KAAK,EAAE,KAAK;IACZ,oHAAoH;IACpH,SAAS,EAAE,KAAK;IAChB,qFAAqF;IACrF,OAAO,EAAE,KAAK;IACd,4CAA4C;IAC5C,QAAQ,EAAE,KAAK;IACf,kFAAkF;IAClF,gBAAgB,EAAE,KAAK;IACvB,uFAAuF;IACvF,gBAAgB,EAAE,KAAK;IACvB,gDAAgD;IAChD,YAAY,EAAE,KAAK;IACnB,uEAAuE;IACvE,eAAe,EAAE,KAAK;IACtB,gFAAgF;IAChF,gBAAgB,EAAE,KAAK;IACvB,sCAAsC;IACtC,cAAc,EAAE,KAAK;IACrB,+GAA+G;IAC/G,mBAAmB,EAAE,KAAK;IAC1B,mHAAmH;IACnH,YAAY,EAAE,KAAK;IACnB,UAAU,EAAE,KAAK;CAClB,CAAC,CAAC;AAEH,MAAM,UAAU,+BAA+B;IAC7C,OAAO,iCAAiC,CAAC;QACvC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACnB,MAAM,EAAE,gCAAgC;QACxC,oBAAoB,EAAE;YACpB,IAAI,EAAE,4CAA4C,CAAC,IAAI;YACvD,kBAAkB,EAAE,4CAA4C,CAAC,kBAAkB;YACnF,mBAAmB,EAAE,4CAA4C,CAAC,mBAAmB;YACrF,iBAAiB,EAAE,4CAA4C,CAAC,cAAc;SAC/E;QACD,mBAAmB,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;YACjC,iBAAiB,EAAE,GAAG,CAAkC,kBAAkB,CAAC,wBAAwB,CAAC;YACpG,OAAO,EAAE,GAAG,CAAwC,kBAAkB,CAAC,8BAA8B,CAAC;SACvG,CAAC;QACF,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE;YAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC7B,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,sBAAsB,EAAE,CAAC;YACrE,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,iBAAiB,CAAC,gBAAgB,EAAE,CAAC;YACvE,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,iBAAiB,CAAC,mBAAmB,EAAE,CAAC;YAC5E,OAAO;gBACL,GAAG,MAAM,EAAE,gBAAgB,EAAE,QAAQ,CAAC,QAAQ,EAAE,YAAY,EAAE,QAAQ,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,CAAC,OAAO;gBAC9G,gBAAgB,EAAE,QAAQ,CAAC,QAAQ,EAAE,cAAc,EAAE,QAAQ,CAAC,MAAM,EAAE,mBAAmB,EAAE,QAAQ,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,CAAC,IAAI;gBACxI,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;aACnC,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * Signature Request Poll — the scheduled re-read of open signature requests (#2293).\n *\n * A vendor's notification only triggers a re-read (#2909), and a vendor that notifies nothing, or a notification lost on\n * the way, would leave a request open for ever. This batch re-reads the open requests every five minutes, oldest move\n * first, within a per-tenant and per-provider bound (`DEFAULT_SIGNATURE_REQUEST_POLL_BOUNDS`), so one tenant or one vendor\n * cannot use the run up.\n *\n * It also SENDS the deliverables approved since the last run whose tool declares an electronic signature\n * (`SignatureRequestTriggerBackendService`), before re-reading, so a request sent this run is read on the next.\n *\n * Then it LINKS the evidence files of the requests SIGNED in the last two days that are not linked yet\n * (`linkPendingEvidence`): a signed document is scanned on write where a scanner runs, and a file is not linkable until\n * its scan ends, so its link is usually this run's work rather than the re-read's.\n *\n * This output is the run's durable record: a steady `notRead` means a vendor is down or a provider answers unusably, and a\n * steady `deferredByBudget` means the bounds are too small for the open population.\n */\nimport { z } from 'zod';\nimport { createCustomBatchExecutionService } from '~wildo-backend-lib/base-classes/services/batches/batches-cronjobs-custom-execution.service';\nimport { ENGINE_SIGNATURE_REQUEST_POLL_BATCH_MANIFEST } from '~wildo-backend-lib/base-classes/services/batches/engine-custom-batch-manifests';\nimport { SAAS_SERVICE_TYPES } from '~wildo-backend-lib/inject/models/service-types';\nimport type { SignatureRequestsBackendService } from './signature-requests.backend.service';\nimport type { SignatureRequestTriggerBackendService } from './signature-request-trigger.backend.service';\n\nconst Count = z.number().int().min(0);\n\nconst SignatureRequestPollOutputSchema = z.strictObject({\n /** Open requests re-read this run. */\n examined: Count,\n /** Requests whose state moved. */\n moved: Count,\n /** Requests the vendor's answer left where they were (including a complete one whose evidence did not validate). */\n unchanged: Count,\n /** Requests whose vendor could not be read, or answered unusably; each is logged. */\n notRead: Count,\n /** Requests another re-read moved first. */\n lostRace: Count,\n /** Open requests left for a later run by the per-tenant or per-provider bound. */\n deferredByBudget: Count,\n /** Sealed approvals whose tool declares a signature, examined for sending this run. */\n dispatchExamined: Count,\n /** Deliverables sent for signature this run. */\n dispatchSent: Count,\n /** Deliverables whose sending was refused this run; each is logged. */\n dispatchRefused: Count,\n /** SIGNED requests of the last two days whose evidence files were looked at. */\n evidenceExamined: Count,\n /** Evidence files linked this run. */\n evidenceLinked: Count,\n /** Evidence files not linkable yet (scan in flight) or whose link failed for now: the next run tries again. */\n evidenceLinkPending: Count,\n /** Evidence files that can never be linked: a SIGNED request names evidence nothing keeps. Each is logged once. */\n evidenceLost: Count,\n durationMs: Count,\n});\n\nexport function createSignatureRequestPollBatch(): ReturnType<typeof createCustomBatchExecutionService> {\n return createCustomBatchExecutionService({\n input: z.object({}),\n output: SignatureRequestPollOutputSchema,\n batchCronjob_Context: {\n kind: ENGINE_SIGNATURE_REQUEST_POLL_BATCH_MANIFEST.kind,\n resourceIdentifier: ENGINE_SIGNATURE_REQUEST_POLL_BATCH_MANIFEST.resourceIdentifier,\n operationIdentifier: ENGINE_SIGNATURE_REQUEST_POLL_BATCH_MANIFEST.operationIdentifier,\n cronJobExpression: ENGINE_SIGNATURE_REQUEST_POLL_BATCH_MANIFEST.cronExpression,\n },\n resolveDependencies: ({ get }) => ({\n signatureRequests: get<SignatureRequestsBackendService>(SAAS_SERVICE_TYPES.SignatureRequestsService),\n trigger: get<SignatureRequestTriggerBackendService>(SAAS_SERVICE_TYPES.SignatureRequestTriggerService),\n }),\n doHandle: async (_input, { dependencies }) => {\n const startTime = Date.now();\n const dispatch = await dependencies.trigger.sendSealedDeliverables();\n const report = await dependencies.signatureRequests.pollOpenRequests();\n const evidence = await dependencies.signatureRequests.linkPendingEvidence();\n return {\n ...report, dispatchExamined: dispatch.examined, dispatchSent: dispatch.sent, dispatchRefused: dispatch.refused,\n evidenceExamined: evidence.examined, evidenceLinked: evidence.linked, evidenceLinkPending: evidence.pending, evidenceLost: evidence.lost,\n durationMs: Date.now() - startTime,\n };\n },\n });\n}\n"]}
@@ -9,6 +9,7 @@ import type { ElectronicSignatureBackendService } from '../../external-providers
9
9
  import type { AuditLogsBackendService } from '../../compliance/audit-trails/services/audit-logs.backend.service';
10
10
  import { type SignedDocumentValidator } from './signed-document-validation.backend';
11
11
  import { type SignatureRequestEvidenceFiles } from './signature-request-evidence-files.backend';
12
+ import type { MetricsService } from '../../monitoring/observability/services/metrics.service';
12
13
  /** Why a deliverable was not sent. */
13
14
  export declare enum SignatureRequestSendRefusal {
14
15
  SEAL_NOT_FOUND = "seal_not_found",
@@ -55,6 +56,43 @@ export type SendForSignatureResult = {
55
56
  readonly retryable: boolean;
56
57
  readonly signatureRequestId?: string;
57
58
  };
59
+ /**
60
+ * Why a request the vendor reported complete was not made SIGNED by its evidence: the label of
61
+ * `signature_request_evidence_refused_total`, and what the re-read's reason explains in words.
62
+ */
63
+ export declare enum SignatureRequestEvidenceFailure {
64
+ /** No signed-document validator is bound in this runtime. */
65
+ NO_VALIDATOR = "no_validator",
66
+ /** The vendor split the request into several documents; one signed document per request is kept. */
67
+ SPLIT_REQUEST = "split_request",
68
+ /** The provider declares no evidence policy (trust anchors). */
69
+ NO_EVIDENCE_POLICY = "no_evidence_policy",
70
+ /** The signed document could not be downloaded. */
71
+ DOWNLOAD_FAILED = "download_failed",
72
+ /** The document did not validate (tampered, updated after signing, untrusted chain, refused algorithm, revocation). */
73
+ REJECTED = "rejected",
74
+ /** The document validated and proves another signer or a lower level than required: the request FAILS. */
75
+ MISMATCHED = "mismatched",
76
+ /** The document validated and its evidence could not be written: the request stays open and is read again. */
77
+ NOT_KEPT = "not_kept"
78
+ }
79
+ /**
80
+ * How long after a request became SIGNED the poll keeps linking its evidence files (#2293). Longer than the files
81
+ * cleanup waits before it removes an unlinked file (a day after its scan ended, its default `unlinkedThresholdMs`), so a
82
+ * scan that ends late is still linked; a file the cleanup removed first is reported lost.
83
+ */
84
+ export declare const SIGNATURE_EVIDENCE_LINK_WINDOW_MS: number;
85
+ /** What one evidence-link pass of the poll did. */
86
+ export interface SignatureEvidenceLinkReport {
87
+ /** SIGNED requests of the window whose evidence was looked at. */
88
+ readonly examined: number;
89
+ /** Evidence files linked by this pass. */
90
+ readonly linked: number;
91
+ /** Evidence files still not linkable (their scan has not ended) or whose link failed for now: the next pass tries again. */
92
+ readonly pending: number;
93
+ /** Evidence files that can never be linked: the request names evidence nothing keeps. Each is logged once. */
94
+ readonly lost: number;
95
+ }
58
96
  /** What the send path reads and writes through. Structural, so a test hands in what it holds. */
59
97
  export type SignatureRequestsRepositories = Pick<RepositoriesRegistryHandlerBackendService, 'findManyForInfrastructure' | 'insertDocumentForInfrastructure' | 'deleteManyForInfrastructure' | 'atomicGuardedMutation'>;
60
98
  export type SignatureRequestsFiles = Pick<FilesBackendService, 'getFile' | 'ensureContentHash' | 'readFileBytes'>;
@@ -105,9 +143,15 @@ export declare class SignatureRequestsBackendService {
105
143
  /** Where a SIGNED request keeps its signed document and its validation's evidence. Absent, nothing becomes SIGNED. */
106
144
  private readonly evidenceFiles?;
107
145
  private readonly auditLogs?;
146
+ private readonly metrics?;
108
147
  constructor(logger: LoggerService, repositories: SignatureRequestsRepositories, executionContextCreator: Pick<ExecutionContextCreatorBackendService, 'createForInternalSystemOperation'>, transport: SignatureRequestsTransport, files?: SignatureRequestsFiles, validator?: SignedDocumentValidator, errorBuilder?: Pick<ErrorBuilderBackendService, 'buildError'>,
109
148
  /** Where a SIGNED request keeps its signed document and its validation's evidence. Absent, nothing becomes SIGNED. */
110
- evidenceFiles?: SignatureRequestEvidenceFiles, auditLogs?: Pick<AuditLogsBackendService, 'logSignatureRequestEvent'>);
149
+ evidenceFiles?: SignatureRequestEvidenceFiles, auditLogs?: Pick<AuditLogsBackendService, 'logSignatureRequestEvent'>, metrics?: Pick<MetricsService, 'recordSignatureRequestSent' | 'recordSignatureRequestMoved' | 'recordSignatureRequestEvidenceRefused' | 'recordSignatureRequestVendorNotRead' | 'recordSignatureRequestEvidenceLink'>,
150
+ /** A test seam, `@unmanaged()`: the container's instance reads the system clock (Inversify counts every parameter). */
151
+ clock?: () => Date);
152
+ private readonly clock;
153
+ /** Evidence files already reported lost by this process, so a lost file is logged once rather than every poll. */
154
+ private readonly reportedLostEvidence;
111
155
  /**
112
156
  * The removal effect of `signatureRequests` (#2293), registered at startup with the evidence teardown: before the rows of
113
157
  * requests whose record goes are destroyed, every OPEN one is cancelled at its vendor, and deleted there where its
@@ -126,6 +170,7 @@ export declare class SignatureRequestsBackendService {
126
170
  * for the seal's bind check, so the sealed-deliverable gate is marked as that check is.)
127
171
  */
128
172
  sendForSignature(input: SendForSignatureInput): Promise<SendForSignatureResult>;
173
+ private sendOnce;
129
174
  /**
130
175
  * Re-read one request at its vendor, through the provider it was sent through, and move it as its one transition
131
176
  * function says. Used by the poll and by a vendor notification's re-read trigger (#2909): a notification is never
@@ -160,6 +205,26 @@ export declare class SignatureRequestsBackendService {
160
205
  * several references cannot keep its evidence in the request's own fields and is left open (stated, never guessed).
161
206
  */
162
207
  private validateEvidence;
208
+ /**
209
+ * Link the evidence files of the requests that became SIGNED in the last {@link SIGNATURE_EVIDENCE_LINK_WINDOW_MS} and
210
+ * are not linked yet (#2293). Run by the poll. A file whose scan has not ended is linked by a later run; one that can
211
+ * never be linked is reported lost, once. Without this, a signed document scanned on write was never linked (its link
212
+ * is refused while it is SCANNING) and the files cleanup removed it a day later. Never throws for one request.
213
+ *
214
+ * Read cost, stated: each run reads every SIGNED request of the window and each of its two files once, a primary-key read
215
+ * per file, up to {@link SIGNATURE_EVIDENCE_LINK_SCAN_LIMIT} requests.
216
+ */
217
+ linkPendingEvidence(): Promise<SignatureEvidenceLinkReport>;
218
+ /**
219
+ * Link one evidence file and say what happened: a lost file at error (once per process, with its metric), a link left
220
+ * for a later poll at info. Never throws; the port never does.
221
+ */
222
+ private linkEvidenceFile;
223
+ /**
224
+ * The SIGNED requests validated in the link window, oldest first, a page at a time. Pages advance on `validatedAt`, ids
225
+ * already seen skipped, so requests validated in the same instant are not lost between pages (the trigger's paging).
226
+ */
227
+ private signedInLinkWindow;
163
228
  /** Write the request's two evidence files, unlinked. A reason when they cannot be kept: the request then stays open. */
164
229
  private keepEvidence;
165
230
  /** One request event on the trail. Never throws: the request's state is the record, the trail observes it. */
@@ -1 +1 @@
1
- {"version":3,"file":"signature-requests.backend.service.d.ts","sourceRoot":"","sources":["../../../../src/compliance/electronic-signatures/signature-requests.backend.service.ts"],"names":[],"mappings":"AAgCA,OAAO,EAQL,sBAAsB,EACtB,4BAA4B,EAC5B,sBAAsB,EACtB,kCAAkC,EAKnC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAEL,uCAAuC,EACvC,KAAK,yBAAyB,EAC/B,MAAM,sCAAsC,CAAC;AAG9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8DAA8D,CAAC;AAClG,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kEAAkE,CAAC;AACnH,OAAO,KAAK,EAAE,yCAAyC,EAAE,MAAM,qGAAqG,CAAC;AACrK,OAAO,KAAK,EAAE,qCAAqC,EAAE,MAAM,+EAA+E,CAAC;AAC3I,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yDAAyD,CAAC;AACnG,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,qFAAqF,CAAC;AAI7I,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gFAAgF,CAAC;AAC9H,OAAO,EAAsD,KAAK,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AACxI,OAAO,EAAiC,KAAK,6BAA6B,EAAE,MAAM,4CAA4C,CAAC;AAE/H,sCAAsC;AACtC,oBAAY,2BAA2B;IACrC,cAAc,mBAAmB;IACjC,wFAAwF;IACxF,eAAe,oBAAoB;IACnC,mFAAmF;IACnF,qBAAqB,0BAA0B;IAC/C,sDAAsD;IACtD,oBAAoB,yBAAyB;IAC7C,sBAAsB,2BAA2B;IACjD,6DAA6D;IAC7D,mBAAmB,wBAAwB;IAC3C,iFAAiF;IACjF,oBAAoB,yBAAyB;IAC7C,wDAAwD;IACxD,YAAY,iBAAiB;IAC7B,+EAA+E;IAC/E,cAAc,mBAAmB;IACjC,oHAAoH;IACpH,kBAAkB,uBAAuB;CAC1C;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,mHAAmH;IACnH,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7F,QAAQ,CAAC,aAAa,EAAE,yBAAyB,CAAC;IAClD;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,sBAAsB,GAC9B;IAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACtG;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,2BAA2B,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExK,iGAAiG;AACjG,MAAM,MAAM,6BAA6B,GAAG,IAAI,CAAC,yCAAyC,EAAE,2BAA2B,GAAG,iCAAiC,GAAG,6BAA6B,GAAG,uBAAuB,CAAC,CAAC;AACvN,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,mBAAmB,EAAE,SAAS,GAAG,mBAAmB,GAAG,eAAe,CAAC,CAAC;AAClH,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAAC,iCAAiC,EAAE,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,wBAAwB,CAAC,GACnI,OAAO,CAAC,IAAI,CAAC,iCAAiC,EAAE,qBAAqB,GAAG,kBAAkB,CAAC,CAAC,CAAC;AAEjG,uFAAuF;AACvF,oBAAY,2BAA2B;IACrC,uBAAuB;IACvB,SAAS,cAAc;IACvB,yFAAyF;IACzF,QAAQ,aAAa;IACrB,8FAA8F;IAC9F,SAAS,cAAc;CACxB;AAED,yCAAyC;AACzC,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,kCAAkC,GAAG,2BAA2B,CAAC;IACnF,QAAQ,CAAC,KAAK,CAAC,EAAE,sBAAsB,CAAC;IACxC,QAAQ,CAAC,KAAK,CAAC,EAAE,sBAAsB,CAAC;IACxC,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,+HAA+H;AAC/H,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,eAAO,MAAM,qCAAqC,EAAE,0BAA4G,CAAC;AAEjK,iDAAiD;AACjD,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,kFAAkF;IAClF,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CACnC;AAOD,qBACa,+BAA+B;IAEL,OAAO,CAAC,QAAQ,CAAC,MAAM;IACK,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC1B,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;IACnB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;IAC/B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IAC1F,sHAAsH;IAChD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAThC,MAAM,EAAE,aAAa,EACO,YAAY,EAAE,6BAA6B,EACxC,uBAAuB,EAAE,IAAI,CAAC,qCAAqC,EAAE,kCAAkC,CAAC,EACnH,SAAS,EAAE,0BAA0B,EAChC,KAAK,CAAC,EAAE,sBAAsB,EAC1B,SAAS,CAAC,EAAE,uBAAuB,EACvC,YAAY,CAAC,EAAE,IAAI,CAAC,0BAA0B,EAAE,YAAY,CAAC;IAC1I,sHAAsH;IAC/B,aAAa,CAAC,EAAE,6BAA6B,EAC1D,SAAS,CAAC,EAAE,IAAI,CAAC,uBAAuB,EAAE,0BAA0B,CAAC;IAGjJ;;;;;;OAMG;IACU,0BAA0B,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA+BpG;;;;;;;;OAQG;IACU,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAoH5F;;;;;;;;;OASG;IACU,cAAc,CAAC,kBAAkB,EAAE,MAAM,EAAE,KAAK,GAAE,4BAAgE,GAAG,OAAO,CAAC,6BAA6B,CAAC;IAOxK;;;;OAIG;IACU,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAQ9H;;;;OAIG;IACU,gBAAgB,CAAC,MAAM,GAAE,0BAAkE,GAAG,OAAO,CAAC,0BAA0B,CAAC;YA2ChI,UAAU;IAwFxB;;;;;;;;OAQG;YACW,gBAAgB;IA+C9B,wHAAwH;YAC1G,YAAY;IAuB1B,8GAA8G;YAChG,MAAM;CAMrB;AAiBD,iFAAiF;AACjF,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;mBAQlC,yBAAyB;;;;;EAGhE;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,SAAS,uCAAuC,EAAE,GAAG,sBAAsB,GAAG,SAAS,CAStI"}
1
+ {"version":3,"file":"signature-requests.backend.service.d.ts","sourceRoot":"","sources":["../../../../src/compliance/electronic-signatures/signature-requests.backend.service.ts"],"names":[],"mappings":"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"}