@rytass/bpm-core-nestjs-module 0.1.2 → 0.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 (609) hide show
  1. package/eslint.config.mjs +20 -0
  2. package/jest.config.cts +15 -0
  3. package/package.json +3 -3
  4. package/project.json +58 -0
  5. package/src/lib/attachment/attachment-options.spec.ts +45 -0
  6. package/src/lib/attachment/attachment-options.ts +130 -0
  7. package/src/lib/attachment/attachment-storage.provider.spec.ts +79 -0
  8. package/src/lib/attachment/attachment-storage.provider.ts +60 -0
  9. package/src/lib/attachment/{attachment-storage.token.d.ts → attachment-storage.token.ts} +3 -1
  10. package/src/lib/attachment/attachment.controller.ts +39 -0
  11. package/src/lib/attachment/attachment.entity.ts +59 -0
  12. package/src/lib/attachment/attachment.module.ts +149 -0
  13. package/src/lib/attachment/attachment.mutations.ts +22 -0
  14. package/src/lib/attachment/attachment.queries.ts +65 -0
  15. package/src/lib/attachment/attachment.service.spec.ts +319 -0
  16. package/src/lib/attachment/attachment.service.ts +477 -0
  17. package/src/lib/attachment/dto/upload-attachment.input.ts +60 -0
  18. package/src/lib/bpm/bpm-root.module.spec.ts +138 -0
  19. package/src/lib/bpm/bpm-root.module.ts +320 -0
  20. package/src/lib/bpm-auth/bpm-auth-context.extractor.ts +106 -0
  21. package/src/lib/bpm-auth/bpm-auth-context.ts +40 -0
  22. package/src/lib/bpm-auth/bpm-auth.authorization.ts +80 -0
  23. package/src/lib/bpm-auth/bpm-auth.decorators.ts +19 -0
  24. package/src/lib/bpm-auth/bpm-auth.guard.ts +31 -0
  25. package/src/lib/bpm-auth/bpm-auth.module.spec.ts +106 -0
  26. package/src/lib/bpm-auth/bpm-auth.module.ts +69 -0
  27. package/src/lib/bpm-auth/bpm-auth.options.ts +21 -0
  28. package/src/lib/bpm-auth/configurable-bpm-auth-context.accessor.ts +55 -0
  29. package/src/lib/common/filters/all-exceptions.filter.ts +138 -0
  30. package/src/lib/common/iso-duration.ts +31 -0
  31. package/src/lib/condition/condition.module.ts +8 -0
  32. package/src/lib/condition/condition.service.spec.ts +50 -0
  33. package/src/lib/condition/condition.service.ts +141 -0
  34. package/src/lib/database/data-source.ts +7 -0
  35. package/src/lib/database/migration-runner.ts +24 -0
  36. package/src/lib/database/typeorm.config.ts +217 -0
  37. package/src/lib/delegation/delegation-rule.entity.ts +84 -0
  38. package/src/lib/delegation/delegation.enums.ts +21 -0
  39. package/src/lib/delegation/delegation.module.ts +14 -0
  40. package/src/lib/delegation/delegation.mutations.ts +92 -0
  41. package/src/lib/delegation/delegation.queries.ts +111 -0
  42. package/src/lib/delegation/delegation.service.spec.ts +295 -0
  43. package/src/lib/delegation/delegation.service.ts +482 -0
  44. package/src/lib/delegation/dto/delegation-rule.input.ts +125 -0
  45. package/src/lib/form/dto/form-definition.input.ts +73 -0
  46. package/src/lib/form/form-definition-version.entity.ts +66 -0
  47. package/src/lib/form/form-definition.entity.ts +54 -0
  48. package/src/lib/form/form-schema-lint.object.ts +10 -0
  49. package/src/lib/form/form-schema.validator.spec.ts +180 -0
  50. package/src/lib/form/form-schema.validator.ts +538 -0
  51. package/src/lib/form/form.enums.ts +20 -0
  52. package/src/lib/form/form.module.ts +19 -0
  53. package/src/lib/form/form.mutations.ts +68 -0
  54. package/src/lib/form/form.queries.ts +72 -0
  55. package/src/lib/form/form.service.spec.ts +144 -0
  56. package/src/lib/form/form.service.ts +490 -0
  57. package/src/lib/identity/identity-options.ts +41 -0
  58. package/src/lib/identity/identity.module.ts +96 -0
  59. package/src/lib/identity/identity.queries.ts +61 -0
  60. package/src/lib/identity/identity.service.spec.ts +105 -0
  61. package/src/lib/identity/identity.service.ts +200 -0
  62. package/src/lib/identity/member-base.adapter.spec.ts +77 -0
  63. package/src/lib/identity/member-base.adapter.ts +244 -0
  64. package/src/lib/identity/member-metadata-cache.entity.ts +27 -0
  65. package/src/lib/identity/member-profile.object.ts +28 -0
  66. package/src/lib/identity/{member-resolver.interface.d.ts → member-resolver.interface.ts} +11 -5
  67. package/src/lib/migrations/0000000000001-enable-postgres-extensions.ts +14 -0
  68. package/src/lib/migrations/{0000000001000-identity-organization-foundation.js → 0000000001000-identity-organization-foundation.ts} +38 -29
  69. package/src/lib/migrations/{0000000002000-form-builder-foundation.js → 0000000002000-form-builder-foundation.ts} +22 -21
  70. package/src/lib/migrations/{0000000003000-approval-template-foundation.js → 0000000003000-approval-template-foundation.ts} +24 -21
  71. package/src/lib/migrations/{0000000004000-workflow-engine-foundation.js → 0000000004000-workflow-engine-foundation.ts} +46 -34
  72. package/src/lib/migrations/{0000000005000-delegation-rules.js → 0000000005000-delegation-rules.ts} +20 -19
  73. package/src/lib/migrations/{0000000006000-notifications-sla.js → 0000000006000-notifications-sla.ts} +26 -23
  74. package/src/lib/migrations/{0000000007000-signatures-attachments.js → 0000000007000-signatures-attachments.ts} +28 -27
  75. package/src/lib/migrations/{0000000008000-approval-template-categories.js → 0000000008000-approval-template-categories.ts} +28 -25
  76. package/src/lib/migrations/{0000000009000-task-candidates.js → 0000000009000-task-candidates.ts} +26 -23
  77. package/src/lib/migrations/{0000000010000-notification-delivery-state.js → 0000000010000-notification-delivery-state.ts} +16 -17
  78. package/src/lib/migrations/0000000011000-remove-attachment-encryption-key.ts +19 -0
  79. package/src/lib/migrations/0000000012000-notification-sla-idempotency.ts +22 -0
  80. package/src/lib/migrations/0000000013000-workflow-query-indexes.ts +113 -0
  81. package/src/lib/migrations/index.ts +47 -0
  82. package/src/lib/notification/dto/notification-preference.input.ts +46 -0
  83. package/src/lib/notification/notification-delivery-scheduler.service.ts +69 -0
  84. package/src/lib/notification/notification-delivery.service.spec.ts +315 -0
  85. package/src/lib/notification/notification-delivery.service.ts +339 -0
  86. package/src/lib/notification/notification-dispatcher.token.ts +13 -0
  87. package/src/lib/notification/notification-options.module.ts +67 -0
  88. package/src/lib/notification/notification-options.spec.ts +93 -0
  89. package/src/lib/notification/notification-options.ts +452 -0
  90. package/src/lib/notification/notification-preference.entity.ts +35 -0
  91. package/src/lib/notification/notification-sla-scheduler.service.ts +66 -0
  92. package/src/lib/notification/notification-template.spec.ts +33 -0
  93. package/src/lib/notification/notification-template.ts +97 -0
  94. package/src/lib/notification/notification.entity.ts +102 -0
  95. package/src/lib/notification/notification.enums.ts +45 -0
  96. package/src/lib/notification/notification.module.ts +37 -0
  97. package/src/lib/notification/notification.mutations.ts +47 -0
  98. package/src/lib/notification/notification.queries.ts +64 -0
  99. package/src/lib/notification/notification.service.spec.ts +412 -0
  100. package/src/lib/notification/notification.service.ts +974 -0
  101. package/src/lib/organization/dto/manager-resolution.input.ts +91 -0
  102. package/src/lib/organization/dto/membership.input.ts +77 -0
  103. package/src/lib/organization/dto/org-unit.input.ts +96 -0
  104. package/src/lib/organization/dto/position.input.ts +50 -0
  105. package/src/lib/organization/json-metadata.ts +15 -0
  106. package/src/lib/organization/manager-resolution.entity.ts +44 -0
  107. package/src/lib/organization/membership.entity.ts +50 -0
  108. package/src/lib/organization/org-unit-tree-commit-result.object.ts +8 -0
  109. package/src/lib/organization/org-unit.entity.ts +53 -0
  110. package/src/lib/organization/organization-summary.object.ts +16 -0
  111. package/src/lib/organization/organization.enums.ts +19 -0
  112. package/src/lib/organization/organization.module.ts +27 -0
  113. package/src/lib/organization/organization.mutations.ts +115 -0
  114. package/src/lib/organization/organization.queries.ts +188 -0
  115. package/src/lib/organization/organization.service.spec.ts +760 -0
  116. package/src/lib/organization/organization.service.ts +1216 -0
  117. package/src/lib/organization/position.entity.ts +39 -0
  118. package/src/lib/organization/resolved-manager.object.ts +10 -0
  119. package/src/lib/signature/signature-options.spec.ts +60 -0
  120. package/src/lib/signature/signature-options.ts +120 -0
  121. package/src/lib/signature/signature-verification.object.ts +16 -0
  122. package/src/lib/signature/signature.entity.ts +62 -0
  123. package/src/lib/signature/signature.module.ts +80 -0
  124. package/src/lib/signature/signature.queries.ts +37 -0
  125. package/src/lib/signature/signature.service.spec.ts +134 -0
  126. package/src/lib/signature/signature.service.ts +205 -0
  127. package/src/lib/template/approval-template-category.entity.ts +40 -0
  128. package/src/lib/template/approval-template-version.entity.ts +82 -0
  129. package/src/lib/template/approval-template.entity.ts +64 -0
  130. package/src/lib/template/dto/approval-template.input.ts +147 -0
  131. package/src/lib/template/template.enums.ts +30 -0
  132. package/src/lib/template/template.module.ts +25 -0
  133. package/src/lib/template/template.mutations.ts +106 -0
  134. package/src/lib/template/template.queries.ts +119 -0
  135. package/src/lib/template/template.service.spec.ts +476 -0
  136. package/src/lib/template/template.service.ts +820 -0
  137. package/src/lib/template/workflow-definition.validator.spec.ts +595 -0
  138. package/src/lib/template/workflow-definition.validator.ts +539 -0
  139. package/src/lib/testing/cel-js.jest.ts +46 -0
  140. package/src/lib/workflow-engine/activity-log.entity.ts +48 -0
  141. package/src/lib/workflow-engine/approval-instance-page-info.object.ts +22 -0
  142. package/src/lib/workflow-engine/approval-instance.entity.ts +86 -0
  143. package/src/lib/workflow-engine/dto/cancel-approval-instance.input.ts +18 -0
  144. package/src/lib/workflow-engine/dto/decide-task.input.ts +33 -0
  145. package/src/lib/workflow-engine/dto/dry-run-approval-workflow.input.ts +22 -0
  146. package/src/lib/workflow-engine/dto/resubmit-approval-instance.input.ts +22 -0
  147. package/src/lib/workflow-engine/dto/submit-approval-instance.input.ts +27 -0
  148. package/src/lib/workflow-engine/task-candidate.entity.ts +56 -0
  149. package/src/lib/workflow-engine/task-decision.entity.ts +43 -0
  150. package/src/lib/workflow-engine/task.entity.ts +85 -0
  151. package/src/lib/workflow-engine/workflow-condition-evaluator.ts +168 -0
  152. package/src/lib/workflow-engine/workflow-dashboard-summary.object.ts +22 -0
  153. package/src/lib/workflow-engine/workflow-dry-run.object.ts +58 -0
  154. package/src/lib/workflow-engine/workflow-engine.enums.ts +99 -0
  155. package/src/lib/workflow-engine/workflow-engine.module.ts +75 -0
  156. package/src/lib/workflow-engine/workflow-engine.mutations.ts +85 -0
  157. package/src/lib/workflow-engine/workflow-engine.queries.ts +229 -0
  158. package/src/lib/workflow-engine/workflow-engine.service.spec.ts +2689 -0
  159. package/src/lib/workflow-engine/workflow-engine.service.ts +4707 -0
  160. package/src/lib/workflow-engine/{workflow-engine.tokens.d.ts → workflow-engine.tokens.ts} +9 -3
  161. package/src/lib/workflow-engine/workflow-service-task-dispatcher.token.ts +69 -0
  162. package/src/lib/workflow-engine/workflow-token.entity.ts +40 -0
  163. package/tsconfig.json +24 -0
  164. package/tsconfig.lib.json +16 -0
  165. package/tsconfig.spec.json +16 -0
  166. package/LICENSE +0 -21
  167. package/src/index.js +0 -18
  168. package/src/index.js.map +0 -1
  169. package/src/lib/attachment/attachment-options.d.ts +0 -44
  170. package/src/lib/attachment/attachment-options.js +0 -62
  171. package/src/lib/attachment/attachment-options.js.map +0 -1
  172. package/src/lib/attachment/attachment-storage.provider.d.ts +0 -4
  173. package/src/lib/attachment/attachment-storage.provider.js +0 -35
  174. package/src/lib/attachment/attachment-storage.provider.js.map +0 -1
  175. package/src/lib/attachment/attachment-storage.token.js +0 -5
  176. package/src/lib/attachment/attachment-storage.token.js.map +0 -1
  177. package/src/lib/attachment/attachment.controller.d.ts +0 -8
  178. package/src/lib/attachment/attachment.controller.js +0 -38
  179. package/src/lib/attachment/attachment.controller.js.map +0 -1
  180. package/src/lib/attachment/attachment.entity.d.ts +0 -14
  181. package/src/lib/attachment/attachment.entity.js +0 -74
  182. package/src/lib/attachment/attachment.entity.js.map +0 -1
  183. package/src/lib/attachment/attachment.module.d.ts +0 -27
  184. package/src/lib/attachment/attachment.module.js +0 -103
  185. package/src/lib/attachment/attachment.module.js.map +0 -1
  186. package/src/lib/attachment/attachment.mutations.d.ts +0 -8
  187. package/src/lib/attachment/attachment.mutations.js +0 -35
  188. package/src/lib/attachment/attachment.mutations.js.map +0 -1
  189. package/src/lib/attachment/attachment.queries.d.ts +0 -9
  190. package/src/lib/attachment/attachment.queries.js +0 -78
  191. package/src/lib/attachment/attachment.queries.js.map +0 -1
  192. package/src/lib/attachment/attachment.service.d.ts +0 -49
  193. package/src/lib/attachment/attachment.service.js +0 -276
  194. package/src/lib/attachment/attachment.service.js.map +0 -1
  195. package/src/lib/attachment/dto/upload-attachment.input.d.ts +0 -11
  196. package/src/lib/attachment/dto/upload-attachment.input.js +0 -68
  197. package/src/lib/attachment/dto/upload-attachment.input.js.map +0 -1
  198. package/src/lib/attachment/index.js +0 -9
  199. package/src/lib/attachment/index.js.map +0 -1
  200. package/src/lib/bpm/bpm-root.module.d.ts +0 -155
  201. package/src/lib/bpm/bpm-root.module.js +0 -170
  202. package/src/lib/bpm/bpm-root.module.js.map +0 -1
  203. package/src/lib/bpm/index.js +0 -5
  204. package/src/lib/bpm/index.js.map +0 -1
  205. package/src/lib/bpm-auth/bpm-auth-context.d.ts +0 -24
  206. package/src/lib/bpm-auth/bpm-auth-context.extractor.d.ts +0 -4
  207. package/src/lib/bpm-auth/bpm-auth-context.extractor.js +0 -69
  208. package/src/lib/bpm-auth/bpm-auth-context.extractor.js.map +0 -1
  209. package/src/lib/bpm-auth/bpm-auth-context.js +0 -15
  210. package/src/lib/bpm-auth/bpm-auth-context.js.map +0 -1
  211. package/src/lib/bpm-auth/bpm-auth.authorization.d.ts +0 -12
  212. package/src/lib/bpm-auth/bpm-auth.authorization.js +0 -67
  213. package/src/lib/bpm-auth/bpm-auth.authorization.js.map +0 -1
  214. package/src/lib/bpm-auth/bpm-auth.decorators.d.ts +0 -3
  215. package/src/lib/bpm-auth/bpm-auth.decorators.js +0 -11
  216. package/src/lib/bpm-auth/bpm-auth.decorators.js.map +0 -1
  217. package/src/lib/bpm-auth/bpm-auth.guard.d.ts +0 -7
  218. package/src/lib/bpm-auth/bpm-auth.guard.js +0 -24
  219. package/src/lib/bpm-auth/bpm-auth.guard.js.map +0 -1
  220. package/src/lib/bpm-auth/bpm-auth.module.d.ts +0 -6
  221. package/src/lib/bpm-auth/bpm-auth.module.js +0 -69
  222. package/src/lib/bpm-auth/bpm-auth.module.js.map +0 -1
  223. package/src/lib/bpm-auth/bpm-auth.options.d.ts +0 -11
  224. package/src/lib/bpm-auth/bpm-auth.options.js +0 -3
  225. package/src/lib/bpm-auth/bpm-auth.options.js.map +0 -1
  226. package/src/lib/bpm-auth/configurable-bpm-auth-context.accessor.d.ts +0 -10
  227. package/src/lib/bpm-auth/configurable-bpm-auth-context.accessor.js +0 -40
  228. package/src/lib/bpm-auth/configurable-bpm-auth-context.accessor.js.map +0 -1
  229. package/src/lib/bpm-auth/index.js +0 -10
  230. package/src/lib/bpm-auth/index.js.map +0 -1
  231. package/src/lib/common/filters/all-exceptions.filter.d.ts +0 -25
  232. package/src/lib/common/filters/all-exceptions.filter.js +0 -93
  233. package/src/lib/common/filters/all-exceptions.filter.js.map +0 -1
  234. package/src/lib/common/index.js +0 -5
  235. package/src/lib/common/index.js.map +0 -1
  236. package/src/lib/common/iso-duration.d.ts +0 -1
  237. package/src/lib/common/iso-duration.js +0 -27
  238. package/src/lib/common/iso-duration.js.map +0 -1
  239. package/src/lib/condition/condition.module.d.ts +0 -2
  240. package/src/lib/condition/condition.module.js +0 -16
  241. package/src/lib/condition/condition.module.js.map +0 -1
  242. package/src/lib/condition/condition.service.d.ts +0 -16
  243. package/src/lib/condition/condition.service.js +0 -82
  244. package/src/lib/condition/condition.service.js.map +0 -1
  245. package/src/lib/condition/index.js +0 -6
  246. package/src/lib/condition/index.js.map +0 -1
  247. package/src/lib/database/data-source.d.ts +0 -4
  248. package/src/lib/database/data-source.js +0 -7
  249. package/src/lib/database/data-source.js.map +0 -1
  250. package/src/lib/database/index.js +0 -6
  251. package/src/lib/database/index.js.map +0 -1
  252. package/src/lib/database/migration-runner.d.ts +0 -1
  253. package/src/lib/database/migration-runner.js +0 -23
  254. package/src/lib/database/migration-runner.js.map +0 -1
  255. package/src/lib/database/typeorm.config.d.ts +0 -14
  256. package/src/lib/database/typeorm.config.js +0 -135
  257. package/src/lib/database/typeorm.config.js.map +0 -1
  258. package/src/lib/delegation/delegation-rule.entity.d.ts +0 -19
  259. package/src/lib/delegation/delegation-rule.entity.js +0 -99
  260. package/src/lib/delegation/delegation-rule.entity.js.map +0 -1
  261. package/src/lib/delegation/delegation.enums.d.ts +0 -10
  262. package/src/lib/delegation/delegation.enums.js +0 -23
  263. package/src/lib/delegation/delegation.enums.js.map +0 -1
  264. package/src/lib/delegation/delegation.module.d.ts +0 -2
  265. package/src/lib/delegation/delegation.module.js +0 -22
  266. package/src/lib/delegation/delegation.module.js.map +0 -1
  267. package/src/lib/delegation/delegation.mutations.d.ts +0 -11
  268. package/src/lib/delegation/delegation.mutations.js +0 -87
  269. package/src/lib/delegation/delegation.mutations.js.map +0 -1
  270. package/src/lib/delegation/delegation.queries.d.ts +0 -10
  271. package/src/lib/delegation/delegation.queries.js +0 -91
  272. package/src/lib/delegation/delegation.queries.js.map +0 -1
  273. package/src/lib/delegation/delegation.service.d.ts +0 -56
  274. package/src/lib/delegation/delegation.service.js +0 -268
  275. package/src/lib/delegation/delegation.service.js.map +0 -1
  276. package/src/lib/delegation/dto/delegation-rule.input.d.ts +0 -24
  277. package/src/lib/delegation/dto/delegation-rule.input.js +0 -143
  278. package/src/lib/delegation/dto/delegation-rule.input.js.map +0 -1
  279. package/src/lib/delegation/index.js +0 -9
  280. package/src/lib/delegation/index.js.map +0 -1
  281. package/src/lib/form/dto/form-definition.input.d.ts +0 -21
  282. package/src/lib/form/dto/form-definition.input.js +0 -103
  283. package/src/lib/form/dto/form-definition.input.js.map +0 -1
  284. package/src/lib/form/form-definition-version.entity.d.ts +0 -17
  285. package/src/lib/form/form-definition-version.entity.js +0 -84
  286. package/src/lib/form/form-definition-version.entity.js.map +0 -1
  287. package/src/lib/form/form-definition.entity.d.ts +0 -13
  288. package/src/lib/form/form-definition.entity.js +0 -66
  289. package/src/lib/form/form-definition.entity.js.map +0 -1
  290. package/src/lib/form/form-schema-lint.object.d.ts +0 -4
  291. package/src/lib/form/form-schema-lint.object.js +0 -20
  292. package/src/lib/form/form-schema-lint.object.js.map +0 -1
  293. package/src/lib/form/form-schema.validator.d.ts +0 -13
  294. package/src/lib/form/form-schema.validator.js +0 -354
  295. package/src/lib/form/form-schema.validator.js.map +0 -1
  296. package/src/lib/form/form.enums.d.ts +0 -9
  297. package/src/lib/form/form.enums.js +0 -22
  298. package/src/lib/form/form.enums.js.map +0 -1
  299. package/src/lib/form/form.module.d.ts +0 -2
  300. package/src/lib/form/form.module.js +0 -27
  301. package/src/lib/form/form.module.js.map +0 -1
  302. package/src/lib/form/form.mutations.d.ts +0 -14
  303. package/src/lib/form/form.mutations.js +0 -88
  304. package/src/lib/form/form.mutations.js.map +0 -1
  305. package/src/lib/form/form.queries.d.ts +0 -16
  306. package/src/lib/form/form.queries.js +0 -96
  307. package/src/lib/form/form.queries.js.map +0 -1
  308. package/src/lib/form/form.service.d.ts +0 -35
  309. package/src/lib/form/form.service.js +0 -297
  310. package/src/lib/form/form.service.js.map +0 -1
  311. package/src/lib/form/index.js +0 -12
  312. package/src/lib/form/index.js.map +0 -1
  313. package/src/lib/identity/identity-options.d.ts +0 -13
  314. package/src/lib/identity/identity-options.js +0 -20
  315. package/src/lib/identity/identity-options.js.map +0 -1
  316. package/src/lib/identity/identity.module.d.ts +0 -17
  317. package/src/lib/identity/identity.module.js +0 -65
  318. package/src/lib/identity/identity.module.js.map +0 -1
  319. package/src/lib/identity/identity.queries.d.ts +0 -12
  320. package/src/lib/identity/identity.queries.js +0 -79
  321. package/src/lib/identity/identity.queries.js.map +0 -1
  322. package/src/lib/identity/identity.service.d.ts +0 -22
  323. package/src/lib/identity/identity.service.js +0 -141
  324. package/src/lib/identity/identity.service.js.map +0 -1
  325. package/src/lib/identity/index.js +0 -7
  326. package/src/lib/identity/index.js.map +0 -1
  327. package/src/lib/identity/member-base.adapter.d.ts +0 -95
  328. package/src/lib/identity/member-base.adapter.js +0 -137
  329. package/src/lib/identity/member-base.adapter.js.map +0 -1
  330. package/src/lib/identity/member-metadata-cache.entity.d.ts +0 -8
  331. package/src/lib/identity/member-metadata-cache.entity.js +0 -39
  332. package/src/lib/identity/member-metadata-cache.entity.js.map +0 -1
  333. package/src/lib/identity/member-profile.object.d.ts +0 -8
  334. package/src/lib/identity/member-profile.object.js +0 -37
  335. package/src/lib/identity/member-profile.object.js.map +0 -1
  336. package/src/lib/identity/member-resolver.interface.js +0 -19
  337. package/src/lib/identity/member-resolver.interface.js.map +0 -1
  338. package/src/lib/migrations/0000000000001-enable-postgres-extensions.d.ts +0 -6
  339. package/src/lib/migrations/0000000000001-enable-postgres-extensions.js +0 -17
  340. package/src/lib/migrations/0000000000001-enable-postgres-extensions.js.map +0 -1
  341. package/src/lib/migrations/0000000001000-identity-organization-foundation.d.ts +0 -6
  342. package/src/lib/migrations/0000000001000-identity-organization-foundation.js.map +0 -1
  343. package/src/lib/migrations/0000000002000-form-builder-foundation.d.ts +0 -6
  344. package/src/lib/migrations/0000000002000-form-builder-foundation.js.map +0 -1
  345. package/src/lib/migrations/0000000003000-approval-template-foundation.d.ts +0 -6
  346. package/src/lib/migrations/0000000003000-approval-template-foundation.js.map +0 -1
  347. package/src/lib/migrations/0000000004000-workflow-engine-foundation.d.ts +0 -6
  348. package/src/lib/migrations/0000000004000-workflow-engine-foundation.js.map +0 -1
  349. package/src/lib/migrations/0000000005000-delegation-rules.d.ts +0 -6
  350. package/src/lib/migrations/0000000005000-delegation-rules.js.map +0 -1
  351. package/src/lib/migrations/0000000006000-notifications-sla.d.ts +0 -6
  352. package/src/lib/migrations/0000000006000-notifications-sla.js.map +0 -1
  353. package/src/lib/migrations/0000000007000-signatures-attachments.d.ts +0 -6
  354. package/src/lib/migrations/0000000007000-signatures-attachments.js.map +0 -1
  355. package/src/lib/migrations/0000000008000-approval-template-categories.d.ts +0 -6
  356. package/src/lib/migrations/0000000008000-approval-template-categories.js.map +0 -1
  357. package/src/lib/migrations/0000000009000-task-candidates.d.ts +0 -6
  358. package/src/lib/migrations/0000000009000-task-candidates.js.map +0 -1
  359. package/src/lib/migrations/0000000010000-notification-delivery-state.d.ts +0 -6
  360. package/src/lib/migrations/0000000010000-notification-delivery-state.js.map +0 -1
  361. package/src/lib/migrations/0000000011000-remove-attachment-encryption-key.d.ts +0 -6
  362. package/src/lib/migrations/0000000011000-remove-attachment-encryption-key.js +0 -22
  363. package/src/lib/migrations/0000000011000-remove-attachment-encryption-key.js.map +0 -1
  364. package/src/lib/migrations/0000000012000-notification-sla-idempotency.d.ts +0 -6
  365. package/src/lib/migrations/0000000012000-notification-sla-idempotency.js +0 -21
  366. package/src/lib/migrations/0000000012000-notification-sla-idempotency.js.map +0 -1
  367. package/src/lib/migrations/0000000013000-workflow-query-indexes.d.ts +0 -6
  368. package/src/lib/migrations/0000000013000-workflow-query-indexes.js +0 -80
  369. package/src/lib/migrations/0000000013000-workflow-query-indexes.js.map +0 -1
  370. package/src/lib/migrations/index.d.ts +0 -16
  371. package/src/lib/migrations/index.js +0 -49
  372. package/src/lib/migrations/index.js.map +0 -1
  373. package/src/lib/notification/dto/notification-preference.input.d.ts +0 -9
  374. package/src/lib/notification/dto/notification-preference.input.js +0 -53
  375. package/src/lib/notification/dto/notification-preference.input.js.map +0 -1
  376. package/src/lib/notification/index.js +0 -11
  377. package/src/lib/notification/index.js.map +0 -1
  378. package/src/lib/notification/notification-delivery-scheduler.service.d.ts +0 -13
  379. package/src/lib/notification/notification-delivery-scheduler.service.js +0 -53
  380. package/src/lib/notification/notification-delivery-scheduler.service.js.map +0 -1
  381. package/src/lib/notification/notification-delivery.service.d.ts +0 -23
  382. package/src/lib/notification/notification-delivery.service.js +0 -245
  383. package/src/lib/notification/notification-delivery.service.js.map +0 -1
  384. package/src/lib/notification/notification-dispatcher.token.d.ts +0 -7
  385. package/src/lib/notification/notification-dispatcher.token.js +0 -5
  386. package/src/lib/notification/notification-dispatcher.token.js.map +0 -1
  387. package/src/lib/notification/notification-options.d.ts +0 -215
  388. package/src/lib/notification/notification-options.js +0 -128
  389. package/src/lib/notification/notification-options.js.map +0 -1
  390. package/src/lib/notification/notification-options.module.d.ts +0 -23
  391. package/src/lib/notification/notification-options.module.js +0 -41
  392. package/src/lib/notification/notification-options.module.js.map +0 -1
  393. package/src/lib/notification/notification-preference.entity.d.ts +0 -10
  394. package/src/lib/notification/notification-preference.entity.js +0 -50
  395. package/src/lib/notification/notification-preference.entity.js.map +0 -1
  396. package/src/lib/notification/notification-sla-scheduler.service.d.ts +0 -13
  397. package/src/lib/notification/notification-sla-scheduler.service.js +0 -51
  398. package/src/lib/notification/notification-sla-scheduler.service.js.map +0 -1
  399. package/src/lib/notification/notification-template.d.ts +0 -13
  400. package/src/lib/notification/notification-template.js +0 -61
  401. package/src/lib/notification/notification-template.js.map +0 -1
  402. package/src/lib/notification/notification.entity.d.ts +0 -23
  403. package/src/lib/notification/notification.entity.js +0 -122
  404. package/src/lib/notification/notification.entity.js.map +0 -1
  405. package/src/lib/notification/notification.enums.d.ts +0 -24
  406. package/src/lib/notification/notification.enums.js +0 -45
  407. package/src/lib/notification/notification.enums.js.map +0 -1
  408. package/src/lib/notification/notification.module.d.ts +0 -2
  409. package/src/lib/notification/notification.module.js +0 -45
  410. package/src/lib/notification/notification.module.js.map +0 -1
  411. package/src/lib/notification/notification.mutations.d.ts +0 -11
  412. package/src/lib/notification/notification.mutations.js +0 -64
  413. package/src/lib/notification/notification.mutations.js.map +0 -1
  414. package/src/lib/notification/notification.queries.d.ts +0 -11
  415. package/src/lib/notification/notification.queries.js +0 -77
  416. package/src/lib/notification/notification.queries.js.map +0 -1
  417. package/src/lib/notification/notification.service.d.ts +0 -81
  418. package/src/lib/notification/notification.service.js +0 -621
  419. package/src/lib/notification/notification.service.js.map +0 -1
  420. package/src/lib/organization/dto/manager-resolution.input.d.ts +0 -18
  421. package/src/lib/organization/dto/manager-resolution.input.js +0 -107
  422. package/src/lib/organization/dto/manager-resolution.input.js.map +0 -1
  423. package/src/lib/organization/dto/membership.input.d.ts +0 -16
  424. package/src/lib/organization/dto/membership.input.js +0 -99
  425. package/src/lib/organization/dto/membership.input.js.map +0 -1
  426. package/src/lib/organization/dto/org-unit.input.d.ts +0 -24
  427. package/src/lib/organization/dto/org-unit.input.js +0 -119
  428. package/src/lib/organization/dto/org-unit.input.js.map +0 -1
  429. package/src/lib/organization/dto/position.input.d.ts +0 -13
  430. package/src/lib/organization/dto/position.input.js +0 -70
  431. package/src/lib/organization/dto/position.input.js.map +0 -1
  432. package/src/lib/organization/index.js +0 -16
  433. package/src/lib/organization/index.js.map +0 -1
  434. package/src/lib/organization/json-metadata.d.ts +0 -1
  435. package/src/lib/organization/json-metadata.js +0 -14
  436. package/src/lib/organization/json-metadata.js.map +0 -1
  437. package/src/lib/organization/manager-resolution.entity.d.ts +0 -11
  438. package/src/lib/organization/manager-resolution.entity.js +0 -55
  439. package/src/lib/organization/manager-resolution.entity.js.map +0 -1
  440. package/src/lib/organization/membership.entity.d.ts +0 -11
  441. package/src/lib/organization/membership.entity.js +0 -60
  442. package/src/lib/organization/membership.entity.js.map +0 -1
  443. package/src/lib/organization/org-unit-tree-commit-result.object.d.ts +0 -4
  444. package/src/lib/organization/org-unit-tree-commit-result.object.js +0 -17
  445. package/src/lib/organization/org-unit-tree-commit-result.object.js.map +0 -1
  446. package/src/lib/organization/org-unit.entity.d.ts +0 -13
  447. package/src/lib/organization/org-unit.entity.js +0 -64
  448. package/src/lib/organization/org-unit.entity.js.map +0 -1
  449. package/src/lib/organization/organization-summary.object.d.ts +0 -6
  450. package/src/lib/organization/organization-summary.object.js +0 -28
  451. package/src/lib/organization/organization-summary.object.js.map +0 -1
  452. package/src/lib/organization/organization.enums.d.ts +0 -11
  453. package/src/lib/organization/organization.enums.js +0 -22
  454. package/src/lib/organization/organization.enums.js.map +0 -1
  455. package/src/lib/organization/organization.module.d.ts +0 -2
  456. package/src/lib/organization/organization.module.js +0 -35
  457. package/src/lib/organization/organization.module.js.map +0 -1
  458. package/src/lib/organization/organization.mutations.d.ts +0 -26
  459. package/src/lib/organization/organization.mutations.js +0 -148
  460. package/src/lib/organization/organization.mutations.js.map +0 -1
  461. package/src/lib/organization/organization.queries.d.ts +0 -23
  462. package/src/lib/organization/organization.queries.js +0 -202
  463. package/src/lib/organization/organization.queries.js.map +0 -1
  464. package/src/lib/organization/organization.service.d.ts +0 -102
  465. package/src/lib/organization/organization.service.js +0 -751
  466. package/src/lib/organization/organization.service.js.map +0 -1
  467. package/src/lib/organization/position.entity.d.ts +0 -9
  468. package/src/lib/organization/position.entity.js +0 -48
  469. package/src/lib/organization/position.entity.js.map +0 -1
  470. package/src/lib/organization/resolved-manager.object.d.ts +0 -4
  471. package/src/lib/organization/resolved-manager.object.js +0 -20
  472. package/src/lib/organization/resolved-manager.object.js.map +0 -1
  473. package/src/lib/signature/index.js +0 -8
  474. package/src/lib/signature/index.js.map +0 -1
  475. package/src/lib/signature/signature-options.d.ts +0 -33
  476. package/src/lib/signature/signature-options.js +0 -51
  477. package/src/lib/signature/signature-options.js.map +0 -1
  478. package/src/lib/signature/signature-verification.object.d.ts +0 -6
  479. package/src/lib/signature/signature-verification.object.js +0 -28
  480. package/src/lib/signature/signature-verification.object.js.map +0 -1
  481. package/src/lib/signature/signature.entity.d.ts +0 -16
  482. package/src/lib/signature/signature.entity.js +0 -88
  483. package/src/lib/signature/signature.entity.js.map +0 -1
  484. package/src/lib/signature/signature.module.d.ts +0 -11
  485. package/src/lib/signature/signature.module.js +0 -60
  486. package/src/lib/signature/signature.module.js.map +0 -1
  487. package/src/lib/signature/signature.queries.d.ts +0 -11
  488. package/src/lib/signature/signature.queries.js +0 -46
  489. package/src/lib/signature/signature.queries.js.map +0 -1
  490. package/src/lib/signature/signature.service.d.ts +0 -25
  491. package/src/lib/signature/signature.service.js +0 -124
  492. package/src/lib/signature/signature.service.js.map +0 -1
  493. package/src/lib/template/approval-template-category.entity.d.ts +0 -9
  494. package/src/lib/template/approval-template-category.entity.js +0 -49
  495. package/src/lib/template/approval-template-category.entity.js.map +0 -1
  496. package/src/lib/template/approval-template-version.entity.d.ts +0 -21
  497. package/src/lib/template/approval-template-version.entity.js +0 -106
  498. package/src/lib/template/approval-template-version.entity.js.map +0 -1
  499. package/src/lib/template/approval-template.entity.d.ts +0 -14
  500. package/src/lib/template/approval-template.entity.js +0 -74
  501. package/src/lib/template/approval-template.entity.js.map +0 -1
  502. package/src/lib/template/dto/approval-template.input.d.ts +0 -36
  503. package/src/lib/template/dto/approval-template.input.js +0 -187
  504. package/src/lib/template/dto/approval-template.input.js.map +0 -1
  505. package/src/lib/template/index.js +0 -12
  506. package/src/lib/template/index.js.map +0 -1
  507. package/src/lib/template/template.enums.d.ts +0 -14
  508. package/src/lib/template/template.enums.js +0 -31
  509. package/src/lib/template/template.enums.js.map +0 -1
  510. package/src/lib/template/template.module.d.ts +0 -2
  511. package/src/lib/template/template.module.js +0 -33
  512. package/src/lib/template/template.module.js.map +0 -1
  513. package/src/lib/template/template.mutations.d.ts +0 -20
  514. package/src/lib/template/template.mutations.js +0 -139
  515. package/src/lib/template/template.mutations.js.map +0 -1
  516. package/src/lib/template/template.queries.d.ts +0 -16
  517. package/src/lib/template/template.queries.js +0 -133
  518. package/src/lib/template/template.queries.js.map +0 -1
  519. package/src/lib/template/template.service.d.ts +0 -64
  520. package/src/lib/template/template.service.js +0 -521
  521. package/src/lib/template/template.service.js.map +0 -1
  522. package/src/lib/template/workflow-definition.validator.d.ts +0 -9
  523. package/src/lib/template/workflow-definition.validator.js +0 -362
  524. package/src/lib/template/workflow-definition.validator.js.map +0 -1
  525. package/src/lib/testing/cel-js.jest.d.ts +0 -15
  526. package/src/lib/testing/cel-js.jest.js +0 -27
  527. package/src/lib/testing/cel-js.jest.js.map +0 -1
  528. package/src/lib/workflow-engine/activity-log.entity.d.ts +0 -12
  529. package/src/lib/workflow-engine/activity-log.entity.js +0 -62
  530. package/src/lib/workflow-engine/activity-log.entity.js.map +0 -1
  531. package/src/lib/workflow-engine/approval-instance-page-info.object.d.ts +0 -8
  532. package/src/lib/workflow-engine/approval-instance-page-info.object.js +0 -36
  533. package/src/lib/workflow-engine/approval-instance-page-info.object.js.map +0 -1
  534. package/src/lib/workflow-engine/approval-instance.entity.d.ts +0 -22
  535. package/src/lib/workflow-engine/approval-instance.entity.js +0 -113
  536. package/src/lib/workflow-engine/approval-instance.entity.js.map +0 -1
  537. package/src/lib/workflow-engine/dto/cancel-approval-instance.input.d.ts +0 -5
  538. package/src/lib/workflow-engine/dto/cancel-approval-instance.input.js +0 -29
  539. package/src/lib/workflow-engine/dto/cancel-approval-instance.input.js.map +0 -1
  540. package/src/lib/workflow-engine/dto/decide-task.input.d.ts +0 -9
  541. package/src/lib/workflow-engine/dto/decide-task.input.js +0 -47
  542. package/src/lib/workflow-engine/dto/decide-task.input.js.map +0 -1
  543. package/src/lib/workflow-engine/dto/dry-run-approval-workflow.input.d.ts +0 -6
  544. package/src/lib/workflow-engine/dto/dry-run-approval-workflow.input.js +0 -34
  545. package/src/lib/workflow-engine/dto/dry-run-approval-workflow.input.js.map +0 -1
  546. package/src/lib/workflow-engine/dto/resubmit-approval-instance.input.d.ts +0 -6
  547. package/src/lib/workflow-engine/dto/resubmit-approval-instance.input.js +0 -34
  548. package/src/lib/workflow-engine/dto/resubmit-approval-instance.input.js.map +0 -1
  549. package/src/lib/workflow-engine/dto/submit-approval-instance.input.d.ts +0 -7
  550. package/src/lib/workflow-engine/dto/submit-approval-instance.input.js +0 -40
  551. package/src/lib/workflow-engine/dto/submit-approval-instance.input.js.map +0 -1
  552. package/src/lib/workflow-engine/index.js +0 -24
  553. package/src/lib/workflow-engine/index.js.map +0 -1
  554. package/src/lib/workflow-engine/task-candidate.entity.d.ts +0 -14
  555. package/src/lib/workflow-engine/task-candidate.entity.js +0 -72
  556. package/src/lib/workflow-engine/task-candidate.entity.js.map +0 -1
  557. package/src/lib/workflow-engine/task-decision.entity.d.ts +0 -12
  558. package/src/lib/workflow-engine/task-decision.entity.js +0 -60
  559. package/src/lib/workflow-engine/task-decision.entity.js.map +0 -1
  560. package/src/lib/workflow-engine/task.entity.d.ts +0 -20
  561. package/src/lib/workflow-engine/task.entity.js +0 -109
  562. package/src/lib/workflow-engine/task.entity.js.map +0 -1
  563. package/src/lib/workflow-engine/workflow-condition-evaluator.d.ts +0 -5
  564. package/src/lib/workflow-engine/workflow-condition-evaluator.js +0 -107
  565. package/src/lib/workflow-engine/workflow-condition-evaluator.js.map +0 -1
  566. package/src/lib/workflow-engine/workflow-dashboard-summary.object.d.ts +0 -8
  567. package/src/lib/workflow-engine/workflow-dashboard-summary.object.js +0 -36
  568. package/src/lib/workflow-engine/workflow-dashboard-summary.object.js.map +0 -1
  569. package/src/lib/workflow-engine/workflow-dry-run.object.d.ts +0 -21
  570. package/src/lib/workflow-engine/workflow-dry-run.object.js +0 -86
  571. package/src/lib/workflow-engine/workflow-dry-run.object.js.map +0 -1
  572. package/src/lib/workflow-engine/workflow-engine.enums.d.ts +0 -58
  573. package/src/lib/workflow-engine/workflow-engine.enums.js +0 -95
  574. package/src/lib/workflow-engine/workflow-engine.enums.js.map +0 -1
  575. package/src/lib/workflow-engine/workflow-engine.module.d.ts +0 -9
  576. package/src/lib/workflow-engine/workflow-engine.module.js +0 -76
  577. package/src/lib/workflow-engine/workflow-engine.module.js.map +0 -1
  578. package/src/lib/workflow-engine/workflow-engine.mutations.d.ts +0 -19
  579. package/src/lib/workflow-engine/workflow-engine.mutations.js +0 -106
  580. package/src/lib/workflow-engine/workflow-engine.mutations.js.map +0 -1
  581. package/src/lib/workflow-engine/workflow-engine.queries.d.ts +0 -29
  582. package/src/lib/workflow-engine/workflow-engine.queries.js +0 -225
  583. package/src/lib/workflow-engine/workflow-engine.queries.js.map +0 -1
  584. package/src/lib/workflow-engine/workflow-engine.service.d.ts +0 -145
  585. package/src/lib/workflow-engine/workflow-engine.service.js +0 -2785
  586. package/src/lib/workflow-engine/workflow-engine.service.js.map +0 -1
  587. package/src/lib/workflow-engine/workflow-engine.tokens.js +0 -5
  588. package/src/lib/workflow-engine/workflow-engine.tokens.js.map +0 -1
  589. package/src/lib/workflow-engine/workflow-service-task-dispatcher.token.d.ts +0 -18
  590. package/src/lib/workflow-engine/workflow-service-task-dispatcher.token.js +0 -39
  591. package/src/lib/workflow-engine/workflow-service-task-dispatcher.token.js.map +0 -1
  592. package/src/lib/workflow-engine/workflow-token.entity.d.ts +0 -10
  593. package/src/lib/workflow-engine/workflow-token.entity.js +0 -50
  594. package/src/lib/workflow-engine/workflow-token.entity.js.map +0 -1
  595. /package/src/{index.d.ts → index.ts} +0 -0
  596. /package/src/lib/attachment/{index.d.ts → index.ts} +0 -0
  597. /package/src/lib/bpm/{index.d.ts → index.ts} +0 -0
  598. /package/src/lib/bpm-auth/{index.d.ts → index.ts} +0 -0
  599. /package/src/lib/common/{index.d.ts → index.ts} +0 -0
  600. /package/src/lib/condition/{index.d.ts → index.ts} +0 -0
  601. /package/src/lib/database/{index.d.ts → index.ts} +0 -0
  602. /package/src/lib/delegation/{index.d.ts → index.ts} +0 -0
  603. /package/src/lib/form/{index.d.ts → index.ts} +0 -0
  604. /package/src/lib/identity/{index.d.ts → index.ts} +0 -0
  605. /package/src/lib/notification/{index.d.ts → index.ts} +0 -0
  606. /package/src/lib/organization/{index.d.ts → index.ts} +0 -0
  607. /package/src/lib/signature/{index.d.ts → index.ts} +0 -0
  608. /package/src/lib/template/{index.d.ts → index.ts} +0 -0
  609. /package/src/lib/workflow-engine/{index.d.ts → index.ts} +0 -0
@@ -0,0 +1,974 @@
1
+ import {
2
+ ServiceTaskNode,
3
+ UserTaskNode,
4
+ } from '@rytass/bpm-core-shared/workflow';
5
+ import {
6
+ Inject,
7
+ Injectable,
8
+ Logger,
9
+ NotFoundException,
10
+ Optional,
11
+ } from '@nestjs/common';
12
+ import { ModuleRef } from '@nestjs/core';
13
+ import { InjectRepository } from '@nestjs/typeorm';
14
+ import {
15
+ EntityManager,
16
+ IsNull,
17
+ LessThanOrEqual,
18
+ MoreThan,
19
+ Not,
20
+ Repository,
21
+ } from 'typeorm';
22
+ import { parseIsoDurationToMilliseconds } from '../common/iso-duration';
23
+ import { ActivityLogEntity } from '../workflow-engine/activity-log.entity';
24
+ import { ApprovalInstanceEntity } from '../workflow-engine/approval-instance.entity';
25
+ import { OrganizationService } from '../organization/organization.service';
26
+ import { TaskCandidateEntity } from '../workflow-engine/task-candidate.entity';
27
+ import { TaskEntity } from '../workflow-engine/task.entity';
28
+ import {
29
+ BPM_WORKFLOW_ENGINE_SERVICE,
30
+ BPMWorkflowEngineService,
31
+ } from '../workflow-engine/workflow-engine.tokens';
32
+ import {
33
+ ActivityLogEventTypeEnum,
34
+ TaskDecisionActionEnum,
35
+ TaskCandidateStatusEnum,
36
+ TaskStatusEnum,
37
+ } from '../workflow-engine/workflow-engine.enums';
38
+ import { NotificationDeliveryService } from './notification-delivery.service';
39
+ import { NotificationPreferenceEntity } from './notification-preference.entity';
40
+ import { NotificationEntity } from './notification.entity';
41
+ import {
42
+ NotificationChannelEnum,
43
+ NotificationStatusEnum,
44
+ NotificationTypeEnum,
45
+ } from './notification.enums';
46
+ import {
47
+ BPM_NOTIFICATION_OPTIONS,
48
+ BPMResolvedNotificationOptions,
49
+ DEFAULT_BPM_NOTIFICATION_OPTIONS,
50
+ } from './notification-options';
51
+ import { renderNotificationTemplate } from './notification-template';
52
+ import { UpdateNotificationPreferenceInput } from './dto/notification-preference.input';
53
+
54
+ interface CreateNotificationInput {
55
+ readonly channels: readonly NotificationChannelEnum[];
56
+ readonly instanceId: string | null;
57
+ readonly payload: Readonly<Record<string, unknown>>;
58
+ readonly recipientMemberId: string;
59
+ readonly taskId: string | null;
60
+ readonly type: NotificationTypeEnum;
61
+ readonly customTemplate?: string | null;
62
+ }
63
+
64
+ interface SlaScanResult {
65
+ readonly overdueCount: number;
66
+ readonly warningCount: number;
67
+ }
68
+
69
+ @Injectable()
70
+ export class NotificationService {
71
+ private readonly logger = new Logger(NotificationService.name);
72
+
73
+ constructor(
74
+ @InjectRepository(NotificationEntity)
75
+ private readonly notificationRepository: Repository<NotificationEntity>,
76
+ @InjectRepository(NotificationPreferenceEntity)
77
+ private readonly notificationPreferenceRepository: Repository<NotificationPreferenceEntity>,
78
+ @InjectRepository(TaskEntity)
79
+ private readonly taskRepository: Repository<TaskEntity>,
80
+ @InjectRepository(TaskCandidateEntity)
81
+ private readonly taskCandidateRepository: Repository<TaskCandidateEntity>,
82
+ @InjectRepository(ApprovalInstanceEntity)
83
+ private readonly approvalInstanceRepository: Repository<ApprovalInstanceEntity>,
84
+ @InjectRepository(ActivityLogEntity)
85
+ private readonly activityLogRepository: Repository<ActivityLogEntity>,
86
+ private readonly deliveryService: NotificationDeliveryService,
87
+ private readonly moduleRef: ModuleRef,
88
+ @Optional()
89
+ @Inject(BPM_NOTIFICATION_OPTIONS)
90
+ private readonly notificationOptions: BPMResolvedNotificationOptions = DEFAULT_BPM_NOTIFICATION_OPTIONS,
91
+ ) {}
92
+
93
+ async listNotifications({
94
+ includeRead = false,
95
+ page = 1,
96
+ pageSize = 10,
97
+ recipientMemberId,
98
+ }: {
99
+ readonly includeRead?: boolean;
100
+ readonly page?: number;
101
+ readonly pageSize?: number;
102
+ readonly recipientMemberId: string;
103
+ }): Promise<readonly NotificationEntity[]> {
104
+ const normalizedPageSize = normalizePageSize(pageSize);
105
+
106
+ return this.notificationRepository.find({
107
+ order: { createdAt: 'DESC' },
108
+ skip: (normalizePage(page) - 1) * normalizedPageSize,
109
+ take: normalizedPageSize,
110
+ where: {
111
+ channel: NotificationChannelEnum.IN_APP,
112
+ recipientMemberId,
113
+ ...(includeRead ? {} : { status: Not(NotificationStatusEnum.READ) }),
114
+ },
115
+ });
116
+ }
117
+
118
+ async countNotifications({
119
+ includeRead = false,
120
+ recipientMemberId,
121
+ }: {
122
+ readonly includeRead?: boolean;
123
+ readonly recipientMemberId: string;
124
+ }): Promise<number> {
125
+ return this.notificationRepository.count({
126
+ where: {
127
+ channel: NotificationChannelEnum.IN_APP,
128
+ recipientMemberId,
129
+ ...(includeRead ? {} : { status: Not(NotificationStatusEnum.READ) }),
130
+ },
131
+ });
132
+ }
133
+
134
+ async countUnreadNotifications(recipientMemberId: string): Promise<number> {
135
+ return this.notificationRepository.count({
136
+ where: {
137
+ channel: NotificationChannelEnum.IN_APP,
138
+ recipientMemberId,
139
+ status: Not(NotificationStatusEnum.READ),
140
+ },
141
+ });
142
+ }
143
+
144
+ async markAllNotificationsRead({
145
+ recipientMemberId,
146
+ }: {
147
+ readonly recipientMemberId: string;
148
+ }): Promise<number> {
149
+ const trimmedRecipientMemberId = recipientMemberId.trim();
150
+
151
+ if (!trimmedRecipientMemberId) {
152
+ return 0;
153
+ }
154
+
155
+ const result = await this.notificationRepository.update(
156
+ {
157
+ channel: NotificationChannelEnum.IN_APP,
158
+ recipientMemberId: trimmedRecipientMemberId,
159
+ status: Not(NotificationStatusEnum.READ),
160
+ },
161
+ {
162
+ readAt: new Date(),
163
+ status: NotificationStatusEnum.READ,
164
+ },
165
+ );
166
+
167
+ return result.affected ?? 0;
168
+ }
169
+
170
+ async markNotificationRead({
171
+ id,
172
+ readerMemberId,
173
+ }: {
174
+ readonly id: string;
175
+ readonly readerMemberId: string | null;
176
+ }): Promise<NotificationEntity> {
177
+ const notification = await this.notificationRepository.findOne({
178
+ where: { id },
179
+ });
180
+
181
+ if (!notification) {
182
+ throw new NotFoundException(`Notification ${id} was not found`);
183
+ }
184
+
185
+ if (
186
+ readerMemberId &&
187
+ notification.recipientMemberId !== readerMemberId.trim()
188
+ ) {
189
+ throw new NotFoundException(`Notification ${id} was not found`);
190
+ }
191
+
192
+ return this.notificationRepository.save(
193
+ this.notificationRepository.create({
194
+ ...notification,
195
+ readAt: notification.readAt ?? new Date(),
196
+ status: NotificationStatusEnum.READ,
197
+ }),
198
+ );
199
+ }
200
+
201
+ async getPreference(memberId: string): Promise<NotificationPreferenceEntity> {
202
+ const existingPreference =
203
+ await this.notificationPreferenceRepository.findOne({
204
+ where: { memberId },
205
+ });
206
+
207
+ return (
208
+ existingPreference ??
209
+ createDefaultPreference(memberId, this.notificationOptions)
210
+ );
211
+ }
212
+
213
+ async updatePreference(
214
+ input: UpdateNotificationPreferenceInput,
215
+ ): Promise<NotificationPreferenceEntity> {
216
+ const currentPreference = await this.getPreference(input.memberId);
217
+
218
+ return this.notificationPreferenceRepository.save({
219
+ ...currentPreference,
220
+ emailDigestMode: input.emailDigestMode,
221
+ emailEnabled: input.emailEnabled,
222
+ inAppEnabled: input.inAppEnabled,
223
+ memberId: input.memberId,
224
+ quietHoursEnd: normalizeTimeInput(input.quietHoursEnd),
225
+ quietHoursStart: normalizeTimeInput(input.quietHoursStart),
226
+ });
227
+ }
228
+
229
+ async createTaskAssignedNotification({
230
+ instance,
231
+ manager,
232
+ node,
233
+ task,
234
+ transferred = false,
235
+ }: {
236
+ readonly instance: ApprovalInstanceEntity;
237
+ readonly manager: EntityManager;
238
+ readonly node: UserTaskNode;
239
+ readonly task: TaskEntity;
240
+ readonly transferred?: boolean;
241
+ }): Promise<readonly NotificationEntity[]> {
242
+ if (!task.assigneeMemberId) {
243
+ return [];
244
+ }
245
+
246
+ return this.createNotifications(
247
+ {
248
+ channels: readNodeNotificationChannels(node, this.notificationOptions),
249
+ customTemplate: node.data.notification?.customTemplate ?? null,
250
+ instanceId: instance.id,
251
+ payload: {
252
+ assigneeMemberId: task.assigneeMemberId,
253
+ instanceId: instance.id,
254
+ instanceTitle: instance.title,
255
+ nodeId: node.id,
256
+ nodeLabel: node.data.label,
257
+ originalAssigneeMemberId: task.originalAssigneeMemberId,
258
+ slaDueAt: task.slaDueAt?.toISOString() ?? null,
259
+ taskId: task.id,
260
+ },
261
+ recipientMemberId: task.assigneeMemberId,
262
+ taskId: task.id,
263
+ type: transferred
264
+ ? NotificationTypeEnum.TASK_TRANSFERRED
265
+ : NotificationTypeEnum.TASK_ASSIGNED,
266
+ },
267
+ manager,
268
+ );
269
+ }
270
+
271
+ async createServiceTaskNotifications({
272
+ instance,
273
+ manager,
274
+ node,
275
+ recipientMemberIds,
276
+ }: {
277
+ readonly instance: ApprovalInstanceEntity;
278
+ readonly manager: EntityManager;
279
+ readonly node: ServiceTaskNode;
280
+ readonly recipientMemberIds: readonly string[];
281
+ }): Promise<readonly NotificationEntity[]> {
282
+ if (node.data.action.type !== 'NOTIFY') {
283
+ return [];
284
+ }
285
+
286
+ const action = node.data.action;
287
+ const channels = normalizeNotificationChannels(action.channels);
288
+ const uniqueRecipientMemberIds = uniqueStrings(recipientMemberIds);
289
+
290
+ return uniqueRecipientMemberIds.reduce<
291
+ Promise<readonly NotificationEntity[]>
292
+ >(
293
+ async (
294
+ previousPromise,
295
+ recipientMemberId,
296
+ ): Promise<readonly NotificationEntity[]> => {
297
+ const previous = await previousPromise;
298
+ const created = await this.createNotifications(
299
+ {
300
+ channels,
301
+ customTemplate: action.template ?? null,
302
+ instanceId: instance.id,
303
+ payload: {
304
+ instanceId: instance.id,
305
+ instanceTitle: instance.title,
306
+ message:
307
+ action.template ??
308
+ `案件 ${instance.title} 的 ${node.data.label} 已送出通知。`,
309
+ nodeId: node.id,
310
+ nodeLabel: node.data.label,
311
+ recipientMemberId,
312
+ },
313
+ recipientMemberId,
314
+ taskId: null,
315
+ type: NotificationTypeEnum.WORKFLOW_NOTIFICATION,
316
+ },
317
+ manager,
318
+ );
319
+
320
+ return [...previous, ...created];
321
+ },
322
+ Promise.resolve([]),
323
+ );
324
+ }
325
+
326
+ async createInstanceCompletedNotification({
327
+ instance,
328
+ manager,
329
+ }: {
330
+ readonly instance: ApprovalInstanceEntity;
331
+ readonly manager: EntityManager;
332
+ }): Promise<readonly NotificationEntity[]> {
333
+ const repository = manager.getRepository(NotificationEntity);
334
+ const existingNotification = await repository.findOne({
335
+ where: {
336
+ channel: NotificationChannelEnum.IN_APP,
337
+ instanceId: instance.id,
338
+ recipientMemberId: instance.initiatorMemberId,
339
+ taskId: IsNull(),
340
+ type: NotificationTypeEnum.INSTANCE_COMPLETED,
341
+ },
342
+ });
343
+
344
+ if (existingNotification) {
345
+ return [];
346
+ }
347
+
348
+ return this.createNotifications(
349
+ {
350
+ channels: [NotificationChannelEnum.IN_APP],
351
+ instanceId: instance.id,
352
+ payload: {
353
+ completedAt: instance.completedAt?.toISOString() ?? null,
354
+ instanceId: instance.id,
355
+ instanceTitle: instance.title,
356
+ recipientMemberId: instance.initiatorMemberId,
357
+ },
358
+ recipientMemberId: instance.initiatorMemberId,
359
+ taskId: null,
360
+ type: NotificationTypeEnum.INSTANCE_COMPLETED,
361
+ },
362
+ manager,
363
+ );
364
+ }
365
+
366
+ async runSlaScan(now: Date = new Date()): Promise<SlaScanResult> {
367
+ const candidateTasks = await this.taskRepository.find({
368
+ order: { slaDueAt: 'ASC' },
369
+ where: [
370
+ {
371
+ slaDueAt: LessThanOrEqual(now),
372
+ status: TaskStatusEnum.PENDING,
373
+ },
374
+ {
375
+ slaDueAt: LessThanOrEqual(now),
376
+ status: TaskStatusEnum.IN_PROGRESS,
377
+ },
378
+ {
379
+ slaDueAt: MoreThan(now),
380
+ status: TaskStatusEnum.PENDING,
381
+ },
382
+ {
383
+ slaDueAt: MoreThan(now),
384
+ status: TaskStatusEnum.IN_PROGRESS,
385
+ },
386
+ ],
387
+ });
388
+ const results = await candidateTasks.reduce<Promise<SlaScanResult>>(
389
+ async (resultPromise, task): Promise<SlaScanResult> => {
390
+ const currentResult = await resultPromise;
391
+
392
+ if (!(await this.tryClaimSlaTask(task.id))) {
393
+ return currentResult;
394
+ }
395
+
396
+ const instance = await this.approvalInstanceRepository.findOne({
397
+ where: { id: task.instanceId },
398
+ });
399
+
400
+ if (!instance) {
401
+ return currentResult;
402
+ }
403
+
404
+ const node = readUserTaskNode(instance, task.nodeId);
405
+
406
+ if (!node?.data.sla || !task.slaDueAt) {
407
+ return currentResult;
408
+ }
409
+
410
+ if (task.slaDueAt.getTime() <= now.getTime()) {
411
+ const created = await this.createSlaNotificationOnce({
412
+ instance,
413
+ node,
414
+ task,
415
+ type: NotificationTypeEnum.SLA_OVERDUE,
416
+ });
417
+
418
+ if (created) {
419
+ await this.recordSlaActivity({
420
+ instance,
421
+ node,
422
+ task,
423
+ trigger: 'OVERDUE',
424
+ });
425
+ await this.runSlaTimeoutHook({ instance, node, task });
426
+ }
427
+
428
+ return {
429
+ overdueCount: currentResult.overdueCount + (created ? 1 : 0),
430
+ warningCount: currentResult.warningCount,
431
+ };
432
+ }
433
+
434
+ const warningAt = node.data.sla.warningAt;
435
+
436
+ if (!warningAt || warningAt <= 0 || warningAt >= 1) {
437
+ return currentResult;
438
+ }
439
+
440
+ const warningAtTime =
441
+ task.createdAt.getTime() +
442
+ (task.slaDueAt.getTime() - task.createdAt.getTime()) * warningAt;
443
+
444
+ if (warningAtTime > now.getTime()) {
445
+ return currentResult;
446
+ }
447
+
448
+ const created = await this.createSlaNotificationOnce({
449
+ instance,
450
+ node,
451
+ task,
452
+ type: NotificationTypeEnum.SLA_WARNING,
453
+ });
454
+
455
+ if (created) {
456
+ await this.recordSlaActivity({
457
+ instance,
458
+ node,
459
+ task,
460
+ trigger: 'WARNING',
461
+ });
462
+ }
463
+
464
+ return {
465
+ overdueCount: currentResult.overdueCount,
466
+ warningCount: currentResult.warningCount + (created ? 1 : 0),
467
+ };
468
+ },
469
+ Promise.resolve({ overdueCount: 0, warningCount: 0 }),
470
+ );
471
+
472
+ return results;
473
+ }
474
+
475
+ private async tryClaimSlaTask(taskId: string): Promise<boolean> {
476
+ if (!this.taskRepository.query) {
477
+ return true;
478
+ }
479
+
480
+ const rows = (await this.taskRepository.query(
481
+ 'SELECT pg_try_advisory_xact_lock(hashtext($1)) AS claimed',
482
+ [`bpm-sla:${taskId}`],
483
+ )) as readonly { readonly claimed?: boolean }[];
484
+
485
+ return rows[0]?.claimed !== false;
486
+ }
487
+
488
+ private async createSlaNotificationOnce({
489
+ instance,
490
+ node,
491
+ task,
492
+ type,
493
+ }: {
494
+ readonly instance: ApprovalInstanceEntity;
495
+ readonly node: UserTaskNode;
496
+ readonly task: TaskEntity;
497
+ readonly type:
498
+ | NotificationTypeEnum.SLA_OVERDUE
499
+ | NotificationTypeEnum.SLA_WARNING;
500
+ }): Promise<boolean> {
501
+ const recipientMemberIds = await this.resolveTaskRecipientMemberIds(task);
502
+
503
+ if (recipientMemberIds.length === 0) {
504
+ return false;
505
+ }
506
+
507
+ const createdNotifications = await recipientMemberIds.reduce<
508
+ Promise<number>
509
+ >(async (countPromise, recipientMemberId): Promise<number> => {
510
+ const count = await countPromise;
511
+ const existingNotification = await this.notificationRepository.findOne({
512
+ where: {
513
+ channel: NotificationChannelEnum.IN_APP,
514
+ recipientMemberId,
515
+ taskId: task.id,
516
+ type,
517
+ },
518
+ });
519
+
520
+ if (existingNotification) {
521
+ return count;
522
+ }
523
+
524
+ try {
525
+ await this.createNotifications({
526
+ channels: [NotificationChannelEnum.IN_APP],
527
+ customTemplate: node.data.notification?.customTemplate ?? null,
528
+ instanceId: instance.id,
529
+ payload: {
530
+ assigneeMemberId: task.assigneeMemberId,
531
+ instanceId: instance.id,
532
+ instanceTitle: instance.title,
533
+ nodeId: node.id,
534
+ nodeLabel: node.data.label,
535
+ onTimeout: node.data.sla?.onTimeout ?? 'REMIND',
536
+ recipientMemberId,
537
+ slaDueAt: task.slaDueAt?.toISOString() ?? null,
538
+ taskId: task.id,
539
+ },
540
+ recipientMemberId,
541
+ taskId: task.id,
542
+ type,
543
+ });
544
+ } catch (error: unknown) {
545
+ if (isUniqueConstraintViolation(error)) {
546
+ return count;
547
+ }
548
+
549
+ throw error;
550
+ }
551
+
552
+ return count + 1;
553
+ }, Promise.resolve(0));
554
+
555
+ return createdNotifications > 0;
556
+ }
557
+
558
+ private async createNotifications(
559
+ input: CreateNotificationInput,
560
+ manager?: EntityManager,
561
+ ): Promise<readonly NotificationEntity[]> {
562
+ const preference = await this.getPreference(input.recipientMemberId);
563
+ const repository = manager
564
+ ? manager.getRepository(NotificationEntity)
565
+ : this.notificationRepository;
566
+ const notifications = input.channels.flatMap((channel) =>
567
+ isChannelEnabled(channel, preference, this.notificationOptions)
568
+ ? [
569
+ createNotificationEntity({
570
+ channel,
571
+ input,
572
+ options: this.notificationOptions,
573
+ repository,
574
+ }),
575
+ ]
576
+ : [],
577
+ );
578
+
579
+ if (notifications.length === 0) {
580
+ return [];
581
+ }
582
+
583
+ const savedNotifications = await repository.save(notifications);
584
+
585
+ await Promise.all(
586
+ savedNotifications
587
+ .filter(
588
+ (notification) =>
589
+ notification.channel !== NotificationChannelEnum.IN_APP,
590
+ )
591
+ .map((notification) =>
592
+ manager
593
+ ? Promise.resolve(false)
594
+ : this.deliveryService.deliverNotification(
595
+ notification,
596
+ this.notificationOptions,
597
+ ),
598
+ ),
599
+ );
600
+
601
+ return savedNotifications;
602
+ }
603
+
604
+ private async recordSlaActivity({
605
+ instance,
606
+ node,
607
+ task,
608
+ trigger,
609
+ }: {
610
+ readonly instance: ApprovalInstanceEntity;
611
+ readonly node: UserTaskNode;
612
+ readonly task: TaskEntity;
613
+ readonly trigger: 'OVERDUE' | 'WARNING';
614
+ }): Promise<void> {
615
+ await this.activityLogRepository.save(
616
+ this.activityLogRepository.create({
617
+ actorMemberId: null,
618
+ eventType: ActivityLogEventTypeEnum.SLA_TRIGGERED,
619
+ instanceId: instance.id,
620
+ nodeId: task.nodeId,
621
+ payload: {
622
+ assigneeMemberId: task.assigneeMemberId,
623
+ nodeLabel: node.data.label,
624
+ onTimeout: node.data.sla?.onTimeout ?? 'REMIND',
625
+ slaDueAt: task.slaDueAt?.toISOString() ?? null,
626
+ trigger,
627
+ },
628
+ taskId: task.id,
629
+ }),
630
+ );
631
+ }
632
+
633
+ private async runSlaTimeoutHook({
634
+ instance,
635
+ node,
636
+ task,
637
+ }: {
638
+ readonly instance: ApprovalInstanceEntity;
639
+ readonly node: UserTaskNode;
640
+ readonly task: TaskEntity;
641
+ }): Promise<void> {
642
+ const timeoutAction = node.data.sla?.onTimeout ?? 'REMIND';
643
+
644
+ if (!isSlaTimeoutActionEnabled(timeoutAction, this.notificationOptions)) {
645
+ return;
646
+ }
647
+
648
+ await this.executeSlaTimeoutAction({
649
+ instance,
650
+ node,
651
+ task,
652
+ timeoutAction,
653
+ });
654
+ }
655
+
656
+ private async executeSlaTimeoutAction({
657
+ instance,
658
+ node,
659
+ task,
660
+ timeoutAction,
661
+ }: {
662
+ readonly instance: ApprovalInstanceEntity;
663
+ readonly node: UserTaskNode;
664
+ readonly task: TaskEntity;
665
+ readonly timeoutAction: NonNullable<
666
+ UserTaskNode['data']['sla']
667
+ >['onTimeout'];
668
+ }): Promise<void> {
669
+ if (timeoutAction === 'REMIND') {
670
+ this.logger.log(`SLA reminder processed for task ${task.id}`);
671
+
672
+ return;
673
+ }
674
+
675
+ const workflowEngine = this.moduleRef.get<BPMWorkflowEngineService>(
676
+ BPM_WORKFLOW_ENGINE_SERVICE,
677
+ { strict: false },
678
+ );
679
+
680
+ if (timeoutAction === 'AUTO_APPROVE') {
681
+ const actorMemberId = await this.resolveTaskActorMemberId(task);
682
+
683
+ await workflowEngine.decideTask({
684
+ action: TaskDecisionActionEnum.APPROVED,
685
+ comment: 'SLA timeout auto-approved this task.',
686
+ decidedByMemberId: actorMemberId,
687
+ taskId: task.id,
688
+ });
689
+
690
+ return;
691
+ }
692
+
693
+ if (timeoutAction === 'ESCALATE') {
694
+ const actorMemberId = await this.resolveTaskActorMemberId(task);
695
+ const targetMemberId = await this.resolveEscalationTargetMemberId({
696
+ actorMemberId,
697
+ node,
698
+ });
699
+
700
+ if (!targetMemberId || targetMemberId === actorMemberId) {
701
+ this.logger.warn(`SLA escalation skipped for task ${task.id}`);
702
+
703
+ return;
704
+ }
705
+
706
+ await workflowEngine.decideTask({
707
+ action: TaskDecisionActionEnum.TRANSFERRED,
708
+ comment: 'SLA timeout escalated this task.',
709
+ decidedByMemberId: actorMemberId,
710
+ taskId: task.id,
711
+ transferToMemberId: targetMemberId,
712
+ });
713
+
714
+ return;
715
+ }
716
+
717
+ await workflowEngine.cancelApprovalInstance({
718
+ cancelledByMemberId: instance.initiatorMemberId,
719
+ comment: 'SLA timeout terminated this instance.',
720
+ instanceId: instance.id,
721
+ });
722
+ }
723
+
724
+ private async resolveTaskActorMemberId(task: TaskEntity): Promise<string> {
725
+ if (task.assigneeMemberId) {
726
+ return task.assigneeMemberId;
727
+ }
728
+
729
+ const candidate = await this.taskCandidateRepository.findOne({
730
+ order: { createdAt: 'ASC' },
731
+ where: { taskId: task.id },
732
+ });
733
+
734
+ if (!candidate) {
735
+ throw new NotFoundException(`Task ${task.id} has no actor candidate`);
736
+ }
737
+
738
+ return candidate.memberId;
739
+ }
740
+
741
+ private async resolveTaskRecipientMemberIds(
742
+ task: TaskEntity,
743
+ ): Promise<readonly string[]> {
744
+ if (task.assigneeMemberId) {
745
+ return [task.assigneeMemberId];
746
+ }
747
+
748
+ const candidates = await this.taskCandidateRepository.find({
749
+ order: { createdAt: 'ASC' },
750
+ where: { taskId: task.id },
751
+ });
752
+
753
+ return uniqueStrings(
754
+ candidates
755
+ .filter(
756
+ (candidate) =>
757
+ candidate.status === TaskCandidateStatusEnum.PENDING ||
758
+ candidate.status === TaskCandidateStatusEnum.CLAIMED,
759
+ )
760
+ .map((candidate) => candidate.memberId),
761
+ );
762
+ }
763
+
764
+ private async resolveEscalationTargetMemberId({
765
+ actorMemberId,
766
+ node,
767
+ }: {
768
+ readonly actorMemberId: string;
769
+ readonly node: UserTaskNode;
770
+ }): Promise<string | null> {
771
+ const organizationService = this.moduleRef.get(OrganizationService, {
772
+ strict: false,
773
+ });
774
+ const levelsUp = Math.max(node.data.sla?.escalateLevelsUp ?? 1, 1);
775
+ let currentMemberId: string | null = actorMemberId;
776
+
777
+ for (let level = 0; level < levelsUp && currentMemberId; level += 1) {
778
+ currentMemberId =
779
+ await organizationService.resolveManagerMemberId(currentMemberId);
780
+ }
781
+
782
+ return currentMemberId;
783
+ }
784
+ }
785
+
786
+ export function calculateTaskSlaDueAt({
787
+ node,
788
+ now,
789
+ }: {
790
+ readonly node: UserTaskNode;
791
+ readonly now: Date;
792
+ }): Date | null {
793
+ const duration = node.data.sla?.duration;
794
+
795
+ if (!duration) {
796
+ return null;
797
+ }
798
+
799
+ const durationMs = parseIsoDurationToMilliseconds(duration);
800
+
801
+ return durationMs ? new Date(now.getTime() + durationMs) : null;
802
+ }
803
+
804
+ function createDefaultPreference(
805
+ memberId: string,
806
+ options: BPMResolvedNotificationOptions,
807
+ ): NotificationPreferenceEntity {
808
+ return Object.assign(new NotificationPreferenceEntity(), {
809
+ emailDigestMode: options.defaultEmailDigestMode,
810
+ emailEnabled: options.defaultEmailPreferenceEnabled,
811
+ inAppEnabled: options.defaultInAppPreferenceEnabled,
812
+ memberId,
813
+ quietHoursEnd: null,
814
+ quietHoursStart: null,
815
+ updatedAt: new Date(0),
816
+ });
817
+ }
818
+
819
+ function normalizeTimeInput(value: string | null): string | null {
820
+ const trimmedValue = value?.trim() ?? '';
821
+
822
+ return trimmedValue || null;
823
+ }
824
+
825
+ function readNodeNotificationChannels(
826
+ node: UserTaskNode,
827
+ options: BPMResolvedNotificationOptions,
828
+ ): readonly NotificationChannelEnum[] {
829
+ const configuredChannels = node.data.notification?.channels ?? [];
830
+ const channels = configuredChannels
831
+ .map((channel): NotificationChannelEnum | null =>
832
+ channel === 'EMAIL'
833
+ ? NotificationChannelEnum.EMAIL
834
+ : channel === 'WEBHOOK'
835
+ ? NotificationChannelEnum.WEBHOOK
836
+ : channel === 'IN_APP'
837
+ ? NotificationChannelEnum.IN_APP
838
+ : null,
839
+ )
840
+ .filter((channel): channel is NotificationChannelEnum => Boolean(channel));
841
+
842
+ return channels.length ? channels : options.defaultChannels;
843
+ }
844
+
845
+ function normalizeNotificationChannels(
846
+ channels: readonly string[],
847
+ ): readonly NotificationChannelEnum[] {
848
+ const normalizedChannels = channels
849
+ .map((channel): NotificationChannelEnum | null =>
850
+ channel === NotificationChannelEnum.EMAIL
851
+ ? NotificationChannelEnum.EMAIL
852
+ : channel === NotificationChannelEnum.IN_APP
853
+ ? NotificationChannelEnum.IN_APP
854
+ : null,
855
+ )
856
+ .filter((channel): channel is NotificationChannelEnum => Boolean(channel));
857
+
858
+ return normalizedChannels.length
859
+ ? normalizedChannels
860
+ : [NotificationChannelEnum.IN_APP];
861
+ }
862
+
863
+ function uniqueStrings(values: readonly string[]): readonly string[] {
864
+ return Array.from(new Set(values));
865
+ }
866
+
867
+ function isUniqueConstraintViolation(error: unknown): boolean {
868
+ return (
869
+ typeof error === 'object' &&
870
+ error !== null &&
871
+ 'code' in error &&
872
+ error.code === '23505'
873
+ );
874
+ }
875
+
876
+ function isChannelEnabled(
877
+ channel: NotificationChannelEnum,
878
+ preference: NotificationPreferenceEntity,
879
+ options: BPMResolvedNotificationOptions,
880
+ ): boolean {
881
+ if (channel === NotificationChannelEnum.IN_APP) {
882
+ return options.inAppEnabled && preference.inAppEnabled;
883
+ }
884
+
885
+ if (channel === NotificationChannelEnum.EMAIL) {
886
+ return options.emailEnabled && preference.emailEnabled;
887
+ }
888
+
889
+ return options.webhookEnabled;
890
+ }
891
+
892
+ function isSlaTimeoutActionEnabled(
893
+ action: NonNullable<UserTaskNode['data']['sla']>['onTimeout'],
894
+ options: BPMResolvedNotificationOptions,
895
+ ): boolean {
896
+ if (action === 'AUTO_APPROVE') {
897
+ return options.slaTimeoutAutoApproveEnabled;
898
+ }
899
+
900
+ if (action === 'ESCALATE') {
901
+ return options.slaTimeoutEscalateEnabled;
902
+ }
903
+
904
+ if (action === 'TERMINATE_INSTANCE') {
905
+ return options.slaTimeoutTerminateInstanceEnabled;
906
+ }
907
+
908
+ return options.slaTimeoutRemindEnabled;
909
+ }
910
+
911
+ function createNotificationEntity({
912
+ channel,
913
+ input,
914
+ options,
915
+ repository,
916
+ }: {
917
+ readonly channel: NotificationChannelEnum;
918
+ readonly input: CreateNotificationInput;
919
+ readonly options: BPMResolvedNotificationOptions;
920
+ readonly repository: Repository<NotificationEntity>;
921
+ }): NotificationEntity {
922
+ const renderedTemplate = renderNotificationTemplate({
923
+ customTemplate: input.customTemplate,
924
+ engine: options.templateEngine,
925
+ payload: input.payload,
926
+ type: input.type,
927
+ });
928
+ const isInApp = channel === NotificationChannelEnum.IN_APP;
929
+
930
+ return repository.create({
931
+ attemptCount: 0,
932
+ body: renderedTemplate.body,
933
+ channel,
934
+ deliveredAt: isInApp ? new Date() : null,
935
+ deliveryError: null,
936
+ deliveryTarget: null,
937
+ instanceId: input.instanceId,
938
+ lastAttemptAt: null,
939
+ nextRetryAt: null,
940
+ payload: input.payload,
941
+ readAt: null,
942
+ recipientMemberId: input.recipientMemberId,
943
+ sentAt: isInApp ? new Date() : null,
944
+ status: isInApp
945
+ ? NotificationStatusEnum.SENT
946
+ : NotificationStatusEnum.PENDING,
947
+ taskId: input.taskId,
948
+ title: renderedTemplate.title,
949
+ type: input.type,
950
+ });
951
+ }
952
+
953
+ function readUserTaskNode(
954
+ instance: ApprovalInstanceEntity,
955
+ nodeId: string,
956
+ ): UserTaskNode | null {
957
+ const node = instance.workflowSnapshot.nodes.find(
958
+ (candidate) => candidate.id === nodeId,
959
+ );
960
+
961
+ return node?.type === 'userTask' ? node : null;
962
+ }
963
+
964
+ function normalizePage(page: number): number {
965
+ return Number.isInteger(page) && page > 0 ? page : 1;
966
+ }
967
+
968
+ function normalizePageSize(pageSize: number): number {
969
+ if (!Number.isInteger(pageSize)) {
970
+ return 10;
971
+ }
972
+
973
+ return Math.min(Math.max(pageSize, 1), 100);
974
+ }