@flowdular/sdk 0.2.4 → 0.3.1

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 (930) hide show
  1. package/.ai/agents/sandbox/business-manager.md +5 -1
  2. package/.ai/blueprints/author-spec/README.md +1 -1
  3. package/.ai/blueprints/author-spec/spec-requirements.yaml +44 -0
  4. package/.ai/blueprints/author-spec/steps.yaml +5 -5
  5. package/.ai/blueprints/author-spec/templates/module.yaml +99 -3
  6. package/.ai/blueprints/edit-module/gates.yaml +4 -0
  7. package/.ai/blueprints/edit-module/required-files.yaml +9 -0
  8. package/.ai/blueprints/new-module/gates.yaml +4 -0
  9. package/.ai/blueprints/new-module/spec-requirements.yaml +2 -2
  10. package/.ai/blueprints/release/gates.yaml +4 -0
  11. package/.ai/platform-capabilities.md +128 -0
  12. package/.ai/policies/capabilities.yaml +130 -3
  13. package/.ai/policies/path-ownership.yaml +5 -2
  14. package/.ai/policies/task-budgets.yaml +5 -3
  15. package/.ai/references/catalog/module.json +4 -4
  16. package/.ai/references/catalog/package.json +2 -2
  17. package/.ai/references/catalog/spec/module.yaml +5 -3
  18. package/.ai/references/catalog/src/platform.ts +2 -0
  19. package/.ai/references/catalog/src/services/catalog-service.ts +89 -1
  20. package/.ai/references/catalog/src/services/data-classes.ts +47 -0
  21. package/.ai/references/catalog/src/services/database-repository.ts +98 -1
  22. package/.ai/references/catalog/src/services/repository.ts +22 -1
  23. package/.ai/references/catalog/tests/data-classes.test.ts +157 -0
  24. package/.ai/references/catalog.provenance.json +12 -10
  25. package/.ai/skills/README.md +10 -0
  26. package/.ai/skills/agent-tool-design/SKILL.md +1 -2
  27. package/.ai/skills/auth-security-review/SKILL.md +1 -1
  28. package/.ai/skills/business-agent-design/SKILL.md +0 -1
  29. package/.ai/skills/cli-extension/SKILL.md +1 -1
  30. package/.ai/skills/deploy-operate/SKILL.md +119 -0
  31. package/.ai/skills/module-new/SKILL.md +29 -3
  32. package/.ai/skills/module-update/SKILL.md +9 -3
  33. package/.ai/skills/perf-audit/SKILL.md +0 -1
  34. package/.ai/skills/release-eject-pr/SKILL.md +0 -1
  35. package/.ai/skills/spec-interview/SKILL.md +120 -0
  36. package/.ai/skills/test-hardening/SKILL.md +1 -0
  37. package/.ai/skills/ux-design/SKILL.md +34 -3
  38. package/.ai/skills/variables/SKILL.md +0 -2
  39. package/.ai/skills/workflow-development/SKILL.md +0 -1
  40. package/AGENTS.md +4 -0
  41. package/docs/agent-contract.md +2 -2
  42. package/docs/design-system.md +185 -31
  43. package/modules/access/migrations/0001_access_core.down.sql +1 -0
  44. package/modules/access/migrations/0001_access_core.up.sql +28 -0
  45. package/modules/access/migrations/README.md +3 -0
  46. package/modules/access/module.json +33 -0
  47. package/modules/access/package.json +43 -0
  48. package/modules/access/spec/module.yaml +225 -0
  49. package/modules/access/src/acl/permissions.ts +6 -0
  50. package/modules/access/src/api/endpoints.ts +244 -0
  51. package/modules/access/src/client/ActivityView.tsrx +245 -0
  52. package/modules/access/src/client/AttestationsView.tsrx +176 -0
  53. package/modules/access/src/client/ReviewView.tsrx +586 -0
  54. package/modules/access/src/client/api.ts +132 -0
  55. package/modules/access/src/client/contribution.tsrx +41 -0
  56. package/modules/access/src/client/index.ts +41 -0
  57. package/modules/access/src/client/navigation.ts +57 -0
  58. package/modules/access/src/client/presentation.ts +69 -0
  59. package/modules/access/src/client/state.ts +72 -0
  60. package/modules/access/src/domain/types.ts +189 -0
  61. package/modules/access/src/index.ts +38 -0
  62. package/modules/access/src/platform.ts +60 -0
  63. package/modules/access/src/server/index.ts +42 -0
  64. package/modules/access/src/server/runtime.ts +105 -0
  65. package/modules/access/src/services/access-service.ts +298 -0
  66. package/modules/access/src/services/audit-window.ts +78 -0
  67. package/modules/access/src/services/auth-directory.ts +72 -0
  68. package/modules/access/src/services/changes.ts +91 -0
  69. package/modules/access/src/services/data-classes.ts +28 -0
  70. package/modules/access/src/services/database-repository.ts +185 -0
  71. package/modules/access/src/services/directory.ts +102 -0
  72. package/modules/access/src/services/index.ts +33 -0
  73. package/modules/access/src/services/list-exports.ts +150 -0
  74. package/modules/access/src/services/migration.ts +54 -0
  75. package/modules/access/src/services/repository.ts +30 -0
  76. package/modules/access/src/services/review.ts +178 -0
  77. package/modules/access/translations/en.json +155 -0
  78. package/modules/access/translations/pl.json +155 -0
  79. package/modules/agents/migrations/0022_credential_rotation_inventory.down.sql +2 -0
  80. package/modules/agents/migrations/0022_credential_rotation_inventory.up.sql +7 -0
  81. package/modules/agents/migrations/0023_agents_retention_indexes.down.sql +2 -0
  82. package/modules/agents/migrations/0023_agents_retention_indexes.up.sql +9 -0
  83. package/modules/agents/migrations/0024_agent_meter_refusals.down.sql +3 -0
  84. package/modules/agents/migrations/0024_agent_meter_refusals.up.sql +22 -0
  85. package/modules/agents/migrations/0025_agent_list_indexes.down.sql +3 -0
  86. package/modules/agents/migrations/0025_agent_list_indexes.up.sql +11 -0
  87. package/modules/agents/module.json +30 -4
  88. package/modules/agents/package.json +2 -1
  89. package/modules/agents/spec/module.yaml +63 -5
  90. package/modules/agents/src/api/endpoints.ts +291 -33
  91. package/modules/agents/src/cli/commands.json +11 -0
  92. package/modules/agents/src/cli/index.ts +45 -0
  93. package/modules/agents/src/client/AgentDashboardWidget.tsrx +19 -11
  94. package/modules/agents/src/client/AgentDefinitionList.tsrx +53 -10
  95. package/modules/agents/src/client/AgentPlaygroundView.tsrx +4 -4
  96. package/modules/agents/src/client/AgentProceduresView.tsrx +2 -2
  97. package/modules/agents/src/client/AgentRunsView.tsrx +143 -40
  98. package/modules/agents/src/client/AgentsView.tsrx +109 -33
  99. package/modules/agents/src/client/api.ts +99 -21
  100. package/modules/agents/src/client/state.ts +97 -0
  101. package/modules/agents/src/domain/types.ts +44 -4
  102. package/modules/agents/src/platform.ts +42 -0
  103. package/modules/agents/src/server/action-execution.ts +201 -106
  104. package/modules/agents/src/server/runtime.ts +32 -0
  105. package/modules/agents/src/services/agent-service.ts +158 -30
  106. package/modules/agents/src/services/credential-rotation.ts +185 -0
  107. package/modules/agents/src/services/credential-vault.ts +71 -46
  108. package/modules/agents/src/services/data-classes.ts +176 -0
  109. package/modules/agents/src/services/database-repository.ts +393 -101
  110. package/modules/agents/src/services/metering.ts +111 -0
  111. package/modules/agents/src/services/migration.ts +109 -0
  112. package/modules/agents/src/services/module-agent-preflight.ts +17 -9
  113. package/modules/agents/src/services/notifications.ts +98 -0
  114. package/modules/agents/src/services/provider-repository.ts +9 -18
  115. package/modules/agents/src/services/provider-service.ts +1 -9
  116. package/modules/agents/src/services/reports.ts +107 -0
  117. package/modules/agents/src/services/repository.ts +86 -6
  118. package/modules/agents/src/services/usage-service.ts +2 -0
  119. package/modules/agents/src/services/worker.ts +114 -4
  120. package/modules/agents/src/settings.ts +14 -3
  121. package/modules/agents/translations/en.json +14 -4
  122. package/modules/agents/translations/pl.json +14 -4
  123. package/modules/approvals/migrations/0001_approvals_core.down.sql +3 -0
  124. package/modules/approvals/migrations/0001_approvals_core.up.sql +78 -0
  125. package/modules/approvals/migrations/0002_approvals_expiry_routing_role.down.sql +2 -0
  126. package/modules/approvals/migrations/0002_approvals_expiry_routing_role.up.sql +19 -0
  127. package/modules/approvals/migrations/0003_approvals_retention_indexes.down.sql +6 -0
  128. package/modules/approvals/migrations/0003_approvals_retention_indexes.up.sql +14 -0
  129. package/modules/approvals/migrations/0004_approvals_inbox_keyset_indexes.down.sql +5 -0
  130. package/modules/approvals/migrations/0004_approvals_inbox_keyset_indexes.up.sql +12 -0
  131. package/modules/approvals/migrations/0005_approvals_grant_audit.down.sql +4 -0
  132. package/modules/approvals/migrations/0005_approvals_grant_audit.up.sql +20 -0
  133. package/modules/approvals/migrations/README.md +3 -0
  134. package/modules/approvals/module.json +34 -0
  135. package/modules/approvals/package.json +43 -0
  136. package/modules/approvals/spec/module.yaml +327 -0
  137. package/modules/approvals/src/acl/permissions.ts +7 -0
  138. package/modules/approvals/src/api/endpoints.ts +457 -0
  139. package/modules/approvals/src/client/ApprovalRequestDrawer.tsrx +138 -0
  140. package/modules/approvals/src/client/ApprovalsView.tsrx +562 -0
  141. package/modules/approvals/src/client/PendingCountWidget.tsrx +52 -0
  142. package/modules/approvals/src/client/api.ts +203 -0
  143. package/modules/approvals/src/client/approvals.css +51 -0
  144. package/modules/approvals/src/client/contribution.tsrx +44 -0
  145. package/modules/approvals/src/client/index.ts +26 -0
  146. package/modules/approvals/src/client/navigation.ts +39 -0
  147. package/modules/approvals/src/client/pending-count.ts +26 -0
  148. package/modules/approvals/src/client/presentation.ts +52 -0
  149. package/modules/approvals/src/client/state.ts +141 -0
  150. package/modules/approvals/src/domain/capability.ts +107 -0
  151. package/modules/approvals/src/domain/grant.ts +69 -0
  152. package/modules/approvals/src/domain/types.ts +168 -0
  153. package/modules/approvals/src/index.ts +61 -0
  154. package/modules/approvals/src/platform.ts +136 -0
  155. package/modules/approvals/src/server/index.ts +42 -0
  156. package/modules/approvals/src/server/runtime.ts +185 -0
  157. package/modules/approvals/src/services/approvals-service.ts +637 -0
  158. package/modules/approvals/src/services/callbacks.ts +75 -0
  159. package/modules/approvals/src/services/data-classes.ts +167 -0
  160. package/modules/approvals/src/services/database-repository.ts +783 -0
  161. package/modules/approvals/src/services/eligibility.ts +121 -0
  162. package/modules/approvals/src/services/expiry-runner.ts +81 -0
  163. package/modules/approvals/src/services/index.ts +31 -0
  164. package/modules/approvals/src/services/migration.ts +256 -0
  165. package/modules/approvals/src/services/notifications.ts +95 -0
  166. package/modules/approvals/src/services/repository.ts +169 -0
  167. package/modules/approvals/src/services/service-error.ts +70 -0
  168. package/modules/approvals/src/settings.ts +102 -0
  169. package/modules/approvals/translations/en.json +104 -0
  170. package/modules/approvals/translations/pl.json +104 -0
  171. package/modules/audit/migrations/0001_audit_core.down.sql +8 -0
  172. package/modules/audit/migrations/0001_audit_core.up.sql +107 -0
  173. package/modules/audit/migrations/0002_audit_sweep_routing_role.down.sql +2 -0
  174. package/modules/audit/migrations/0002_audit_sweep_routing_role.up.sql +21 -0
  175. package/modules/audit/migrations/0003_audit_export_request.down.sql +12 -0
  176. package/modules/audit/migrations/0003_audit_export_request.up.sql +40 -0
  177. package/modules/audit/migrations/0004_audit_hold_seal_erasure.down.sql +17 -0
  178. package/modules/audit/migrations/0004_audit_hold_seal_erasure.up.sql +192 -0
  179. package/modules/audit/migrations/0005_audit_event_format.down.sql +17 -0
  180. package/modules/audit/migrations/0005_audit_event_format.up.sql +60 -0
  181. package/modules/audit/migrations/0006_audit_own_class_walks.down.sql +3 -0
  182. package/modules/audit/migrations/0006_audit_own_class_walks.up.sql +14 -0
  183. package/modules/audit/migrations/README.md +3 -0
  184. package/modules/audit/module.json +32 -0
  185. package/modules/audit/package.json +49 -0
  186. package/modules/audit/spec/module.yaml +809 -0
  187. package/modules/audit/src/acl/permissions.ts +7 -0
  188. package/modules/audit/src/api/endpoints.ts +315 -0
  189. package/modules/audit/src/cli/commands.json +95 -0
  190. package/modules/audit/src/cli/index.ts +658 -0
  191. package/modules/audit/src/client/DataClassesView.tsrx +420 -0
  192. package/modules/audit/src/client/ExportsView.tsrx +256 -0
  193. package/modules/audit/src/client/HoldsView.tsrx +604 -0
  194. package/modules/audit/src/client/SweepsView.tsrx +251 -0
  195. package/modules/audit/src/client/api.ts +185 -0
  196. package/modules/audit/src/client/contribution.tsrx +52 -0
  197. package/modules/audit/src/client/index.ts +23 -0
  198. package/modules/audit/src/client/navigation.ts +74 -0
  199. package/modules/audit/src/client/presentation.ts +105 -0
  200. package/modules/audit/src/client/state.ts +86 -0
  201. package/modules/audit/src/domain/data-classes.ts +16 -0
  202. package/modules/audit/src/domain/types.ts +339 -0
  203. package/modules/audit/src/index.ts +76 -0
  204. package/modules/audit/src/platform.ts +44 -0
  205. package/modules/audit/src/server/index.ts +177 -0
  206. package/modules/audit/src/server/runtime.ts +303 -0
  207. package/modules/audit/src/services/anchor-key.ts +143 -0
  208. package/modules/audit/src/services/anchor-rotation.ts +147 -0
  209. package/modules/audit/src/services/audit-runners.ts +278 -0
  210. package/modules/audit/src/services/backup-guard.ts +95 -0
  211. package/modules/audit/src/services/database-repository.ts +1946 -0
  212. package/modules/audit/src/services/declared-classes.ts +64 -0
  213. package/modules/audit/src/services/erasure-port.ts +126 -0
  214. package/modules/audit/src/services/erasure-service.ts +770 -0
  215. package/modules/audit/src/services/export-directory.ts +106 -0
  216. package/modules/audit/src/services/export-service.ts +714 -0
  217. package/modules/audit/src/services/hold-service.ts +295 -0
  218. package/modules/audit/src/services/index.ts +17 -0
  219. package/modules/audit/src/services/migration.ts +658 -0
  220. package/modules/audit/src/services/own-classes.ts +318 -0
  221. package/modules/audit/src/services/platform-version.ts +23 -0
  222. package/modules/audit/src/services/repository.ts +495 -0
  223. package/modules/audit/src/services/retention-service.ts +191 -0
  224. package/modules/audit/src/services/seal-service.ts +769 -0
  225. package/modules/audit/src/services/service-error.ts +61 -0
  226. package/modules/audit/src/services/subject-keys.ts +90 -0
  227. package/modules/audit/src/services/sweep-service.ts +298 -0
  228. package/modules/audit/src/services/zip.ts +217 -0
  229. package/modules/audit/src/settings.ts +69 -0
  230. package/modules/audit/translations/en.json +210 -0
  231. package/modules/audit/translations/pl.json +210 -0
  232. package/modules/auth/README.md +77 -29
  233. package/modules/auth/migrations/0016_external_identities.up.sql +16 -0
  234. package/modules/auth/migrations/0017_mfa_key_id.up.sql +8 -0
  235. package/modules/auth/migrations/0018_retire_bundled_module_scopes.up.sql +29 -0
  236. package/modules/auth/migrations/0019_notifications_member_scopes.up.sql +44 -0
  237. package/modules/auth/migrations/0020_identity_providers.up.sql +61 -0
  238. package/modules/auth/migrations/0021_membership_status.up.sql +19 -0
  239. package/modules/auth/migrations/0022_auth_provider_scopes.up.sql +45 -0
  240. package/modules/auth/migrations/0023_enterprise_module_scopes.down.sql +19 -0
  241. package/modules/auth/migrations/0023_enterprise_module_scopes.up.sql +71 -0
  242. package/modules/auth/migrations/0024_approvals_member_scopes.down.sql +22 -0
  243. package/modules/auth/migrations/0024_approvals_member_scopes.up.sql +48 -0
  244. package/modules/auth/migrations/0025_audit_holds_owner_scope.down.sql +21 -0
  245. package/modules/auth/migrations/0025_audit_holds_owner_scope.up.sql +47 -0
  246. package/modules/auth/migrations/0026_auth_export_keyset_indexes.down.sql +6 -0
  247. package/modules/auth/migrations/0026_auth_export_keyset_indexes.up.sql +15 -0
  248. package/modules/auth/migrations/0027_workflow_automation_profile_scopes.down.sql +34 -0
  249. package/modules/auth/migrations/0027_workflow_automation_profile_scopes.up.sql +72 -0
  250. package/modules/auth/migrations/0028_auth_member_search_prefix_indexes.down.sql +6 -0
  251. package/modules/auth/migrations/0028_auth_member_search_prefix_indexes.up.sql +21 -0
  252. package/modules/auth/migrations/0029_reports_exports_access_scopes.down.sql +22 -0
  253. package/modules/auth/migrations/0029_reports_exports_access_scopes.up.sql +56 -0
  254. package/modules/auth/migrations/0030_auth_membership_keyset_index.down.sql +4 -0
  255. package/modules/auth/migrations/0030_auth_membership_keyset_index.up.sql +10 -0
  256. package/modules/auth/migrations/0031_membership_scope_backfills_under_rls.down.sql +4 -0
  257. package/modules/auth/migrations/0031_membership_scope_backfills_under_rls.up.sql +31 -0
  258. package/modules/auth/migrations/0032_audit_actor_service.down.sql +9 -0
  259. package/modules/auth/migrations/0032_audit_actor_service.up.sql +10 -0
  260. package/modules/auth/migrations/0033_auth_account_keyset_indexes.down.sql +5 -0
  261. package/modules/auth/migrations/0033_auth_account_keyset_indexes.up.sql +23 -0
  262. package/modules/auth/module.json +3 -3
  263. package/modules/auth/package.json +2 -1
  264. package/modules/auth/spec/module.yaml +372 -3
  265. package/modules/auth/src/acl/scopes.ts +50 -6
  266. package/modules/auth/src/cli/commands.json +11 -0
  267. package/modules/auth/src/cli/greenfield.ts +2 -2
  268. package/modules/auth/src/cli/index.ts +14 -0
  269. package/modules/auth/src/cli/secrets.ts +114 -0
  270. package/modules/auth/src/client/AuthenticationCore.tsrx +61 -8
  271. package/modules/auth/src/client/api.ts +72 -6
  272. package/modules/auth/src/client/contribution.tsrx +23 -0
  273. package/modules/auth/src/client/index.ts +6 -0
  274. package/modules/auth/src/client/providers/IdentityProviderForm.tsrx +191 -0
  275. package/modules/auth/src/client/providers/IdentityProvidersView.tsrx +358 -0
  276. package/modules/auth/src/client/providers/api.ts +128 -0
  277. package/modules/auth/src/client/providers/provider-columns.tsrx +60 -0
  278. package/modules/auth/src/client/providers/state.ts +35 -0
  279. package/modules/auth/src/client/security/SecurityView.tsrx +9 -1
  280. package/modules/auth/src/client/state.ts +15 -1
  281. package/modules/auth/src/domain/types.ts +55 -0
  282. package/modules/auth/src/index.ts +11 -1
  283. package/modules/auth/src/middleware/authentication.ts +4 -0
  284. package/modules/auth/src/server/endpoints.ts +467 -171
  285. package/modules/auth/src/server/http.ts +3 -2
  286. package/modules/auth/src/server/index.ts +22 -1
  287. package/modules/auth/src/server/membership-endpoints.ts +62 -0
  288. package/modules/auth/src/server/mfa-enforcement.ts +156 -0
  289. package/modules/auth/src/server/oidc.ts +389 -0
  290. package/modules/auth/src/server/provider-endpoints.ts +246 -0
  291. package/modules/auth/src/server/provider-host.ts +77 -0
  292. package/modules/auth/src/server/runtime.ts +231 -55
  293. package/modules/auth/src/services/auth-service-error.ts +7 -2
  294. package/modules/auth/src/services/auth-service.ts +948 -51
  295. package/modules/auth/src/services/data-classes.ts +236 -0
  296. package/modules/auth/src/services/database-repository.ts +853 -71
  297. package/modules/auth/src/services/identity-provider-service.ts +571 -0
  298. package/modules/auth/src/services/mail-delivery.ts +16 -16
  299. package/modules/auth/src/services/mail-message.ts +54 -0
  300. package/modules/auth/src/services/mail-port.ts +24 -0
  301. package/modules/auth/src/services/mail-smtp.ts +85 -0
  302. package/modules/auth/src/services/mfa-rotation.ts +144 -0
  303. package/modules/auth/src/services/migration.ts +810 -0
  304. package/modules/auth/src/services/password.ts +14 -0
  305. package/modules/auth/src/services/provider-secret-rotation.ts +169 -0
  306. package/modules/auth/src/services/provider-secrets.ts +136 -0
  307. package/modules/auth/src/services/repository.ts +321 -5
  308. package/modules/auth/src/services/session-sweep-runner.ts +73 -0
  309. package/modules/auth/src/services/settings-store.ts +10 -83
  310. package/modules/auth/src/services/totp.ts +88 -62
  311. package/modules/auth/src/services/validation.ts +194 -7
  312. package/modules/auth/src/settings.ts +18 -0
  313. package/modules/auth/translations/en.json +84 -1
  314. package/modules/auth/translations/pl.json +84 -1
  315. package/modules/automations/migrations/0005_secret_rotation_inventory.down.sql +1 -0
  316. package/modules/automations/migrations/0005_secret_rotation_inventory.up.sql +6 -0
  317. package/modules/automations/migrations/0006_automations_list_sort_indexes.down.sql +4 -0
  318. package/modules/automations/migrations/0006_automations_list_sort_indexes.up.sql +11 -0
  319. package/modules/automations/module.json +24 -6
  320. package/modules/automations/package.json +4 -1
  321. package/modules/automations/spec/module.yaml +81 -7
  322. package/modules/automations/src/api/endpoints.ts +202 -28
  323. package/modules/automations/src/cli/commands.json +17 -0
  324. package/modules/automations/src/cli/index.ts +114 -0
  325. package/modules/automations/src/client/AutomationScheduleForm.tsrx +77 -19
  326. package/modules/automations/src/client/AutomationSchedulesView.tsrx +144 -40
  327. package/modules/automations/src/client/AutomationTriggersView.tsrx +131 -32
  328. package/modules/automations/src/client/api.ts +62 -19
  329. package/modules/automations/src/client/presentation.ts +20 -2
  330. package/modules/automations/src/client/state.ts +84 -0
  331. package/modules/automations/src/domain/cadence.ts +99 -3
  332. package/modules/automations/src/domain/cron.ts +366 -0
  333. package/modules/automations/src/domain/time-zone.ts +61 -0
  334. package/modules/automations/src/platform.ts +38 -4
  335. package/modules/automations/src/server/index.ts +11 -0
  336. package/modules/automations/src/server/runtime.ts +46 -22
  337. package/modules/{automations-workflows-integration/src/server/adapter.ts → automations/src/server/workflow-target.ts} +13 -14
  338. package/modules/{automations-workflows-integration/src/server/tools.ts → automations/src/server/workflow-tools.ts} +0 -0
  339. package/modules/automations/src/services/data-classes.ts +62 -0
  340. package/modules/automations/src/services/database-repository.ts +152 -38
  341. package/modules/automations/src/services/migration.ts +119 -9
  342. package/modules/automations/src/services/repository.ts +52 -1
  343. package/modules/automations/src/services/schedule-runner.ts +84 -0
  344. package/modules/automations/src/services/schedule-service.ts +152 -26
  345. package/modules/automations/src/services/secret-rotation.ts +176 -0
  346. package/modules/automations/src/services/secret-vault.ts +68 -41
  347. package/modules/automations/src/services/trigger-service.ts +13 -10
  348. package/modules/automations/translations/en.json +15 -2
  349. package/modules/automations/translations/pl.json +15 -2
  350. package/modules/connectors/migrations/0001_connectors_core.down.sql +3 -0
  351. package/modules/connectors/migrations/0001_connectors_core.up.sql +72 -0
  352. package/modules/connectors/migrations/0002_connectors_call_keys.down.sql +3 -0
  353. package/modules/connectors/migrations/0002_connectors_call_keys.up.sql +18 -0
  354. package/modules/connectors/migrations/0003_connectors_rotation_inventory.down.sql +2 -0
  355. package/modules/connectors/migrations/0003_connectors_rotation_inventory.up.sql +19 -0
  356. package/modules/connectors/migrations/README.md +3 -0
  357. package/modules/connectors/module.json +32 -0
  358. package/modules/{automations-workflows-integration → connectors}/package.json +28 -26
  359. package/modules/connectors/spec/module.yaml +448 -0
  360. package/modules/connectors/src/acl/permissions.ts +6 -0
  361. package/modules/connectors/src/agent/tools.ts +180 -0
  362. package/modules/connectors/src/api/endpoints.ts +572 -0
  363. package/modules/connectors/src/cli/commands.json +17 -0
  364. package/modules/connectors/src/cli/index.ts +126 -0
  365. package/modules/connectors/src/client/ConnectorCallsView.tsrx +358 -0
  366. package/modules/connectors/src/client/ConnectorForm.tsrx +424 -0
  367. package/modules/connectors/src/client/ConnectorsView.tsrx +711 -0
  368. package/modules/connectors/src/client/api.ts +281 -0
  369. package/modules/connectors/src/client/consent.ts +48 -0
  370. package/modules/connectors/src/client/contribution.tsrx +37 -0
  371. package/modules/connectors/src/client/index.ts +22 -0
  372. package/modules/connectors/src/client/navigation.ts +42 -0
  373. package/modules/connectors/src/client/presentation.ts +38 -0
  374. package/modules/connectors/src/client/state.ts +175 -0
  375. package/modules/connectors/src/domain/calls.ts +70 -0
  376. package/modules/connectors/src/domain/definitions.ts +190 -0
  377. package/modules/connectors/src/domain/http-json.ts +68 -0
  378. package/modules/connectors/src/domain/types.ts +185 -0
  379. package/modules/connectors/src/index.ts +64 -0
  380. package/modules/connectors/src/platform.ts +56 -0
  381. package/modules/connectors/src/server/index.ts +66 -0
  382. package/modules/connectors/src/server/runtime.ts +163 -0
  383. package/modules/connectors/src/services/call-service.ts +903 -0
  384. package/modules/connectors/src/services/connectors-service.ts +653 -0
  385. package/modules/connectors/src/services/credential-rotation.ts +221 -0
  386. package/modules/connectors/src/services/credential-vault.ts +194 -0
  387. package/modules/connectors/src/services/data-classes.ts +158 -0
  388. package/modules/connectors/src/services/database-repository.ts +897 -0
  389. package/modules/connectors/src/services/egress.ts +261 -0
  390. package/modules/connectors/src/services/index.ts +19 -0
  391. package/modules/connectors/src/services/migration.ts +202 -0
  392. package/modules/connectors/src/services/repository.ts +175 -0
  393. package/modules/connectors/src/services/service-error.ts +46 -0
  394. package/modules/connectors/src/settings.ts +69 -0
  395. package/modules/connectors/translations/en.json +191 -0
  396. package/modules/connectors/translations/pl.json +191 -0
  397. package/modules/directory/migrations/0001_directory_core.down.sql +5 -0
  398. package/modules/directory/migrations/0001_directory_core.up.sql +111 -0
  399. package/modules/directory/migrations/README.md +3 -0
  400. package/modules/directory/module.json +27 -0
  401. package/modules/directory/package.json +46 -0
  402. package/modules/directory/spec/module.yaml +351 -0
  403. package/modules/directory/src/acl/permissions.ts +7 -0
  404. package/modules/directory/src/api/endpoints.ts +478 -0
  405. package/modules/directory/src/api/scim-endpoints.ts +516 -0
  406. package/modules/directory/src/client/GroupMappingsView.tsrx +430 -0
  407. package/modules/directory/src/client/ProvisioningLogView.tsrx +248 -0
  408. package/modules/directory/src/client/ScimTokensView.tsrx +587 -0
  409. package/modules/directory/src/client/api.ts +222 -0
  410. package/modules/directory/src/client/contribution.tsrx +46 -0
  411. package/modules/directory/src/client/index.ts +22 -0
  412. package/modules/directory/src/client/navigation.ts +57 -0
  413. package/modules/directory/src/client/presentation.ts +143 -0
  414. package/modules/directory/src/client/state.ts +173 -0
  415. package/modules/directory/src/domain/scim.ts +346 -0
  416. package/modules/directory/src/domain/types.ts +166 -0
  417. package/modules/directory/src/index.ts +44 -0
  418. package/modules/directory/src/platform.ts +43 -0
  419. package/modules/directory/src/server/index.ts +17 -0
  420. package/modules/directory/src/server/runtime.ts +124 -0
  421. package/modules/directory/src/services/auth-port.ts +127 -0
  422. package/modules/directory/src/services/data-classes.ts +41 -0
  423. package/modules/directory/src/services/database-repository.ts +1067 -0
  424. package/modules/directory/src/services/directory-service.ts +311 -0
  425. package/modules/directory/src/services/index.ts +43 -0
  426. package/modules/directory/src/services/migration.ts +146 -0
  427. package/modules/directory/src/services/provisioning-service.ts +1420 -0
  428. package/modules/directory/src/services/rate-limiter.ts +103 -0
  429. package/modules/directory/src/services/repository.ts +208 -0
  430. package/modules/directory/src/services/service-error.ts +42 -0
  431. package/modules/directory/src/services/token-service.ts +215 -0
  432. package/modules/directory/src/settings.ts +86 -0
  433. package/modules/directory/translations/en.json +185 -0
  434. package/modules/directory/translations/pl.json +185 -0
  435. package/modules/documents/migrations/0001_documents_core.down.sql +1 -0
  436. package/modules/documents/migrations/0001_documents_core.up.sql +35 -0
  437. package/modules/documents/migrations/0002_documents_files_page.down.sql +1 -0
  438. package/modules/documents/migrations/0002_documents_files_page.up.sql +6 -0
  439. package/modules/documents/migrations/0003_documents_rotation_inventory.down.sql +2 -0
  440. package/modules/documents/migrations/0003_documents_rotation_inventory.up.sql +18 -0
  441. package/modules/documents/migrations/README.md +3 -0
  442. package/modules/documents/module.json +32 -0
  443. package/modules/documents/package.json +50 -0
  444. package/modules/documents/spec/module.yaml +248 -0
  445. package/modules/documents/src/acl/permissions.ts +6 -0
  446. package/modules/documents/src/api/endpoints.ts +401 -0
  447. package/modules/documents/src/cli/commands.json +17 -0
  448. package/modules/documents/src/cli/index.ts +145 -0
  449. package/modules/documents/src/client/DocumentUploader.tsrx +148 -0
  450. package/modules/documents/src/client/DocumentsView.tsrx +540 -0
  451. package/modules/documents/src/client/api.ts +209 -0
  452. package/modules/documents/src/client/contribution.tsrx +29 -0
  453. package/modules/documents/src/client/download.ts +70 -0
  454. package/modules/documents/src/client/index.ts +22 -0
  455. package/modules/documents/src/client/navigation.ts +25 -0
  456. package/modules/documents/src/client/presentation.ts +110 -0
  457. package/modules/documents/src/client/state.ts +117 -0
  458. package/modules/documents/src/domain/attachments.ts +84 -0
  459. package/modules/documents/src/domain/types.ts +80 -0
  460. package/modules/documents/src/index.ts +46 -0
  461. package/modules/documents/src/platform.ts +61 -0
  462. package/modules/documents/src/server/index.ts +30 -0
  463. package/modules/documents/src/server/runtime.ts +107 -0
  464. package/modules/documents/src/services/attachments.ts +39 -0
  465. package/modules/documents/src/services/data-classes.ts +25 -0
  466. package/modules/documents/src/services/database-repository.ts +270 -0
  467. package/modules/documents/src/services/documents-service.ts +590 -0
  468. package/modules/documents/src/services/index.ts +18 -0
  469. package/modules/documents/src/services/migration.ts +117 -0
  470. package/modules/documents/src/services/repository.ts +58 -0
  471. package/modules/documents/src/services/storage-rotation.ts +157 -0
  472. package/modules/documents/src/settings.ts +107 -0
  473. package/modules/documents/translations/en.json +111 -0
  474. package/modules/documents/translations/pl.json +111 -0
  475. package/modules/exports/migrations/0001_exports_core.down.sql +2 -0
  476. package/modules/exports/migrations/0001_exports_core.up.sql +28 -0
  477. package/modules/exports/migrations/0002_exports_job_routing_role.down.sql +4 -0
  478. package/modules/exports/migrations/0002_exports_job_routing_role.up.sql +21 -0
  479. package/modules/exports/migrations/0003_exports_rotation_inventory.down.sql +1 -0
  480. package/modules/exports/migrations/0003_exports_rotation_inventory.up.sql +9 -0
  481. package/modules/exports/migrations/README.md +3 -0
  482. package/modules/exports/module.json +32 -0
  483. package/modules/exports/package.json +45 -0
  484. package/modules/exports/spec/module.yaml +230 -0
  485. package/modules/exports/src/acl/permissions.ts +6 -0
  486. package/modules/exports/src/api/endpoints.ts +211 -0
  487. package/modules/exports/src/cli/commands.json +17 -0
  488. package/modules/exports/src/cli/index.ts +145 -0
  489. package/modules/exports/src/client/ExportsView.tsrx +327 -0
  490. package/modules/exports/src/client/api.ts +133 -0
  491. package/modules/exports/src/client/contribution.tsrx +31 -0
  492. package/modules/exports/src/client/index.ts +20 -0
  493. package/modules/exports/src/client/navigation.ts +25 -0
  494. package/modules/exports/src/client/presentation.ts +53 -0
  495. package/modules/exports/src/client/state.ts +56 -0
  496. package/modules/exports/src/domain/lists.ts +29 -0
  497. package/modules/exports/src/domain/types.ts +120 -0
  498. package/modules/exports/src/index.ts +41 -0
  499. package/modules/exports/src/platform.ts +80 -0
  500. package/modules/exports/src/server/index.ts +50 -0
  501. package/modules/exports/src/server/runtime.ts +160 -0
  502. package/modules/exports/src/services/data-classes.ts +59 -0
  503. package/modules/exports/src/services/database-repository.ts +403 -0
  504. package/modules/exports/src/services/export-runner.ts +123 -0
  505. package/modules/exports/src/services/export-service.ts +356 -0
  506. package/modules/exports/src/services/index.ts +6 -0
  507. package/modules/exports/src/services/list-registry.ts +105 -0
  508. package/modules/exports/src/services/migration.ts +116 -0
  509. package/modules/exports/src/services/repository.ts +96 -0
  510. package/modules/exports/src/services/storage-rotation.ts +138 -0
  511. package/modules/exports/src/settings.ts +70 -0
  512. package/modules/exports/translations/en.json +69 -0
  513. package/modules/exports/translations/pl.json +69 -0
  514. package/modules/import/migrations/0001_import_core.down.sql +6 -0
  515. package/modules/import/migrations/0001_import_core.up.sql +61 -0
  516. package/modules/import/migrations/0002_import_job_routing_role.down.sql +4 -0
  517. package/modules/import/migrations/0002_import_job_routing_role.up.sql +20 -0
  518. package/modules/import/migrations/0003_import_jobs_export_index.down.sql +1 -0
  519. package/modules/import/migrations/0003_import_jobs_export_index.up.sql +7 -0
  520. package/modules/import/migrations/0004_import_jobs_traceparent.down.sql +1 -0
  521. package/modules/import/migrations/0004_import_jobs_traceparent.up.sql +7 -0
  522. package/modules/import/migrations/README.md +3 -0
  523. package/modules/import/module.json +37 -0
  524. package/modules/import/package.json +50 -0
  525. package/modules/import/spec/module.yaml +335 -0
  526. package/modules/import/src/acl/permissions.ts +6 -0
  527. package/modules/import/src/api/endpoints.ts +400 -0
  528. package/modules/import/src/client/ImportJobDrawer.tsrx +229 -0
  529. package/modules/import/src/client/ImportsView.tsrx +455 -0
  530. package/modules/import/src/client/NewImportForm.tsrx +274 -0
  531. package/modules/import/src/client/api.ts +243 -0
  532. package/modules/import/src/client/contribution.tsrx +29 -0
  533. package/modules/import/src/client/index.ts +23 -0
  534. package/modules/import/src/client/navigation.ts +25 -0
  535. package/modules/import/src/client/presentation.ts +59 -0
  536. package/modules/import/src/client/state.ts +43 -0
  537. package/modules/import/src/domain/csv.ts +258 -0
  538. package/modules/import/src/domain/ports.ts +157 -0
  539. package/modules/import/src/domain/types.ts +179 -0
  540. package/modules/import/src/index.ts +58 -0
  541. package/modules/import/src/platform.ts +60 -0
  542. package/modules/import/src/server/index.ts +49 -0
  543. package/modules/import/src/server/runtime.ts +158 -0
  544. package/modules/import/src/services/csv-source.ts +121 -0
  545. package/modules/import/src/services/data-classes.ts +63 -0
  546. package/modules/import/src/services/database-repository.ts +780 -0
  547. package/modules/import/src/services/import-runner.ts +127 -0
  548. package/modules/import/src/services/import-service.ts +872 -0
  549. package/modules/import/src/services/index.ts +6 -0
  550. package/modules/import/src/services/migration.ts +156 -0
  551. package/modules/import/src/services/port-registry.ts +158 -0
  552. package/modules/import/src/services/repository.ts +147 -0
  553. package/modules/import/src/settings.ts +70 -0
  554. package/modules/import/translations/en.json +175 -0
  555. package/modules/import/translations/pl.json +175 -0
  556. package/modules/metering/migrations/0001_metering_core.down.sql +6 -0
  557. package/modules/metering/migrations/0001_metering_core.up.sql +119 -0
  558. package/modules/metering/migrations/0002_metering_bucket_export.down.sql +3 -0
  559. package/modules/metering/migrations/0002_metering_bucket_export.up.sql +5 -0
  560. package/modules/metering/migrations/README.md +3 -0
  561. package/modules/metering/module.json +46 -0
  562. package/modules/metering/package.json +50 -0
  563. package/modules/metering/spec/module.yaml +269 -0
  564. package/modules/metering/src/acl/permissions.ts +5 -0
  565. package/modules/metering/src/api/endpoints.ts +104 -0
  566. package/modules/metering/src/cli/commands.json +28 -0
  567. package/modules/metering/src/cli/index.ts +246 -0
  568. package/modules/metering/src/client/LimitsView.tsrx +170 -0
  569. package/modules/metering/src/client/UsageSummaryWidget.tsrx +63 -0
  570. package/modules/metering/src/client/UsageView.tsrx +205 -0
  571. package/modules/metering/src/client/api.ts +91 -0
  572. package/modules/metering/src/client/contribution.tsrx +42 -0
  573. package/modules/metering/src/client/index.ts +26 -0
  574. package/modules/metering/src/client/navigation.ts +54 -0
  575. package/modules/metering/src/client/presentation.ts +63 -0
  576. package/modules/metering/src/client/state.ts +31 -0
  577. package/modules/metering/src/domain/meters.ts +100 -0
  578. package/modules/metering/src/domain/types.ts +71 -0
  579. package/modules/metering/src/index.ts +51 -0
  580. package/modules/metering/src/platform.ts +84 -0
  581. package/modules/metering/src/server/index.ts +40 -0
  582. package/modules/metering/src/server/runtime.ts +165 -0
  583. package/modules/metering/src/services/data-classes.ts +34 -0
  584. package/modules/metering/src/services/database-repository.ts +574 -0
  585. package/modules/metering/src/services/index.ts +9 -0
  586. package/modules/metering/src/services/meter-registry.ts +145 -0
  587. package/modules/metering/src/services/metering-service.ts +441 -0
  588. package/modules/metering/src/services/migration.ts +183 -0
  589. package/modules/metering/src/services/notifications.ts +75 -0
  590. package/modules/metering/src/services/reports.ts +105 -0
  591. package/modules/metering/src/services/repository.ts +132 -0
  592. package/modules/metering/src/services/service-error.ts +46 -0
  593. package/modules/metering/src/settings.ts +47 -0
  594. package/modules/metering/translations/en.json +68 -0
  595. package/modules/metering/translations/pl.json +68 -0
  596. package/modules/notifications/migrations/0001_notifications_core.down.sql +1 -0
  597. package/modules/notifications/migrations/0001_notifications_core.up.sql +26 -0
  598. package/modules/notifications/migrations/0002_notifications_preferences.down.sql +1 -0
  599. package/modules/notifications/migrations/0002_notifications_preferences.up.sql +17 -0
  600. package/modules/notifications/migrations/0003_notifications_webhook_subscriptions.down.sql +1 -0
  601. package/modules/notifications/migrations/0003_notifications_webhook_subscriptions.up.sql +30 -0
  602. package/modules/notifications/migrations/0004_notifications_deliveries.down.sql +1 -0
  603. package/modules/notifications/migrations/0004_notifications_deliveries.up.sql +35 -0
  604. package/modules/notifications/migrations/0005_notifications_delivery_routing_role.down.sql +2 -0
  605. package/modules/notifications/migrations/0005_notifications_delivery_routing_role.up.sql +17 -0
  606. package/modules/notifications/migrations/0006_notifications_delivery_title.down.sql +1 -0
  607. package/modules/notifications/migrations/0006_notifications_delivery_title.up.sql +11 -0
  608. package/modules/notifications/migrations/0007_notifications_secret_rotation_inventory.down.sql +2 -0
  609. package/modules/notifications/migrations/0007_notifications_secret_rotation_inventory.up.sql +19 -0
  610. package/modules/notifications/migrations/0008_notifications_delivery_claim.down.sql +8 -0
  611. package/modules/notifications/migrations/0008_notifications_delivery_claim.up.sql +19 -0
  612. package/modules/notifications/migrations/0009_notifications_kind_approvals.down.sql +16 -0
  613. package/modules/notifications/migrations/0009_notifications_kind_approvals.up.sql +18 -0
  614. package/modules/notifications/migrations/0010_notifications_kind_meter_threshold.down.sql +16 -0
  615. package/modules/notifications/migrations/0010_notifications_kind_meter_threshold.up.sql +18 -0
  616. package/modules/notifications/migrations/0011_notifications_retention_keyset.down.sql +5 -0
  617. package/modules/notifications/migrations/0011_notifications_retention_keyset.up.sql +15 -0
  618. package/modules/notifications/migrations/0012_notifications_email_channel.down.sql +12 -0
  619. package/modules/notifications/migrations/0012_notifications_email_channel.up.sql +38 -0
  620. package/modules/notifications/migrations/0013_notifications_list_pages.down.sql +5 -0
  621. package/modules/notifications/migrations/0013_notifications_list_pages.up.sql +13 -0
  622. package/modules/notifications/migrations/README.md +3 -0
  623. package/modules/notifications/module.json +32 -0
  624. package/modules/notifications/package.json +49 -0
  625. package/modules/notifications/spec/module.yaml +718 -0
  626. package/modules/notifications/src/acl/permissions.ts +11 -0
  627. package/modules/notifications/src/api/endpoints.ts +814 -0
  628. package/modules/notifications/src/cli/commands.json +17 -0
  629. package/modules/notifications/src/cli/index.ts +126 -0
  630. package/modules/notifications/src/client/DeliveriesView.tsrx +483 -0
  631. package/modules/notifications/src/client/FactList.tsrx +24 -0
  632. package/modules/notifications/src/client/NotificationPreferencesView.tsrx +240 -0
  633. package/modules/notifications/src/client/NotificationsInboxView.tsrx +592 -0
  634. package/modules/notifications/src/client/UnreadCountWidget.tsrx +62 -0
  635. package/modules/notifications/src/client/WebhookForm.tsrx +297 -0
  636. package/modules/notifications/src/client/WebhooksView.tsrx +637 -0
  637. package/modules/notifications/src/client/api.ts +382 -0
  638. package/modules/notifications/src/client/contribution.tsrx +83 -0
  639. package/modules/notifications/src/client/inbox.ts +41 -0
  640. package/modules/notifications/src/client/index.ts +29 -0
  641. package/modules/notifications/src/client/navigation.ts +92 -0
  642. package/modules/notifications/src/client/notifications.css +70 -0
  643. package/modules/notifications/src/client/presentation.ts +81 -0
  644. package/modules/notifications/src/client/state.ts +246 -0
  645. package/modules/notifications/src/client/unread-count.ts +26 -0
  646. package/modules/notifications/src/domain/locale.ts +47 -0
  647. package/modules/notifications/src/domain/publish.ts +46 -0
  648. package/modules/notifications/src/domain/types.ts +186 -0
  649. package/modules/notifications/src/index.ts +62 -0
  650. package/modules/notifications/src/platform.ts +85 -0
  651. package/modules/notifications/src/server/index.ts +82 -0
  652. package/modules/notifications/src/server/runtime.ts +251 -0
  653. package/modules/notifications/src/services/data-classes.ts +139 -0
  654. package/modules/notifications/src/services/database-repository.ts +1334 -0
  655. package/modules/notifications/src/services/delivery-payload.ts +93 -0
  656. package/modules/notifications/src/services/delivery-runner.ts +170 -0
  657. package/modules/notifications/src/services/delivery-service.ts +811 -0
  658. package/modules/notifications/src/services/egress.ts +239 -0
  659. package/modules/notifications/src/services/email-channel.ts +93 -0
  660. package/modules/notifications/src/services/index.ts +23 -0
  661. package/modules/notifications/src/services/migration.ts +572 -0
  662. package/modules/notifications/src/services/notifications-service.ts +297 -0
  663. package/modules/notifications/src/services/paging.ts +60 -0
  664. package/modules/notifications/src/services/publish-service.ts +133 -0
  665. package/modules/notifications/src/services/repository.ts +342 -0
  666. package/modules/notifications/src/services/secret-rotation.ts +177 -0
  667. package/modules/notifications/src/services/secret-vault.ts +168 -0
  668. package/modules/notifications/src/services/service-error.ts +67 -0
  669. package/modules/notifications/src/services/signature.ts +81 -0
  670. package/modules/notifications/src/services/webhook-service.ts +307 -0
  671. package/modules/notifications/src/settings.ts +130 -0
  672. package/modules/notifications/translations/en.json +255 -0
  673. package/modules/notifications/translations/pl.json +255 -0
  674. package/modules/profile/module.json +3 -3
  675. package/modules/profile/package.json +1 -1
  676. package/modules/profile/spec/module.yaml +3 -3
  677. package/modules/profile/src/services/database-repository.ts +3 -13
  678. package/modules/reports/module.json +28 -0
  679. package/modules/reports/package.json +42 -0
  680. package/modules/reports/spec/module.yaml +231 -0
  681. package/modules/reports/src/acl/permissions.ts +5 -0
  682. package/modules/reports/src/api/endpoints.ts +72 -0
  683. package/modules/reports/src/client/ReportsSummaryWidget.tsrx +52 -0
  684. package/modules/reports/src/client/ReportsView.tsrx +246 -0
  685. package/modules/reports/src/client/api.ts +65 -0
  686. package/modules/reports/src/client/contribution.tsrx +36 -0
  687. package/modules/reports/src/client/index.ts +18 -0
  688. package/modules/reports/src/client/navigation.ts +39 -0
  689. package/modules/reports/src/client/presentation.ts +123 -0
  690. package/modules/reports/src/client/state.ts +28 -0
  691. package/modules/reports/src/domain/providers.ts +115 -0
  692. package/modules/reports/src/domain/types.ts +44 -0
  693. package/modules/reports/src/index.ts +47 -0
  694. package/modules/reports/src/platform.ts +37 -0
  695. package/modules/reports/src/server/index.ts +21 -0
  696. package/modules/reports/src/server/runtime.ts +40 -0
  697. package/modules/reports/src/services/index.ts +17 -0
  698. package/modules/reports/src/services/provider-registry.ts +144 -0
  699. package/modules/reports/src/services/range.ts +65 -0
  700. package/modules/reports/src/services/reports-service.ts +316 -0
  701. package/modules/reports/src/services/service-error.ts +26 -0
  702. package/modules/reports/src/settings.ts +49 -0
  703. package/modules/reports/translations/en.json +35 -0
  704. package/modules/reports/translations/pl.json +35 -0
  705. package/modules/sandbox/module.json +4 -4
  706. package/modules/sandbox/package.json +1 -1
  707. package/modules/sandbox/spec/module.yaml +3 -3
  708. package/modules/sandbox/src/services/database-repository.ts +14 -23
  709. package/modules/sandbox/src/services/directory.ts +16 -0
  710. package/modules/sandbox/src/services/sandbox-service.ts +13 -11
  711. package/modules/search/migrations/0001_search_core.down.sql +1 -0
  712. package/modules/search/migrations/0001_search_core.up.sql +22 -0
  713. package/modules/search/migrations/0002_search_recent_export.down.sql +3 -0
  714. package/modules/search/migrations/0002_search_recent_export.up.sql +5 -0
  715. package/modules/search/migrations/README.md +3 -0
  716. package/modules/search/module.json +28 -0
  717. package/modules/search/package.json +43 -0
  718. package/modules/search/spec/module.yaml +177 -0
  719. package/modules/search/src/acl/permissions.ts +5 -0
  720. package/modules/search/src/api/endpoints.ts +221 -0
  721. package/modules/search/src/client/SearchView.tsrx +346 -0
  722. package/modules/search/src/client/api.ts +157 -0
  723. package/modules/search/src/client/contribution.tsrx +31 -0
  724. package/modules/search/src/client/index.ts +17 -0
  725. package/modules/search/src/client/navigation.ts +97 -0
  726. package/modules/search/src/client/search.css +56 -0
  727. package/modules/search/src/client/state.ts +113 -0
  728. package/modules/search/src/domain/data-classes.ts +73 -0
  729. package/modules/search/src/domain/providers.ts +88 -0
  730. package/modules/search/src/domain/types.ts +56 -0
  731. package/modules/search/src/index.ts +46 -0
  732. package/modules/search/src/platform.ts +42 -0
  733. package/modules/search/src/server/index.ts +25 -0
  734. package/modules/search/src/server/runtime.ts +123 -0
  735. package/modules/search/src/services/database-repository.ts +163 -0
  736. package/modules/search/src/services/index.ts +21 -0
  737. package/modules/search/src/services/migration.ts +65 -0
  738. package/modules/search/src/services/provider-registry.ts +137 -0
  739. package/modules/search/src/services/repository.ts +43 -0
  740. package/modules/search/src/services/search-service.ts +442 -0
  741. package/modules/search/src/services/service-error.ts +35 -0
  742. package/modules/search/src/settings.ts +68 -0
  743. package/modules/search/translations/en.json +45 -0
  744. package/modules/search/translations/pl.json +45 -0
  745. package/modules/system/module.json +2 -2
  746. package/modules/system/package.json +1 -1
  747. package/modules/system/spec/module.yaml +30 -3
  748. package/modules/system/src/client/FlagsPanel.tsrx +127 -0
  749. package/modules/system/src/client/ModuleSettingRow.tsrx +17 -7
  750. package/modules/system/src/client/ModuleSettingsSection.tsrx +10 -71
  751. package/modules/system/src/client/ModulesView.tsrx +91 -65
  752. package/modules/system/src/client/flags.ts +35 -0
  753. package/modules/system/src/client/index.ts +8 -0
  754. package/modules/system/src/client/navigation.ts +8 -0
  755. package/modules/system/src/client/settings-state.ts +159 -0
  756. package/modules/system/src/client/state.ts +2 -0
  757. package/modules/system/src/domain/time-zone.ts +105 -0
  758. package/modules/system/src/index.ts +12 -0
  759. package/modules/system/src/platform.ts +5 -1
  760. package/modules/system/src/server/endpoints.ts +72 -21
  761. package/modules/system/src/settings.ts +28 -0
  762. package/modules/system/translations/en.json +17 -0
  763. package/modules/system/translations/pl.json +17 -0
  764. package/modules/users/module.json +30 -4
  765. package/modules/users/package.json +4 -1
  766. package/modules/users/spec/module.yaml +290 -7
  767. package/modules/users/src/api/endpoints.ts +228 -15
  768. package/modules/users/src/client/InviteMemberForm.tsrx +2 -2
  769. package/modules/users/src/client/MemberDrawer.tsrx +142 -26
  770. package/modules/users/src/client/UserAccountForm.tsrx +2 -2
  771. package/modules/users/src/client/UsersView.tsrx +432 -71
  772. package/modules/users/src/client/api.ts +106 -12
  773. package/modules/users/src/client/contribution.tsrx +5 -0
  774. package/modules/users/src/client/member-columns.tsrx +22 -9
  775. package/modules/users/src/client/state.ts +172 -7
  776. package/modules/users/src/domain/lists.ts +9 -0
  777. package/modules/users/src/index.ts +11 -0
  778. package/modules/users/src/platform.ts +50 -1
  779. package/modules/users/src/services/member-export.ts +51 -0
  780. package/modules/users/src/services/member-import.ts +249 -0
  781. package/modules/users/src/services/member-search.ts +145 -0
  782. package/modules/users/src/services/users-service.ts +117 -4
  783. package/modules/users/translations/en.json +57 -8
  784. package/modules/users/translations/pl.json +57 -8
  785. package/modules/workflows/migrations/0004_payload_rotation_inventory.up.sql +17 -0
  786. package/modules/workflows/migrations/0005_workflows_human_approval.up.sql +28 -0
  787. package/modules/workflows/migrations/0006_workflows_retention_indexes.up.sql +11 -0
  788. package/modules/workflows/migrations/0007_workflows_erasure_subject_indexes.up.sql +17 -0
  789. package/modules/workflows/migrations/0008_workflows_subject_account.up.sql +24 -0
  790. package/modules/workflows/migrations/0009_workflows_definition_list_indexes.up.sql +9 -0
  791. package/modules/workflows/module.json +34 -6
  792. package/modules/workflows/package.json +2 -1
  793. package/modules/workflows/spec/module.yaml +26 -9
  794. package/modules/workflows/src/api/endpoints.ts +131 -25
  795. package/modules/workflows/src/cli/commands.json +17 -0
  796. package/modules/workflows/src/cli/index.ts +114 -0
  797. package/modules/workflows/src/client/WorkflowExecutionHistory.tsrx +36 -27
  798. package/modules/workflows/src/client/WorkflowInspector.tsrx +116 -0
  799. package/modules/workflows/src/client/WorkflowNodePalette.tsrx +1 -0
  800. package/modules/workflows/src/client/WorkflowsView.tsrx +236 -99
  801. package/modules/workflows/src/client/api.ts +54 -34
  802. package/modules/workflows/src/client/canvas-model.ts +12 -0
  803. package/modules/workflows/src/client/state.ts +95 -0
  804. package/modules/workflows/src/domain/events.ts +25 -11
  805. package/modules/workflows/src/domain/graph.ts +135 -1
  806. package/modules/workflows/src/domain/types.ts +91 -4
  807. package/modules/workflows/src/platform.ts +12 -0
  808. package/modules/workflows/src/server/runtime.ts +78 -5
  809. package/modules/workflows/src/services/approvals.ts +62 -0
  810. package/modules/workflows/src/services/cursors.ts +37 -0
  811. package/modules/workflows/src/services/data-classes.ts +232 -0
  812. package/modules/workflows/src/services/database-repository.ts +660 -171
  813. package/modules/workflows/src/services/migration.ts +240 -0
  814. package/modules/workflows/src/services/notifications.ts +98 -0
  815. package/modules/workflows/src/services/payload-codec.ts +51 -28
  816. package/modules/workflows/src/services/payload-rotation.ts +171 -0
  817. package/modules/workflows/src/services/repository.ts +123 -8
  818. package/modules/workflows/src/services/simulation.ts +7 -0
  819. package/modules/workflows/src/services/worker.ts +446 -25
  820. package/modules/workflows/src/services/workflows-service.ts +264 -103
  821. package/modules/workflows/translations/en.json +12 -4
  822. package/modules/workflows/translations/pl.json +12 -4
  823. package/modules.json +48 -4
  824. package/package.json +64 -6
  825. package/packages/client/package.json +1 -0
  826. package/packages/client/src/ApplicationShell.tsrx +43 -0
  827. package/packages/client/src/contributions.ts +55 -0
  828. package/packages/client/src/i18n/locales/en.json +5 -0
  829. package/packages/client/src/i18n/locales/pl.json +5 -0
  830. package/packages/client/src/index.ts +13 -1
  831. package/packages/client/src/routing.ts +22 -0
  832. package/packages/client/src/shell/CommandPalette.tsrx +223 -11
  833. package/packages/client/src/shell/command-search.ts +126 -0
  834. package/packages/client/src/shell/command.ts +30 -0
  835. package/packages/client/src/shell/navigation.ts +12 -0
  836. package/packages/client/src/shell/palette-keys.ts +27 -0
  837. package/packages/client/src/shell/shell.css +7 -0
  838. package/packages/contracts/schemas/module-spec.schema.json +287 -1
  839. package/packages/contracts/schemas/module.schema.json +25 -0
  840. package/packages/contracts/src/index.ts +144 -1
  841. package/packages/database/src/backup.ts +180 -0
  842. package/packages/database/src/decoders.ts +25 -0
  843. package/packages/database/src/index.ts +17 -0
  844. package/packages/database/src/migrations.ts +7 -0
  845. package/packages/database/src/record-history.ts +5 -14
  846. package/packages/harness/src/index.ts +2 -0
  847. package/packages/harness/src/runtime.ts +378 -2
  848. package/packages/harness/src/tool-adapters.ts +20 -9
  849. package/packages/kernel/src/acl.ts +179 -0
  850. package/packages/kernel/src/approval-grant.ts +310 -0
  851. package/packages/kernel/src/capability-registry.ts +69 -2
  852. package/packages/kernel/src/data-class-registry.ts +354 -0
  853. package/packages/kernel/src/index.ts +85 -4
  854. package/packages/kernel/src/keyring.ts +208 -0
  855. package/packages/kernel/src/module-compatibility.ts +35 -4
  856. package/packages/kernel/src/module-registry.ts +49 -2
  857. package/packages/kernel/src/module-settings.ts +189 -27
  858. package/packages/server/package.json +2 -1
  859. package/packages/server/src/composition.ts +38 -0
  860. package/packages/server/src/endpoint.ts +104 -47
  861. package/packages/server/src/export/csv.ts +34 -0
  862. package/packages/server/src/export/definition.ts +346 -0
  863. package/packages/server/src/export/index.ts +61 -0
  864. package/packages/server/src/export/run.ts +116 -0
  865. package/packages/server/src/index.ts +155 -0
  866. package/packages/server/src/jobs/index.ts +93 -0
  867. package/packages/server/src/jobs/runner.ts +486 -0
  868. package/packages/server/src/log.ts +291 -0
  869. package/packages/server/src/mail/config.ts +184 -0
  870. package/packages/server/src/mail/contracts.ts +251 -0
  871. package/packages/server/src/mail/index.ts +31 -0
  872. package/packages/server/src/mail/port.ts +101 -0
  873. package/packages/server/src/mail/smtp.ts +191 -0
  874. package/packages/server/src/mail/template.ts +105 -0
  875. package/packages/server/src/metrics.ts +447 -0
  876. package/packages/server/src/pagination.ts +246 -0
  877. package/packages/server/src/trace/context.ts +103 -0
  878. package/packages/server/src/trace/egress.ts +66 -0
  879. package/packages/server/src/trace/error-sink.ts +296 -0
  880. package/packages/server/src/trace/exporter.ts +295 -0
  881. package/packages/server/src/trace/index.ts +60 -0
  882. package/packages/server/src/trace/job-sink.ts +172 -0
  883. package/packages/server/src/trace/tracer.ts +338 -0
  884. package/packages/server/src/web.ts +5 -1
  885. package/packages/storage/package.json +40 -0
  886. package/packages/storage/src/config.ts +189 -0
  887. package/packages/storage/src/content-type.ts +124 -0
  888. package/packages/storage/src/contracts.ts +112 -0
  889. package/packages/storage/src/envelope.ts +238 -0
  890. package/packages/storage/src/index.ts +49 -0
  891. package/packages/storage/src/local.ts +75 -0
  892. package/packages/storage/src/port.ts +262 -0
  893. package/packages/storage/src/read-token.ts +130 -0
  894. package/packages/storage/src/reseal.ts +128 -0
  895. package/packages/storage/src/s3.ts +144 -0
  896. package/packages/storage/src/scanner.ts +22 -0
  897. package/packages/storage/src/sigv4.ts +104 -0
  898. package/packages/storage/src/store.ts +13 -0
  899. package/packages/ui/package.json +1 -0
  900. package/packages/ui/src/components/Button.tsrx +3 -0
  901. package/packages/ui/src/components/ConfirmDialog.tsrx +13 -2
  902. package/packages/ui/src/components/DateField.tsrx +92 -0
  903. package/packages/ui/src/components/DatePicker.tsrx +525 -0
  904. package/packages/ui/src/components/DateRangeField.tsrx +93 -0
  905. package/packages/ui/src/components/Drawer.tsrx +10 -1
  906. package/packages/ui/src/components/FileUpload.tsrx +158 -0
  907. package/packages/ui/src/components/Pagination.tsrx +130 -0
  908. package/packages/ui/src/components/Select.tsrx +78 -0
  909. package/packages/ui/src/components/Table.tsrx +498 -81
  910. package/packages/ui/src/components/Tabs.tsrx +53 -0
  911. package/packages/ui/src/components/ToastHost.tsrx +48 -0
  912. package/packages/ui/src/components/calendar.ts +243 -0
  913. package/packages/ui/src/components/date-field.ts +62 -0
  914. package/packages/ui/src/components/file-upload.ts +49 -0
  915. package/packages/ui/src/components/focus-trap.ts +62 -0
  916. package/packages/ui/src/components/pagination.ts +68 -0
  917. package/packages/ui/src/components/table-sorting.ts +49 -0
  918. package/packages/ui/src/components/tabs.ts +61 -0
  919. package/packages/ui/src/components/toast-store.ts +116 -0
  920. package/packages/ui/src/icons/Icon.tsrx +5 -0
  921. package/packages/ui/src/index.ts +45 -0
  922. package/packages/ui/src/styles/components.css +598 -0
  923. package/modules/automations-workflows-integration/module.json +0 -27
  924. package/modules/automations-workflows-integration/spec/module.yaml +0 -93
  925. package/modules/automations-workflows-integration/src/index.ts +0 -14
  926. package/modules/automations-workflows-integration/src/platform.ts +0 -24
  927. package/modules/automations-workflows-integration/src/server/index.ts +0 -11
  928. package/modules/automations-workflows-integration/translations/en.json +0 -21
  929. package/modules/automations-workflows-integration/translations/pl.json +0 -21
  930. package/modules/workflows/src/services/cursor-codec.ts +0 -62
@@ -0,0 +1,811 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import type { IncomingMessage } from 'node:http';
3
+ import { Agent, request as httpsRequest } from 'node:https';
4
+ import { MailError, type MailPort } from '@flowdular/sdk/server';
5
+ import { NOTIFICATIONS_PERMISSIONS } from '../acl/permissions.ts';
6
+ import { DEFAULT_MAIL_LOCALE } from '../domain/locale.ts';
7
+ import {
8
+ DELIVERY_STATUSES,
9
+ type DeliveryAttempt,
10
+ type DeliveryErrorClass,
11
+ type DeliveryRouting,
12
+ type NotificationsInbox,
13
+ } from '../domain/types.ts';
14
+ import {
15
+ emailPayloadFingerprint,
16
+ webhookPayloadFingerprint,
17
+ } from './delivery-payload.ts';
18
+ import {
19
+ emailDeliveryAttempt,
20
+ notificationMailMessage,
21
+ } from './email-channel.ts';
22
+ import {
23
+ normalizeHost,
24
+ pinnedLookup,
25
+ WebhookEgressError,
26
+ type ResolvedAddress,
27
+ type WebhookEgressPolicy,
28
+ } from './egress.ts';
29
+ import {
30
+ listPage,
31
+ timeKey,
32
+ type ListPageInput,
33
+ type ListResult,
34
+ } from './paging.ts';
35
+ import type {
36
+ DeliveryFilters,
37
+ NotificationsRepository,
38
+ StoredWebhookSubscription,
39
+ } from './repository.ts';
40
+ import { secretContext, type SecretVault } from './secret-vault.ts';
41
+ import { bounded, NotificationsServiceError, oneOf } from './service-error.ts';
42
+ import { webhookSignatureHeader } from './signature.ts';
43
+
44
+ /** Hard request bounds. Neither is configurable: they are the egress contract. */
45
+ export const DELIVERY_TIMEOUT_MS = 10_000;
46
+ export const DELIVERY_RESPONSE_CAP_BYTES = 64 * 1_024;
47
+ /** First retry gap; each further attempt doubles it up to the tenant maximum. */
48
+ export const DELIVERY_BASE_BACKOFF_MS = 60_000;
49
+ /**
50
+ * A claim older than this was abandoned by a process that died mid-send: the
51
+ * request bound plus room for the ledger write that follows it. Another process
52
+ * takes such an attempt over instead of leaving it stranded.
53
+ */
54
+ export const DELIVERY_CLAIM_TIMEOUT_MS = DELIVERY_TIMEOUT_MS + 30_000;
55
+ /**
56
+ * How far a held attempt is parked when its subscription is not active. Long
57
+ * enough that a paused backlog cannot keep taking the routing page from every
58
+ * other tenant, short enough that a resumed subscription drains within a minute.
59
+ */
60
+ export const DELIVERY_HOLD_MS = 60_000;
61
+ /**
62
+ * Routing rows one tick inspects per queue read, and rows one retention pass
63
+ * removes.
64
+ */
65
+ export const DELIVERY_TICK_LIMIT = 50;
66
+ export const RETENTION_BATCH_LIMIT = 500;
67
+ export const RETENTION_TENANT_LIMIT = 100;
68
+ export const DELIVERY_SEARCH_MAX = 80;
69
+
70
+ export interface TenantDeliverySettings {
71
+ readonly retryMaxAttempts: number;
72
+ readonly retryMaxBackoffMinutes: number;
73
+ readonly retentionDays: number;
74
+ }
75
+
76
+ /** A tenant member and the scopes it currently holds, from auth.core. */
77
+ export interface TenantMemberScopes {
78
+ readonly accountId: string;
79
+ /** Resolved at send time, never copied into this module's tables. */
80
+ readonly email: string;
81
+ readonly scopes: readonly string[];
82
+ }
83
+
84
+ /**
85
+ * One workspace's members as one pass sees them. auth.core is asked once per
86
+ * tenant per pass; the index is what keeps addressing an attempt O(1) rather
87
+ * than a scan of the workspace per queued message.
88
+ */
89
+ interface TenantMembers {
90
+ readonly list: readonly TenantMemberScopes[];
91
+ readonly byAccount: ReadonlyMap<string, TenantMemberScopes>;
92
+ }
93
+
94
+ type MemberLookup = (tenantId: string) => Promise<TenantMembers>;
95
+
96
+ /** One pass over the delivery queue, and the workspace lookups it holds. */
97
+ export interface DeliveryPass {
98
+ /**
99
+ * Reads one routing row again under the workspace it named and takes it. Null
100
+ * for an attempt that moved since the routing read, or one another process is
101
+ * already sending: neither is this pass's work, and neither is an attempt it
102
+ * has to report as one.
103
+ */
104
+ claim(routing: DeliveryRouting, at: number): Promise<DeliveryAttempt | null>;
105
+ /** Sends one attempt this pass claimed and records what came back. */
106
+ deliver(attempt: DeliveryAttempt, at: number): Promise<void>;
107
+ }
108
+
109
+ export interface DeliveryOutcome {
110
+ readonly status: 'succeeded' | 'failed';
111
+ readonly responseStatus: number | null;
112
+ readonly errorClass: DeliveryErrorClass | null;
113
+ }
114
+
115
+ export interface DeliveryTransport {
116
+ send(request: {
117
+ readonly url: string;
118
+ readonly body: string;
119
+ readonly timestamp: string;
120
+ readonly signature: string;
121
+ /** The addresses the policy accepted; the socket may reach no other. */
122
+ readonly addresses: readonly ResolvedAddress[];
123
+ }): Promise<DeliveryOutcome>;
124
+ }
125
+
126
+ /**
127
+ * Test seam for the outbound socket; never reachable from configuration. A
128
+ * deployment leaves it unset, so a delivery dials the address the policy
129
+ * verified and trusts the system store. A test maps that address onto the
130
+ * loopback port its server listens on and adds that server's certificate, which
131
+ * runs the delivery path with exactly the address rules a deployment has. `ca`
132
+ * only ever widens trust: there is no form of this seam that turns verification
133
+ * off.
134
+ */
135
+ export interface WebhookConnectSeam {
136
+ readonly dial?: ((address: string) => string) | undefined;
137
+ readonly ca?: string | undefined;
138
+ }
139
+
140
+ export interface DeliveryServiceOptions {
141
+ readonly repository: NotificationsRepository;
142
+ readonly vault: SecretVault;
143
+ readonly policy: () => WebhookEgressPolicy;
144
+ readonly settings: (
145
+ tenantId: string,
146
+ ) => TenantDeliverySettings | Promise<TenantDeliverySettings>;
147
+ readonly members: (
148
+ tenantId: string,
149
+ ) => Promise<readonly TenantMemberScopes[]>;
150
+ /** Platform-owned outbound mail; the e-mail channel sends through it. */
151
+ readonly mail: MailPort;
152
+ /** The language one workspace's messages say they are written in. */
153
+ readonly locale?: (tenantId: string) => string | Promise<string>;
154
+ readonly now?: () => number;
155
+ readonly transport?: DeliveryTransport;
156
+ readonly connect?: WebhookConnectSeam | undefined;
157
+ }
158
+
159
+ function classifyResponse(status: number): DeliveryOutcome {
160
+ if (status >= 200 && status < 300) {
161
+ return { status: 'succeeded', responseStatus: status, errorClass: null };
162
+ }
163
+ /* A redirect is a refusal, not a hop: node never follows one, so the 3xx comes
164
+ back and the delivery is recorded as refused rather than chased. */
165
+ const errorClass: DeliveryErrorClass =
166
+ status >= 500
167
+ ? 'response-5xx'
168
+ : status >= 400
169
+ ? 'response-4xx'
170
+ : status >= 300
171
+ ? 'egress-refused'
172
+ : 'network';
173
+ return { status: 'failed', responseStatus: status, errorClass };
174
+ }
175
+
176
+ function failed(errorClass: DeliveryErrorClass): DeliveryOutcome {
177
+ return { status: 'failed', responseStatus: null, errorClass };
178
+ }
179
+
180
+ /**
181
+ * An e-mail failure no later pass would survive. The ledger records the class
182
+ * and the attempt ends there instead of spending the whole retry budget.
183
+ */
184
+ interface PermanentEmailFailure {
185
+ readonly deadLetter: DeliveryErrorClass;
186
+ }
187
+
188
+ const UNREACHABLE_RECIPIENT: PermanentEmailFailure = {
189
+ deadLetter: 'recipient-unknown',
190
+ };
191
+
192
+ /* A rejected message is these bytes being unacceptable to the port, so every
193
+ attempt of the same message is refused the same way and the first one ends
194
+ it. A deployment that composed no transport may still compose one, and a
195
+ transport failure is the relay being unreachable; both keep the budget a
196
+ network error gets, under the class the ledger shows. */
197
+ function classifyMailError(
198
+ error: unknown,
199
+ ): DeliveryOutcome | PermanentEmailFailure {
200
+ if (error instanceof MailError) {
201
+ if (error.code === 'MAIL_MESSAGE_REJECTED') {
202
+ return { deadLetter: 'mail-refused' };
203
+ }
204
+ return failed(
205
+ error.code === 'MAIL_DELIVERY_FAILED' ? 'network' : 'mail-refused',
206
+ );
207
+ }
208
+ return failed('network');
209
+ }
210
+
211
+ function classifyError(error: unknown): DeliveryOutcome {
212
+ if (error instanceof WebhookEgressError) {
213
+ return failed(
214
+ error.code === 'WEBHOOK_HOST_UNRESOLVED' ? 'dns' : 'egress-refused',
215
+ );
216
+ }
217
+ const name = (error as { name?: unknown })?.name;
218
+ if (name === 'TimeoutError' || name === 'AbortError')
219
+ return failed('timeout');
220
+ /* node reports the resolver failure on the error, fetch reported it on the
221
+ cause; both shapes are read so the class stays the same either way. */
222
+ const failure = error as { code?: unknown; cause?: { code?: unknown } };
223
+ const code = String(failure?.code ?? failure?.cause?.code);
224
+ if (code === 'ENOTFOUND' || code === 'EAI_AGAIN') return failed('dns');
225
+ return failed('network');
226
+ }
227
+
228
+ /**
229
+ * Reads at most the cap and drops the rest. The body is never stored; it is
230
+ * consumed only so the connection is released instead of left half-open.
231
+ */
232
+ async function drainResponse(response: IncomingMessage): Promise<void> {
233
+ let read = 0;
234
+ try {
235
+ for await (const chunk of response) {
236
+ read += (chunk as Buffer).byteLength;
237
+ if (read >= DELIVERY_RESPONSE_CAP_BYTES) return;
238
+ }
239
+ } finally {
240
+ response.destroy();
241
+ }
242
+ }
243
+
244
+ /** Reads as an abort so the classifier records a timeout, not a reset. */
245
+ function abortFailure(): Error {
246
+ const error = new Error('The webhook delivery was aborted.');
247
+ error.name = 'AbortError';
248
+ return error;
249
+ }
250
+
251
+ /**
252
+ * One request over TLS to an address the egress policy already accepted. The
253
+ * agent is built per delivery and destroyed with it: a pooled socket would
254
+ * outlive the address check that admitted it, which is the window this closes.
255
+ */
256
+ function sendPinned(
257
+ target: URL,
258
+ init: {
259
+ readonly headers: Readonly<Record<string, string>>;
260
+ readonly body: string;
261
+ readonly addresses: readonly ResolvedAddress[];
262
+ readonly signal: AbortSignal;
263
+ readonly ca?: string | undefined;
264
+ },
265
+ ): Promise<number> {
266
+ const agent = new Agent({
267
+ keepAlive: false,
268
+ maxSockets: 1,
269
+ lookup: pinnedLookup(normalizeHost(target.hostname), init.addresses),
270
+ ...(init.ca === undefined ? {} : { ca: init.ca }),
271
+ });
272
+ return new Promise<number>((resolve, reject) => {
273
+ const fail = (error: unknown) =>
274
+ reject(init.signal.aborted ? abortFailure() : error);
275
+ const request = httpsRequest(target, {
276
+ method: 'POST',
277
+ agent,
278
+ /* An explicit length rather than a chunked body: a customer endpoint
279
+ that refuses chunked requests must still see the same request it saw
280
+ before the transport changed. */
281
+ headers: {
282
+ ...init.headers,
283
+ 'content-length': String(Buffer.byteLength(init.body, 'utf8')),
284
+ },
285
+ signal: init.signal,
286
+ });
287
+ request.on('error', fail);
288
+ request.on('response', (response) => {
289
+ /* The drain shares this rejection: an endpoint that answers with headers
290
+ and then stalls its body makes the read reject on the request
291
+ deadline, and that rejection is this attempt's outcome, not the whole
292
+ pass's. */
293
+ void drainResponse(response).then(
294
+ () => resolve(response.statusCode ?? 0),
295
+ fail,
296
+ );
297
+ });
298
+ request.write(init.body);
299
+ request.end();
300
+ }).finally(() => agent.destroy());
301
+ }
302
+
303
+ /* The verified addresses as they are dialled. A deployment dials exactly what
304
+ it verified; the seam is what lets a test reach its own server. */
305
+ function dialable(
306
+ connect: WebhookConnectSeam,
307
+ addresses: readonly ResolvedAddress[],
308
+ ): readonly ResolvedAddress[] {
309
+ const dial = connect.dial;
310
+ if (!dial) return addresses;
311
+ return addresses.map((entry) => ({ address: dial(entry.address) }));
312
+ }
313
+
314
+ export function createDeliveryTransport(
315
+ connect: WebhookConnectSeam = {},
316
+ ): DeliveryTransport {
317
+ return {
318
+ async send(request) {
319
+ try {
320
+ const status = await sendPinned(new URL(request.url), {
321
+ addresses: dialable(connect, request.addresses),
322
+ /* One deadline over the headers and the body, so an endpoint that
323
+ answers and then stalls mid-body is still bounded. */
324
+ signal: AbortSignal.timeout(DELIVERY_TIMEOUT_MS),
325
+ headers: {
326
+ 'content-type': 'application/json',
327
+ 'x-flowdular-signature': request.signature,
328
+ 'x-flowdular-timestamp': request.timestamp,
329
+ },
330
+ body: request.body,
331
+ ...(connect.ca === undefined ? {} : { ca: connect.ca }),
332
+ });
333
+ return classifyResponse(status);
334
+ } catch (error) {
335
+ return classifyError(error);
336
+ }
337
+ },
338
+ };
339
+ }
340
+
341
+ /**
342
+ * Drains the delivery queue. The cross-tenant poll reads routing columns on the
343
+ * read-only background lease; every attempt is then read, sent and written
344
+ * again under the tenant the routing row named.
345
+ */
346
+ export class DeliveryService {
347
+ readonly #options: DeliveryServiceOptions;
348
+ readonly #transport: DeliveryTransport;
349
+ readonly #now: () => number;
350
+ readonly #locale: (tenantId: string) => string | Promise<string>;
351
+ /** Last tenant a retention pass reached; '' restarts the rotation. */
352
+ #retentionCursor = '';
353
+
354
+ constructor(options: DeliveryServiceOptions) {
355
+ this.#options = options;
356
+ this.#transport =
357
+ options.transport ?? createDeliveryTransport(options.connect);
358
+ this.#now = options.now ?? Date.now;
359
+ this.#locale = options.locale ?? (() => DEFAULT_MAIL_LOCALE);
360
+ }
361
+
362
+ async list(
363
+ tenantId: string,
364
+ filters: DeliveryFilters = {},
365
+ page: ListPageInput<number> = {},
366
+ ): Promise<readonly DeliveryAttempt[]> {
367
+ return (await this.listPage(tenantId, filters, page)).items;
368
+ }
369
+
370
+ /** One page of the ledger, latest schedule first unless asked otherwise. */
371
+ async listPage(
372
+ tenantId: string,
373
+ filters: DeliveryFilters = {},
374
+ page: ListPageInput<number> = {},
375
+ ): Promise<ListResult<DeliveryAttempt, number>> {
376
+ const result = await this.#options.repository.listDeliveries(
377
+ bounded(tenantId, 'tenantId', 1, 128),
378
+ {
379
+ status: filters.status
380
+ ? oneOf(filters.status, 'status', DELIVERY_STATUSES)
381
+ : undefined,
382
+ subscriptionId: filters.subscriptionId
383
+ ? bounded(filters.subscriptionId, 'subscriptionId', 1, 128)
384
+ : undefined,
385
+ search: filters.search
386
+ ? bounded(filters.search, 'search', 1, DELIVERY_SEARCH_MAX)
387
+ : undefined,
388
+ },
389
+ listPage(page, 'desc', timeKey),
390
+ );
391
+ return { items: result.rows, next: result.next };
392
+ }
393
+
394
+ /** Queues a fresh attempt run for a dead-lettered delivery. */
395
+ async replay(tenantId: string, id: string): Promise<DeliveryAttempt> {
396
+ const trustedTenantId = bounded(tenantId, 'tenantId', 1, 128);
397
+ const existing = await this.#options.repository.getDelivery(
398
+ trustedTenantId,
399
+ bounded(id, 'deliveryId', 1, 128),
400
+ );
401
+ if (!existing) {
402
+ throw new NotificationsServiceError(
403
+ 'DELIVERY_NOT_FOUND',
404
+ 'Delivery attempt not found.',
405
+ 404,
406
+ );
407
+ }
408
+ if (existing.status !== 'dead-letter') {
409
+ throw new NotificationsServiceError(
410
+ 'DELIVERY_NOT_DEAD_LETTER',
411
+ 'Only a dead-lettered delivery can be replayed.',
412
+ 409,
413
+ );
414
+ }
415
+ const sequence =
416
+ (await this.#options.repository.latestDeliverySequence(existing)) + 1;
417
+ const queued = await this.#append(existing, sequence, 1, this.#now());
418
+ if (!queued) {
419
+ throw new NotificationsServiceError(
420
+ 'DELIVERY_REPLAY_CONFLICT',
421
+ 'A replay of this delivery is already queued.',
422
+ 409,
423
+ );
424
+ }
425
+ return queued;
426
+ }
427
+
428
+ /**
429
+ * One pass over the delivery queue. The workspace lookups it needs are asked
430
+ * for once and held by the pass alone, bounded by the tenants its routing
431
+ * rows named, so a membership or an address change is picked up by the next
432
+ * pass rather than by the next attempt.
433
+ */
434
+ pass(): DeliveryPass {
435
+ const members = this.#passMembers();
436
+ return {
437
+ /* The routing read crossed tenants; the row is authoritative only now,
438
+ read back and claimed under its own tenant in one statement. The claim
439
+ is what keeps two poll loops from repeating one request. */
440
+ claim: (routing, at) =>
441
+ this.#options.repository.claimDelivery({
442
+ tenantId: routing.tenantId,
443
+ id: routing.id,
444
+ now: at,
445
+ strandedBefore: at - DELIVERY_CLAIM_TIMEOUT_MS,
446
+ }),
447
+ deliver: (attempt, at) => this.#deliver(attempt, at, members),
448
+ };
449
+ }
450
+
451
+ #passMembers(): MemberLookup {
452
+ const pending = new Map<string, Promise<TenantMembers>>();
453
+ return (tenantId) => {
454
+ let members = pending.get(tenantId);
455
+ if (!members) {
456
+ members = this.#options.members(tenantId).then((list) => ({
457
+ list,
458
+ byAccount: new Map(list.map((member) => [member.accountId, member])),
459
+ }));
460
+ pending.set(tenantId, members);
461
+ }
462
+ return members;
463
+ };
464
+ }
465
+
466
+ /**
467
+ * Deletes completed attempts past each tenant's retention window. One pass
468
+ * covers at most RETENTION_TENANT_LIMIT tenants and resumes from where the
469
+ * last one stopped, so no tenant is starved by the ones sorting before it.
470
+ */
471
+ async collectRetention(now = this.#now()): Promise<number> {
472
+ const tenants = await this.#options.repository.listDeliveryTenants(
473
+ RETENTION_TENANT_LIMIT,
474
+ this.#retentionCursor,
475
+ );
476
+ this.#retentionCursor =
477
+ tenants.length < RETENTION_TENANT_LIMIT
478
+ ? ''
479
+ : (tenants[tenants.length - 1] ?? '');
480
+ let removed = 0;
481
+ for (const tenantId of tenants) {
482
+ const { retentionDays } = await this.#options.settings(tenantId);
483
+ removed += await this.#options.repository.deleteCompletedDeliveriesBefore(
484
+ tenantId,
485
+ now - retentionDays * 86_400_000,
486
+ RETENTION_BATCH_LIMIT,
487
+ );
488
+ }
489
+ return removed;
490
+ }
491
+
492
+ async #deliver(
493
+ attempt: DeliveryAttempt,
494
+ now: number,
495
+ members: MemberLookup,
496
+ ): Promise<void> {
497
+ const tenantId = attempt.tenantId;
498
+ if (attempt.channel === 'email') {
499
+ const outcome = await this.#sendEmail(attempt, members);
500
+ /* A member who left the workspace or an item that is gone is the e-mail
501
+ channel's missing subscription, and a message the port refuses is
502
+ refused again on every attempt: no later pass would do better, so the
503
+ attempt ends here instead of spending the retry budget. */
504
+ if ('deadLetter' in outcome) {
505
+ await this.#deadLetter(attempt, now, outcome.deadLetter);
506
+ return;
507
+ }
508
+ await this.#record(attempt, null, outcome, now, members);
509
+ return;
510
+ }
511
+ const subscription = await this.#options.repository.getSubscription(
512
+ tenantId,
513
+ attempt.subscriptionId ?? '',
514
+ );
515
+ if (!subscription) {
516
+ await this.#deadLetter(attempt, now, 'egress-refused');
517
+ return;
518
+ }
519
+ /* A paused or disabled subscription holds its queue: the attempt returns to
520
+ it unchanged and nothing is counted against the retry budget. It is
521
+ parked past this pass, because a held backlog larger than the page would
522
+ otherwise take the routing page from every other subscription forever. */
523
+ if (subscription.status !== 'active') {
524
+ await this.#options.repository.releaseDelivery(
525
+ tenantId,
526
+ attempt.id,
527
+ now + DELIVERY_HOLD_MS,
528
+ );
529
+ return;
530
+ }
531
+
532
+ const payload = webhookPayloadFingerprint({
533
+ tenantId,
534
+ subscriptionId: subscription.id,
535
+ kind: attempt.kind,
536
+ sourceModule: attempt.sourceModule,
537
+ sourceRef: attempt.sourceRef,
538
+ title: attempt.title,
539
+ occurredAt: attempt.occurredAt,
540
+ });
541
+ const outcome = await this.#send(subscription, payload.body, now);
542
+ await this.#record(attempt, subscription, outcome, now, members);
543
+ }
544
+
545
+ /** Ends one attempt without an outcome to retry; the ledger keeps the class. */
546
+ async #deadLetter(
547
+ attempt: DeliveryAttempt,
548
+ now: number,
549
+ errorClass: DeliveryErrorClass,
550
+ ): Promise<void> {
551
+ await this.#options.repository.completeDelivery({
552
+ tenantId: attempt.tenantId,
553
+ id: attempt.id,
554
+ status: 'dead-letter',
555
+ completedAt: now,
556
+ responseStatus: null,
557
+ errorClass,
558
+ });
559
+ }
560
+
561
+ /**
562
+ * One message to one member, through the platform port. The address comes
563
+ * from auth.core at send time and the body from the member's own inbox item,
564
+ * so nothing about the person is stored in this module's queue. A
565
+ * `deadLetter` result means no later pass would do better.
566
+ */
567
+ async #sendEmail(
568
+ attempt: DeliveryAttempt,
569
+ members: MemberLookup,
570
+ ): Promise<DeliveryOutcome | PermanentEmailFailure> {
571
+ const recipient = attempt.recipientAccountId;
572
+ if (!recipient) return UNREACHABLE_RECIPIENT;
573
+ let member: TenantMemberScopes | undefined;
574
+ try {
575
+ member = (await members(attempt.tenantId)).byAccount.get(recipient);
576
+ } catch {
577
+ /* auth.core being unavailable is not this member's fault: the attempt
578
+ keeps its budget and the next pass asks again. */
579
+ return failed('network');
580
+ }
581
+ /* The workspace no longer holds the member, so there is no address to
582
+ resolve and none is kept here to fall back on. */
583
+ if (!member?.email) return UNREACHABLE_RECIPIENT;
584
+ const item = await this.#options.repository.findInboxItem(
585
+ attempt.tenantId,
586
+ recipient,
587
+ attempt.kind,
588
+ attempt.sourceRef,
589
+ );
590
+ if (!item) return UNREACHABLE_RECIPIENT;
591
+ try {
592
+ await this.#options.mail.send(
593
+ notificationMailMessage(
594
+ item,
595
+ member.email,
596
+ await this.#locale(attempt.tenantId),
597
+ ),
598
+ );
599
+ return { status: 'succeeded', responseStatus: null, errorClass: null };
600
+ } catch (error) {
601
+ return classifyMailError(error);
602
+ }
603
+ }
604
+
605
+ async #send(
606
+ subscription: StoredWebhookSubscription,
607
+ body: string,
608
+ now: number,
609
+ ): Promise<DeliveryOutcome> {
610
+ let url: URL;
611
+ let addresses: readonly ResolvedAddress[];
612
+ try {
613
+ url = new URL(subscription.url);
614
+ /* The save path is the only writer of this row and refuses anything but
615
+ https, but the socket is opened here, so the scheme is refused again
616
+ immediately before it. */
617
+ if (url.protocol !== 'https:') {
618
+ throw new WebhookEgressError(
619
+ 'WEBHOOK_URL_BLOCKED',
620
+ 'A webhook is delivered over https only.',
621
+ );
622
+ }
623
+ /* Resolution is re-checked on every delivery: a name that was public at
624
+ save time can start answering with a private address. The accepted
625
+ addresses are the only ones the connection is allowed to reach, so
626
+ nothing between this check and the socket may resolve the name again. */
627
+ addresses = await this.#options.policy().assertResolvable(url.hostname);
628
+ } catch (error) {
629
+ return classifyError(error);
630
+ }
631
+ let secret: string;
632
+ try {
633
+ secret = this.#options.vault.decrypt(
634
+ subscription.secret,
635
+ secretContext(subscription.tenantId, subscription.id),
636
+ );
637
+ } catch {
638
+ return {
639
+ status: 'failed',
640
+ responseStatus: null,
641
+ errorClass: 'egress-refused',
642
+ };
643
+ }
644
+ const timestamp = String(now);
645
+ return this.#transport.send({
646
+ url: url.toString(),
647
+ body,
648
+ timestamp,
649
+ signature: webhookSignatureHeader(secret, timestamp, body),
650
+ addresses,
651
+ });
652
+ }
653
+
654
+ async #record(
655
+ attempt: DeliveryAttempt,
656
+ subscription: StoredWebhookSubscription | null,
657
+ outcome: DeliveryOutcome,
658
+ now: number,
659
+ members: MemberLookup,
660
+ ): Promise<void> {
661
+ const { retryMaxAttempts, retryMaxBackoffMinutes } =
662
+ await this.#options.settings(attempt.tenantId);
663
+ const exhausted = attempt.attemptNumber >= retryMaxAttempts;
664
+ const status =
665
+ outcome.status === 'succeeded'
666
+ ? 'succeeded'
667
+ : exhausted
668
+ ? 'dead-letter'
669
+ : 'failed';
670
+ const written = await this.#options.repository.completeDelivery({
671
+ tenantId: attempt.tenantId,
672
+ id: attempt.id,
673
+ status,
674
+ completedAt: now,
675
+ responseStatus: outcome.responseStatus,
676
+ errorClass: outcome.errorClass,
677
+ });
678
+ /* Another worker finished this attempt first; it owns what follows. */
679
+ if (!written) return;
680
+ if (subscription) {
681
+ await this.#options.repository.stampSubscriptionDelivery(
682
+ attempt.tenantId,
683
+ subscription.id,
684
+ now,
685
+ );
686
+ }
687
+ if (status === 'succeeded') return;
688
+ if (status === 'failed') {
689
+ await this.#append(
690
+ attempt,
691
+ attempt.sequence,
692
+ attempt.attemptNumber + 1,
693
+ now + backoffMs(attempt.attemptNumber, retryMaxBackoffMinutes),
694
+ );
695
+ return;
696
+ }
697
+ /* An e-mail attempt has no subscription, and its dead letter writes no
698
+ inbox item either. That item would be mailed to every member who asked
699
+ for mail, fail the same way and dead-letter again under a new source
700
+ reference; the ledger is where a failed message is read. */
701
+ if (!subscription) return;
702
+ await this.#notifyDeadLetter(attempt, subscription, now, members);
703
+ }
704
+
705
+ async #append(
706
+ source: DeliveryAttempt,
707
+ sequence: number,
708
+ attemptNumber: number,
709
+ scheduledFor: number,
710
+ ): Promise<DeliveryAttempt | null> {
711
+ /* Both fingerprints are taken from the row alone, so the digest of a retry
712
+ and of a replay matches the one the first attempt recorded. */
713
+ const payload =
714
+ source.channel === 'email'
715
+ ? emailPayloadFingerprint({
716
+ tenantId: source.tenantId,
717
+ recipientAccountId: source.recipientAccountId ?? '',
718
+ kind: source.kind,
719
+ sourceModule: source.sourceModule,
720
+ sourceRef: source.sourceRef,
721
+ title: source.title,
722
+ occurredAt: source.occurredAt,
723
+ })
724
+ : webhookPayloadFingerprint({
725
+ tenantId: source.tenantId,
726
+ subscriptionId: source.subscriptionId ?? '',
727
+ kind: source.kind,
728
+ sourceModule: source.sourceModule,
729
+ sourceRef: source.sourceRef,
730
+ title: source.title,
731
+ occurredAt: source.occurredAt,
732
+ });
733
+ return this.#options.repository.appendDelivery({
734
+ id: randomUUID(),
735
+ tenantId: source.tenantId,
736
+ channel: source.channel,
737
+ subscriptionId: source.subscriptionId,
738
+ recipientAccountId: source.recipientAccountId,
739
+ kind: source.kind,
740
+ sourceModule: source.sourceModule,
741
+ sourceRef: source.sourceRef,
742
+ title: source.title,
743
+ sequence,
744
+ attemptNumber,
745
+ status: 'pending',
746
+ scheduledFor,
747
+ completedAt: null,
748
+ responseStatus: null,
749
+ errorClass: null,
750
+ payloadDigest: payload.digest,
751
+ payloadBytes: payload.bytes,
752
+ occurredAt: source.occurredAt,
753
+ createdAt: this.#now(),
754
+ });
755
+ }
756
+
757
+ /* Every member who can read the dead letter and has not switched the kind off
758
+ is told about it; the preference is applied by the same inbox write the
759
+ publication path uses. The row is keyed by the exhausted attempt, so a
760
+ second pass writes nothing. */
761
+ async #notifyDeadLetter(
762
+ attempt: DeliveryAttempt,
763
+ subscription: StoredWebhookSubscription,
764
+ now: number,
765
+ lookup: MemberLookup,
766
+ ): Promise<void> {
767
+ let members: readonly TenantMemberScopes[];
768
+ try {
769
+ members = (await lookup(attempt.tenantId)).list;
770
+ } catch {
771
+ /* auth.core being unavailable must not undo a recorded dead letter. */
772
+ return;
773
+ }
774
+ const records: NotificationsInbox[] = [];
775
+ for (const member of members) {
776
+ if (!member.scopes.includes(NOTIFICATIONS_PERMISSIONS.deliveriesRead)) {
777
+ continue;
778
+ }
779
+ records.push({
780
+ id: randomUUID(),
781
+ tenantId: attempt.tenantId,
782
+ recipientAccountId: member.accountId,
783
+ kind: 'webhook-dead-letter',
784
+ title: `Webhook delivery failed: ${subscription.name}`,
785
+ body: `Delivery of ${attempt.kind} for ${attempt.sourceRef} was moved to the dead letter after ${attempt.attemptNumber} attempts.`,
786
+ sourceModule: 'notifications.core',
787
+ sourceRef: attempt.id,
788
+ status: 'unread',
789
+ readAt: null,
790
+ createdAt: now,
791
+ });
792
+ }
793
+ await this.#options.repository.appendInboxItems(
794
+ attempt.tenantId,
795
+ records,
796
+ (item) => emailDeliveryAttempt(item, this.#now()),
797
+ );
798
+ }
799
+ }
800
+
801
+ /** One minute, doubling per attempt, clamped to the tenant maximum. */
802
+ export function backoffMs(
803
+ attemptNumber: number,
804
+ maximumMinutes: number,
805
+ ): number {
806
+ const doublings = Math.min(Math.max(attemptNumber, 1) - 1, 30);
807
+ return Math.min(
808
+ DELIVERY_BASE_BACKOFF_MS * 2 ** doublings,
809
+ maximumMinutes * 60_000,
810
+ );
811
+ }