@flowdular/sdk 0.2.4 → 0.3.0

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 (908) 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 +100 -0
  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/deploy-operate/SKILL.md +114 -0
  30. package/.ai/skills/module-new/SKILL.md +29 -3
  31. package/.ai/skills/module-update/SKILL.md +9 -3
  32. package/.ai/skills/perf-audit/SKILL.md +0 -1
  33. package/.ai/skills/release-eject-pr/SKILL.md +0 -1
  34. package/.ai/skills/spec-interview/SKILL.md +120 -0
  35. package/.ai/skills/test-hardening/SKILL.md +1 -0
  36. package/.ai/skills/ux-design/SKILL.md +34 -3
  37. package/.ai/skills/variables/SKILL.md +0 -2
  38. package/.ai/skills/workflow-development/SKILL.md +0 -1
  39. package/AGENTS.md +4 -0
  40. package/docs/agent-contract.md +2 -2
  41. package/docs/design-system.md +185 -31
  42. package/modules/access/migrations/0001_access_core.down.sql +1 -0
  43. package/modules/access/migrations/0001_access_core.up.sql +28 -0
  44. package/modules/access/migrations/README.md +3 -0
  45. package/modules/access/module.json +33 -0
  46. package/modules/access/package.json +43 -0
  47. package/modules/access/spec/module.yaml +225 -0
  48. package/modules/access/src/acl/permissions.ts +6 -0
  49. package/modules/access/src/api/endpoints.ts +244 -0
  50. package/modules/access/src/client/ActivityView.tsrx +245 -0
  51. package/modules/access/src/client/AttestationsView.tsrx +176 -0
  52. package/modules/access/src/client/ReviewView.tsrx +586 -0
  53. package/modules/access/src/client/api.ts +132 -0
  54. package/modules/access/src/client/contribution.tsrx +41 -0
  55. package/modules/access/src/client/index.ts +41 -0
  56. package/modules/access/src/client/navigation.ts +57 -0
  57. package/modules/access/src/client/presentation.ts +69 -0
  58. package/modules/access/src/client/state.ts +72 -0
  59. package/modules/access/src/domain/types.ts +189 -0
  60. package/modules/access/src/index.ts +38 -0
  61. package/modules/access/src/platform.ts +60 -0
  62. package/modules/access/src/server/index.ts +42 -0
  63. package/modules/access/src/server/runtime.ts +105 -0
  64. package/modules/access/src/services/access-service.ts +298 -0
  65. package/modules/access/src/services/audit-window.ts +78 -0
  66. package/modules/access/src/services/auth-directory.ts +72 -0
  67. package/modules/access/src/services/changes.ts +91 -0
  68. package/modules/access/src/services/data-classes.ts +28 -0
  69. package/modules/access/src/services/database-repository.ts +185 -0
  70. package/modules/access/src/services/directory.ts +102 -0
  71. package/modules/access/src/services/index.ts +33 -0
  72. package/modules/access/src/services/list-exports.ts +150 -0
  73. package/modules/access/src/services/migration.ts +54 -0
  74. package/modules/access/src/services/repository.ts +30 -0
  75. package/modules/access/src/services/review.ts +178 -0
  76. package/modules/access/translations/en.json +155 -0
  77. package/modules/access/translations/pl.json +155 -0
  78. package/modules/agents/migrations/0022_credential_rotation_inventory.down.sql +2 -0
  79. package/modules/agents/migrations/0022_credential_rotation_inventory.up.sql +7 -0
  80. package/modules/agents/migrations/0023_agents_retention_indexes.down.sql +2 -0
  81. package/modules/agents/migrations/0023_agents_retention_indexes.up.sql +9 -0
  82. package/modules/agents/migrations/0024_agent_meter_refusals.down.sql +3 -0
  83. package/modules/agents/migrations/0024_agent_meter_refusals.up.sql +22 -0
  84. package/modules/agents/migrations/0025_agent_list_indexes.down.sql +3 -0
  85. package/modules/agents/migrations/0025_agent_list_indexes.up.sql +11 -0
  86. package/modules/agents/module.json +30 -4
  87. package/modules/agents/package.json +2 -1
  88. package/modules/agents/spec/module.yaml +63 -5
  89. package/modules/agents/src/api/endpoints.ts +291 -33
  90. package/modules/agents/src/cli/commands.json +11 -0
  91. package/modules/agents/src/cli/index.ts +45 -0
  92. package/modules/agents/src/client/AgentDashboardWidget.tsrx +19 -11
  93. package/modules/agents/src/client/AgentDefinitionList.tsrx +53 -10
  94. package/modules/agents/src/client/AgentPlaygroundView.tsrx +4 -4
  95. package/modules/agents/src/client/AgentProceduresView.tsrx +2 -2
  96. package/modules/agents/src/client/AgentRunsView.tsrx +143 -40
  97. package/modules/agents/src/client/AgentsView.tsrx +109 -33
  98. package/modules/agents/src/client/api.ts +99 -21
  99. package/modules/agents/src/client/state.ts +97 -0
  100. package/modules/agents/src/domain/types.ts +44 -4
  101. package/modules/agents/src/platform.ts +42 -0
  102. package/modules/agents/src/server/action-execution.ts +201 -106
  103. package/modules/agents/src/server/runtime.ts +32 -0
  104. package/modules/agents/src/services/agent-service.ts +158 -30
  105. package/modules/agents/src/services/credential-rotation.ts +185 -0
  106. package/modules/agents/src/services/credential-vault.ts +71 -46
  107. package/modules/agents/src/services/data-classes.ts +176 -0
  108. package/modules/agents/src/services/database-repository.ts +393 -101
  109. package/modules/agents/src/services/metering.ts +111 -0
  110. package/modules/agents/src/services/migration.ts +109 -0
  111. package/modules/agents/src/services/module-agent-preflight.ts +17 -9
  112. package/modules/agents/src/services/notifications.ts +98 -0
  113. package/modules/agents/src/services/provider-repository.ts +9 -18
  114. package/modules/agents/src/services/provider-service.ts +1 -9
  115. package/modules/agents/src/services/reports.ts +107 -0
  116. package/modules/agents/src/services/repository.ts +86 -6
  117. package/modules/agents/src/services/usage-service.ts +2 -0
  118. package/modules/agents/src/services/worker.ts +114 -4
  119. package/modules/agents/src/settings.ts +14 -3
  120. package/modules/agents/translations/en.json +14 -4
  121. package/modules/agents/translations/pl.json +14 -4
  122. package/modules/approvals/migrations/0001_approvals_core.down.sql +3 -0
  123. package/modules/approvals/migrations/0001_approvals_core.up.sql +78 -0
  124. package/modules/approvals/migrations/0002_approvals_expiry_routing_role.down.sql +2 -0
  125. package/modules/approvals/migrations/0002_approvals_expiry_routing_role.up.sql +19 -0
  126. package/modules/approvals/migrations/0003_approvals_retention_indexes.down.sql +6 -0
  127. package/modules/approvals/migrations/0003_approvals_retention_indexes.up.sql +14 -0
  128. package/modules/approvals/migrations/0004_approvals_inbox_keyset_indexes.down.sql +5 -0
  129. package/modules/approvals/migrations/0004_approvals_inbox_keyset_indexes.up.sql +12 -0
  130. package/modules/approvals/migrations/README.md +3 -0
  131. package/modules/approvals/module.json +34 -0
  132. package/modules/approvals/package.json +43 -0
  133. package/modules/approvals/spec/module.yaml +318 -0
  134. package/modules/approvals/src/acl/permissions.ts +7 -0
  135. package/modules/approvals/src/api/endpoints.ts +457 -0
  136. package/modules/approvals/src/client/ApprovalRequestDrawer.tsrx +138 -0
  137. package/modules/approvals/src/client/ApprovalsView.tsrx +562 -0
  138. package/modules/approvals/src/client/PendingCountWidget.tsrx +52 -0
  139. package/modules/approvals/src/client/api.ts +203 -0
  140. package/modules/approvals/src/client/approvals.css +51 -0
  141. package/modules/approvals/src/client/contribution.tsrx +44 -0
  142. package/modules/approvals/src/client/index.ts +26 -0
  143. package/modules/approvals/src/client/navigation.ts +39 -0
  144. package/modules/approvals/src/client/pending-count.ts +26 -0
  145. package/modules/approvals/src/client/presentation.ts +52 -0
  146. package/modules/approvals/src/client/state.ts +141 -0
  147. package/modules/approvals/src/domain/capability.ts +95 -0
  148. package/modules/approvals/src/domain/types.ts +154 -0
  149. package/modules/approvals/src/index.ts +52 -0
  150. package/modules/approvals/src/platform.ts +128 -0
  151. package/modules/approvals/src/server/index.ts +42 -0
  152. package/modules/approvals/src/server/runtime.ts +181 -0
  153. package/modules/approvals/src/services/approvals-service.ts +557 -0
  154. package/modules/approvals/src/services/callbacks.ts +75 -0
  155. package/modules/approvals/src/services/data-classes.ts +167 -0
  156. package/modules/approvals/src/services/database-repository.ts +724 -0
  157. package/modules/approvals/src/services/eligibility.ts +121 -0
  158. package/modules/approvals/src/services/expiry-runner.ts +81 -0
  159. package/modules/approvals/src/services/index.ts +31 -0
  160. package/modules/approvals/src/services/migration.ts +222 -0
  161. package/modules/approvals/src/services/notifications.ts +95 -0
  162. package/modules/approvals/src/services/repository.ts +161 -0
  163. package/modules/approvals/src/services/service-error.ts +70 -0
  164. package/modules/approvals/src/settings.ts +102 -0
  165. package/modules/approvals/translations/en.json +104 -0
  166. package/modules/approvals/translations/pl.json +104 -0
  167. package/modules/audit/migrations/0001_audit_core.down.sql +8 -0
  168. package/modules/audit/migrations/0001_audit_core.up.sql +107 -0
  169. package/modules/audit/migrations/0002_audit_sweep_routing_role.down.sql +2 -0
  170. package/modules/audit/migrations/0002_audit_sweep_routing_role.up.sql +21 -0
  171. package/modules/audit/migrations/0003_audit_export_request.down.sql +12 -0
  172. package/modules/audit/migrations/0003_audit_export_request.up.sql +40 -0
  173. package/modules/audit/migrations/0004_audit_hold_seal_erasure.down.sql +17 -0
  174. package/modules/audit/migrations/0004_audit_hold_seal_erasure.up.sql +192 -0
  175. package/modules/audit/migrations/0005_audit_event_format.down.sql +17 -0
  176. package/modules/audit/migrations/0005_audit_event_format.up.sql +60 -0
  177. package/modules/audit/migrations/0006_audit_own_class_walks.down.sql +3 -0
  178. package/modules/audit/migrations/0006_audit_own_class_walks.up.sql +14 -0
  179. package/modules/audit/migrations/README.md +3 -0
  180. package/modules/audit/module.json +32 -0
  181. package/modules/audit/package.json +49 -0
  182. package/modules/audit/spec/module.yaml +809 -0
  183. package/modules/audit/src/acl/permissions.ts +7 -0
  184. package/modules/audit/src/api/endpoints.ts +315 -0
  185. package/modules/audit/src/cli/commands.json +95 -0
  186. package/modules/audit/src/cli/index.ts +658 -0
  187. package/modules/audit/src/client/DataClassesView.tsrx +420 -0
  188. package/modules/audit/src/client/ExportsView.tsrx +256 -0
  189. package/modules/audit/src/client/HoldsView.tsrx +604 -0
  190. package/modules/audit/src/client/SweepsView.tsrx +251 -0
  191. package/modules/audit/src/client/api.ts +185 -0
  192. package/modules/audit/src/client/contribution.tsrx +52 -0
  193. package/modules/audit/src/client/index.ts +23 -0
  194. package/modules/audit/src/client/navigation.ts +74 -0
  195. package/modules/audit/src/client/presentation.ts +105 -0
  196. package/modules/audit/src/client/state.ts +86 -0
  197. package/modules/audit/src/domain/data-classes.ts +16 -0
  198. package/modules/audit/src/domain/types.ts +339 -0
  199. package/modules/audit/src/index.ts +76 -0
  200. package/modules/audit/src/platform.ts +44 -0
  201. package/modules/audit/src/server/index.ts +177 -0
  202. package/modules/audit/src/server/runtime.ts +303 -0
  203. package/modules/audit/src/services/anchor-key.ts +143 -0
  204. package/modules/audit/src/services/anchor-rotation.ts +147 -0
  205. package/modules/audit/src/services/audit-runners.ts +278 -0
  206. package/modules/audit/src/services/backup-guard.ts +95 -0
  207. package/modules/audit/src/services/database-repository.ts +1946 -0
  208. package/modules/audit/src/services/declared-classes.ts +64 -0
  209. package/modules/audit/src/services/erasure-port.ts +126 -0
  210. package/modules/audit/src/services/erasure-service.ts +770 -0
  211. package/modules/audit/src/services/export-directory.ts +106 -0
  212. package/modules/audit/src/services/export-service.ts +714 -0
  213. package/modules/audit/src/services/hold-service.ts +295 -0
  214. package/modules/audit/src/services/index.ts +17 -0
  215. package/modules/audit/src/services/migration.ts +658 -0
  216. package/modules/audit/src/services/own-classes.ts +318 -0
  217. package/modules/audit/src/services/platform-version.ts +23 -0
  218. package/modules/audit/src/services/repository.ts +495 -0
  219. package/modules/audit/src/services/retention-service.ts +191 -0
  220. package/modules/audit/src/services/seal-service.ts +769 -0
  221. package/modules/audit/src/services/service-error.ts +61 -0
  222. package/modules/audit/src/services/subject-keys.ts +90 -0
  223. package/modules/audit/src/services/sweep-service.ts +298 -0
  224. package/modules/audit/src/services/zip.ts +217 -0
  225. package/modules/audit/src/settings.ts +69 -0
  226. package/modules/audit/translations/en.json +210 -0
  227. package/modules/audit/translations/pl.json +210 -0
  228. package/modules/auth/README.md +77 -29
  229. package/modules/auth/migrations/0016_external_identities.up.sql +16 -0
  230. package/modules/auth/migrations/0017_mfa_key_id.up.sql +8 -0
  231. package/modules/auth/migrations/0018_retire_bundled_module_scopes.up.sql +29 -0
  232. package/modules/auth/migrations/0019_notifications_member_scopes.up.sql +44 -0
  233. package/modules/auth/migrations/0020_identity_providers.up.sql +61 -0
  234. package/modules/auth/migrations/0021_membership_status.up.sql +19 -0
  235. package/modules/auth/migrations/0022_auth_provider_scopes.up.sql +45 -0
  236. package/modules/auth/migrations/0023_enterprise_module_scopes.down.sql +19 -0
  237. package/modules/auth/migrations/0023_enterprise_module_scopes.up.sql +71 -0
  238. package/modules/auth/migrations/0024_approvals_member_scopes.down.sql +22 -0
  239. package/modules/auth/migrations/0024_approvals_member_scopes.up.sql +48 -0
  240. package/modules/auth/migrations/0025_audit_holds_owner_scope.down.sql +21 -0
  241. package/modules/auth/migrations/0025_audit_holds_owner_scope.up.sql +47 -0
  242. package/modules/auth/migrations/0026_auth_export_keyset_indexes.down.sql +6 -0
  243. package/modules/auth/migrations/0026_auth_export_keyset_indexes.up.sql +15 -0
  244. package/modules/auth/migrations/0027_workflow_automation_profile_scopes.down.sql +34 -0
  245. package/modules/auth/migrations/0027_workflow_automation_profile_scopes.up.sql +72 -0
  246. package/modules/auth/migrations/0028_auth_member_search_prefix_indexes.down.sql +6 -0
  247. package/modules/auth/migrations/0028_auth_member_search_prefix_indexes.up.sql +21 -0
  248. package/modules/auth/migrations/0029_reports_exports_access_scopes.down.sql +22 -0
  249. package/modules/auth/migrations/0029_reports_exports_access_scopes.up.sql +56 -0
  250. package/modules/auth/migrations/0030_auth_membership_keyset_index.down.sql +4 -0
  251. package/modules/auth/migrations/0030_auth_membership_keyset_index.up.sql +10 -0
  252. package/modules/auth/migrations/0031_membership_scope_backfills_under_rls.down.sql +4 -0
  253. package/modules/auth/migrations/0031_membership_scope_backfills_under_rls.up.sql +31 -0
  254. package/modules/auth/migrations/0032_audit_actor_service.down.sql +9 -0
  255. package/modules/auth/migrations/0032_audit_actor_service.up.sql +10 -0
  256. package/modules/auth/migrations/0033_auth_account_keyset_indexes.down.sql +5 -0
  257. package/modules/auth/migrations/0033_auth_account_keyset_indexes.up.sql +23 -0
  258. package/modules/auth/module.json +3 -3
  259. package/modules/auth/package.json +2 -1
  260. package/modules/auth/spec/module.yaml +372 -3
  261. package/modules/auth/src/acl/scopes.ts +50 -6
  262. package/modules/auth/src/cli/commands.json +11 -0
  263. package/modules/auth/src/cli/greenfield.ts +2 -2
  264. package/modules/auth/src/cli/index.ts +14 -0
  265. package/modules/auth/src/cli/secrets.ts +114 -0
  266. package/modules/auth/src/client/AuthenticationCore.tsrx +61 -8
  267. package/modules/auth/src/client/api.ts +72 -6
  268. package/modules/auth/src/client/contribution.tsrx +23 -0
  269. package/modules/auth/src/client/index.ts +6 -0
  270. package/modules/auth/src/client/providers/IdentityProviderForm.tsrx +191 -0
  271. package/modules/auth/src/client/providers/IdentityProvidersView.tsrx +358 -0
  272. package/modules/auth/src/client/providers/api.ts +128 -0
  273. package/modules/auth/src/client/providers/provider-columns.tsrx +60 -0
  274. package/modules/auth/src/client/providers/state.ts +35 -0
  275. package/modules/auth/src/client/security/SecurityView.tsrx +9 -1
  276. package/modules/auth/src/client/state.ts +15 -1
  277. package/modules/auth/src/domain/types.ts +55 -0
  278. package/modules/auth/src/index.ts +11 -1
  279. package/modules/auth/src/middleware/authentication.ts +4 -0
  280. package/modules/auth/src/server/endpoints.ts +467 -171
  281. package/modules/auth/src/server/http.ts +3 -2
  282. package/modules/auth/src/server/index.ts +22 -1
  283. package/modules/auth/src/server/membership-endpoints.ts +62 -0
  284. package/modules/auth/src/server/mfa-enforcement.ts +156 -0
  285. package/modules/auth/src/server/oidc.ts +389 -0
  286. package/modules/auth/src/server/provider-endpoints.ts +246 -0
  287. package/modules/auth/src/server/provider-host.ts +77 -0
  288. package/modules/auth/src/server/runtime.ts +231 -55
  289. package/modules/auth/src/services/auth-service-error.ts +7 -2
  290. package/modules/auth/src/services/auth-service.ts +948 -51
  291. package/modules/auth/src/services/data-classes.ts +236 -0
  292. package/modules/auth/src/services/database-repository.ts +853 -71
  293. package/modules/auth/src/services/identity-provider-service.ts +571 -0
  294. package/modules/auth/src/services/mail-delivery.ts +16 -16
  295. package/modules/auth/src/services/mail-message.ts +54 -0
  296. package/modules/auth/src/services/mail-port.ts +24 -0
  297. package/modules/auth/src/services/mail-smtp.ts +85 -0
  298. package/modules/auth/src/services/mfa-rotation.ts +144 -0
  299. package/modules/auth/src/services/migration.ts +810 -0
  300. package/modules/auth/src/services/password.ts +14 -0
  301. package/modules/auth/src/services/provider-secret-rotation.ts +169 -0
  302. package/modules/auth/src/services/provider-secrets.ts +136 -0
  303. package/modules/auth/src/services/repository.ts +321 -5
  304. package/modules/auth/src/services/session-sweep-runner.ts +73 -0
  305. package/modules/auth/src/services/settings-store.ts +10 -83
  306. package/modules/auth/src/services/totp.ts +88 -62
  307. package/modules/auth/src/services/validation.ts +194 -7
  308. package/modules/auth/src/settings.ts +18 -0
  309. package/modules/auth/translations/en.json +84 -1
  310. package/modules/auth/translations/pl.json +84 -1
  311. package/modules/automations/migrations/0005_secret_rotation_inventory.down.sql +1 -0
  312. package/modules/automations/migrations/0005_secret_rotation_inventory.up.sql +6 -0
  313. package/modules/automations/migrations/0006_automations_list_sort_indexes.down.sql +4 -0
  314. package/modules/automations/migrations/0006_automations_list_sort_indexes.up.sql +11 -0
  315. package/modules/automations/module.json +24 -6
  316. package/modules/automations/package.json +4 -1
  317. package/modules/automations/spec/module.yaml +81 -7
  318. package/modules/automations/src/api/endpoints.ts +202 -28
  319. package/modules/automations/src/cli/commands.json +17 -0
  320. package/modules/automations/src/cli/index.ts +114 -0
  321. package/modules/automations/src/client/AutomationScheduleForm.tsrx +77 -19
  322. package/modules/automations/src/client/AutomationSchedulesView.tsrx +144 -40
  323. package/modules/automations/src/client/AutomationTriggersView.tsrx +131 -32
  324. package/modules/automations/src/client/api.ts +62 -19
  325. package/modules/automations/src/client/presentation.ts +20 -2
  326. package/modules/automations/src/client/state.ts +84 -0
  327. package/modules/automations/src/domain/cadence.ts +99 -3
  328. package/modules/automations/src/domain/cron.ts +366 -0
  329. package/modules/automations/src/domain/time-zone.ts +61 -0
  330. package/modules/automations/src/platform.ts +38 -4
  331. package/modules/automations/src/server/index.ts +11 -0
  332. package/modules/automations/src/server/runtime.ts +46 -22
  333. package/modules/{automations-workflows-integration/src/server/adapter.ts → automations/src/server/workflow-target.ts} +13 -14
  334. package/modules/{automations-workflows-integration/src/server/tools.ts → automations/src/server/workflow-tools.ts} +0 -0
  335. package/modules/automations/src/services/data-classes.ts +62 -0
  336. package/modules/automations/src/services/database-repository.ts +152 -38
  337. package/modules/automations/src/services/migration.ts +119 -9
  338. package/modules/automations/src/services/repository.ts +52 -1
  339. package/modules/automations/src/services/schedule-runner.ts +84 -0
  340. package/modules/automations/src/services/schedule-service.ts +152 -26
  341. package/modules/automations/src/services/secret-rotation.ts +176 -0
  342. package/modules/automations/src/services/secret-vault.ts +68 -41
  343. package/modules/automations/src/services/trigger-service.ts +13 -10
  344. package/modules/automations/translations/en.json +15 -2
  345. package/modules/automations/translations/pl.json +15 -2
  346. package/modules/connectors/migrations/0001_connectors_core.down.sql +3 -0
  347. package/modules/connectors/migrations/0001_connectors_core.up.sql +72 -0
  348. package/modules/connectors/migrations/0002_connectors_call_keys.down.sql +3 -0
  349. package/modules/connectors/migrations/0002_connectors_call_keys.up.sql +18 -0
  350. package/modules/connectors/migrations/README.md +3 -0
  351. package/modules/connectors/module.json +28 -0
  352. package/modules/{automations-workflows-integration → connectors}/package.json +27 -26
  353. package/modules/connectors/spec/module.yaml +447 -0
  354. package/modules/connectors/src/acl/permissions.ts +6 -0
  355. package/modules/connectors/src/agent/tools.ts +180 -0
  356. package/modules/connectors/src/api/endpoints.ts +572 -0
  357. package/modules/connectors/src/client/ConnectorCallsView.tsrx +358 -0
  358. package/modules/connectors/src/client/ConnectorForm.tsrx +424 -0
  359. package/modules/connectors/src/client/ConnectorsView.tsrx +711 -0
  360. package/modules/connectors/src/client/api.ts +281 -0
  361. package/modules/connectors/src/client/consent.ts +48 -0
  362. package/modules/connectors/src/client/contribution.tsrx +37 -0
  363. package/modules/connectors/src/client/index.ts +22 -0
  364. package/modules/connectors/src/client/navigation.ts +42 -0
  365. package/modules/connectors/src/client/presentation.ts +38 -0
  366. package/modules/connectors/src/client/state.ts +175 -0
  367. package/modules/connectors/src/domain/calls.ts +70 -0
  368. package/modules/connectors/src/domain/definitions.ts +190 -0
  369. package/modules/connectors/src/domain/http-json.ts +68 -0
  370. package/modules/connectors/src/domain/types.ts +185 -0
  371. package/modules/connectors/src/index.ts +64 -0
  372. package/modules/connectors/src/platform.ts +56 -0
  373. package/modules/connectors/src/server/index.ts +66 -0
  374. package/modules/connectors/src/server/runtime.ts +163 -0
  375. package/modules/connectors/src/services/call-service.ts +903 -0
  376. package/modules/connectors/src/services/connectors-service.ts +653 -0
  377. package/modules/connectors/src/services/credential-vault.ts +188 -0
  378. package/modules/connectors/src/services/data-classes.ts +158 -0
  379. package/modules/connectors/src/services/database-repository.ts +897 -0
  380. package/modules/connectors/src/services/egress.ts +261 -0
  381. package/modules/connectors/src/services/index.ts +19 -0
  382. package/modules/connectors/src/services/migration.ts +166 -0
  383. package/modules/connectors/src/services/repository.ts +175 -0
  384. package/modules/connectors/src/services/service-error.ts +46 -0
  385. package/modules/connectors/src/settings.ts +69 -0
  386. package/modules/connectors/translations/en.json +191 -0
  387. package/modules/connectors/translations/pl.json +191 -0
  388. package/modules/directory/migrations/0001_directory_core.down.sql +5 -0
  389. package/modules/directory/migrations/0001_directory_core.up.sql +111 -0
  390. package/modules/directory/migrations/README.md +3 -0
  391. package/modules/directory/module.json +27 -0
  392. package/modules/directory/package.json +46 -0
  393. package/modules/directory/spec/module.yaml +351 -0
  394. package/modules/directory/src/acl/permissions.ts +7 -0
  395. package/modules/directory/src/api/endpoints.ts +478 -0
  396. package/modules/directory/src/api/scim-endpoints.ts +516 -0
  397. package/modules/directory/src/client/GroupMappingsView.tsrx +430 -0
  398. package/modules/directory/src/client/ProvisioningLogView.tsrx +248 -0
  399. package/modules/directory/src/client/ScimTokensView.tsrx +587 -0
  400. package/modules/directory/src/client/api.ts +222 -0
  401. package/modules/directory/src/client/contribution.tsrx +46 -0
  402. package/modules/directory/src/client/index.ts +22 -0
  403. package/modules/directory/src/client/navigation.ts +57 -0
  404. package/modules/directory/src/client/presentation.ts +143 -0
  405. package/modules/directory/src/client/state.ts +173 -0
  406. package/modules/directory/src/domain/scim.ts +346 -0
  407. package/modules/directory/src/domain/types.ts +166 -0
  408. package/modules/directory/src/index.ts +44 -0
  409. package/modules/directory/src/platform.ts +43 -0
  410. package/modules/directory/src/server/index.ts +17 -0
  411. package/modules/directory/src/server/runtime.ts +124 -0
  412. package/modules/directory/src/services/auth-port.ts +127 -0
  413. package/modules/directory/src/services/data-classes.ts +41 -0
  414. package/modules/directory/src/services/database-repository.ts +1067 -0
  415. package/modules/directory/src/services/directory-service.ts +311 -0
  416. package/modules/directory/src/services/index.ts +43 -0
  417. package/modules/directory/src/services/migration.ts +146 -0
  418. package/modules/directory/src/services/provisioning-service.ts +1420 -0
  419. package/modules/directory/src/services/rate-limiter.ts +103 -0
  420. package/modules/directory/src/services/repository.ts +208 -0
  421. package/modules/directory/src/services/service-error.ts +42 -0
  422. package/modules/directory/src/services/token-service.ts +215 -0
  423. package/modules/directory/src/settings.ts +86 -0
  424. package/modules/directory/translations/en.json +185 -0
  425. package/modules/directory/translations/pl.json +185 -0
  426. package/modules/documents/migrations/0001_documents_core.down.sql +1 -0
  427. package/modules/documents/migrations/0001_documents_core.up.sql +35 -0
  428. package/modules/documents/migrations/0002_documents_files_page.down.sql +1 -0
  429. package/modules/documents/migrations/0002_documents_files_page.up.sql +6 -0
  430. package/modules/documents/migrations/README.md +3 -0
  431. package/modules/documents/module.json +28 -0
  432. package/modules/documents/package.json +49 -0
  433. package/modules/documents/spec/module.yaml +247 -0
  434. package/modules/documents/src/acl/permissions.ts +6 -0
  435. package/modules/documents/src/api/endpoints.ts +401 -0
  436. package/modules/documents/src/client/DocumentUploader.tsrx +148 -0
  437. package/modules/documents/src/client/DocumentsView.tsrx +540 -0
  438. package/modules/documents/src/client/api.ts +209 -0
  439. package/modules/documents/src/client/contribution.tsrx +29 -0
  440. package/modules/documents/src/client/download.ts +70 -0
  441. package/modules/documents/src/client/index.ts +22 -0
  442. package/modules/documents/src/client/navigation.ts +25 -0
  443. package/modules/documents/src/client/presentation.ts +110 -0
  444. package/modules/documents/src/client/state.ts +117 -0
  445. package/modules/documents/src/domain/attachments.ts +84 -0
  446. package/modules/documents/src/domain/types.ts +80 -0
  447. package/modules/documents/src/index.ts +46 -0
  448. package/modules/documents/src/platform.ts +61 -0
  449. package/modules/documents/src/server/index.ts +30 -0
  450. package/modules/documents/src/server/runtime.ts +107 -0
  451. package/modules/documents/src/services/attachments.ts +39 -0
  452. package/modules/documents/src/services/data-classes.ts +25 -0
  453. package/modules/documents/src/services/database-repository.ts +259 -0
  454. package/modules/documents/src/services/documents-service.ts +586 -0
  455. package/modules/documents/src/services/index.ts +18 -0
  456. package/modules/documents/src/services/migration.ts +82 -0
  457. package/modules/documents/src/services/repository.ts +48 -0
  458. package/modules/documents/src/settings.ts +107 -0
  459. package/modules/documents/translations/en.json +111 -0
  460. package/modules/documents/translations/pl.json +111 -0
  461. package/modules/exports/migrations/0001_exports_core.down.sql +2 -0
  462. package/modules/exports/migrations/0001_exports_core.up.sql +28 -0
  463. package/modules/exports/migrations/0002_exports_job_routing_role.down.sql +4 -0
  464. package/modules/exports/migrations/0002_exports_job_routing_role.up.sql +21 -0
  465. package/modules/exports/migrations/README.md +3 -0
  466. package/modules/exports/module.json +28 -0
  467. package/modules/exports/package.json +44 -0
  468. package/modules/exports/spec/module.yaml +229 -0
  469. package/modules/exports/src/acl/permissions.ts +6 -0
  470. package/modules/exports/src/api/endpoints.ts +211 -0
  471. package/modules/exports/src/client/ExportsView.tsrx +327 -0
  472. package/modules/exports/src/client/api.ts +133 -0
  473. package/modules/exports/src/client/contribution.tsrx +31 -0
  474. package/modules/exports/src/client/index.ts +20 -0
  475. package/modules/exports/src/client/navigation.ts +25 -0
  476. package/modules/exports/src/client/presentation.ts +53 -0
  477. package/modules/exports/src/client/state.ts +56 -0
  478. package/modules/exports/src/domain/lists.ts +29 -0
  479. package/modules/exports/src/domain/types.ts +120 -0
  480. package/modules/exports/src/index.ts +41 -0
  481. package/modules/exports/src/platform.ts +80 -0
  482. package/modules/exports/src/server/index.ts +51 -0
  483. package/modules/exports/src/server/runtime.ts +160 -0
  484. package/modules/exports/src/services/data-classes.ts +56 -0
  485. package/modules/exports/src/services/database-repository.ts +405 -0
  486. package/modules/exports/src/services/export-runner.ts +123 -0
  487. package/modules/exports/src/services/export-service.ts +356 -0
  488. package/modules/exports/src/services/index.ts +6 -0
  489. package/modules/exports/src/services/list-registry.ts +105 -0
  490. package/modules/exports/src/services/migration.ts +89 -0
  491. package/modules/exports/src/services/repository.ts +97 -0
  492. package/modules/exports/src/settings.ts +70 -0
  493. package/modules/exports/translations/en.json +69 -0
  494. package/modules/exports/translations/pl.json +69 -0
  495. package/modules/import/migrations/0001_import_core.down.sql +6 -0
  496. package/modules/import/migrations/0001_import_core.up.sql +61 -0
  497. package/modules/import/migrations/0002_import_job_routing_role.down.sql +4 -0
  498. package/modules/import/migrations/0002_import_job_routing_role.up.sql +20 -0
  499. package/modules/import/migrations/0003_import_jobs_export_index.down.sql +1 -0
  500. package/modules/import/migrations/0003_import_jobs_export_index.up.sql +7 -0
  501. package/modules/import/migrations/0004_import_jobs_traceparent.down.sql +1 -0
  502. package/modules/import/migrations/0004_import_jobs_traceparent.up.sql +7 -0
  503. package/modules/import/migrations/README.md +3 -0
  504. package/modules/import/module.json +37 -0
  505. package/modules/import/package.json +50 -0
  506. package/modules/import/spec/module.yaml +335 -0
  507. package/modules/import/src/acl/permissions.ts +6 -0
  508. package/modules/import/src/api/endpoints.ts +400 -0
  509. package/modules/import/src/client/ImportJobDrawer.tsrx +229 -0
  510. package/modules/import/src/client/ImportsView.tsrx +455 -0
  511. package/modules/import/src/client/NewImportForm.tsrx +274 -0
  512. package/modules/import/src/client/api.ts +243 -0
  513. package/modules/import/src/client/contribution.tsrx +29 -0
  514. package/modules/import/src/client/index.ts +23 -0
  515. package/modules/import/src/client/navigation.ts +25 -0
  516. package/modules/import/src/client/presentation.ts +59 -0
  517. package/modules/import/src/client/state.ts +43 -0
  518. package/modules/import/src/domain/csv.ts +258 -0
  519. package/modules/import/src/domain/ports.ts +157 -0
  520. package/modules/import/src/domain/types.ts +179 -0
  521. package/modules/import/src/index.ts +58 -0
  522. package/modules/import/src/platform.ts +60 -0
  523. package/modules/import/src/server/index.ts +49 -0
  524. package/modules/import/src/server/runtime.ts +158 -0
  525. package/modules/import/src/services/csv-source.ts +121 -0
  526. package/modules/import/src/services/data-classes.ts +63 -0
  527. package/modules/import/src/services/database-repository.ts +780 -0
  528. package/modules/import/src/services/import-runner.ts +127 -0
  529. package/modules/import/src/services/import-service.ts +872 -0
  530. package/modules/import/src/services/index.ts +6 -0
  531. package/modules/import/src/services/migration.ts +156 -0
  532. package/modules/import/src/services/port-registry.ts +158 -0
  533. package/modules/import/src/services/repository.ts +147 -0
  534. package/modules/import/src/settings.ts +70 -0
  535. package/modules/import/translations/en.json +175 -0
  536. package/modules/import/translations/pl.json +175 -0
  537. package/modules/metering/migrations/0001_metering_core.down.sql +6 -0
  538. package/modules/metering/migrations/0001_metering_core.up.sql +119 -0
  539. package/modules/metering/migrations/0002_metering_bucket_export.down.sql +3 -0
  540. package/modules/metering/migrations/0002_metering_bucket_export.up.sql +5 -0
  541. package/modules/metering/migrations/README.md +3 -0
  542. package/modules/metering/module.json +46 -0
  543. package/modules/metering/package.json +50 -0
  544. package/modules/metering/spec/module.yaml +269 -0
  545. package/modules/metering/src/acl/permissions.ts +5 -0
  546. package/modules/metering/src/api/endpoints.ts +104 -0
  547. package/modules/metering/src/cli/commands.json +28 -0
  548. package/modules/metering/src/cli/index.ts +246 -0
  549. package/modules/metering/src/client/LimitsView.tsrx +170 -0
  550. package/modules/metering/src/client/UsageSummaryWidget.tsrx +63 -0
  551. package/modules/metering/src/client/UsageView.tsrx +205 -0
  552. package/modules/metering/src/client/api.ts +91 -0
  553. package/modules/metering/src/client/contribution.tsrx +42 -0
  554. package/modules/metering/src/client/index.ts +26 -0
  555. package/modules/metering/src/client/navigation.ts +54 -0
  556. package/modules/metering/src/client/presentation.ts +63 -0
  557. package/modules/metering/src/client/state.ts +31 -0
  558. package/modules/metering/src/domain/meters.ts +100 -0
  559. package/modules/metering/src/domain/types.ts +71 -0
  560. package/modules/metering/src/index.ts +51 -0
  561. package/modules/metering/src/platform.ts +84 -0
  562. package/modules/metering/src/server/index.ts +40 -0
  563. package/modules/metering/src/server/runtime.ts +165 -0
  564. package/modules/metering/src/services/data-classes.ts +34 -0
  565. package/modules/metering/src/services/database-repository.ts +574 -0
  566. package/modules/metering/src/services/index.ts +9 -0
  567. package/modules/metering/src/services/meter-registry.ts +145 -0
  568. package/modules/metering/src/services/metering-service.ts +441 -0
  569. package/modules/metering/src/services/migration.ts +183 -0
  570. package/modules/metering/src/services/notifications.ts +75 -0
  571. package/modules/metering/src/services/reports.ts +105 -0
  572. package/modules/metering/src/services/repository.ts +132 -0
  573. package/modules/metering/src/services/service-error.ts +46 -0
  574. package/modules/metering/src/settings.ts +47 -0
  575. package/modules/metering/translations/en.json +68 -0
  576. package/modules/metering/translations/pl.json +68 -0
  577. package/modules/notifications/migrations/0001_notifications_core.down.sql +1 -0
  578. package/modules/notifications/migrations/0001_notifications_core.up.sql +26 -0
  579. package/modules/notifications/migrations/0002_notifications_preferences.down.sql +1 -0
  580. package/modules/notifications/migrations/0002_notifications_preferences.up.sql +17 -0
  581. package/modules/notifications/migrations/0003_notifications_webhook_subscriptions.down.sql +1 -0
  582. package/modules/notifications/migrations/0003_notifications_webhook_subscriptions.up.sql +30 -0
  583. package/modules/notifications/migrations/0004_notifications_deliveries.down.sql +1 -0
  584. package/modules/notifications/migrations/0004_notifications_deliveries.up.sql +35 -0
  585. package/modules/notifications/migrations/0005_notifications_delivery_routing_role.down.sql +2 -0
  586. package/modules/notifications/migrations/0005_notifications_delivery_routing_role.up.sql +17 -0
  587. package/modules/notifications/migrations/0006_notifications_delivery_title.down.sql +1 -0
  588. package/modules/notifications/migrations/0006_notifications_delivery_title.up.sql +11 -0
  589. package/modules/notifications/migrations/0007_notifications_secret_rotation_inventory.down.sql +2 -0
  590. package/modules/notifications/migrations/0007_notifications_secret_rotation_inventory.up.sql +19 -0
  591. package/modules/notifications/migrations/0008_notifications_delivery_claim.down.sql +8 -0
  592. package/modules/notifications/migrations/0008_notifications_delivery_claim.up.sql +19 -0
  593. package/modules/notifications/migrations/0009_notifications_kind_approvals.down.sql +16 -0
  594. package/modules/notifications/migrations/0009_notifications_kind_approvals.up.sql +18 -0
  595. package/modules/notifications/migrations/0010_notifications_kind_meter_threshold.down.sql +16 -0
  596. package/modules/notifications/migrations/0010_notifications_kind_meter_threshold.up.sql +18 -0
  597. package/modules/notifications/migrations/0011_notifications_retention_keyset.down.sql +5 -0
  598. package/modules/notifications/migrations/0011_notifications_retention_keyset.up.sql +15 -0
  599. package/modules/notifications/migrations/0012_notifications_email_channel.down.sql +12 -0
  600. package/modules/notifications/migrations/0012_notifications_email_channel.up.sql +38 -0
  601. package/modules/notifications/migrations/0013_notifications_list_pages.down.sql +5 -0
  602. package/modules/notifications/migrations/0013_notifications_list_pages.up.sql +13 -0
  603. package/modules/notifications/migrations/README.md +3 -0
  604. package/modules/notifications/module.json +32 -0
  605. package/modules/notifications/package.json +49 -0
  606. package/modules/notifications/spec/module.yaml +718 -0
  607. package/modules/notifications/src/acl/permissions.ts +11 -0
  608. package/modules/notifications/src/api/endpoints.ts +814 -0
  609. package/modules/notifications/src/cli/commands.json +17 -0
  610. package/modules/notifications/src/cli/index.ts +126 -0
  611. package/modules/notifications/src/client/DeliveriesView.tsrx +483 -0
  612. package/modules/notifications/src/client/FactList.tsrx +24 -0
  613. package/modules/notifications/src/client/NotificationPreferencesView.tsrx +240 -0
  614. package/modules/notifications/src/client/NotificationsInboxView.tsrx +592 -0
  615. package/modules/notifications/src/client/UnreadCountWidget.tsrx +62 -0
  616. package/modules/notifications/src/client/WebhookForm.tsrx +297 -0
  617. package/modules/notifications/src/client/WebhooksView.tsrx +637 -0
  618. package/modules/notifications/src/client/api.ts +382 -0
  619. package/modules/notifications/src/client/contribution.tsrx +83 -0
  620. package/modules/notifications/src/client/inbox.ts +41 -0
  621. package/modules/notifications/src/client/index.ts +29 -0
  622. package/modules/notifications/src/client/navigation.ts +92 -0
  623. package/modules/notifications/src/client/notifications.css +70 -0
  624. package/modules/notifications/src/client/presentation.ts +81 -0
  625. package/modules/notifications/src/client/state.ts +246 -0
  626. package/modules/notifications/src/client/unread-count.ts +26 -0
  627. package/modules/notifications/src/domain/locale.ts +47 -0
  628. package/modules/notifications/src/domain/publish.ts +46 -0
  629. package/modules/notifications/src/domain/types.ts +186 -0
  630. package/modules/notifications/src/index.ts +62 -0
  631. package/modules/notifications/src/platform.ts +85 -0
  632. package/modules/notifications/src/server/index.ts +82 -0
  633. package/modules/notifications/src/server/runtime.ts +251 -0
  634. package/modules/notifications/src/services/data-classes.ts +139 -0
  635. package/modules/notifications/src/services/database-repository.ts +1334 -0
  636. package/modules/notifications/src/services/delivery-payload.ts +93 -0
  637. package/modules/notifications/src/services/delivery-runner.ts +170 -0
  638. package/modules/notifications/src/services/delivery-service.ts +811 -0
  639. package/modules/notifications/src/services/egress.ts +239 -0
  640. package/modules/notifications/src/services/email-channel.ts +93 -0
  641. package/modules/notifications/src/services/index.ts +23 -0
  642. package/modules/notifications/src/services/migration.ts +572 -0
  643. package/modules/notifications/src/services/notifications-service.ts +297 -0
  644. package/modules/notifications/src/services/paging.ts +60 -0
  645. package/modules/notifications/src/services/publish-service.ts +133 -0
  646. package/modules/notifications/src/services/repository.ts +342 -0
  647. package/modules/notifications/src/services/secret-rotation.ts +177 -0
  648. package/modules/notifications/src/services/secret-vault.ts +168 -0
  649. package/modules/notifications/src/services/service-error.ts +67 -0
  650. package/modules/notifications/src/services/signature.ts +81 -0
  651. package/modules/notifications/src/services/webhook-service.ts +307 -0
  652. package/modules/notifications/src/settings.ts +130 -0
  653. package/modules/notifications/translations/en.json +255 -0
  654. package/modules/notifications/translations/pl.json +255 -0
  655. package/modules/profile/module.json +3 -3
  656. package/modules/profile/package.json +1 -1
  657. package/modules/profile/spec/module.yaml +3 -3
  658. package/modules/profile/src/services/database-repository.ts +3 -13
  659. package/modules/reports/module.json +28 -0
  660. package/modules/reports/package.json +42 -0
  661. package/modules/reports/spec/module.yaml +231 -0
  662. package/modules/reports/src/acl/permissions.ts +5 -0
  663. package/modules/reports/src/api/endpoints.ts +72 -0
  664. package/modules/reports/src/client/ReportsSummaryWidget.tsrx +52 -0
  665. package/modules/reports/src/client/ReportsView.tsrx +246 -0
  666. package/modules/reports/src/client/api.ts +65 -0
  667. package/modules/reports/src/client/contribution.tsrx +36 -0
  668. package/modules/reports/src/client/index.ts +18 -0
  669. package/modules/reports/src/client/navigation.ts +39 -0
  670. package/modules/reports/src/client/presentation.ts +123 -0
  671. package/modules/reports/src/client/state.ts +28 -0
  672. package/modules/reports/src/domain/providers.ts +115 -0
  673. package/modules/reports/src/domain/types.ts +44 -0
  674. package/modules/reports/src/index.ts +47 -0
  675. package/modules/reports/src/platform.ts +37 -0
  676. package/modules/reports/src/server/index.ts +21 -0
  677. package/modules/reports/src/server/runtime.ts +40 -0
  678. package/modules/reports/src/services/index.ts +17 -0
  679. package/modules/reports/src/services/provider-registry.ts +144 -0
  680. package/modules/reports/src/services/range.ts +65 -0
  681. package/modules/reports/src/services/reports-service.ts +316 -0
  682. package/modules/reports/src/services/service-error.ts +26 -0
  683. package/modules/reports/src/settings.ts +49 -0
  684. package/modules/reports/translations/en.json +35 -0
  685. package/modules/reports/translations/pl.json +35 -0
  686. package/modules/sandbox/module.json +4 -4
  687. package/modules/sandbox/package.json +1 -1
  688. package/modules/sandbox/spec/module.yaml +3 -3
  689. package/modules/sandbox/src/services/database-repository.ts +14 -23
  690. package/modules/sandbox/src/services/directory.ts +16 -0
  691. package/modules/sandbox/src/services/sandbox-service.ts +13 -11
  692. package/modules/search/migrations/0001_search_core.down.sql +1 -0
  693. package/modules/search/migrations/0001_search_core.up.sql +22 -0
  694. package/modules/search/migrations/0002_search_recent_export.down.sql +3 -0
  695. package/modules/search/migrations/0002_search_recent_export.up.sql +5 -0
  696. package/modules/search/migrations/README.md +3 -0
  697. package/modules/search/module.json +28 -0
  698. package/modules/search/package.json +43 -0
  699. package/modules/search/spec/module.yaml +177 -0
  700. package/modules/search/src/acl/permissions.ts +5 -0
  701. package/modules/search/src/api/endpoints.ts +221 -0
  702. package/modules/search/src/client/SearchView.tsrx +346 -0
  703. package/modules/search/src/client/api.ts +157 -0
  704. package/modules/search/src/client/contribution.tsrx +31 -0
  705. package/modules/search/src/client/index.ts +17 -0
  706. package/modules/search/src/client/navigation.ts +97 -0
  707. package/modules/search/src/client/search.css +56 -0
  708. package/modules/search/src/client/state.ts +113 -0
  709. package/modules/search/src/domain/data-classes.ts +73 -0
  710. package/modules/search/src/domain/providers.ts +88 -0
  711. package/modules/search/src/domain/types.ts +56 -0
  712. package/modules/search/src/index.ts +46 -0
  713. package/modules/search/src/platform.ts +42 -0
  714. package/modules/search/src/server/index.ts +25 -0
  715. package/modules/search/src/server/runtime.ts +123 -0
  716. package/modules/search/src/services/database-repository.ts +163 -0
  717. package/modules/search/src/services/index.ts +21 -0
  718. package/modules/search/src/services/migration.ts +65 -0
  719. package/modules/search/src/services/provider-registry.ts +137 -0
  720. package/modules/search/src/services/repository.ts +43 -0
  721. package/modules/search/src/services/search-service.ts +442 -0
  722. package/modules/search/src/services/service-error.ts +35 -0
  723. package/modules/search/src/settings.ts +68 -0
  724. package/modules/search/translations/en.json +45 -0
  725. package/modules/search/translations/pl.json +45 -0
  726. package/modules/system/module.json +2 -2
  727. package/modules/system/package.json +1 -1
  728. package/modules/system/spec/module.yaml +30 -3
  729. package/modules/system/src/client/FlagsPanel.tsrx +127 -0
  730. package/modules/system/src/client/ModuleSettingRow.tsrx +17 -7
  731. package/modules/system/src/client/ModuleSettingsSection.tsrx +10 -71
  732. package/modules/system/src/client/ModulesView.tsrx +91 -65
  733. package/modules/system/src/client/flags.ts +35 -0
  734. package/modules/system/src/client/index.ts +8 -0
  735. package/modules/system/src/client/navigation.ts +8 -0
  736. package/modules/system/src/client/settings-state.ts +159 -0
  737. package/modules/system/src/client/state.ts +2 -0
  738. package/modules/system/src/domain/time-zone.ts +105 -0
  739. package/modules/system/src/index.ts +12 -0
  740. package/modules/system/src/platform.ts +5 -1
  741. package/modules/system/src/server/endpoints.ts +72 -21
  742. package/modules/system/src/settings.ts +28 -0
  743. package/modules/system/translations/en.json +17 -0
  744. package/modules/system/translations/pl.json +17 -0
  745. package/modules/users/module.json +30 -4
  746. package/modules/users/package.json +4 -1
  747. package/modules/users/spec/module.yaml +290 -7
  748. package/modules/users/src/api/endpoints.ts +228 -15
  749. package/modules/users/src/client/InviteMemberForm.tsrx +2 -2
  750. package/modules/users/src/client/MemberDrawer.tsrx +142 -26
  751. package/modules/users/src/client/UserAccountForm.tsrx +2 -2
  752. package/modules/users/src/client/UsersView.tsrx +432 -71
  753. package/modules/users/src/client/api.ts +106 -12
  754. package/modules/users/src/client/contribution.tsrx +5 -0
  755. package/modules/users/src/client/member-columns.tsrx +22 -9
  756. package/modules/users/src/client/state.ts +172 -7
  757. package/modules/users/src/domain/lists.ts +9 -0
  758. package/modules/users/src/index.ts +11 -0
  759. package/modules/users/src/platform.ts +50 -1
  760. package/modules/users/src/services/member-export.ts +51 -0
  761. package/modules/users/src/services/member-import.ts +249 -0
  762. package/modules/users/src/services/member-search.ts +145 -0
  763. package/modules/users/src/services/users-service.ts +117 -4
  764. package/modules/users/translations/en.json +57 -8
  765. package/modules/users/translations/pl.json +57 -8
  766. package/modules/workflows/migrations/0004_payload_rotation_inventory.up.sql +17 -0
  767. package/modules/workflows/migrations/0005_workflows_human_approval.up.sql +28 -0
  768. package/modules/workflows/migrations/0006_workflows_retention_indexes.up.sql +11 -0
  769. package/modules/workflows/migrations/0007_workflows_erasure_subject_indexes.up.sql +17 -0
  770. package/modules/workflows/migrations/0008_workflows_subject_account.up.sql +24 -0
  771. package/modules/workflows/migrations/0009_workflows_definition_list_indexes.up.sql +9 -0
  772. package/modules/workflows/module.json +34 -6
  773. package/modules/workflows/package.json +2 -1
  774. package/modules/workflows/spec/module.yaml +26 -9
  775. package/modules/workflows/src/api/endpoints.ts +131 -25
  776. package/modules/workflows/src/cli/commands.json +17 -0
  777. package/modules/workflows/src/cli/index.ts +114 -0
  778. package/modules/workflows/src/client/WorkflowExecutionHistory.tsrx +36 -27
  779. package/modules/workflows/src/client/WorkflowInspector.tsrx +116 -0
  780. package/modules/workflows/src/client/WorkflowNodePalette.tsrx +1 -0
  781. package/modules/workflows/src/client/WorkflowsView.tsrx +236 -99
  782. package/modules/workflows/src/client/api.ts +54 -34
  783. package/modules/workflows/src/client/canvas-model.ts +12 -0
  784. package/modules/workflows/src/client/state.ts +95 -0
  785. package/modules/workflows/src/domain/events.ts +25 -11
  786. package/modules/workflows/src/domain/graph.ts +135 -1
  787. package/modules/workflows/src/domain/types.ts +91 -4
  788. package/modules/workflows/src/platform.ts +12 -0
  789. package/modules/workflows/src/server/runtime.ts +78 -5
  790. package/modules/workflows/src/services/approvals.ts +62 -0
  791. package/modules/workflows/src/services/cursors.ts +37 -0
  792. package/modules/workflows/src/services/data-classes.ts +232 -0
  793. package/modules/workflows/src/services/database-repository.ts +660 -171
  794. package/modules/workflows/src/services/migration.ts +240 -0
  795. package/modules/workflows/src/services/notifications.ts +98 -0
  796. package/modules/workflows/src/services/payload-codec.ts +51 -28
  797. package/modules/workflows/src/services/payload-rotation.ts +171 -0
  798. package/modules/workflows/src/services/repository.ts +123 -8
  799. package/modules/workflows/src/services/simulation.ts +7 -0
  800. package/modules/workflows/src/services/worker.ts +446 -25
  801. package/modules/workflows/src/services/workflows-service.ts +264 -103
  802. package/modules/workflows/translations/en.json +12 -4
  803. package/modules/workflows/translations/pl.json +12 -4
  804. package/modules.json +48 -4
  805. package/package.json +64 -6
  806. package/packages/client/package.json +1 -0
  807. package/packages/client/src/ApplicationShell.tsrx +43 -0
  808. package/packages/client/src/contributions.ts +55 -0
  809. package/packages/client/src/i18n/locales/en.json +5 -0
  810. package/packages/client/src/i18n/locales/pl.json +5 -0
  811. package/packages/client/src/index.ts +13 -1
  812. package/packages/client/src/routing.ts +22 -0
  813. package/packages/client/src/shell/CommandPalette.tsrx +223 -11
  814. package/packages/client/src/shell/command-search.ts +126 -0
  815. package/packages/client/src/shell/command.ts +30 -0
  816. package/packages/client/src/shell/navigation.ts +12 -0
  817. package/packages/client/src/shell/palette-keys.ts +27 -0
  818. package/packages/client/src/shell/shell.css +7 -0
  819. package/packages/contracts/schemas/module-spec.schema.json +287 -1
  820. package/packages/contracts/schemas/module.schema.json +25 -0
  821. package/packages/contracts/src/index.ts +144 -1
  822. package/packages/database/src/backup.ts +179 -0
  823. package/packages/database/src/decoders.ts +25 -0
  824. package/packages/database/src/index.ts +17 -0
  825. package/packages/database/src/record-history.ts +5 -14
  826. package/packages/harness/src/index.ts +2 -0
  827. package/packages/harness/src/runtime.ts +218 -1
  828. package/packages/harness/src/tool-adapters.ts +19 -1
  829. package/packages/kernel/src/acl.ts +179 -0
  830. package/packages/kernel/src/capability-registry.ts +69 -2
  831. package/packages/kernel/src/data-class-registry.ts +354 -0
  832. package/packages/kernel/src/index.ts +65 -4
  833. package/packages/kernel/src/keyring.ts +208 -0
  834. package/packages/kernel/src/module-compatibility.ts +35 -4
  835. package/packages/kernel/src/module-registry.ts +49 -2
  836. package/packages/kernel/src/module-settings.ts +189 -27
  837. package/packages/server/package.json +2 -1
  838. package/packages/server/src/composition.ts +38 -0
  839. package/packages/server/src/endpoint.ts +104 -47
  840. package/packages/server/src/export/csv.ts +34 -0
  841. package/packages/server/src/export/definition.ts +346 -0
  842. package/packages/server/src/export/index.ts +61 -0
  843. package/packages/server/src/export/run.ts +116 -0
  844. package/packages/server/src/index.ts +155 -0
  845. package/packages/server/src/jobs/index.ts +93 -0
  846. package/packages/server/src/jobs/runner.ts +486 -0
  847. package/packages/server/src/log.ts +291 -0
  848. package/packages/server/src/mail/config.ts +184 -0
  849. package/packages/server/src/mail/contracts.ts +251 -0
  850. package/packages/server/src/mail/index.ts +31 -0
  851. package/packages/server/src/mail/port.ts +101 -0
  852. package/packages/server/src/mail/smtp.ts +191 -0
  853. package/packages/server/src/mail/template.ts +105 -0
  854. package/packages/server/src/metrics.ts +447 -0
  855. package/packages/server/src/pagination.ts +246 -0
  856. package/packages/server/src/trace/context.ts +103 -0
  857. package/packages/server/src/trace/egress.ts +66 -0
  858. package/packages/server/src/trace/error-sink.ts +296 -0
  859. package/packages/server/src/trace/exporter.ts +295 -0
  860. package/packages/server/src/trace/index.ts +60 -0
  861. package/packages/server/src/trace/job-sink.ts +172 -0
  862. package/packages/server/src/trace/tracer.ts +338 -0
  863. package/packages/server/src/web.ts +5 -1
  864. package/packages/storage/package.json +40 -0
  865. package/packages/storage/src/config.ts +189 -0
  866. package/packages/storage/src/content-type.ts +124 -0
  867. package/packages/storage/src/contracts.ts +112 -0
  868. package/packages/storage/src/envelope.ts +189 -0
  869. package/packages/storage/src/index.ts +43 -0
  870. package/packages/storage/src/local.ts +75 -0
  871. package/packages/storage/src/port.ts +251 -0
  872. package/packages/storage/src/read-token.ts +130 -0
  873. package/packages/storage/src/s3.ts +144 -0
  874. package/packages/storage/src/scanner.ts +22 -0
  875. package/packages/storage/src/sigv4.ts +104 -0
  876. package/packages/storage/src/store.ts +13 -0
  877. package/packages/ui/package.json +1 -0
  878. package/packages/ui/src/components/Button.tsrx +3 -0
  879. package/packages/ui/src/components/ConfirmDialog.tsrx +13 -2
  880. package/packages/ui/src/components/DateField.tsrx +92 -0
  881. package/packages/ui/src/components/DatePicker.tsrx +525 -0
  882. package/packages/ui/src/components/DateRangeField.tsrx +93 -0
  883. package/packages/ui/src/components/Drawer.tsrx +10 -1
  884. package/packages/ui/src/components/FileUpload.tsrx +158 -0
  885. package/packages/ui/src/components/Pagination.tsrx +130 -0
  886. package/packages/ui/src/components/Select.tsrx +78 -0
  887. package/packages/ui/src/components/Table.tsrx +498 -81
  888. package/packages/ui/src/components/Tabs.tsrx +53 -0
  889. package/packages/ui/src/components/ToastHost.tsrx +48 -0
  890. package/packages/ui/src/components/calendar.ts +243 -0
  891. package/packages/ui/src/components/date-field.ts +62 -0
  892. package/packages/ui/src/components/file-upload.ts +49 -0
  893. package/packages/ui/src/components/focus-trap.ts +62 -0
  894. package/packages/ui/src/components/pagination.ts +68 -0
  895. package/packages/ui/src/components/table-sorting.ts +49 -0
  896. package/packages/ui/src/components/tabs.ts +61 -0
  897. package/packages/ui/src/components/toast-store.ts +116 -0
  898. package/packages/ui/src/icons/Icon.tsrx +5 -0
  899. package/packages/ui/src/index.ts +45 -0
  900. package/packages/ui/src/styles/components.css +598 -0
  901. package/modules/automations-workflows-integration/module.json +0 -27
  902. package/modules/automations-workflows-integration/spec/module.yaml +0 -93
  903. package/modules/automations-workflows-integration/src/index.ts +0 -14
  904. package/modules/automations-workflows-integration/src/platform.ts +0 -24
  905. package/modules/automations-workflows-integration/src/server/index.ts +0 -11
  906. package/modules/automations-workflows-integration/translations/en.json +0 -21
  907. package/modules/automations-workflows-integration/translations/pl.json +0 -21
  908. package/modules/workflows/src/services/cursor-codec.ts +0 -62
@@ -1,10 +1,12 @@
1
1
  import { createHash, randomUUID } from 'node:crypto';
2
2
  import {
3
+ integer,
3
4
  runDatabaseMigrations,
4
5
  type DatabaseHandle,
5
6
  type DatabaseTransaction,
6
7
  } from '@flowdular/sdk/database';
7
8
  import type { Actor, UserActor } from '@flowdular/sdk/kernel';
9
+ import { keysetWhere } from '@flowdular/sdk/server';
8
10
  import type {
9
11
  JsonValue,
10
12
  WorkflowAuditEvent,
@@ -23,9 +25,9 @@ import type {
23
25
  WorkflowRunDetail,
24
26
  WorkflowRunEventTypeV1,
25
27
  WorkflowRunEventV1,
26
- WorkflowRunFilters,
27
- WorkflowRunPage,
28
28
  WorkflowRunStatus,
29
+ WorkflowRunSummary,
30
+ WorkflowSortDirection,
29
31
  WorkflowUsageRollupV1,
30
32
  } from '../domain/types.ts';
31
33
  import { WORKFLOW_LIMITS } from '../domain/types.ts';
@@ -38,11 +40,18 @@ import { databaseMigrations } from './migration.ts';
38
40
  import type { WorkflowPayloadCodec } from './payload-codec.ts';
39
41
  import type {
40
42
  CreateWorkflowRunWrite,
43
+ ExportedWorkflowDefinition,
44
+ ExportedWorkflowRun,
41
45
  SettleAttemptWrite,
42
46
  SettleEdgeWrite,
43
47
  StartAttemptWrite,
44
- WorkflowAuditPage,
48
+ WorkflowAuditListRead,
49
+ WorkflowDefinitionExportCursor,
50
+ WorkflowDefinitionListRead,
45
51
  WorkflowDefinitionWrite,
52
+ WorkflowKeysetPage,
53
+ WorkflowRunExportCursor,
54
+ WorkflowRunListRead,
46
55
  WorkflowRunRecord,
47
56
  WorkflowsRepository,
48
57
  } from './repository.ts';
@@ -54,20 +63,11 @@ const TERMINAL_RUNS = new Set<WorkflowRunStatus>([
54
63
  'cancelled',
55
64
  ]);
56
65
 
57
- /* PostgreSQL returns BIGINT as a string, so every integer column is
58
- normalized on the way out of a row. */
59
- function integer(value: number | bigint | string): number {
60
- const normalized = Number(value);
61
- if (!Number.isSafeInteger(normalized)) {
62
- throw new Error('The workflows database returned an invalid integer.');
63
- }
64
- return normalized;
65
- }
66
-
67
66
  function optionalInteger(
68
67
  value: number | bigint | string | null,
68
+ field: string,
69
69
  ): number | null {
70
- return value === null ? null : integer(value);
70
+ return value === null ? null : integer(value, field);
71
71
  }
72
72
 
73
73
  type Int = number | bigint | string;
@@ -97,6 +97,19 @@ interface RevisionRow {
97
97
  published_actor_json: string | null;
98
98
  }
99
99
 
100
+ /** A definition and the revision it publishes, read in one statement. */
101
+ interface ExportDefinitionRow extends DefinitionRow {
102
+ revision_id: string;
103
+ revision_workflow_id: string;
104
+ revision_number: Int;
105
+ graph_json: string;
106
+ graph_checksum: string;
107
+ compiler_version: Int;
108
+ compiled_order_json: string;
109
+ published_at: Int | null;
110
+ published_actor_json: string | null;
111
+ }
112
+
100
113
  interface RunRow {
101
114
  id: string;
102
115
  tenant_id: string;
@@ -179,6 +192,19 @@ interface EdgeRow {
179
192
  settled_at: Int;
180
193
  }
181
194
 
195
+ /** The run id a page of child rows carries, so one query serves many runs. */
196
+ interface ExportNodeStateRow extends NodeStateRow {
197
+ run_id: string;
198
+ }
199
+
200
+ interface ExportAttemptRow extends AttemptRow {
201
+ run_id: string;
202
+ }
203
+
204
+ interface ExportEdgeRow extends EdgeRow {
205
+ run_id: string;
206
+ }
207
+
182
208
  interface EventRow {
183
209
  event_id: string;
184
210
  tenant_id: string;
@@ -229,10 +255,16 @@ function definitionFromRow(row: DefinitionRow): WorkflowDefinition {
229
255
  name: row.name,
230
256
  description: row.description,
231
257
  status: row.status,
232
- currentDraftRevision: integer(row.current_draft_revision),
233
- publishedRevision: optionalInteger(row.published_revision),
234
- createdAt: integer(row.created_at),
235
- updatedAt: integer(row.updated_at),
258
+ currentDraftRevision: integer(
259
+ row.current_draft_revision,
260
+ 'current_draft_revision',
261
+ ),
262
+ publishedRevision: optionalInteger(
263
+ row.published_revision,
264
+ 'published_revision',
265
+ ),
266
+ createdAt: integer(row.created_at, 'created_at'),
267
+ updatedAt: integer(row.updated_at, 'updated_at'),
236
268
  };
237
269
  }
238
270
 
@@ -240,12 +272,12 @@ function revisionFromRow(row: RevisionRow): WorkflowRevision {
240
272
  return {
241
273
  id: row.id,
242
274
  workflowId: row.workflow_id,
243
- revision: integer(row.revision),
275
+ revision: integer(row.revision, 'revision'),
244
276
  graph: parse<WorkflowGraphV1>(row.graph_json),
245
277
  graphChecksum: row.graph_checksum,
246
- compilerVersion: integer(row.compiler_version) as 1,
278
+ compilerVersion: integer(row.compiler_version, 'compiler_version') as 1,
247
279
  compiledOrder: parse<readonly string[]>(row.compiled_order_json),
248
- publishedAt: optionalInteger(row.published_at),
280
+ publishedAt: optionalInteger(row.published_at, 'published_at'),
249
281
  publishedBy:
250
282
  row.published_actor_json === null
251
283
  ? null
@@ -253,16 +285,51 @@ function revisionFromRow(row: RevisionRow): WorkflowRevision {
253
285
  };
254
286
  }
255
287
 
288
+ function nodeExecutionFromRow(
289
+ row: NodeStateRow,
290
+ attempts: readonly WorkflowNodeAttempt[],
291
+ ): WorkflowNodeExecution {
292
+ return {
293
+ nodeId: row.node_id,
294
+ status: row.status,
295
+ latestAttempt: integer(row.latest_attempt, 'latest_attempt'),
296
+ selectedOutcomePort: row.selected_outcome_port,
297
+ nextAttemptAt: optionalInteger(row.next_attempt_at, 'next_attempt_at'),
298
+ readyAt: optionalInteger(row.ready_at, 'ready_at'),
299
+ startedAt: optionalInteger(row.started_at, 'started_at'),
300
+ settledAt: optionalInteger(row.settled_at, 'settled_at'),
301
+ attempts,
302
+ };
303
+ }
304
+
305
+ function edgeFromRow(row: EdgeRow): WorkflowEdgeTransfer {
306
+ return {
307
+ edgeId: row.edge_id,
308
+ sourceNodeId: row.source_node_id,
309
+ sourcePort: row.source_port,
310
+ sourceAttempt: optionalInteger(row.source_attempt, 'source_attempt'),
311
+ targetNodeId: row.target_node_id,
312
+ targetPort: row.target_port,
313
+ state: row.state,
314
+ reason: row.reason,
315
+ evidence: parse<WorkflowPayloadEvidenceV1>(row.evidence_json),
316
+ settledAt: integer(row.settled_at, 'settled_at'),
317
+ };
318
+ }
319
+
256
320
  function runFromRow(row: RunRow): WorkflowRunRecord {
257
- const queuedAt = integer(row.queued_at);
258
- const completedAt = optionalInteger(row.completed_at);
321
+ const queuedAt = integer(row.queued_at, 'queued_at');
322
+ const completedAt = optionalInteger(row.completed_at, 'completed_at');
259
323
  return {
260
324
  id: row.id,
261
325
  tenantId: row.tenant_id,
262
326
  workflowId: row.workflow_id,
263
327
  workflowKey: row.workflow_key,
264
328
  workflowName: row.workflow_name,
265
- workflowRevision: optionalInteger(row.workflow_revision),
329
+ workflowRevision: optionalInteger(
330
+ row.workflow_revision,
331
+ 'workflow_revision',
332
+ ),
266
333
  graphChecksum: row.graph_checksum,
267
334
  graph: parse<WorkflowGraphV1>(row.graph_json),
268
335
  compiledOrder: parse<readonly string[]>(row.compiled_order_json),
@@ -280,24 +347,27 @@ function runFromRow(row: RunRow): WorkflowRunRecord {
280
347
  inputPayloadId: row.input_payload_id,
281
348
  idempotencyKey: row.idempotency_key,
282
349
  leaseOwner: row.lease_owner,
283
- leaseExpiresAt: optionalInteger(row.lease_expires_at),
284
- completedNodes: integer(row.completed_nodes),
285
- totalNodes: integer(row.total_nodes),
350
+ leaseExpiresAt: optionalInteger(row.lease_expires_at, 'lease_expires_at'),
351
+ completedNodes: integer(row.completed_nodes, 'completed_nodes'),
352
+ totalNodes: integer(row.total_nodes, 'total_nodes'),
286
353
  usage: parse<WorkflowUsageRollupV1>(row.usage_json),
287
354
  cost: parse<WorkflowCostRollupV1>(row.cost_json),
288
355
  failureCode: row.failure_code,
289
356
  queuedAt,
290
- startedAt: optionalInteger(row.started_at),
357
+ startedAt: optionalInteger(row.started_at, 'started_at'),
291
358
  completedAt,
292
359
  durationMs: completedAt === null ? null : completedAt - queuedAt,
293
- cancellationRequestedAt: optionalInteger(row.cancellation_requested_at),
360
+ cancellationRequestedAt: optionalInteger(
361
+ row.cancellation_requested_at,
362
+ 'cancellation_requested_at',
363
+ ),
294
364
  };
295
365
  }
296
366
 
297
367
  function attemptFromRow(row: AttemptRow): WorkflowNodeAttempt {
298
368
  return {
299
369
  nodeId: row.node_id,
300
- attempt: integer(row.attempt),
370
+ attempt: integer(row.attempt, 'attempt'),
301
371
  nodeType: row.node_type,
302
372
  status: row.status,
303
373
  outcomePort: row.outcome_port,
@@ -309,27 +379,34 @@ function attemptFromRow(row: AttemptRow): WorkflowNodeAttempt {
309
379
  childId: row.child_id,
310
380
  childObservationDeadlineAt: optionalInteger(
311
381
  row.child_observation_deadline_at,
382
+ 'child_observation_deadline_at',
312
383
  ),
313
384
  failureCode: row.failure_code,
314
385
  retryClassification: row.retry_classification,
315
- selectedBackoffMs: optionalInteger(row.selected_backoff_ms),
316
- nextAttemptAt: optionalInteger(row.next_attempt_at),
317
- startedAt: integer(row.started_at),
318
- completedAt: optionalInteger(row.completed_at),
319
- durationMs: optionalInteger(row.duration_ms),
386
+ selectedBackoffMs: optionalInteger(
387
+ row.selected_backoff_ms,
388
+ 'selected_backoff_ms',
389
+ ),
390
+ nextAttemptAt: optionalInteger(row.next_attempt_at, 'next_attempt_at'),
391
+ startedAt: integer(row.started_at, 'started_at'),
392
+ completedAt: optionalInteger(row.completed_at, 'completed_at'),
393
+ durationMs: optionalInteger(row.duration_ms, 'duration_ms'),
320
394
  };
321
395
  }
322
396
 
323
397
  function eventFromRow(row: EventRow): WorkflowRunEventV1 {
324
- const virtualOffsetMs = optionalInteger(row.virtual_offset_ms);
398
+ const virtualOffsetMs = optionalInteger(
399
+ row.virtual_offset_ms,
400
+ 'virtual_offset_ms',
401
+ );
325
402
  return {
326
403
  eventId: row.event_id,
327
404
  schemaVersion: 1,
328
405
  tenantId: row.tenant_id,
329
406
  runId: row.run_id,
330
- sequence: integer(row.sequence),
407
+ sequence: integer(row.sequence, 'sequence'),
331
408
  type: row.event_type,
332
- recordedAt: integer(row.recorded_at),
409
+ recordedAt: integer(row.recorded_at, 'recorded_at'),
333
410
  ...(virtualOffsetMs === null ? {} : { virtualOffsetMs }),
334
411
  payload: parse<Readonly<Record<string, JsonValue>>>(row.payload_json),
335
412
  };
@@ -337,14 +414,14 @@ function eventFromRow(row: EventRow): WorkflowRunEventV1 {
337
414
 
338
415
  function auditFromRow(row: AuditRow): WorkflowAuditEvent {
339
416
  return {
340
- sequence: integer(row.sequence),
417
+ sequence: integer(row.sequence, 'sequence'),
341
418
  actor: parse<Actor>(row.actor_json),
342
419
  origin: parse<WorkflowExecutionOrigin>(row.origin_json),
343
420
  action: row.action,
344
421
  subjectType: row.subject_type,
345
422
  subjectId: row.subject_id,
346
423
  metadata: parse<Readonly<Record<string, JsonValue>>>(row.metadata_json),
347
- occurredAt: integer(row.occurred_at),
424
+ occurredAt: integer(row.occurred_at, 'occurred_at'),
348
425
  previousHash: row.previous_hash,
349
426
  eventHash: row.event_hash,
350
427
  };
@@ -373,6 +450,64 @@ function jsonKind(column: string): string {
373
450
  return `${column}::jsonb ->> 'kind'`;
374
451
  }
375
452
 
453
+ /* A search term is matched as a substring, so the three characters LIKE reads
454
+ as syntax are escaped with PostgreSQL's default escape character. */
455
+ function likePattern(term: string): string {
456
+ return '%' + term.replace(/[\\%_]/g, (character) => '\\' + character) + '%';
457
+ }
458
+
459
+ const ORDER: Readonly<Record<WorkflowSortDirection, 'ASC' | 'DESC'>> = {
460
+ asc: 'ASC',
461
+ desc: 'DESC',
462
+ };
463
+
464
+ /* The direction reaches the statement text, so anything but the two words the
465
+ type allows is refused before it is interpolated. */
466
+ function orderDirection(direction: WorkflowSortDirection): 'ASC' | 'DESC' {
467
+ const order = ORDER[direction];
468
+ if (!order) throw new Error('A list direction is asc or desc.');
469
+ return order;
470
+ }
471
+
472
+ /** Numbered parameters for a statement assembled from optional predicates. */
473
+ function binder() {
474
+ const parameters: Array<string | number> = [];
475
+ return {
476
+ parameters,
477
+ bind(value: string | number): string {
478
+ parameters.push(value);
479
+ return `$${parameters.length}`;
480
+ },
481
+ };
482
+ }
483
+
484
+ /**
485
+ * The person behind a run, in the order migration 0008 backfilled the column:
486
+ * the account a service actor was configured by, then the delegated
487
+ * authorization subject, then the actor itself. It must stay that order, or a
488
+ * run written now would answer an erasure differently from one backfilled.
489
+ */
490
+ function subjectAccountId(
491
+ actor: Actor,
492
+ authorizationSubject: UserActor | null,
493
+ ): string {
494
+ if (actor.kind === 'service') return actor.configuredBy.id;
495
+ return authorizationSubject?.id ?? actor.id;
496
+ }
497
+
498
+ /** Appends into the bucket `key` names, creating it on first use. */
499
+ function bucketed<T>(map: Map<string, T[]>, key: string, value: T): void {
500
+ const bucket = map.get(key);
501
+ if (bucket) bucket.push(value);
502
+ else map.set(key, [value]);
503
+ }
504
+
505
+ /* One node of one run. A run id is a UUID and a node id is a dotted
506
+ identifier, so neither can hold the separator and two pairs never collide. */
507
+ function nodeKey(runId: string, nodeId: string): string {
508
+ return `${runId} ${nodeId}`;
509
+ }
510
+
376
511
  /* Marks a stored evidence document expired without touching its hash or
377
512
  byte size, so the audit of what was there survives the redaction. */
378
513
  function expire(column: string): string {
@@ -397,8 +532,6 @@ const SQL = Object.freeze({
397
532
  (id, tenant_id, run_id, kind, schema_id, payload_hash,
398
533
  original_byte_size, ciphertext, encryption_key_id, created_at)
399
534
  VALUES ($1, $2, $3, 'execution', $4, $5, $6, $7, $8, $9)`,
400
- listDefinitions: `SELECT * FROM workflow_definitions WHERE tenant_id = $1
401
- ORDER BY lower(name), id`,
402
535
  findDefinition: `SELECT * FROM workflow_definitions
403
536
  WHERE tenant_id = $1 AND id = $2`,
404
537
  findDefinitionByKey: `SELECT * FROM workflow_definitions
@@ -445,13 +578,13 @@ const SQL = Object.freeze({
445
578
  (id, tenant_id, workflow_id, workflow_key, workflow_name,
446
579
  workflow_revision, graph_checksum, compiler_version, graph_json,
447
580
  compiled_order_json, mode, status, actor_json, authorization_subject_json, origin_json,
448
- permission_snapshot_json, permission_digest, input_hash,
581
+ subject_account_id, permission_snapshot_json, permission_digest, input_hash,
449
582
  input_payload_id, input_evidence_json, output_evidence_json,
450
583
  idempotency_key, limits_json, lease_owner, lease_expires_at,
451
584
  completed_nodes, total_nodes, usage_json, cost_json, failure_code,
452
585
  queued_at, started_at, completed_at, cancellation_requested_at)
453
586
  VALUES ($1, $2, $3, $4, $5, $6, $7, 1, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19,
454
- NULL, $20, $21, NULL, NULL, 0, $22, $23, $24, NULL, $25, NULL, NULL, NULL)`,
587
+ $20, NULL, $21, $22, NULL, NULL, 0, $23, $24, $25, NULL, $26, NULL, NULL, NULL)`,
455
588
  insertNodeState: `INSERT INTO workflow_node_states
456
589
  (tenant_id, run_id, node_id, status, latest_attempt)
457
590
  VALUES ($1, $2, $3, 'pending', 0)`,
@@ -469,6 +602,11 @@ const SQL = Object.freeze({
469
602
  SELECT 1 FROM workflow_node_states n
470
603
  WHERE n.tenant_id = workflow_runs.tenant_id AND n.run_id = workflow_runs.id
471
604
  AND n.status = 'waiting-retry' AND n.next_attempt_at <= $3
605
+ ))
606
+ OR (status = 'waiting-approval' AND (lease_expires_at IS NULL OR lease_expires_at <= $6) AND EXISTS (
607
+ SELECT 1 FROM workflow_node_states n
608
+ WHERE n.tenant_id = workflow_runs.tenant_id AND n.run_id = workflow_runs.id
609
+ AND n.status = 'waiting-child' AND n.next_attempt_at <= $7
472
610
  ))
473
611
  OR (status = 'cancel-requested' AND (lease_expires_at IS NULL OR lease_expires_at <= $4))
474
612
  )
@@ -492,8 +630,11 @@ const SQL = Object.freeze({
492
630
  semantic_group, side_effect_idempotency_key, input_payload_id,
493
631
  input_evidence_json, output_evidence_json, started_at)
494
632
  VALUES ($1, $2, $3, $4, $5, 'running', $6, $7, $8, $9, $10, $11)`,
633
+ /* The recheck a retry armed has fired by the time the attempt starts.
634
+ Leaving it set would keep the node matching the claim poll's due-work
635
+ predicate, which reads this column for every waiting state. */
495
636
  startNodeState: `UPDATE workflow_node_states
496
- SET status = 'running', latest_attempt = $1,
637
+ SET status = 'running', latest_attempt = $1, next_attempt_at = NULL,
497
638
  ready_at = coalesce(ready_at, $2), started_at = coalesce(started_at, $3)
498
639
  WHERE tenant_id = $4 AND run_id = $5 AND node_id = $6`,
499
640
  markAttemptWaitingChild: `UPDATE workflow_node_attempts
@@ -501,10 +642,29 @@ const SQL = Object.freeze({
501
642
  child_observation_deadline_at = $3
502
643
  WHERE tenant_id = $4 AND run_id = $5 AND node_id = $6 AND attempt = $7
503
644
  AND status = 'running'`,
504
- markNodeWaitingChild: `UPDATE workflow_node_states SET status = 'waiting-child'
645
+ /* An agent or an action child is polled while the run stays claimable on its
646
+ own status, so such a node arms no recheck: only an approval does, and it
647
+ arms it right after this. */
648
+ markNodeWaitingChild: `UPDATE workflow_node_states
649
+ SET status = 'waiting-child', next_attempt_at = NULL
505
650
  WHERE tenant_id = $1 AND run_id = $2 AND node_id = $3`,
506
651
  markRunWaitingAgent: `UPDATE workflow_runs SET status = 'waiting-agent'
507
652
  WHERE tenant_id = $1 AND id = $2 AND status = 'running'`,
653
+ markRunWaitingApproval: `UPDATE workflow_runs SET status = 'waiting-approval'
654
+ WHERE tenant_id = $1 AND id = $2 AND status IN ('running', 'waiting-approval')`,
655
+ armNodeRecheck: `UPDATE workflow_node_states SET next_attempt_at = $1
656
+ WHERE tenant_id = $2 AND run_id = $3 AND node_id = $4
657
+ AND status = 'waiting-child'`,
658
+ wakeApprovalRun: `UPDATE workflow_node_states SET next_attempt_at = $1
659
+ FROM workflow_node_attempts a
660
+ WHERE workflow_node_states.tenant_id = $2
661
+ AND workflow_node_states.run_id = $3
662
+ AND workflow_node_states.status = 'waiting-child'
663
+ AND a.tenant_id = workflow_node_states.tenant_id
664
+ AND a.run_id = workflow_node_states.run_id
665
+ AND a.node_id = workflow_node_states.node_id
666
+ AND a.attempt = workflow_node_states.latest_attempt
667
+ AND a.child_kind = 'approval' AND a.child_id = $4`,
508
668
  getAttempt: `SELECT * FROM workflow_node_attempts
509
669
  WHERE tenant_id = $1 AND run_id = $2 AND node_id = $3 AND attempt = $4`,
510
670
  settleAttempt: `UPDATE workflow_node_attempts
@@ -562,17 +722,17 @@ const SQL = Object.freeze({
562
722
  target_node_id, target_port, state, reason, evidence_json, settled_at
563
723
  FROM workflow_edge_transfers WHERE tenant_id = $1 AND run_id = $2
564
724
  ORDER BY edge_id`,
565
- listAudit: `SELECT sequence, actor_json, origin_json, action, subject_type,
566
- subject_id, metadata_json, occurred_at, previous_hash, event_hash
567
- FROM workflow_audit_events WHERE tenant_id = $1
568
- ORDER BY sequence DESC LIMIT $2`,
569
- listAuditBefore: `SELECT sequence, actor_json, origin_json, action, subject_type,
570
- subject_id, metadata_json, occurred_at, previous_hash, event_hash
571
- FROM workflow_audit_events WHERE tenant_id = $1 AND sequence < $2
572
- ORDER BY sequence DESC LIMIT $3`,
573
725
  auditChain: `SELECT sequence, actor_json, origin_json, action, subject_type,
574
726
  subject_id, metadata_json, occurred_at, previous_hash, event_hash
575
727
  FROM workflow_audit_events WHERE tenant_id = $1 ORDER BY sequence`,
728
+ /* Chain order, which is the primary key's own order, so the export walk is
729
+ an index range scan and an event appended during it lands ahead of the
730
+ cursor rather than being visited twice. */
731
+ exportAuditEventsPage: `SELECT sequence, actor_json, origin_json, action,
732
+ subject_type, subject_id, metadata_json, occurred_at, previous_hash,
733
+ event_hash FROM workflow_audit_events
734
+ WHERE tenant_id = $1 AND sequence > $2
735
+ ORDER BY sequence LIMIT $3`,
576
736
  /* Cross-tenant, routing columns only: the retention writes that follow
577
737
  run under the tenant each row named. */
578
738
  retentionCandidates: `SELECT p.id, p.tenant_id, p.run_id, p.payload_hash
@@ -597,6 +757,77 @@ const SQL = Object.freeze({
597
757
  CASE WHEN output_evidence_json IS NULL THEN NULL ELSE ${expire('output_evidence_json')} END
598
758
  WHERE tenant_id = $1 AND id = $2`,
599
759
  countRuns: `SELECT count(*) AS count FROM workflow_runs WHERE tenant_id = $1`,
760
+ /* The order workflow_runs_tenant_queue_idx already carries, so the export
761
+ walk is an index range scan and a run queued during it lands ahead of the
762
+ cursor rather than being visited twice. */
763
+ exportRunsPage: `SELECT * FROM workflow_runs WHERE tenant_id = $1
764
+ ORDER BY queued_at DESC, id DESC LIMIT $2`,
765
+ exportRunsPageAfter: `SELECT * FROM workflow_runs WHERE tenant_id = $1
766
+ AND (queued_at < $2 OR (queued_at = $3 AND id < $4))
767
+ ORDER BY queued_at DESC, id DESC LIMIT $5`,
768
+ exportNodeStates: `SELECT run_id, node_id, status, latest_attempt,
769
+ selected_outcome_port, next_attempt_at, ready_at, started_at, settled_at
770
+ FROM workflow_node_states
771
+ WHERE tenant_id = $1 AND run_id = ANY($2::text[])
772
+ ORDER BY run_id, node_id`,
773
+ exportAttempts: `SELECT run_id, node_id, attempt, node_type, status,
774
+ outcome_port, semantic_group, side_effect_idempotency_key,
775
+ input_evidence_json, output_evidence_json, child_kind, child_id,
776
+ child_observation_deadline_at, failure_code, retry_classification,
777
+ selected_backoff_ms, next_attempt_at, started_at, completed_at,
778
+ duration_ms FROM workflow_node_attempts
779
+ WHERE tenant_id = $1 AND run_id = ANY($2::text[])
780
+ ORDER BY run_id, node_id, attempt`,
781
+ exportEdges: `SELECT run_id, edge_id, source_node_id, source_port,
782
+ source_attempt, target_node_id, target_port, state, reason,
783
+ evidence_json, settled_at FROM workflow_edge_transfers
784
+ WHERE tenant_id = $1 AND run_id = ANY($2::text[])
785
+ ORDER BY run_id, edge_id`,
786
+ /* The inner select applies the batch limit; the child rows of the runs it
787
+ names are removed with them in the same transaction. */
788
+ settledRunsBefore: `SELECT id FROM workflow_runs
789
+ WHERE tenant_id = $1 AND completed_at < $2
790
+ AND status IN ('succeeded', 'failed', 'refused', 'cancelled')
791
+ ORDER BY completed_at LIMIT $3`,
792
+ /* One plain equality on the column 0008 resolves at write time, which is
793
+ what makes an erasure an index range scan on the connection it runs on.
794
+ Reading the person out of the actor document instead cannot use an index
795
+ there: the jsonb extraction is not leakproof, so the forced row level
796
+ security policy is applied first and the comparison stays a filter. */
797
+ runsOfSubject: `SELECT id FROM workflow_runs
798
+ WHERE tenant_id = $1 AND subject_account_id = $2
799
+ ORDER BY id LIMIT $3`,
800
+ deleteRunNodeStates: `DELETE FROM workflow_node_states
801
+ WHERE tenant_id = $1 AND run_id = ANY($2::text[])`,
802
+ deleteRunAttempts: `DELETE FROM workflow_node_attempts
803
+ WHERE tenant_id = $1 AND run_id = ANY($2::text[])`,
804
+ deleteRunEdges: `DELETE FROM workflow_edge_transfers
805
+ WHERE tenant_id = $1 AND run_id = ANY($2::text[])`,
806
+ deleteRunEvents: `DELETE FROM workflow_run_events
807
+ WHERE tenant_id = $1 AND run_id = ANY($2::text[])`,
808
+ deleteRunPayloads: `DELETE FROM workflow_payloads
809
+ WHERE tenant_id = $1 AND run_id = ANY($2::text[])`,
810
+ deleteRunRows: `DELETE FROM workflow_runs
811
+ WHERE tenant_id = $1 AND id = ANY($2::text[])`,
812
+ exportPublishedDefinitions: `SELECT d.*, r.id AS revision_id,
813
+ r.workflow_id AS revision_workflow_id, r.revision AS revision_number,
814
+ r.graph_json, r.graph_checksum, r.compiler_version,
815
+ r.compiled_order_json, r.published_at, r.published_actor_json
816
+ FROM workflow_definitions d
817
+ JOIN workflow_revisions r ON r.tenant_id = d.tenant_id
818
+ AND r.workflow_id = d.id AND r.revision = d.published_revision
819
+ WHERE d.tenant_id = $1 AND d.published_revision IS NOT NULL
820
+ ORDER BY d.name, d.id LIMIT $2`,
821
+ exportPublishedDefinitionsAfter: `SELECT d.*, r.id AS revision_id,
822
+ r.workflow_id AS revision_workflow_id, r.revision AS revision_number,
823
+ r.graph_json, r.graph_checksum, r.compiler_version,
824
+ r.compiled_order_json, r.published_at, r.published_actor_json
825
+ FROM workflow_definitions d
826
+ JOIN workflow_revisions r ON r.tenant_id = d.tenant_id
827
+ AND r.workflow_id = d.id AND r.revision = d.published_revision
828
+ WHERE d.tenant_id = $1 AND d.published_revision IS NOT NULL
829
+ AND (d.name > $2 OR (d.name = $3 AND d.id > $4))
830
+ ORDER BY d.name, d.id LIMIT $5`,
600
831
  });
601
832
 
602
833
  export async function migrateWorkflowsDatabase(
@@ -685,7 +916,7 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
685
916
  )
686
917
  )[0];
687
918
  const base = {
688
- sequence: (previous ? integer(previous.sequence) : 0) + 1,
919
+ sequence: (previous ? integer(previous.sequence, 'sequence') : 0) + 1,
689
920
  actor,
690
921
  origin,
691
922
  action,
@@ -728,7 +959,8 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
728
959
  [tenantId, runId],
729
960
  )
730
961
  )[0];
731
- const sequence = (optionalInteger(previous?.sequence ?? null) ?? 0) + 1;
962
+ const sequence =
963
+ (optionalInteger(previous?.sequence ?? null, 'sequence') ?? 0) + 1;
732
964
  if (sequence > WORKFLOW_LIMITS.maxRunEvents) {
733
965
  throw new Error('WORKFLOW_LIMIT_EXCEEDED');
734
966
  }
@@ -853,16 +1085,54 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
853
1085
  ]);
854
1086
  }
855
1087
 
1088
+ /* The name order is lower(name), which 0009 indexes as an expression. The
1089
+ keyset predicate compares plain columns, so the subquery names that
1090
+ expression once and the planner folds it back onto the index. */
856
1091
  async listDefinitions(
857
1092
  tenantId: string,
858
- ): Promise<readonly WorkflowDefinition[]> {
859
- return this.#tx(tenantId, 'read', async (transaction) =>
860
- (
861
- await this.#query<DefinitionRow>(transaction, SQL.listDefinitions, [
862
- tenantId,
863
- ])
864
- ).map(definitionFromRow),
1093
+ read: WorkflowDefinitionListRead,
1094
+ ): Promise<WorkflowKeysetPage<WorkflowDefinition>> {
1095
+ const { parameters, bind } = binder();
1096
+ const clauses = [`tenant_id = ${bind(tenantId)}`];
1097
+ if (read.status) clauses.push(`status = ${bind(read.status)}`);
1098
+ if (read.search) {
1099
+ const pattern = bind(likePattern(read.search));
1100
+ clauses.push(`(name ILIKE ${pattern} OR workflow_key ILIKE ${pattern})`);
1101
+ }
1102
+ const sortColumn = read.sort === 'name' ? 'sort_name' : 'updated_at';
1103
+ const order = orderDirection(read.direction);
1104
+ let text = `SELECT * FROM (SELECT *, lower(name) AS sort_name
1105
+ FROM workflow_definitions WHERE ${clauses.join(' AND ')}) d`;
1106
+ if (read.after) {
1107
+ const keyset = keysetWhere(
1108
+ [sortColumn, 'id'],
1109
+ [read.after.key, read.after.id],
1110
+ { direction: read.direction, parameterOffset: parameters.length },
1111
+ );
1112
+ text += ` WHERE ${keyset.text}`;
1113
+ parameters.push(...keyset.parameters);
1114
+ }
1115
+ text += ` ORDER BY ${sortColumn} ${order}, id ${order} LIMIT ${bind(read.limit)}`;
1116
+ const rows = await this.#tx(tenantId, 'read', (transaction) =>
1117
+ this.#query<DefinitionRow & { sort_name: string }>(
1118
+ transaction,
1119
+ text,
1120
+ parameters,
1121
+ ),
865
1122
  );
1123
+ const last = rows.at(-1);
1124
+ return {
1125
+ items: rows.map(definitionFromRow),
1126
+ last: last
1127
+ ? {
1128
+ key:
1129
+ read.sort === 'name'
1130
+ ? last.sort_name
1131
+ : integer(last.updated_at, 'updated_at'),
1132
+ id: last.id,
1133
+ }
1134
+ : null,
1135
+ };
866
1136
  }
867
1137
 
868
1138
  async findDefinition(
@@ -1093,7 +1363,7 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
1093
1363
  )[0];
1094
1364
  if (
1095
1365
  definition.publishedRevision !== null ||
1096
- integer(runs?.count ?? 0) > 0
1366
+ integer(runs?.count ?? 0, 'count') > 0
1097
1367
  ) {
1098
1368
  return 'in-use';
1099
1369
  }
@@ -1136,7 +1406,7 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
1136
1406
  id: row.id,
1137
1407
  key: row.workflow_key,
1138
1408
  name: row.name,
1139
- revision: integer(row.published_revision),
1409
+ revision: integer(row.published_revision, 'published_revision'),
1140
1410
  graphChecksum: row.graph_checksum,
1141
1411
  })),
1142
1412
  );
@@ -1168,6 +1438,7 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
1168
1438
  JSON.stringify(run.actor),
1169
1439
  JSON.stringify(run.authorizationSubject),
1170
1440
  JSON.stringify(run.origin),
1441
+ subjectAccountId(run.actor, run.authorizationSubject),
1171
1442
  JSON.stringify(run.permissionSnapshot),
1172
1443
  run.permissionDigest,
1173
1444
  run.inputHash,
@@ -1247,72 +1518,48 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
1247
1518
 
1248
1519
  async listRuns(
1249
1520
  tenantId: string,
1250
- filters: WorkflowRunFilters,
1251
- ): Promise<WorkflowRunPage> {
1252
- const limit = Math.min(
1253
- Math.max(1, Math.trunc(filters.limit ?? 50)),
1254
- WORKFLOW_LIMITS.maxInteractivePage,
1255
- );
1256
- const parameters: Array<string | number> = [];
1257
- const bind = (value: string | number) => {
1258
- parameters.push(value);
1259
- return `$${parameters.length}`;
1260
- };
1521
+ read: WorkflowRunListRead,
1522
+ ): Promise<WorkflowKeysetPage<WorkflowRunSummary>> {
1523
+ const { parameters, bind } = binder();
1261
1524
  const clauses = [`tenant_id = ${bind(tenantId)}`];
1262
- if (filters.workflowId) {
1263
- clauses.push(`workflow_id = ${bind(filters.workflowId)}`);
1525
+ if (read.workflowId) {
1526
+ clauses.push(`workflow_id = ${bind(read.workflowId)}`);
1264
1527
  }
1265
- if (filters.mode) clauses.push(`mode = ${bind(filters.mode)}`);
1266
- if (filters.status) clauses.push(`status = ${bind(filters.status)}`);
1267
- if (filters.actorKind) {
1268
- clauses.push(`${jsonKind('actor_json')} = ${bind(filters.actorKind)}`);
1528
+ if (read.mode) clauses.push(`mode = ${bind(read.mode)}`);
1529
+ if (read.status) clauses.push(`status = ${bind(read.status)}`);
1530
+ if (read.actorKind) {
1531
+ clauses.push(`${jsonKind('actor_json')} = ${bind(read.actorKind)}`);
1269
1532
  }
1270
- if (filters.originKind) {
1271
- clauses.push(`${jsonKind('origin_json')} = ${bind(filters.originKind)}`);
1533
+ if (read.originKind) {
1534
+ clauses.push(`${jsonKind('origin_json')} = ${bind(read.originKind)}`);
1272
1535
  }
1273
- let snapshot: { readonly queuedAt: number; readonly id: string } | null =
1274
- null;
1275
- if (filters.cursor) {
1276
- const [snapshotRaw, positionRaw, extra] = filters.cursor.split('|');
1277
- const parseBoundary = (raw: string | undefined) => {
1278
- const separator = raw?.indexOf(':') ?? -1;
1279
- const queuedAt = Number(raw?.slice(0, separator));
1280
- const id = raw?.slice(separator + 1) ?? '';
1281
- if (separator < 1 || !Number.isSafeInteger(queuedAt) || !id) {
1282
- throw new Error('WORKFLOW_CURSOR_INVALID');
1283
- }
1284
- return { queuedAt, id };
1285
- };
1286
- if (extra !== undefined) throw new Error('WORKFLOW_CURSOR_INVALID');
1287
- snapshot = parseBoundary(snapshotRaw);
1288
- const position = parseBoundary(positionRaw);
1536
+ if (read.search) {
1537
+ const pattern = bind(likePattern(read.search));
1289
1538
  clauses.push(
1290
- `(queued_at < ${bind(snapshot.queuedAt)} OR (queued_at = ${bind(
1291
- snapshot.queuedAt,
1292
- )} AND id <= ${bind(snapshot.id)}))`,
1539
+ `(workflow_name ILIKE ${pattern} OR workflow_key ILIKE ${pattern}
1540
+ OR id ILIKE ${pattern} OR actor_json::jsonb ->> 'label' ILIKE ${pattern})`,
1293
1541
  );
1294
- clauses.push(
1295
- `(queued_at < ${bind(position.queuedAt)} OR (queued_at = ${bind(
1296
- position.queuedAt,
1297
- )} AND id < ${bind(position.id)}))`,
1542
+ }
1543
+ if (read.after) {
1544
+ const keyset = keysetWhere(
1545
+ ['queued_at', 'id'],
1546
+ [read.after.key, read.after.id],
1547
+ { direction: read.direction, parameterOffset: parameters.length },
1298
1548
  );
1549
+ clauses.push(keyset.text);
1550
+ parameters.push(...keyset.parameters);
1299
1551
  }
1552
+ const order = orderDirection(read.direction);
1300
1553
  const text = `SELECT * FROM workflow_runs WHERE ${clauses.join(' AND ')}
1301
- ORDER BY queued_at DESC, id DESC LIMIT ${bind(limit + 1)}`;
1554
+ ORDER BY queued_at ${order}, id ${order} LIMIT ${bind(read.limit)}`;
1302
1555
  const rows = await this.#tx(tenantId, 'read', (transaction) =>
1303
1556
  this.#query<RunRow>(transaction, text, parameters),
1304
1557
  );
1305
- const page = rows.slice(0, limit).map(runFromRow);
1306
- const first = page[0];
1307
- const last = page.at(-1);
1308
- const highWaterMark =
1309
- snapshot ?? (first ? { queuedAt: first.queuedAt, id: first.id } : null);
1558
+ const items = rows.map(runFromRow);
1559
+ const last = items.at(-1);
1310
1560
  return {
1311
- runs: page,
1312
- nextCursor:
1313
- rows.length > limit && last && highWaterMark
1314
- ? `${highWaterMark.queuedAt}:${highWaterMark.id}|${last.queuedAt}:${last.id}`
1315
- : null,
1561
+ items,
1562
+ last: last ? { key: last.queuedAt, id: last.id } : null,
1316
1563
  };
1317
1564
  }
1318
1565
 
@@ -1412,7 +1659,7 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
1412
1659
  (transaction) =>
1413
1660
  transaction.query<RunRoutingRow>({
1414
1661
  text: SQL.claimCandidates,
1415
- parameters: [now, now, now, now, 20] as never,
1662
+ parameters: [now, now, now, now, 20, now, now] as never,
1416
1663
  }),
1417
1664
  { access: 'read' },
1418
1665
  )
@@ -1443,7 +1690,8 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
1443
1690
  )[0];
1444
1691
  if (!row) return null;
1445
1692
  const leaseExpired =
1446
- row.lease_expires_at === null || integer(row.lease_expires_at) <= now;
1693
+ row.lease_expires_at === null ||
1694
+ integer(row.lease_expires_at, 'lease_expires_at') <= now;
1447
1695
  const claimable =
1448
1696
  row.mode === 'live' &&
1449
1697
  (row.status === 'queued' ||
@@ -1451,7 +1699,8 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
1451
1699
  row.status,
1452
1700
  ) &&
1453
1701
  leaseExpired) ||
1454
- (row.status === 'waiting-retry' && leaseExpired));
1702
+ (['waiting-retry', 'waiting-approval'].includes(row.status) &&
1703
+ leaseExpired));
1455
1704
  if (!claimable) return null;
1456
1705
  const priorLease = row.lease_owner;
1457
1706
  const recovering = priorLease !== null && row.status !== 'queued';
@@ -1459,7 +1708,9 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
1459
1708
  after its node starts would make the new waiting-child projection
1460
1709
  unreachable by the next claim. */
1461
1710
  const status =
1462
- row.status === 'queued' || row.status === 'waiting-retry'
1711
+ row.status === 'queued' ||
1712
+ row.status === 'waiting-retry' ||
1713
+ row.status === 'waiting-approval'
1463
1714
  ? 'running'
1464
1715
  : row.status;
1465
1716
  const changed = await this.#exec(transaction, SQL.claimRun, [
@@ -1711,10 +1962,11 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
1711
1962
  runId: string,
1712
1963
  nodeId: string,
1713
1964
  attempt: number,
1714
- childKind: 'agent' | 'action',
1965
+ childKind: 'agent' | 'action' | 'approval',
1715
1966
  childId: string,
1716
1967
  observationDeadlineAt: number,
1717
1968
  recordedAt: number,
1969
+ recheckAt?: number,
1718
1970
  ): Promise<void> {
1719
1971
  await this.#tx(tenantId, 'write', async (transaction) => {
1720
1972
  const changed = await this.#exec(
@@ -1742,6 +1994,20 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
1742
1994
  runId,
1743
1995
  ]);
1744
1996
  }
1997
+ /* An approval takes the run out of the claim queue entirely, so the
1998
+ recheck it arms is the only thing that brings it back on its own. */
1999
+ if (childKind === 'approval') {
2000
+ await this.#exec(transaction, SQL.armNodeRecheck, [
2001
+ recheckAt ?? recordedAt,
2002
+ tenantId,
2003
+ runId,
2004
+ nodeId,
2005
+ ]);
2006
+ await this.#exec(transaction, SQL.markRunWaitingApproval, [
2007
+ tenantId,
2008
+ runId,
2009
+ ]);
2010
+ }
1745
2011
  await this.#appendEvent(
1746
2012
  transaction,
1747
2013
  tenantId,
@@ -1753,6 +2019,53 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
1753
2019
  });
1754
2020
  }
1755
2021
 
2022
+ /**
2023
+ * Re-arms the wait on an approval the worker found still pending. It records
2024
+ * no event and touches no attempt: the run simply goes back to sleep with a
2025
+ * later recheck than the one that woke it.
2026
+ */
2027
+ async suspendApproval(
2028
+ tenantId: string,
2029
+ runId: string,
2030
+ nodeId: string,
2031
+ recheckAt: number,
2032
+ ): Promise<void> {
2033
+ await this.#tx(tenantId, 'write', async (transaction) => {
2034
+ await this.#exec(transaction, SQL.armNodeRecheck, [
2035
+ recheckAt,
2036
+ tenantId,
2037
+ runId,
2038
+ nodeId,
2039
+ ]);
2040
+ await this.#exec(transaction, SQL.markRunWaitingApproval, [
2041
+ tenantId,
2042
+ runId,
2043
+ ]);
2044
+ });
2045
+ }
2046
+
2047
+ /**
2048
+ * Brings a sleeping run back into the claim queue the moment approvals.core
2049
+ * reports a decision, by making the node's recheck due now. It matches on the
2050
+ * request id, so a callback for a request the run has moved past changes
2051
+ * nothing.
2052
+ */
2053
+ async wakeApproval(
2054
+ tenantId: string,
2055
+ runId: string,
2056
+ requestId: string,
2057
+ now: number,
2058
+ ): Promise<void> {
2059
+ await this.#tx(tenantId, 'write', async (transaction) => {
2060
+ await this.#exec(transaction, SQL.wakeApprovalRun, [
2061
+ now,
2062
+ tenantId,
2063
+ runId,
2064
+ requestId,
2065
+ ]);
2066
+ });
2067
+ }
2068
+
1756
2069
  async settleAttempt(
1757
2070
  write: SettleAttemptWrite,
1758
2071
  actor: Actor,
@@ -1783,7 +2096,7 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
1783
2096
  );
1784
2097
  const duration = Math.max(
1785
2098
  0,
1786
- write.recordedAt - integer(prior.started_at),
2099
+ write.recordedAt - integer(prior.started_at, 'started_at'),
1787
2100
  );
1788
2101
  await this.#exec(transaction, SQL.settleAttempt, [
1789
2102
  write.status,
@@ -2214,19 +2527,14 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
2214
2527
  SQL.readAttempts,
2215
2528
  [tenantId, runId],
2216
2529
  );
2217
- return states.map((state) => ({
2218
- nodeId: state.node_id,
2219
- status: state.status,
2220
- latestAttempt: integer(state.latest_attempt),
2221
- selectedOutcomePort: state.selected_outcome_port,
2222
- nextAttemptAt: optionalInteger(state.next_attempt_at),
2223
- readyAt: optionalInteger(state.ready_at),
2224
- startedAt: optionalInteger(state.started_at),
2225
- settledAt: optionalInteger(state.settled_at),
2226
- attempts: attempts
2227
- .filter((attempt) => attempt.node_id === state.node_id)
2228
- .map(attemptFromRow),
2229
- }));
2530
+ return states.map((state) =>
2531
+ nodeExecutionFromRow(
2532
+ state,
2533
+ attempts
2534
+ .filter((attempt) => attempt.node_id === state.node_id)
2535
+ .map(attemptFromRow),
2536
+ ),
2537
+ );
2230
2538
  });
2231
2539
  }
2232
2540
 
@@ -2240,46 +2548,50 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
2240
2548
  tenantId,
2241
2549
  runId,
2242
2550
  ])
2243
- ).map((row) => ({
2244
- edgeId: row.edge_id,
2245
- sourceNodeId: row.source_node_id,
2246
- sourcePort: row.source_port,
2247
- sourceAttempt: optionalInteger(row.source_attempt),
2248
- targetNodeId: row.target_node_id,
2249
- targetPort: row.target_port,
2250
- state: row.state,
2251
- reason: row.reason,
2252
- evidence: parse<WorkflowPayloadEvidenceV1>(row.evidence_json),
2253
- settledAt: integer(row.settled_at),
2254
- })),
2551
+ ).map(edgeFromRow),
2255
2552
  );
2256
2553
  }
2257
2554
 
2555
+ /* The chain order is the sequence; the time order rides the index 0001 made
2556
+ for it, with the sequence as the tie breaker in both. */
2258
2557
  async listAudit(
2259
2558
  tenantId: string,
2260
- limit: number,
2261
- beforeSequence?: number,
2262
- ): Promise<WorkflowAuditPage> {
2263
- const bounded = Math.min(Math.max(1, Math.trunc(limit)), 100);
2559
+ read: WorkflowAuditListRead,
2560
+ ): Promise<WorkflowKeysetPage<WorkflowAuditEvent>> {
2561
+ const { parameters, bind } = binder();
2562
+ const clauses = [`tenant_id = ${bind(tenantId)}`];
2563
+ const columns =
2564
+ read.sort === 'sequence' ? ['sequence'] : ['occurred_at', 'sequence'];
2565
+ if (read.after) {
2566
+ const keyset = keysetWhere(
2567
+ columns,
2568
+ read.sort === 'sequence'
2569
+ ? [read.after.id]
2570
+ : [read.after.key, read.after.id],
2571
+ { direction: read.direction, parameterOffset: parameters.length },
2572
+ );
2573
+ clauses.push(keyset.text);
2574
+ parameters.push(...keyset.parameters);
2575
+ }
2576
+ const order = orderDirection(read.direction);
2577
+ const text = `SELECT sequence, actor_json, origin_json, action, subject_type,
2578
+ subject_id, metadata_json, occurred_at, previous_hash, event_hash
2579
+ FROM workflow_audit_events WHERE ${clauses.join(' AND ')}
2580
+ ORDER BY ${columns.map((column) => `${column} ${order}`).join(', ')}
2581
+ LIMIT ${bind(read.limit)}`;
2264
2582
  const rows = await this.#tx(tenantId, 'read', (transaction) =>
2265
- beforeSequence === undefined
2266
- ? this.#query<AuditRow>(transaction, SQL.listAudit, [
2267
- tenantId,
2268
- bounded + 1,
2269
- ])
2270
- : this.#query<AuditRow>(transaction, SQL.listAuditBefore, [
2271
- tenantId,
2272
- beforeSequence,
2273
- bounded + 1,
2274
- ]),
2583
+ this.#query<AuditRow>(transaction, text, parameters),
2275
2584
  );
2276
- const events = rows.slice(0, bounded).map(auditFromRow);
2585
+ const items = rows.map(auditFromRow);
2586
+ const last = items.at(-1);
2277
2587
  return {
2278
- events,
2279
- nextCursor:
2280
- rows.length > bounded && events.at(-1)
2281
- ? String(events.at(-1)!.sequence)
2282
- : null,
2588
+ items,
2589
+ last: last
2590
+ ? {
2591
+ key: read.sort === 'sequence' ? last.sequence : last.occurredAt,
2592
+ id: last.sequence,
2593
+ }
2594
+ : null,
2283
2595
  };
2284
2596
  }
2285
2597
 
@@ -2378,7 +2690,7 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
2378
2690
  [row.tenant_id, row.run_id],
2379
2691
  )
2380
2692
  )[0];
2381
- if (integer(remaining?.count ?? 0) === 0) {
2693
+ if (integer(remaining?.count ?? 0, 'count') === 0) {
2382
2694
  await this.#exec(transaction, SQL.expireRunOutputEvidence, [
2383
2695
  row.tenant_id,
2384
2696
  row.run_id,
@@ -2400,7 +2712,184 @@ export class DatabaseWorkflowsRepository implements WorkflowsRepository {
2400
2712
  ])
2401
2713
  )[0],
2402
2714
  );
2403
- return integer(row?.count ?? 0);
2715
+ return integer(row?.count ?? 0, 'count');
2716
+ }
2717
+
2718
+ /* The operations behind the declared data classes. Each runs on this
2719
+ module's own lease, inside its own tenant-scoped transaction. */
2720
+
2721
+ async exportRunsPage(
2722
+ tenantId: string,
2723
+ after: WorkflowRunExportCursor | null,
2724
+ limit: number,
2725
+ ): Promise<readonly ExportedWorkflowRun[]> {
2726
+ return this.#tx(tenantId, 'read', async (transaction) => {
2727
+ const runs =
2728
+ after === null
2729
+ ? await this.#query<RunRow>(transaction, SQL.exportRunsPage, [
2730
+ tenantId,
2731
+ limit,
2732
+ ])
2733
+ : await this.#query<RunRow>(transaction, SQL.exportRunsPageAfter, [
2734
+ tenantId,
2735
+ after.queuedAt,
2736
+ after.queuedAt,
2737
+ after.id,
2738
+ limit,
2739
+ ]);
2740
+ if (runs.length === 0) return [];
2741
+ /* Three queries for the whole page: a run is a row, not four round
2742
+ trips. */
2743
+ const ids = runs.map((run) => run.id);
2744
+ const states = await this.#query<ExportNodeStateRow>(
2745
+ transaction,
2746
+ SQL.exportNodeStates,
2747
+ [tenantId, ids],
2748
+ );
2749
+ const attempts = await this.#query<ExportAttemptRow>(
2750
+ transaction,
2751
+ SQL.exportAttempts,
2752
+ [tenantId, ids],
2753
+ );
2754
+ const edges = await this.#query<ExportEdgeRow>(
2755
+ transaction,
2756
+ SQL.exportEdges,
2757
+ [tenantId, ids],
2758
+ );
2759
+ /* One pass per result set into its buckets, so assembling a page costs
2760
+ O(runs + states + attempts + edges). Scanning each child set once per
2761
+ run is what turns a page of long runs quadratic. Each bucket keeps
2762
+ the order its query returned. */
2763
+ const statesByRun = new Map<string, ExportNodeStateRow[]>();
2764
+ for (const state of states) bucketed(statesByRun, state.run_id, state);
2765
+ const attemptsByNode = new Map<string, ExportAttemptRow[]>();
2766
+ for (const attempt of attempts) {
2767
+ bucketed(
2768
+ attemptsByNode,
2769
+ nodeKey(attempt.run_id, attempt.node_id),
2770
+ attempt,
2771
+ );
2772
+ }
2773
+ const edgesByRun = new Map<string, ExportEdgeRow[]>();
2774
+ for (const edge of edges) bucketed(edgesByRun, edge.run_id, edge);
2775
+ return runs.map((run) => ({
2776
+ run: runFromRow(run),
2777
+ nodes: (statesByRun.get(run.id) ?? []).map((state) =>
2778
+ nodeExecutionFromRow(
2779
+ state,
2780
+ (attemptsByNode.get(nodeKey(run.id, state.node_id)) ?? []).map(
2781
+ attemptFromRow,
2782
+ ),
2783
+ ),
2784
+ ),
2785
+ edges: (edgesByRun.get(run.id) ?? []).map(edgeFromRow),
2786
+ }));
2787
+ });
2788
+ }
2789
+
2790
+ async exportAuditEventsPage(
2791
+ tenantId: string,
2792
+ afterSequence: number,
2793
+ limit: number,
2794
+ ): Promise<readonly WorkflowAuditEvent[]> {
2795
+ return this.#tx(tenantId, 'read', async (transaction) =>
2796
+ (
2797
+ await this.#query<AuditRow>(transaction, SQL.exportAuditEventsPage, [
2798
+ tenantId,
2799
+ afterSequence,
2800
+ limit,
2801
+ ])
2802
+ ).map(auditFromRow),
2803
+ );
2804
+ }
2805
+
2806
+ async deleteRunsSettledBefore(
2807
+ tenantId: string,
2808
+ before: number,
2809
+ limit: number,
2810
+ ): Promise<number> {
2811
+ return this.#tx(tenantId, 'write', async (transaction) => {
2812
+ const rows = await this.#query<{ id: string }>(
2813
+ transaction,
2814
+ SQL.settledRunsBefore,
2815
+ [tenantId, before, limit],
2816
+ );
2817
+ return this.#deleteRunsIn(transaction, tenantId, rows);
2818
+ });
2819
+ }
2820
+
2821
+ /* A run this removes while a worker holds it takes its lease with it: the
2822
+ next renewal finds no row and the worker stops as it does for any lease
2823
+ it lost. */
2824
+ async deleteRunsOfSubject(
2825
+ tenantId: string,
2826
+ accountId: string,
2827
+ limit: number,
2828
+ ): Promise<number> {
2829
+ return this.#tx(tenantId, 'write', async (transaction) => {
2830
+ const rows = await this.#query<{ id: string }>(
2831
+ transaction,
2832
+ SQL.runsOfSubject,
2833
+ [tenantId, accountId, limit],
2834
+ );
2835
+ return this.#deleteRunsIn(transaction, tenantId, rows);
2836
+ });
2837
+ }
2838
+
2839
+ /* No foreign key hangs off a run, so the child rows are named here. A run
2840
+ and its evidence leave in one transaction or not at all. */
2841
+ async #deleteRunsIn(
2842
+ transaction: DatabaseTransaction,
2843
+ tenantId: string,
2844
+ rows: readonly { readonly id: string }[],
2845
+ ): Promise<number> {
2846
+ if (rows.length === 0) return 0;
2847
+ const ids = rows.map((row) => row.id);
2848
+ for (const statement of [
2849
+ SQL.deleteRunNodeStates,
2850
+ SQL.deleteRunAttempts,
2851
+ SQL.deleteRunEdges,
2852
+ SQL.deleteRunEvents,
2853
+ SQL.deleteRunPayloads,
2854
+ ]) {
2855
+ await this.#exec(transaction, statement, [tenantId, ids]);
2856
+ }
2857
+ return this.#exec(transaction, SQL.deleteRunRows, [tenantId, ids]);
2858
+ }
2859
+
2860
+ async exportPublishedDefinitionsPage(
2861
+ tenantId: string,
2862
+ after: WorkflowDefinitionExportCursor | null,
2863
+ limit: number,
2864
+ ): Promise<readonly ExportedWorkflowDefinition[]> {
2865
+ return this.#tx(tenantId, 'read', async (transaction) => {
2866
+ const rows =
2867
+ after === null
2868
+ ? await this.#query<ExportDefinitionRow>(
2869
+ transaction,
2870
+ SQL.exportPublishedDefinitions,
2871
+ [tenantId, limit],
2872
+ )
2873
+ : await this.#query<ExportDefinitionRow>(
2874
+ transaction,
2875
+ SQL.exportPublishedDefinitionsAfter,
2876
+ [tenantId, after.name, after.name, after.id, limit],
2877
+ );
2878
+ return rows.map((row) => ({
2879
+ definition: definitionFromRow(row),
2880
+ revision: revisionFromRow({
2881
+ id: row.revision_id,
2882
+ workflow_id: row.revision_workflow_id,
2883
+ revision: row.revision_number,
2884
+ graph_json: row.graph_json,
2885
+ graph_checksum: row.graph_checksum,
2886
+ compiler_version: row.compiler_version,
2887
+ compiled_order_json: row.compiled_order_json,
2888
+ published_at: row.published_at,
2889
+ published_actor_json: row.published_actor_json,
2890
+ }),
2891
+ }));
2892
+ });
2404
2893
  }
2405
2894
 
2406
2895
  async close(): Promise<void> {}