@weave-kit/engine 0.5.0 → 0.6.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 (622) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +6 -6
  3. package/dist/adapters/auth/index.d.ts +4 -2
  4. package/dist/adapters/auth/index.d.ts.map +1 -1
  5. package/dist/adapters/auth/index.js +1 -0
  6. package/dist/adapters/auth/index.js.map +1 -1
  7. package/dist/adapters/auth/source.d.ts +4 -4
  8. package/dist/adapters/auth/source.d.ts.map +1 -1
  9. package/dist/adapters/auth/subject.d.ts +22 -0
  10. package/dist/adapters/auth/subject.d.ts.map +1 -0
  11. package/dist/adapters/auth/subject.js +42 -0
  12. package/dist/adapters/auth/subject.js.map +1 -0
  13. package/dist/adapters/auth/verify.d.ts +12 -0
  14. package/dist/adapters/auth/verify.d.ts.map +1 -0
  15. package/dist/adapters/auth/verify.js +2 -0
  16. package/dist/adapters/auth/verify.js.map +1 -0
  17. package/dist/adapters/events/index.d.ts +2 -1
  18. package/dist/adapters/events/index.d.ts.map +1 -1
  19. package/dist/adapters/events/index.js +2 -1
  20. package/dist/adapters/events/index.js.map +1 -1
  21. package/dist/adapters/mcp/generate.d.ts +3 -3
  22. package/dist/adapters/mcp/generate.d.ts.map +1 -1
  23. package/dist/adapters/mcp/generate.js +34 -11
  24. package/dist/adapters/mcp/generate.js.map +1 -1
  25. package/dist/adapters/mcp/guardrails.d.ts +1 -1
  26. package/dist/adapters/mcp/http.d.ts +3 -1
  27. package/dist/adapters/mcp/http.d.ts.map +1 -1
  28. package/dist/adapters/mcp/http.js +2 -2
  29. package/dist/adapters/mcp/http.js.map +1 -1
  30. package/dist/adapters/mcp/index.d.ts +13 -4
  31. package/dist/adapters/mcp/index.d.ts.map +1 -1
  32. package/dist/adapters/mcp/index.js +12 -8
  33. package/dist/adapters/mcp/index.js.map +1 -1
  34. package/dist/adapters/mcp/session.d.ts +5 -5
  35. package/dist/adapters/mcp/session.d.ts.map +1 -1
  36. package/dist/adapters/mcp/tools.d.ts +6 -0
  37. package/dist/adapters/mcp/tools.d.ts.map +1 -1
  38. package/dist/adapters/mcp/tools.js +38 -14
  39. package/dist/adapters/mcp/tools.js.map +1 -1
  40. package/dist/adapters/mcp/types.d.ts +3 -1
  41. package/dist/adapters/mcp/types.d.ts.map +1 -1
  42. package/dist/adapters/mcp/types.js +1 -1
  43. package/dist/adapters/mcp/types.js.map +1 -1
  44. package/dist/adapters/openapi/document.d.ts.map +1 -1
  45. package/dist/adapters/openapi/document.js +72 -2
  46. package/dist/adapters/openapi/document.js.map +1 -1
  47. package/dist/adapters/openapi/schema.d.ts.map +1 -1
  48. package/dist/adapters/openapi/schema.js +40 -4
  49. package/dist/adapters/openapi/schema.js.map +1 -1
  50. package/dist/adapters/openapi/types.d.ts +1 -0
  51. package/dist/adapters/openapi/types.d.ts.map +1 -1
  52. package/dist/adapters/openapi/types.js +2 -0
  53. package/dist/adapters/openapi/types.js.map +1 -1
  54. package/dist/adapters/rest/approvals.d.ts +2 -2
  55. package/dist/adapters/rest/approvals.js +2 -2
  56. package/dist/adapters/rest/audit.d.ts +2 -2
  57. package/dist/adapters/rest/audit.js +2 -2
  58. package/dist/adapters/rest/common.d.ts +3 -3
  59. package/dist/adapters/rest/common.d.ts.map +1 -1
  60. package/dist/adapters/rest/common.js +1 -1
  61. package/dist/adapters/rest/guardrails.d.ts +1 -1
  62. package/dist/adapters/rest/guardrails.js +1 -1
  63. package/dist/adapters/rest/identities.d.ts +4 -4
  64. package/dist/adapters/rest/identities.d.ts.map +1 -1
  65. package/dist/adapters/rest/identities.js +3 -3
  66. package/dist/adapters/rest/identities.js.map +1 -1
  67. package/dist/adapters/rest/identityAdmin.d.ts +18 -0
  68. package/dist/adapters/rest/identityAdmin.d.ts.map +1 -0
  69. package/dist/adapters/rest/identityAdmin.js +58 -0
  70. package/dist/adapters/rest/identityAdmin.js.map +1 -0
  71. package/dist/adapters/rest/index.d.ts +4 -0
  72. package/dist/adapters/rest/index.d.ts.map +1 -1
  73. package/dist/adapters/rest/index.js +3 -0
  74. package/dist/adapters/rest/index.js.map +1 -1
  75. package/dist/adapters/rest/metadata.d.ts +1 -1
  76. package/dist/adapters/rest/metadata.js +1 -1
  77. package/dist/adapters/rest/pages.d.ts +1 -1
  78. package/dist/adapters/rest/pages.d.ts.map +1 -1
  79. package/dist/adapters/rest/permissions.d.ts +1 -1
  80. package/dist/adapters/rest/permissions.js +1 -1
  81. package/dist/adapters/rest/plugin.d.ts +2 -2
  82. package/dist/adapters/rest/plugin.d.ts.map +1 -1
  83. package/dist/adapters/rest/schemas.d.ts +1 -1
  84. package/dist/adapters/rest/schemas.d.ts.map +1 -1
  85. package/dist/adapters/rest/workflow.d.ts +15 -0
  86. package/dist/adapters/rest/workflow.d.ts.map +1 -0
  87. package/dist/adapters/rest/workflow.js +89 -0
  88. package/dist/adapters/rest/workflow.js.map +1 -0
  89. package/dist/adapters/rest/workflowSource.d.ts +15 -0
  90. package/dist/adapters/rest/workflowSource.d.ts.map +1 -0
  91. package/dist/adapters/rest/workflowSource.js +63 -0
  92. package/dist/adapters/rest/workflowSource.js.map +1 -0
  93. package/dist/cli/commands/build.js +1 -1
  94. package/dist/cli/commands/build.js.map +1 -1
  95. package/dist/cli/commands/connect.d.ts +1 -1
  96. package/dist/cli/commands/default-view.d.ts +2 -2
  97. package/dist/cli/commands/default-view.js +2 -2
  98. package/dist/cli/commands/dev.d.ts.map +1 -1
  99. package/dist/cli/commands/dev.js +18 -9
  100. package/dist/cli/commands/dev.js.map +1 -1
  101. package/dist/cli/commands/identity.d.ts +15 -0
  102. package/dist/cli/commands/identity.d.ts.map +1 -0
  103. package/dist/cli/commands/identity.js +115 -0
  104. package/dist/cli/commands/identity.js.map +1 -0
  105. package/dist/cli/commands/introspect.d.ts.map +1 -1
  106. package/dist/cli/commands/introspect.js +23 -0
  107. package/dist/cli/commands/introspect.js.map +1 -1
  108. package/dist/cli/commands/mcp-config.js +1 -1
  109. package/dist/cli/commands/mcp-config.js.map +1 -1
  110. package/dist/cli/commands/migrate.js +2 -2
  111. package/dist/cli/commands/migrate.js.map +1 -1
  112. package/dist/cli/commands/module.d.ts +2 -2
  113. package/dist/cli/commands/module.d.ts.map +1 -1
  114. package/dist/cli/commands/module.js +2 -2
  115. package/dist/cli/commands/module.js.map +1 -1
  116. package/dist/cli/commands/object-create.d.ts.map +1 -1
  117. package/dist/cli/commands/object-create.js +15 -15
  118. package/dist/cli/commands/object-create.js.map +1 -1
  119. package/dist/cli/commands/workflow-close.d.ts +9 -0
  120. package/dist/cli/commands/workflow-close.d.ts.map +1 -0
  121. package/dist/cli/commands/workflow-close.js +48 -0
  122. package/dist/cli/commands/workflow-close.js.map +1 -0
  123. package/dist/cli/commands/workflow-migrate.d.ts +11 -0
  124. package/dist/cli/commands/workflow-migrate.d.ts.map +1 -0
  125. package/dist/cli/commands/workflow-migrate.js +120 -0
  126. package/dist/cli/commands/workflow-migrate.js.map +1 -0
  127. package/dist/cli/commands/workflow-open.d.ts +10 -0
  128. package/dist/cli/commands/workflow-open.d.ts.map +1 -0
  129. package/dist/cli/commands/workflow-open.js +112 -0
  130. package/dist/cli/commands/workflow-open.js.map +1 -0
  131. package/dist/cli/commands/workflow-starter.d.ts +10 -0
  132. package/dist/cli/commands/workflow-starter.d.ts.map +1 -0
  133. package/dist/cli/commands/workflow-starter.js +29 -0
  134. package/dist/cli/commands/workflow-starter.js.map +1 -0
  135. package/dist/cli/commands/workflow-switch.d.ts +10 -0
  136. package/dist/cli/commands/workflow-switch.d.ts.map +1 -0
  137. package/dist/cli/commands/workflow-switch.js +60 -0
  138. package/dist/cli/commands/workflow-switch.js.map +1 -0
  139. package/dist/cli/commands/workflow-upgrade.d.ts +12 -0
  140. package/dist/cli/commands/workflow-upgrade.d.ts.map +1 -0
  141. package/dist/cli/commands/workflow-upgrade.js +116 -0
  142. package/dist/cli/commands/workflow-upgrade.js.map +1 -0
  143. package/dist/cli/index.js +72 -3
  144. package/dist/cli/index.js.map +1 -1
  145. package/dist/cli/project-types/manifest.d.ts +25 -0
  146. package/dist/cli/project-types/manifest.d.ts.map +1 -0
  147. package/dist/cli/project-types/manifest.js +40 -0
  148. package/dist/cli/project-types/manifest.js.map +1 -0
  149. package/dist/cli/ready-screen.js +1 -1
  150. package/dist/cli/ready-screen.js.map +1 -1
  151. package/dist/cli/scaffold.d.ts.map +1 -1
  152. package/dist/cli/scaffold.js +21 -34
  153. package/dist/cli/scaffold.js.map +1 -1
  154. package/dist/cli/types/commands.d.ts +46 -0
  155. package/dist/cli/types/commands.d.ts.map +1 -1
  156. package/dist/cli/types/index.d.ts +1 -1
  157. package/dist/cli/types/index.d.ts.map +1 -1
  158. package/dist/cli/types/values.d.ts +9 -0
  159. package/dist/cli/types/values.d.ts.map +1 -1
  160. package/dist/cli/types/values.js +9 -0
  161. package/dist/cli/types/values.js.map +1 -1
  162. package/dist/core/api/error.d.ts.map +1 -1
  163. package/dist/core/api/error.js +7 -4
  164. package/dist/core/api/error.js.map +1 -1
  165. package/dist/core/audit/types.d.ts +4 -2
  166. package/dist/core/audit/types.d.ts.map +1 -1
  167. package/dist/core/audit/types.js +2 -0
  168. package/dist/core/audit/types.js.map +1 -1
  169. package/dist/core/formula/validate.d.ts.map +1 -1
  170. package/dist/core/formula/validate.js +6 -0
  171. package/dist/core/formula/validate.js.map +1 -1
  172. package/dist/core/i18n/ar.d.ts.map +1 -1
  173. package/dist/core/i18n/ar.js +37 -3
  174. package/dist/core/i18n/ar.js.map +1 -1
  175. package/dist/core/i18n/de.d.ts.map +1 -1
  176. package/dist/core/i18n/de.js +37 -3
  177. package/dist/core/i18n/de.js.map +1 -1
  178. package/dist/core/i18n/en.d.ts +38 -4
  179. package/dist/core/i18n/en.d.ts.map +1 -1
  180. package/dist/core/i18n/en.js +38 -4
  181. package/dist/core/i18n/en.js.map +1 -1
  182. package/dist/core/i18n/es.d.ts.map +1 -1
  183. package/dist/core/i18n/es.js +37 -3
  184. package/dist/core/i18n/es.js.map +1 -1
  185. package/dist/core/i18n/fr.d.ts.map +1 -1
  186. package/dist/core/i18n/fr.js +37 -3
  187. package/dist/core/i18n/fr.js.map +1 -1
  188. package/dist/core/i18n/hi.d.ts.map +1 -1
  189. package/dist/core/i18n/hi.js +37 -3
  190. package/dist/core/i18n/hi.js.map +1 -1
  191. package/dist/core/i18n/id.d.ts.map +1 -1
  192. package/dist/core/i18n/id.js +37 -3
  193. package/dist/core/i18n/id.js.map +1 -1
  194. package/dist/core/i18n/ja.d.ts.map +1 -1
  195. package/dist/core/i18n/ja.js +37 -3
  196. package/dist/core/i18n/ja.js.map +1 -1
  197. package/dist/core/i18n/ko.d.ts.map +1 -1
  198. package/dist/core/i18n/ko.js +37 -3
  199. package/dist/core/i18n/ko.js.map +1 -1
  200. package/dist/core/i18n/pt.d.ts.map +1 -1
  201. package/dist/core/i18n/pt.js +37 -3
  202. package/dist/core/i18n/pt.js.map +1 -1
  203. package/dist/core/i18n/ru.d.ts.map +1 -1
  204. package/dist/core/i18n/ru.js +37 -3
  205. package/dist/core/i18n/ru.js.map +1 -1
  206. package/dist/core/i18n/vi.d.ts.map +1 -1
  207. package/dist/core/i18n/vi.js +37 -3
  208. package/dist/core/i18n/vi.js.map +1 -1
  209. package/dist/core/i18n/zh-hant.d.ts.map +1 -1
  210. package/dist/core/i18n/zh-hant.js +37 -3
  211. package/dist/core/i18n/zh-hant.js.map +1 -1
  212. package/dist/core/i18n/zh.d.ts.map +1 -1
  213. package/dist/core/i18n/zh.js +38 -4
  214. package/dist/core/i18n/zh.js.map +1 -1
  215. package/dist/core/object/describe.d.ts +34 -3
  216. package/dist/core/object/describe.d.ts.map +1 -1
  217. package/dist/core/object/describe.js +48 -8
  218. package/dist/core/object/describe.js.map +1 -1
  219. package/dist/core/object/gen-types.d.ts.map +1 -1
  220. package/dist/core/object/gen-types.js +12 -1
  221. package/dist/core/object/gen-types.js.map +1 -1
  222. package/dist/core/object/graph.d.ts.map +1 -1
  223. package/dist/core/object/graph.js +52 -22
  224. package/dist/core/object/graph.js.map +1 -1
  225. package/dist/core/object/index.d.ts +5 -1
  226. package/dist/core/object/index.d.ts.map +1 -1
  227. package/dist/core/object/index.js +5 -1
  228. package/dist/core/object/index.js.map +1 -1
  229. package/dist/core/object/migrations.d.ts.map +1 -1
  230. package/dist/core/object/migrations.js +39 -0
  231. package/dist/core/object/migrations.js.map +1 -1
  232. package/dist/core/object/parse.d.ts +7 -0
  233. package/dist/core/object/parse.d.ts.map +1 -1
  234. package/dist/core/object/parse.js +32 -1
  235. package/dist/core/object/parse.js.map +1 -1
  236. package/dist/core/object/record-key.d.ts +19 -0
  237. package/dist/core/object/record-key.d.ts.map +1 -0
  238. package/dist/core/object/record-key.js +100 -0
  239. package/dist/core/object/record-key.js.map +1 -0
  240. package/dist/core/object/schema-version.d.ts +1 -1
  241. package/dist/core/object/schema-version.js +1 -1
  242. package/dist/core/object/system-objects.d.ts +16 -0
  243. package/dist/core/object/system-objects.d.ts.map +1 -0
  244. package/dist/core/object/system-objects.js +72 -0
  245. package/dist/core/object/system-objects.js.map +1 -0
  246. package/dist/core/object/validate/field.d.ts.map +1 -1
  247. package/dist/core/object/validate/field.js +235 -35
  248. package/dist/core/object/validate/field.js.map +1 -1
  249. package/dist/core/object/validate/formulas.d.ts.map +1 -1
  250. package/dist/core/object/validate/formulas.js +6 -0
  251. package/dist/core/object/validate/formulas.js.map +1 -1
  252. package/dist/core/object/validate/object.d.ts +2 -0
  253. package/dist/core/object/validate/object.d.ts.map +1 -1
  254. package/dist/core/object/validate/object.js +51 -19
  255. package/dist/core/object/validate/object.js.map +1 -1
  256. package/dist/core/object/validate/permissions.d.ts.map +1 -1
  257. package/dist/core/object/validate/permissions.js +4 -0
  258. package/dist/core/object/validate/permissions.js.map +1 -1
  259. package/dist/core/object/validate/primitives.d.ts +0 -1
  260. package/dist/core/object/validate/primitives.d.ts.map +1 -1
  261. package/dist/core/object/validate/primitives.js +1 -2
  262. package/dist/core/object/validate/primitives.js.map +1 -1
  263. package/dist/core/object/validate/workflow.d.ts +10 -0
  264. package/dist/core/object/validate/workflow.d.ts.map +1 -0
  265. package/dist/core/object/validate/workflow.js +143 -0
  266. package/dist/core/object/validate/workflow.js.map +1 -0
  267. package/dist/core/object/workflow-hash.d.ts +10 -0
  268. package/dist/core/object/workflow-hash.d.ts.map +1 -0
  269. package/dist/core/object/workflow-hash.js +27 -0
  270. package/dist/core/object/workflow-hash.js.map +1 -0
  271. package/dist/core/object/workflow-migrations.d.ts +27 -0
  272. package/dist/core/object/workflow-migrations.d.ts.map +1 -0
  273. package/dist/core/object/workflow-migrations.js +125 -0
  274. package/dist/core/object/workflow-migrations.js.map +1 -0
  275. package/dist/core/provider/event/index.d.ts +1 -1
  276. package/dist/core/provider/event/index.d.ts.map +1 -1
  277. package/dist/core/provider/event/index.js.map +1 -1
  278. package/dist/core/provider/event/types.d.ts +17 -2
  279. package/dist/core/provider/event/types.d.ts.map +1 -1
  280. package/dist/core/provider/event/types.js +2 -1
  281. package/dist/core/provider/event/types.js.map +1 -1
  282. package/dist/core/provider/identity/directory.d.ts +90 -0
  283. package/dist/core/provider/identity/directory.d.ts.map +1 -0
  284. package/dist/core/provider/identity/directory.js +3 -0
  285. package/dist/core/provider/identity/directory.js.map +1 -0
  286. package/dist/core/provider/identity/index.d.ts +5 -1
  287. package/dist/core/provider/identity/index.d.ts.map +1 -1
  288. package/dist/core/provider/identity/index.js +2 -1
  289. package/dist/core/provider/identity/index.js.map +1 -1
  290. package/dist/core/provider/identity/source.d.ts +22 -0
  291. package/dist/core/provider/identity/source.d.ts.map +1 -0
  292. package/dist/core/provider/identity/source.js +3 -0
  293. package/dist/core/provider/identity/source.js.map +1 -0
  294. package/dist/core/provider/identity/types.d.ts +62 -7
  295. package/dist/core/provider/identity/types.d.ts.map +1 -1
  296. package/dist/core/provider/identity/types.js +13 -0
  297. package/dist/core/provider/identity/types.js.map +1 -1
  298. package/dist/core/proxy/types.d.ts +4 -4
  299. package/dist/core/proxy/types.d.ts.map +1 -1
  300. package/dist/core/rbac/authorize.d.ts +10 -9
  301. package/dist/core/rbac/authorize.d.ts.map +1 -1
  302. package/dist/core/rbac/authorize.js +23 -18
  303. package/dist/core/rbac/authorize.js.map +1 -1
  304. package/dist/core/rbac/details.d.ts +33 -0
  305. package/dist/core/rbac/details.d.ts.map +1 -0
  306. package/dist/core/rbac/details.js +74 -0
  307. package/dist/core/rbac/details.js.map +1 -0
  308. package/dist/core/rbac/fields.d.ts +2 -1
  309. package/dist/core/rbac/fields.d.ts.map +1 -1
  310. package/dist/core/rbac/fields.js +3 -2
  311. package/dist/core/rbac/fields.js.map +1 -1
  312. package/dist/core/rbac/index.d.ts +3 -2
  313. package/dist/core/rbac/index.d.ts.map +1 -1
  314. package/dist/core/rbac/index.js +2 -1
  315. package/dist/core/rbac/index.js.map +1 -1
  316. package/dist/core/rbac/resolve.d.ts +3 -1
  317. package/dist/core/rbac/resolve.d.ts.map +1 -1
  318. package/dist/core/rbac/resolve.js +17 -9
  319. package/dist/core/rbac/resolve.js.map +1 -1
  320. package/dist/core/rbac/rls.d.ts +6 -0
  321. package/dist/core/rbac/rls.d.ts.map +1 -1
  322. package/dist/core/rbac/rls.js +52 -7
  323. package/dist/core/rbac/rls.js.map +1 -1
  324. package/dist/core/rbac/rowScope.d.ts +13 -6
  325. package/dist/core/rbac/rowScope.d.ts.map +1 -1
  326. package/dist/core/rbac/rowScope.js +88 -16
  327. package/dist/core/rbac/rowScope.js.map +1 -1
  328. package/dist/core/rbac/types.d.ts +6 -7
  329. package/dist/core/rbac/types.d.ts.map +1 -1
  330. package/dist/core/script/types.d.ts +1 -1
  331. package/dist/core/script/types.d.ts.map +1 -1
  332. package/dist/core/storage/diff.d.ts +4 -2
  333. package/dist/core/storage/diff.d.ts.map +1 -1
  334. package/dist/core/storage/diff.js +20 -17
  335. package/dist/core/storage/diff.js.map +1 -1
  336. package/dist/core/storage/index.d.ts +7 -1
  337. package/dist/core/storage/index.d.ts.map +1 -1
  338. package/dist/core/storage/index.js +6 -1
  339. package/dist/core/storage/index.js.map +1 -1
  340. package/dist/core/storage/inspect.d.ts +12 -3
  341. package/dist/core/storage/inspect.d.ts.map +1 -1
  342. package/dist/core/storage/inspect.js +39 -22
  343. package/dist/core/storage/inspect.js.map +1 -1
  344. package/dist/core/storage/introspect.d.ts +9 -2
  345. package/dist/core/storage/introspect.d.ts.map +1 -1
  346. package/dist/core/storage/introspect.js +100 -43
  347. package/dist/core/storage/introspect.js.map +1 -1
  348. package/dist/core/storage/link-table.d.ts +47 -0
  349. package/dist/core/storage/link-table.d.ts.map +1 -0
  350. package/dist/core/storage/link-table.js +110 -0
  351. package/dist/core/storage/link-table.js.map +1 -0
  352. package/dist/core/storage/map.d.ts.map +1 -1
  353. package/dist/core/storage/map.js +135 -81
  354. package/dist/core/storage/map.js.map +1 -1
  355. package/dist/core/storage/meta.d.ts +6 -3
  356. package/dist/core/storage/meta.d.ts.map +1 -1
  357. package/dist/core/storage/meta.js +9 -5
  358. package/dist/core/storage/meta.js.map +1 -1
  359. package/dist/core/storage/migrate.d.ts.map +1 -1
  360. package/dist/core/storage/migrate.js +144 -11
  361. package/dist/core/storage/migrate.js.map +1 -1
  362. package/dist/core/storage/record-key-sql.d.ts +19 -0
  363. package/dist/core/storage/record-key-sql.d.ts.map +1 -0
  364. package/dist/core/storage/record-key-sql.js +43 -0
  365. package/dist/core/storage/record-key-sql.js.map +1 -0
  366. package/dist/core/storage/record-meta.d.ts +68 -0
  367. package/dist/core/storage/record-meta.d.ts.map +1 -0
  368. package/dist/core/storage/record-meta.js +108 -0
  369. package/dist/core/storage/record-meta.js.map +1 -0
  370. package/dist/core/storage/report.d.ts.map +1 -1
  371. package/dist/core/storage/report.js +17 -7
  372. package/dist/core/storage/report.js.map +1 -1
  373. package/dist/core/storage/sql-literals.d.ts +9 -0
  374. package/dist/core/storage/sql-literals.d.ts.map +1 -0
  375. package/dist/core/storage/sql-literals.js +13 -0
  376. package/dist/core/storage/sql-literals.js.map +1 -0
  377. package/dist/core/storage/system-tables.d.ts +44 -0
  378. package/dist/core/storage/system-tables.d.ts.map +1 -0
  379. package/dist/core/storage/system-tables.js +268 -0
  380. package/dist/core/storage/system-tables.js.map +1 -0
  381. package/dist/core/tools/policies.d.ts +2 -2
  382. package/dist/core/tools/policies.js +2 -2
  383. package/dist/core/tools/types.d.ts +6 -6
  384. package/dist/core/tools/types.d.ts.map +1 -1
  385. package/dist/core/tools/values.d.ts +5 -0
  386. package/dist/core/tools/values.d.ts.map +1 -1
  387. package/dist/core/tools/values.js +9 -1
  388. package/dist/core/tools/values.js.map +1 -1
  389. package/dist/core/types/currency.d.ts +9 -0
  390. package/dist/core/types/currency.d.ts.map +1 -0
  391. package/dist/core/types/currency.js +28 -0
  392. package/dist/core/types/currency.js.map +1 -0
  393. package/dist/core/types/field-type.d.ts +4 -1
  394. package/dist/core/types/field-type.d.ts.map +1 -1
  395. package/dist/core/types/fields.d.ts +105 -19
  396. package/dist/core/types/fields.d.ts.map +1 -1
  397. package/dist/core/types/index.d.ts +8 -6
  398. package/dist/core/types/index.d.ts.map +1 -1
  399. package/dist/core/types/index.js +4 -3
  400. package/dist/core/types/index.js.map +1 -1
  401. package/dist/core/types/object.d.ts +18 -1
  402. package/dist/core/types/object.d.ts.map +1 -1
  403. package/dist/core/types/permission.d.ts +5 -0
  404. package/dist/core/types/permission.d.ts.map +1 -1
  405. package/dist/core/types/primaryField.d.ts +6 -1
  406. package/dist/core/types/primaryField.d.ts.map +1 -1
  407. package/dist/core/types/primaryField.js +8 -1
  408. package/dist/core/types/primaryField.js.map +1 -1
  409. package/dist/core/types/registry.d.ts +6 -4
  410. package/dist/core/types/registry.d.ts.map +1 -1
  411. package/dist/core/types/registry.js +40 -30
  412. package/dist/core/types/registry.js.map +1 -1
  413. package/dist/core/types/values.d.ts +97 -27
  414. package/dist/core/types/values.d.ts.map +1 -1
  415. package/dist/core/types/values.js +64 -29
  416. package/dist/core/types/values.js.map +1 -1
  417. package/dist/core/types/workflow.d.ts +140 -0
  418. package/dist/core/types/workflow.d.ts.map +1 -0
  419. package/dist/core/types/workflow.js +49 -0
  420. package/dist/core/types/workflow.js.map +1 -0
  421. package/dist/index.d.ts +2 -0
  422. package/dist/index.d.ts.map +1 -1
  423. package/dist/index.js +5 -3
  424. package/dist/index.js.map +1 -1
  425. package/dist/infrastructure/event/bus.d.ts.map +1 -1
  426. package/dist/infrastructure/event/bus.js +14 -0
  427. package/dist/infrastructure/event/bus.js.map +1 -1
  428. package/dist/infrastructure/identity.d.ts +2 -2
  429. package/dist/infrastructure/identity.d.ts.map +1 -1
  430. package/dist/infrastructure/identity.js.map +1 -1
  431. package/dist/layout-format.d.ts +6 -6
  432. package/dist/layout-format.js +4 -4
  433. package/dist/runtime/data-access/builder.d.ts +15 -5
  434. package/dist/runtime/data-access/builder.d.ts.map +1 -1
  435. package/dist/runtime/data-access/builder.js +222 -30
  436. package/dist/runtime/data-access/builder.js.map +1 -1
  437. package/dist/runtime/data-access/details.d.ts.map +1 -1
  438. package/dist/runtime/data-access/details.js +7 -2
  439. package/dist/runtime/data-access/details.js.map +1 -1
  440. package/dist/runtime/data-access/formula.d.ts +11 -3
  441. package/dist/runtime/data-access/formula.d.ts.map +1 -1
  442. package/dist/runtime/data-access/formula.js +82 -19
  443. package/dist/runtime/data-access/formula.js.map +1 -1
  444. package/dist/runtime/data-access/index.d.ts +1 -1
  445. package/dist/runtime/data-access/index.d.ts.map +1 -1
  446. package/dist/runtime/data-access/index.js +1 -1
  447. package/dist/runtime/data-access/index.js.map +1 -1
  448. package/dist/runtime/data-access/link.d.ts +7 -0
  449. package/dist/runtime/data-access/link.d.ts.map +1 -0
  450. package/dist/runtime/data-access/link.js +80 -0
  451. package/dist/runtime/data-access/link.js.map +1 -0
  452. package/dist/runtime/data-access/query.d.ts +48 -3
  453. package/dist/runtime/data-access/query.d.ts.map +1 -1
  454. package/dist/runtime/data-access/query.js +381 -45
  455. package/dist/runtime/data-access/query.js.map +1 -1
  456. package/dist/runtime/data-access/rbac.d.ts.map +1 -1
  457. package/dist/runtime/data-access/rbac.js +134 -16
  458. package/dist/runtime/data-access/rbac.js.map +1 -1
  459. package/dist/runtime/data-access/seqno.d.ts +0 -2
  460. package/dist/runtime/data-access/seqno.d.ts.map +1 -1
  461. package/dist/runtime/data-access/seqno.js +0 -9
  462. package/dist/runtime/data-access/seqno.js.map +1 -1
  463. package/dist/runtime/data-access/sql-executor.d.ts +13 -3
  464. package/dist/runtime/data-access/sql-executor.d.ts.map +1 -1
  465. package/dist/runtime/data-access/sql-executor.js +20 -14
  466. package/dist/runtime/data-access/sql-executor.js.map +1 -1
  467. package/dist/runtime/data-access/sql-gate.d.ts +4 -4
  468. package/dist/runtime/data-access/sql-gate.d.ts.map +1 -1
  469. package/dist/runtime/data-access/sql-gate.js +5 -5
  470. package/dist/runtime/data-access/sql-gate.js.map +1 -1
  471. package/dist/runtime/data-access/tx.d.ts +1 -1
  472. package/dist/runtime/data-access/tx.js +1 -1
  473. package/dist/runtime/data-access/types.d.ts +31 -3
  474. package/dist/runtime/data-access/types.d.ts.map +1 -1
  475. package/dist/runtime/data-access/validate.d.ts.map +1 -1
  476. package/dist/runtime/data-access/validate.js +79 -15
  477. package/dist/runtime/data-access/validate.js.map +1 -1
  478. package/dist/runtime/data-access/workflow.d.ts +146 -0
  479. package/dist/runtime/data-access/workflow.d.ts.map +1 -0
  480. package/dist/runtime/data-access/workflow.js +636 -0
  481. package/dist/runtime/data-access/workflow.js.map +1 -0
  482. package/dist/runtime/engine.d.ts +89 -14
  483. package/dist/runtime/engine.d.ts.map +1 -1
  484. package/dist/runtime/engine.js +123 -26
  485. package/dist/runtime/engine.js.map +1 -1
  486. package/dist/runtime/fieldtypes/loader.d.ts.map +1 -1
  487. package/dist/runtime/fieldtypes/loader.js +12 -1
  488. package/dist/runtime/fieldtypes/loader.js.map +1 -1
  489. package/dist/runtime/git/guardrailSource.d.ts +1 -1
  490. package/dist/runtime/git/index.d.ts +4 -2
  491. package/dist/runtime/git/index.d.ts.map +1 -1
  492. package/dist/runtime/git/index.js +2 -1
  493. package/dist/runtime/git/index.js.map +1 -1
  494. package/dist/runtime/git/layoutSource.d.ts +1 -1
  495. package/dist/runtime/git/loader.d.ts.map +1 -1
  496. package/dist/runtime/git/loader.js +18 -6
  497. package/dist/runtime/git/loader.js.map +1 -1
  498. package/dist/runtime/git/pageCatalog.d.ts +1 -1
  499. package/dist/runtime/git/schemaChange.d.ts +22 -0
  500. package/dist/runtime/git/schemaChange.d.ts.map +1 -1
  501. package/dist/runtime/git/schemaChange.js +28 -2
  502. package/dist/runtime/git/schemaChange.js.map +1 -1
  503. package/dist/runtime/git/schemaSource.d.ts +1 -1
  504. package/dist/runtime/git/sourceFile.d.ts +1 -1
  505. package/dist/runtime/git/sourceFile.js +1 -1
  506. package/dist/runtime/git/sourceTransaction.d.ts +1 -1
  507. package/dist/runtime/git/workflowSource.d.ts +40 -0
  508. package/dist/runtime/git/workflowSource.d.ts.map +1 -0
  509. package/dist/runtime/git/workflowSource.js +45 -0
  510. package/dist/runtime/git/workflowSource.js.map +1 -0
  511. package/dist/runtime/identity/admin.d.ts +18 -0
  512. package/dist/runtime/identity/admin.d.ts.map +1 -0
  513. package/dist/runtime/identity/admin.js +27 -0
  514. package/dist/runtime/identity/admin.js.map +1 -0
  515. package/dist/runtime/identity/directory.d.ts +12 -0
  516. package/dist/runtime/identity/directory.d.ts.map +1 -0
  517. package/dist/runtime/identity/directory.js +22 -0
  518. package/dist/runtime/identity/directory.js.map +1 -0
  519. package/dist/runtime/identity/index.d.ts +11 -0
  520. package/dist/runtime/identity/index.d.ts.map +1 -0
  521. package/dist/runtime/identity/index.js +8 -0
  522. package/dist/runtime/identity/index.js.map +1 -0
  523. package/dist/runtime/identity/resolve.d.ts +10 -0
  524. package/dist/runtime/identity/resolve.d.ts.map +1 -0
  525. package/dist/runtime/identity/resolve.js +16 -0
  526. package/dist/runtime/identity/resolve.js.map +1 -0
  527. package/dist/runtime/identity/sources/function.d.ts +10 -0
  528. package/dist/runtime/identity/sources/function.d.ts.map +1 -0
  529. package/dist/runtime/identity/sources/function.js +9 -0
  530. package/dist/runtime/identity/sources/function.js.map +1 -0
  531. package/dist/runtime/identity/sources/pg.d.ts +42 -0
  532. package/dist/runtime/identity/sources/pg.d.ts.map +1 -0
  533. package/dist/runtime/identity/sources/pg.js +121 -0
  534. package/dist/runtime/identity/sources/pg.js.map +1 -0
  535. package/dist/runtime/identity/store.d.ts +27 -0
  536. package/dist/runtime/identity/store.d.ts.map +1 -0
  537. package/dist/runtime/identity/store.js +139 -0
  538. package/dist/runtime/identity/store.js.map +1 -0
  539. package/dist/runtime/identity/sync.d.ts +34 -0
  540. package/dist/runtime/identity/sync.d.ts.map +1 -0
  541. package/dist/runtime/identity/sync.js +149 -0
  542. package/dist/runtime/identity/sync.js.map +1 -0
  543. package/dist/runtime/metadata/cache.d.ts +0 -2
  544. package/dist/runtime/metadata/cache.d.ts.map +1 -1
  545. package/dist/runtime/metadata/cache.js +0 -11
  546. package/dist/runtime/metadata/cache.js.map +1 -1
  547. package/dist/runtime/metadata/index.d.ts +1 -1
  548. package/dist/runtime/metadata/index.d.ts.map +1 -1
  549. package/dist/runtime/metadata/index.js +1 -1
  550. package/dist/runtime/metadata/index.js.map +1 -1
  551. package/dist/runtime/record-meta/index.d.ts +2 -0
  552. package/dist/runtime/record-meta/index.d.ts.map +1 -0
  553. package/dist/runtime/record-meta/index.js +2 -0
  554. package/dist/runtime/record-meta/index.js.map +1 -0
  555. package/dist/runtime/record-meta/store.d.ts +43 -0
  556. package/dist/runtime/record-meta/store.d.ts.map +1 -0
  557. package/dist/runtime/record-meta/store.js +88 -0
  558. package/dist/runtime/record-meta/store.js.map +1 -0
  559. package/dist/runtime/sql-analyzer/index.d.ts.map +1 -1
  560. package/dist/runtime/sql-analyzer/index.js +59 -0
  561. package/dist/runtime/sql-analyzer/index.js.map +1 -1
  562. package/dist/runtime/tools/executor.d.ts +11 -11
  563. package/dist/runtime/tools/executor.d.ts.map +1 -1
  564. package/dist/runtime/tools/executor.js +6 -6
  565. package/dist/runtime/tools/executor.js.map +1 -1
  566. package/dist/runtime/tools/index.d.ts +2 -0
  567. package/dist/runtime/tools/index.d.ts.map +1 -1
  568. package/dist/runtime/tools/index.js +1 -0
  569. package/dist/runtime/tools/index.js.map +1 -1
  570. package/dist/runtime/tools/policies.d.ts +22 -5
  571. package/dist/runtime/tools/policies.d.ts.map +1 -1
  572. package/dist/runtime/tools/policies.js +42 -12
  573. package/dist/runtime/tools/policies.js.map +1 -1
  574. package/dist/runtime/tunnel/connector.d.ts +1 -1
  575. package/dist/runtime/tunnel/forwarder.js +1 -1
  576. package/dist/runtime/tunnel/framing.d.ts +1 -1
  577. package/dist/runtime/tunnel/server.d.ts +1 -1
  578. package/dist/subsystems/approvals/index.d.ts +4 -4
  579. package/dist/subsystems/approvals/index.d.ts.map +1 -1
  580. package/dist/subsystems/approvals/index.js +5 -6
  581. package/dist/subsystems/approvals/index.js.map +1 -1
  582. package/dist/subsystems/approvals/store.d.ts +1 -3
  583. package/dist/subsystems/approvals/store.d.ts.map +1 -1
  584. package/dist/subsystems/approvals/store.js +1 -16
  585. package/dist/subsystems/approvals/store.js.map +1 -1
  586. package/dist/subsystems/audit/index.d.ts +1 -1
  587. package/dist/subsystems/audit/index.d.ts.map +1 -1
  588. package/dist/subsystems/audit/index.js +2 -3
  589. package/dist/subsystems/audit/index.js.map +1 -1
  590. package/dist/subsystems/audit/store.d.ts +0 -2
  591. package/dist/subsystems/audit/store.d.ts.map +1 -1
  592. package/dist/subsystems/audit/store.js +0 -21
  593. package/dist/subsystems/audit/store.js.map +1 -1
  594. package/dist/subsystems/quota/store.d.ts +9 -0
  595. package/dist/subsystems/quota/store.d.ts.map +1 -1
  596. package/dist/subsystems/quota/store.js +0 -8
  597. package/dist/subsystems/quota/store.js.map +1 -1
  598. package/dist/subsystems/script/backend/isolated-vm.js +1 -1
  599. package/dist/subsystems/script/backend/types.d.ts +2 -2
  600. package/dist/subsystems/script/backend/types.d.ts.map +1 -1
  601. package/dist/subsystems/script/bridge.d.ts +1 -1
  602. package/dist/subsystems/script/bridge.d.ts.map +1 -1
  603. package/dist/subsystems/script/bridge.js +6 -4
  604. package/dist/subsystems/script/bridge.js.map +1 -1
  605. package/dist/subsystems/script/dispatcher.d.ts.map +1 -1
  606. package/dist/subsystems/script/dispatcher.js +3 -1
  607. package/dist/subsystems/script/dispatcher.js.map +1 -1
  608. package/dist/subsystems/workflow/index.d.ts +4 -0
  609. package/dist/subsystems/workflow/index.d.ts.map +1 -0
  610. package/dist/subsystems/workflow/index.js +3 -0
  611. package/dist/subsystems/workflow/index.js.map +1 -0
  612. package/dist/subsystems/workflow/scheduler.d.ts +27 -0
  613. package/dist/subsystems/workflow/scheduler.d.ts.map +1 -0
  614. package/dist/subsystems/workflow/scheduler.js +109 -0
  615. package/dist/subsystems/workflow/scheduler.js.map +1 -0
  616. package/dist/subsystems/workflow/store.d.ts +10 -0
  617. package/dist/subsystems/workflow/store.d.ts.map +1 -0
  618. package/dist/subsystems/workflow/store.js +44 -0
  619. package/dist/subsystems/workflow/store.js.map +1 -0
  620. package/dist/version.d.ts +1 -1
  621. package/dist/version.js +1 -1
  622. package/package.json +7 -3
@@ -0,0 +1,636 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { SchemaError, WEAVE_STATUS, WORKFLOW_START_NODE, parseDuration, } from '../../core/index.js';
3
+ import { SYSTEM_TABLES } from '../../core/storage/system-tables.js';
4
+ import { upsertRecordMeta } from '../record-meta/index.js';
5
+ const q = (id) => `"${id}"`;
6
+ const T = SYSTEM_TABLES;
7
+ const USER_TABLE = 'weavekit_user';
8
+ /** the workflow action set (single source of truth) */
9
+ export const WORKFLOW_ACTIONS = {
10
+ SUBMIT: 'submit',
11
+ APPROVE: 'approve',
12
+ REJECT: 'reject',
13
+ WITHDRAW: 'withdraw',
14
+ CANCEL: 'cancel',
15
+ FORWARD: 'forward',
16
+ REACTIVATE: 'reactivate',
17
+ };
18
+ /** role name that may run admin-only actions (reactivate / future override) */
19
+ export const WORKFLOW_ADMIN_ROLE = 'admin';
20
+ /** true when the subject holds an admin role */
21
+ export function isWorkflowAdmin(subject) {
22
+ return subject !== undefined && subject.roles.includes(WORKFLOW_ADMIN_ROLE);
23
+ }
24
+ /** side-table `status` mirror values (map instance state → record status) */
25
+ const SIDE_STATUS = {
26
+ running: WEAVE_STATUS.RUNNING,
27
+ finished: WEAVE_STATUS.EFFECTIVE,
28
+ canceled: WEAVE_STATUS.CANCELED,
29
+ };
30
+ /** load (and row-lock) the single instance for a record, if any */
31
+ async function loadInstance(client, object, recordKey) {
32
+ const res = await client.query(`SELECT state, workflow_hash, current_step_id, originator, originator_parent
33
+ FROM ${q(T.WORKFLOW_INSTANCES)} WHERE object = $1 AND record_key = $2 FOR UPDATE`, [object, recordKey]);
34
+ return res.rows[0];
35
+ }
36
+ /** the current active step of an instance (row-locked) */
37
+ async function loadActiveStep(client, stepId) {
38
+ if (stepId === null)
39
+ return undefined;
40
+ const res = await client.query(`SELECT id, node_id, kind, ordinal, state FROM ${q(T.WORKFLOW_STEPS)} WHERE id = $1 FOR UPDATE`, [stepId]);
41
+ return res.rows[0];
42
+ }
43
+ /** open (active) workitems of a step (row-locked) */
44
+ async function loadOpenWorkitems(client, stepId) {
45
+ const res = await client.query(`SELECT id, step_id, node_id, kind, participant, state
46
+ FROM ${q(T.WORKFLOW_WORKITEMS)} WHERE step_id = $1 AND state = 'active' FOR UPDATE`, [stepId]);
47
+ return res.rows;
48
+ }
49
+ async function nextOrdinal(client, object, recordKey) {
50
+ const res = await client.query(`SELECT COALESCE(MAX(ordinal), 0) + 1 AS n FROM ${q(T.WORKFLOW_STEPS)} WHERE object = $1 AND record_key = $2`, [object, recordKey]);
51
+ return Number(res.rows[0].n);
52
+ }
53
+ /** resolve node roles to internal user ids (`weavekit_user.roles` jsonb containment) */
54
+ async function resolveAssignees(client, roles) {
55
+ if (roles.length === 0)
56
+ return [];
57
+ const res = await client.query(`SELECT id::text AS id FROM ${q(USER_TABLE)} WHERE enabled IS NOT FALSE AND roles ?| $1::text[]`, [roles]);
58
+ return res.rows.map((r) => r.id);
59
+ }
60
+ /** resolve the definition an instance is pinned to (registry fast-path, else the registry table) */
61
+ async function resolveDefinition(client, def, hash, locale) {
62
+ if (def.workflow !== undefined && def.workflowHash === hash)
63
+ return def.workflow;
64
+ const res = await client.query(`SELECT definition FROM ${q(T.WORKFLOW_DEFINITIONS)} WHERE object = $1 AND hash = $2`, [def.name, hash]);
65
+ const row = res.rows[0];
66
+ if (row === undefined) {
67
+ throw new SchemaError('workflow.definition.missing', { object: def.name }, locale);
68
+ }
69
+ return row.definition;
70
+ }
71
+ /** content-address the current definition (idempotent, append-only) */
72
+ async function registerDefinition(client, object, hash, workflow) {
73
+ await client.query(`INSERT INTO ${q(T.WORKFLOW_DEFINITIONS)} (object, hash, version_seq, definition)
74
+ VALUES ($1, $2, (SELECT COALESCE(MAX(version_seq), 0) + 1 FROM ${q(T.WORKFLOW_DEFINITIONS)} WHERE object = $1), $3::jsonb)
75
+ ON CONFLICT (object, hash) DO NOTHING`, [object, hash, JSON.stringify(workflow)]);
76
+ }
77
+ async function createStep(client, object, recordKey, nodeId, kind, prevStepId, now) {
78
+ const stepId = randomUUID();
79
+ const ordinal = await nextOrdinal(client, object, recordKey);
80
+ await client.query(`INSERT INTO ${q(T.WORKFLOW_STEPS)} (id, object, record_key, node_id, kind, ordinal, state, prev_step_id, entered_at)
81
+ VALUES ($1, $2, $3, $4, $5, $6, 'active', $7, $8)`, [stepId, object, recordKey, nodeId, kind, ordinal, prevStepId, now]);
82
+ return stepId;
83
+ }
84
+ async function insertWorkitem(client, w) {
85
+ const id = randomUUID();
86
+ await client.query(`INSERT INTO ${q(T.WORKFLOW_WORKITEMS)}
87
+ (id, object, record_key, step_id, node_id, kind, participant, state, approval, action,
88
+ finisher, delegant, receiptor, comment, received_at, finished_at, allowed_at)
89
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14, now(), $15, $16)`, [
90
+ id,
91
+ w.object,
92
+ w.recordKey,
93
+ w.stepId,
94
+ w.nodeId,
95
+ w.kind,
96
+ w.participant,
97
+ w.state,
98
+ w.approval ?? null,
99
+ w.action ?? null,
100
+ w.finisher ?? null,
101
+ w.delegant ?? null,
102
+ w.receiptor ?? null,
103
+ w.comment ?? null,
104
+ w.finishedAt ?? null,
105
+ w.allowedAt ?? null,
106
+ ]);
107
+ return id;
108
+ }
109
+ async function closeWorkitem(client, id, fields, now) {
110
+ await client.query(`UPDATE ${q(T.WORKFLOW_WORKITEMS)}
111
+ SET state = $2, approval = $3, action = $4, finisher = $5, comment = $6, finished_at = $7
112
+ WHERE id = $1`, [id, fields.state, fields.approval ?? null, fields.action ?? null, fields.finisher ?? null, fields.comment ?? null, now]);
113
+ }
114
+ async function cancelOpenWorkitems(client, stepId, now) {
115
+ await client.query(`UPDATE ${q(T.WORKFLOW_WORKITEMS)} SET state = 'canceled', finished_at = $2 WHERE step_id = $1 AND state = 'active'`, [stepId, now]);
116
+ }
117
+ async function closeStep(client, id, state, approval, now) {
118
+ await client.query(`UPDATE ${q(T.WORKFLOW_STEPS)} SET state = $2, approval = $3, finished_at = $4 WHERE id = $1`, [
119
+ id,
120
+ state,
121
+ approval,
122
+ now,
123
+ ]);
124
+ }
125
+ async function updateInstance(client, object, recordKey, sets) {
126
+ const cols = Object.keys(sets);
127
+ if (cols.length === 0)
128
+ return;
129
+ const setSql = cols.map((c, i) => `${q(c)} = $${i + 3}`).join(', ');
130
+ await client.query(`UPDATE ${q(T.WORKFLOW_INSTANCES)} SET ${setSql} WHERE object = $1 AND record_key = $2`, [object, recordKey, ...cols.map((c) => sets[c])]);
131
+ }
132
+ async function mirrorSide(client, object, recordKey, state, actor, now) {
133
+ await upsertRecordMeta(client, object, recordKey, {
134
+ status: SIDE_STATUS[state] ?? WEAVE_STATUS.RUNNING,
135
+ workflowInstanceId: recordKey,
136
+ modifiedBy: actor,
137
+ modifiedTime: now,
138
+ });
139
+ }
140
+ /** create a node's step + workitems; `notify` nodes auto-advance. Returns the active step or `finished` */
141
+ async function enterNode(client, ctx, nodeIndex) {
142
+ if (nodeIndex >= ctx.wf.nodes.length)
143
+ return { finished: true };
144
+ const node = ctx.wf.nodes[nodeIndex];
145
+ const kind = node.kind ?? 'approve';
146
+ const stepId = await createStep(client, ctx.def.name, ctx.recordKey, node.id, kind, ctx.prevStepId, ctx.now);
147
+ ctx.prevStepId = stepId;
148
+ const users = await resolveAssignees(client, node.assign.roles);
149
+ if (kind === 'notify') {
150
+ for (const participant of users) {
151
+ await insertWorkitem(client, {
152
+ object: ctx.def.name,
153
+ recordKey: ctx.recordKey,
154
+ stepId,
155
+ nodeId: node.id,
156
+ kind: 'cc',
157
+ participant,
158
+ state: 'done',
159
+ action: 'notify',
160
+ finishedAt: ctx.now,
161
+ });
162
+ }
163
+ await closeStep(client, stepId, 'finished', null, ctx.now);
164
+ return enterNode(client, ctx, nodeIndex + 1);
165
+ }
166
+ if (users.length === 0) {
167
+ throw new SchemaError('workflow.assignee.none', { object: ctx.def.name, node: node.id }, ctx.locale);
168
+ }
169
+ const timeoutMs = node.onTimeout === undefined ? undefined : parseDuration(node.onTimeout.after);
170
+ const allowedAt = timeoutMs === undefined || timeoutMs <= 0 ? null : new Date(ctx.now.getTime() + timeoutMs);
171
+ for (const participant of users) {
172
+ await insertWorkitem(client, {
173
+ object: ctx.def.name,
174
+ recordKey: ctx.recordKey,
175
+ stepId,
176
+ nodeId: node.id,
177
+ kind: 'approve',
178
+ participant,
179
+ state: 'active',
180
+ allowedAt,
181
+ });
182
+ }
183
+ return { stepId, nodeId: node.id };
184
+ }
185
+ /** create the implicit start node's step (originator acts via `submit`) */
186
+ async function enterStart(client, ctx) {
187
+ const stepId = await createStep(client, ctx.def.name, ctx.recordKey, WORKFLOW_START_NODE, 'start', ctx.prevStepId, ctx.now);
188
+ ctx.prevStepId = stepId;
189
+ return stepId;
190
+ }
191
+ function nodeIndexOf(wf, nodeId) {
192
+ return wf.nodes.findIndex((n) => n.id === nodeId);
193
+ }
194
+ /** cancel/withdraw/cancel guard: nobody else may be actively viewing the record */
195
+ async function assertNoForeignLock(client, object, recordKey, requester, locale) {
196
+ const res = await client.query(`SELECT holder FROM ${q(T.WORKFLOW_LOCKS)}
197
+ WHERE object = $1 AND record_key = $2 AND expires_at > now() AND holder <> $3 LIMIT 1`, [object, recordKey, requester]);
198
+ const row = res.rows[0];
199
+ if (row !== undefined) {
200
+ throw new SchemaError('workflow.withdraw.locked', { object, holder: row.holder }, locale);
201
+ }
202
+ }
203
+ /** find the caller's open workitem (or undefined) */
204
+ function findMyWorkitem(items, subject) {
205
+ if (subject === undefined)
206
+ return undefined;
207
+ return items.find((w) => w.kind === 'approve' && w.participant === subject.id);
208
+ }
209
+ /**
210
+ * Run one workflow action within the caller's transaction. The instance row is
211
+ * locked; steps/workitems are opened/closed accordingly. The side-table status
212
+ * mirror is updated in the same transaction.
213
+ */
214
+ export async function runWorkflowTransition(client, def, recordKey, action, subject, payload, locale) {
215
+ const now = new Date();
216
+ const actor = subject?.id ?? 'system';
217
+ const inst = await loadInstance(client, def.name, recordKey);
218
+ if (action === WORKFLOW_ACTIONS.SUBMIT) {
219
+ const hash = def.workflowHash;
220
+ if (def.workflow === undefined || def.workflow.nodes.length === 0 || hash === undefined) {
221
+ throw new SchemaError('workflow.transition.unknown', { object: def.name, action }, locale);
222
+ }
223
+ let prevStepId = null;
224
+ if (inst !== undefined && inst.state === 'running') {
225
+ const step = await loadActiveStep(client, inst.current_step_id);
226
+ if (step === undefined || step.node_id !== WORKFLOW_START_NODE) {
227
+ throw new SchemaError('workflow.transition.notAllowed', { object: def.name, action }, locale);
228
+ }
229
+ await closeStep(client, step.id, 'finished', null, now);
230
+ prevStepId = step.id;
231
+ }
232
+ await registerDefinition(client, def.name, hash, def.workflow);
233
+ if (inst === undefined) {
234
+ await client.query(`INSERT INTO ${q(T.WORKFLOW_INSTANCES)}
235
+ (object, record_key, workflow_hash, state, current_step_id, originator, originator_parent, approval, created_at, started_at, activated_at)
236
+ VALUES ($1,$2,$3,'running',NULL,$4,$5,NULL,$6,$6,$6)`, [def.name, recordKey, hash, actor, subject?.departmentId ?? null, now]);
237
+ }
238
+ else {
239
+ await updateInstance(client, def.name, recordKey, {
240
+ state: 'running',
241
+ workflow_hash: hash,
242
+ approval: null,
243
+ started_at: inst.state === 'running' ? undefined : now,
244
+ activated_at: now,
245
+ finished_at: null,
246
+ });
247
+ }
248
+ const ctx = { def, recordKey, wf: def.workflow, now, locale, prevStepId };
249
+ const entered = await enterNode(client, ctx, 0);
250
+ if ('finished' in entered) {
251
+ await updateInstance(client, def.name, recordKey, { state: 'finished', approval: 'approved', finished_at: now, current_step_id: null });
252
+ await mirrorSide(client, def.name, recordKey, 'finished', actor, now);
253
+ return { state: 'finished', fromNodeId: WORKFLOW_START_NODE };
254
+ }
255
+ await updateInstance(client, def.name, recordKey, { current_step_id: entered.stepId });
256
+ await mirrorSide(client, def.name, recordKey, 'running', actor, now);
257
+ return { state: 'running', nodeId: entered.nodeId, toNodeId: entered.nodeId, fromNodeId: WORKFLOW_START_NODE };
258
+ }
259
+ if (action === WORKFLOW_ACTIONS.REACTIVATE) {
260
+ if (!isWorkflowAdmin(subject)) {
261
+ throw new SchemaError('workflow.transition.denied', { object: def.name, role: subject?.roles.join(',') ?? '', action }, locale);
262
+ }
263
+ if (inst === undefined || inst.state === 'running') {
264
+ throw new SchemaError('workflow.transition.notAllowed', { object: def.name, action }, locale);
265
+ }
266
+ const wf = await resolveDefinition(client, def, inst.workflow_hash, locale);
267
+ const nodeId = payload?.node;
268
+ const idx = typeof nodeId === 'string' ? wf.nodes.findIndex((n) => n.id === nodeId) : -1;
269
+ if (typeof nodeId !== 'string' || idx < 0) {
270
+ throw new SchemaError('workflow.node.unknown', { object: def.name, node: String(nodeId ?? '') }, locale);
271
+ }
272
+ const ctx = { def, recordKey, wf, now, locale, prevStepId: null };
273
+ const entered = await enterNode(client, ctx, idx);
274
+ if ('finished' in entered) {
275
+ await updateInstance(client, def.name, recordKey, {
276
+ state: 'finished',
277
+ approval: 'approved',
278
+ finished_at: now,
279
+ current_step_id: null,
280
+ activated_at: now,
281
+ });
282
+ await mirrorSide(client, def.name, recordKey, 'finished', actor, now);
283
+ return { state: 'finished' };
284
+ }
285
+ await updateInstance(client, def.name, recordKey, {
286
+ state: 'running',
287
+ current_step_id: entered.stepId,
288
+ approval: null,
289
+ finished_at: null,
290
+ activated_at: now,
291
+ });
292
+ await mirrorSide(client, def.name, recordKey, 'running', actor, now);
293
+ return { state: 'running', nodeId: entered.nodeId, toNodeId: entered.nodeId };
294
+ }
295
+ if (inst === undefined || inst.state !== 'running') {
296
+ throw new SchemaError('workflow.transition.notAllowed', { object: def.name, action }, locale);
297
+ }
298
+ const wf = await resolveDefinition(client, def, inst.workflow_hash, locale);
299
+ const step = await loadActiveStep(client, inst.current_step_id);
300
+ if (step === undefined) {
301
+ throw new SchemaError('workflow.transition.notAllowed', { object: def.name, action }, locale);
302
+ }
303
+ const node = wf.nodes.find((n) => n.id === step.node_id);
304
+ const items = await loadOpenWorkitems(client, step.id);
305
+ const mine = findMyWorkitem(items, subject);
306
+ const isOriginator = subject !== undefined && subject.id === inst.originator;
307
+ const enterCtx = { def, recordKey, wf, now, locale, prevStepId: step.id };
308
+ if (action === WORKFLOW_ACTIONS.APPROVE || action === WORKFLOW_ACTIONS.REJECT || action === WORKFLOW_ACTIONS.FORWARD) {
309
+ if (subject !== undefined && mine === undefined) {
310
+ throw new SchemaError('workflow.transition.denied', { object: def.name, role: subject.roles.join(','), action }, locale);
311
+ }
312
+ if (action === WORKFLOW_ACTIONS.FORWARD) {
313
+ const to = payload?.to?.userId;
314
+ if (typeof to !== 'string' || to.length === 0 || mine === undefined) {
315
+ throw new SchemaError('workflow.transition.unknown', { object: def.name, action }, locale);
316
+ }
317
+ await client.query(`UPDATE ${q(T.WORKFLOW_WORKITEMS)}
318
+ SET state = 'transferred', action = 'forward', finisher = $2, delegant = $2, receiptor = $3, comment = $4, finished_at = $5
319
+ WHERE id = $1`, [mine.id, actor, to, commentOf(payload), now]);
320
+ const alreadyOpen = await client.query(`SELECT 1 FROM ${q(T.WORKFLOW_WORKITEMS)}
321
+ WHERE step_id = $1 AND participant = $2 AND kind = 'approve' AND state = 'active' LIMIT 1`, [step.id, to]);
322
+ if ((alreadyOpen.rowCount ?? 0) === 0) {
323
+ await insertWorkitem(client, {
324
+ object: def.name,
325
+ recordKey,
326
+ stepId: step.id,
327
+ nodeId: step.node_id,
328
+ kind: 'approve',
329
+ participant: to,
330
+ state: 'active',
331
+ delegant: actor,
332
+ });
333
+ }
334
+ return { state: 'running', nodeId: step.node_id, fromNodeId: step.node_id, toNodeId: step.node_id };
335
+ }
336
+ const approval = action === WORKFLOW_ACTIONS.APPROVE ? 'approved' : 'rejected';
337
+ if (mine !== undefined) {
338
+ await closeWorkitem(client, mine.id, { state: 'done', approval, action, finisher: actor, comment: commentOf(payload) }, now);
339
+ }
340
+ if (action === WORKFLOW_ACTIONS.REJECT) {
341
+ await cancelOpenWorkitems(client, step.id, now);
342
+ await closeStep(client, step.id, 'finished', 'rejected', now);
343
+ return rollbackTo(client, enterCtx, node, step.id, WORKFLOW_ACTIONS.REJECT, actor, now);
344
+ }
345
+ // approve: evaluate the node quorum
346
+ const mode = node?.assign.mode ?? 'any';
347
+ const remaining = (await loadOpenWorkitems(client, step.id)).filter((w) => w.kind === 'approve');
348
+ const quorumMet = mode === 'all' ? remaining.length === 0 : true;
349
+ if (!quorumMet) {
350
+ return { state: 'running', nodeId: step.node_id, fromNodeId: step.node_id, toNodeId: step.node_id };
351
+ }
352
+ await cancelOpenWorkitems(client, step.id, now);
353
+ await closeStep(client, step.id, 'finished', 'approved', now);
354
+ const idx = node === undefined ? wf.nodes.length : nodeIndexOf(wf, node.id);
355
+ const entered = await enterNode(client, enterCtx, idx + 1);
356
+ if ('finished' in entered) {
357
+ await updateInstance(client, def.name, recordKey, { state: 'finished', approval: 'approved', finished_at: now, current_step_id: null });
358
+ await mirrorSide(client, def.name, recordKey, 'finished', actor, now);
359
+ return { state: 'finished', fromNodeId: step.node_id };
360
+ }
361
+ await updateInstance(client, def.name, recordKey, { current_step_id: entered.stepId });
362
+ await mirrorSide(client, def.name, recordKey, 'running', actor, now);
363
+ return { state: 'running', nodeId: entered.nodeId, fromNodeId: step.node_id, toNodeId: entered.nodeId };
364
+ }
365
+ if (action === WORKFLOW_ACTIONS.WITHDRAW || action === WORKFLOW_ACTIONS.CANCEL) {
366
+ if (subject !== undefined && !isOriginator && mine === undefined) {
367
+ throw new SchemaError('workflow.transition.denied', { object: def.name, role: subject.roles.join(','), action }, locale);
368
+ }
369
+ await assertNoForeignLock(client, def.name, recordKey, actor, locale);
370
+ if (action === WORKFLOW_ACTIONS.CANCEL) {
371
+ await cancelOpenWorkitems(client, step.id, now);
372
+ await closeStep(client, step.id, 'canceled', 'canceled', now);
373
+ await updateInstance(client, def.name, recordKey, { state: 'canceled', approval: 'rejected', finished_at: now, current_step_id: null });
374
+ await mirrorSide(client, def.name, recordKey, 'canceled', actor, now);
375
+ return { state: 'canceled', fromNodeId: step.node_id };
376
+ }
377
+ await cancelOpenWorkitems(client, step.id, now);
378
+ await closeStep(client, step.id, 'finished', 'withdrawn', now);
379
+ return rollbackTo(client, enterCtx, node, step.id, WORKFLOW_ACTIONS.WITHDRAW, actor, now);
380
+ }
381
+ throw new SchemaError('workflow.transition.unknown', { object: def.name, action }, locale);
382
+ }
383
+ /** roll back to a node (or the start node) after reject/withdraw */
384
+ async function rollbackTo(client, ctx, node, fromStepId, action, actor, now) {
385
+ const targetId = (action === WORKFLOW_ACTIONS.REJECT ? node?.onReject : node?.onWithdraw) ?? undefined;
386
+ if (targetId === undefined) {
387
+ const stepId = await enterStart(client, ctx);
388
+ await updateInstance(client, ctx.def.name, ctx.recordKey, { current_step_id: stepId, state: 'running' });
389
+ await mirrorSide(client, ctx.def.name, ctx.recordKey, 'running', actor, now);
390
+ return { state: 'running', nodeId: WORKFLOW_START_NODE, fromNodeId: node?.id, toNodeId: WORKFLOW_START_NODE };
391
+ }
392
+ const idx = nodeIndexOf(ctx.wf, targetId);
393
+ const entered = await enterNode(client, ctx, idx);
394
+ if ('finished' in entered) {
395
+ await updateInstance(client, ctx.def.name, ctx.recordKey, { state: 'finished', finished_at: now, current_step_id: null });
396
+ await mirrorSide(client, ctx.def.name, ctx.recordKey, 'finished', actor, now);
397
+ return { state: 'finished', fromNodeId: node?.id };
398
+ }
399
+ await updateInstance(client, ctx.def.name, ctx.recordKey, { current_step_id: entered.stepId, state: 'running' });
400
+ await mirrorSide(client, ctx.def.name, ctx.recordKey, 'running', actor, now);
401
+ return { state: 'running', nodeId: entered.nodeId, fromNodeId: node?.id, toNodeId: entered.nodeId };
402
+ }
403
+ function commentOf(payload) {
404
+ const comment = payload?.comment;
405
+ return typeof comment === 'string' && comment.length > 0 ? comment : null;
406
+ }
407
+ /** presence-lock TTL (seconds) — matches the frontend heartbeat convention */
408
+ export const WORKFLOW_LOCK_TTL_SECONDS = 60;
409
+ /**
410
+ * Read a record's workflow status (no locking): instance state, current node
411
+ * and the actions available to `subject`. Used by the REST/MCP read surface.
412
+ */
413
+ export async function getWorkflowStatus(client, def, recordKey, subject) {
414
+ const instRes = await client.query(`SELECT state, approval, current_step_id, originator FROM ${q(T.WORKFLOW_INSTANCES)}
415
+ WHERE object = $1 AND record_key = $2`, [def.name, recordKey]);
416
+ const inst = instRes.rows[0];
417
+ if (inst === undefined) {
418
+ return { state: 'draft', actions: subject === undefined ? [] : [WORKFLOW_ACTIONS.SUBMIT], workitems: [] };
419
+ }
420
+ if (inst.state !== 'running') {
421
+ return {
422
+ state: inst.state,
423
+ approval: inst.approval,
424
+ actions: [],
425
+ workitems: [],
426
+ };
427
+ }
428
+ const stepRes = await client.query(`SELECT node_id, kind FROM ${q(T.WORKFLOW_STEPS)} WHERE id = $1`, [inst.current_step_id]);
429
+ const step = stepRes.rows[0];
430
+ const openRes = await client.query(`SELECT id, node_id, kind, state, participant FROM ${q(T.WORKFLOW_WORKITEMS)}
431
+ WHERE step_id = $1 AND kind = 'approve' AND state = 'active'`, [inst.current_step_id]);
432
+ const open = openRes.rows;
433
+ const mine = subject === undefined ? [] : open.filter((w) => w.participant === subject.id);
434
+ const isOriginator = subject !== undefined && subject.id === inst.originator;
435
+ const actions = [];
436
+ if (subject !== undefined) {
437
+ if (step?.node_id === WORKFLOW_START_NODE) {
438
+ actions.push(WORKFLOW_ACTIONS.SUBMIT);
439
+ }
440
+ else {
441
+ if (mine.length > 0)
442
+ actions.push(WORKFLOW_ACTIONS.APPROVE, WORKFLOW_ACTIONS.REJECT, WORKFLOW_ACTIONS.FORWARD);
443
+ if (mine.length > 0 || isOriginator)
444
+ actions.push(WORKFLOW_ACTIONS.WITHDRAW);
445
+ }
446
+ if (isOriginator)
447
+ actions.push(WORKFLOW_ACTIONS.CANCEL);
448
+ }
449
+ return {
450
+ state: 'running',
451
+ ...(step === undefined ? {} : { node: step.node_id }),
452
+ approval: inst.approval,
453
+ actions,
454
+ workitems: mine,
455
+ };
456
+ }
457
+ /** acquire/renew the caller's presence lock on the current step (TTL lease) */
458
+ export async function acquireWorkflowLock(client, def, recordKey, subject, locale) {
459
+ if (subject === undefined) {
460
+ throw new SchemaError('workflow.transition.denied', { object: def.name, role: '', action: 'lock' }, locale);
461
+ }
462
+ const instRes = await client.query(`SELECT current_step_id FROM ${q(T.WORKFLOW_INSTANCES)} WHERE object = $1 AND record_key = $2 AND state = 'running'`, [def.name, recordKey]);
463
+ const stepId = instRes.rows[0]?.current_step_id ?? null;
464
+ if (stepId === null) {
465
+ throw new SchemaError('workflow.transition.notAllowed', { object: def.name, action: 'lock' }, locale);
466
+ }
467
+ const wi = await client.query(`SELECT id FROM ${q(T.WORKFLOW_WORKITEMS)}
468
+ WHERE step_id = $1 AND participant = $2 AND kind = 'approve' AND state = 'active' LIMIT 1`, [stepId, subject.id]);
469
+ const workitemId = wi.rows[0]?.id;
470
+ if (workitemId === undefined) {
471
+ throw new SchemaError('workflow.transition.denied', { object: def.name, role: subject.roles.join(','), action: 'lock' }, locale);
472
+ }
473
+ const res = await client.query(`INSERT INTO ${q(T.WORKFLOW_LOCKS)} (workitem_id, object, record_key, holder, acquired_at, expires_at)
474
+ VALUES ($1, $2, $3, $4, now(), now() + ($5 || ' seconds')::interval)
475
+ ON CONFLICT (workitem_id) DO UPDATE SET holder = EXCLUDED.holder, acquired_at = now(), expires_at = EXCLUDED.expires_at
476
+ RETURNING expires_at`, [workitemId, def.name, recordKey, subject.id, String(WORKFLOW_LOCK_TTL_SECONDS)]);
477
+ return { expiresAt: res.rows[0].expires_at };
478
+ }
479
+ /** release the caller's presence lock (and drop any expired locks for the record) */
480
+ export async function releaseWorkflowLock(client, def, recordKey, subject) {
481
+ await client.query(`DELETE FROM ${q(T.WORKFLOW_LOCKS)} WHERE object = $1 AND record_key = $2 AND (holder = $3 OR expires_at <= now())`, [
482
+ def.name,
483
+ recordKey,
484
+ subject?.id ?? '',
485
+ ]);
486
+ }
487
+ /** read a record's workflow history (steps + workitems), oldest first */
488
+ export async function getWorkflowHistory(client, def, recordKey) {
489
+ const inst = await client.query(`SELECT state, approval FROM ${q(T.WORKFLOW_INSTANCES)} WHERE object = $1 AND record_key = $2`, [def.name, recordKey]);
490
+ const instRow = inst.rows[0];
491
+ const steps = await client.query(`SELECT id, node_id, kind, ordinal, state, approval, entered_at, finished_at
492
+ FROM ${q(T.WORKFLOW_STEPS)} WHERE object = $1 AND record_key = $2 ORDER BY ordinal`, [def.name, recordKey]);
493
+ const items = await client.query(`SELECT id, step_id, node_id, kind, participant, state, approval, action, finisher, delegant, receiptor, comment, received_at, finished_at, allowed_at
494
+ FROM ${q(T.WORKFLOW_WORKITEMS)} WHERE object = $1 AND record_key = $2 ORDER BY received_at`, [def.name, recordKey]);
495
+ return {
496
+ state: instRow?.state ?? 'draft',
497
+ approval: instRow?.approval ?? null,
498
+ steps: steps.rows.map((r) => ({
499
+ id: String(r.id),
500
+ nodeId: String(r.node_id),
501
+ kind: String(r.kind),
502
+ ordinal: Number(r.ordinal),
503
+ state: String(r.state),
504
+ approval: r.approval ?? null,
505
+ enteredAt: r.entered_at,
506
+ finishedAt: r.finished_at ?? null,
507
+ })),
508
+ workitems: items.rows.map((r) => ({
509
+ id: String(r.id),
510
+ stepId: String(r.step_id),
511
+ nodeId: String(r.node_id),
512
+ kind: String(r.kind),
513
+ participant: String(r.participant),
514
+ state: String(r.state),
515
+ approval: r.approval ?? null,
516
+ action: r.action ?? null,
517
+ finisher: r.finisher ?? null,
518
+ delegant: r.delegant ?? null,
519
+ receiptor: r.receiptor ?? null,
520
+ comment: r.comment ?? null,
521
+ receivedAt: r.received_at,
522
+ finishedAt: r.finished_at ?? null,
523
+ allowedAt: r.allowed_at ?? null,
524
+ })),
525
+ };
526
+ }
527
+ /** the subject's pending workitems across all objects (`approve` items awaiting action) */
528
+ export async function getWorkflowTodos(client, subject) {
529
+ if (subject === undefined)
530
+ return [];
531
+ const res = await client.query(`SELECT object, record_key, id, node_id, kind, state
532
+ FROM ${q(T.WORKFLOW_WORKITEMS)}
533
+ WHERE participant = $1 AND kind = 'approve' AND state = 'active'
534
+ ORDER BY received_at`, [subject.id]);
535
+ return res.rows.map((r) => ({
536
+ object: String(r.object),
537
+ recordKey: String(r.record_key),
538
+ workitemId: String(r.id),
539
+ nodeId: String(r.node_id),
540
+ kind: String(r.kind),
541
+ state: String(r.state),
542
+ }));
543
+ }
544
+ /**
545
+ * Fire a node's `onTimeout` action (system actor): approve advances, reject
546
+ * rolls back. Stale timers (the record already left the node) are ignored.
547
+ * Returns the node the record is now at so the caller can re-arm the timer.
548
+ */
549
+ export async function advanceOnTimeout(client, def, recordKey, nodeId, action, locale) {
550
+ const now = new Date();
551
+ const inst = await loadInstance(client, def.name, recordKey);
552
+ if (inst === undefined || inst.state !== 'running')
553
+ return { state: 'running' };
554
+ const step = await loadActiveStep(client, inst.current_step_id);
555
+ if (step === undefined || step.node_id !== nodeId)
556
+ return { state: 'running' };
557
+ const wf = await resolveDefinition(client, def, inst.workflow_hash, locale);
558
+ const node = wf.nodes.find((n) => n.id === step.node_id);
559
+ const ctx = { def, recordKey, wf, now, locale, prevStepId: step.id };
560
+ if (action === 'reject') {
561
+ await cancelOpenWorkitems(client, step.id, now);
562
+ await closeStep(client, step.id, 'finished', 'rejected', now);
563
+ const outcome = await rollbackTo(client, ctx, node, step.id, WORKFLOW_ACTIONS.REJECT, 'system', now);
564
+ return { state: 'running', ...(outcome.nodeId === undefined ? {} : { nodeId: outcome.nodeId }) };
565
+ }
566
+ await cancelOpenWorkitems(client, step.id, now);
567
+ await closeStep(client, step.id, 'finished', 'approved', now);
568
+ const idx = node === undefined ? wf.nodes.length : nodeIndexOf(wf, node.id);
569
+ const entered = await enterNode(client, ctx, idx + 1);
570
+ if ('finished' in entered) {
571
+ await updateInstance(client, def.name, recordKey, {
572
+ state: 'finished',
573
+ approval: 'approved',
574
+ finished_at: now,
575
+ current_step_id: null,
576
+ });
577
+ await mirrorSide(client, def.name, recordKey, 'finished', 'system', now);
578
+ return { state: 'finished' };
579
+ }
580
+ await updateInstance(client, def.name, recordKey, { current_step_id: entered.stepId, state: 'running' });
581
+ await mirrorSide(client, def.name, recordKey, 'running', 'system', now);
582
+ return { state: 'running', nodeId: entered.nodeId };
583
+ }
584
+ /**
585
+ * Admin override: jump a record to a node, or terminate it. Admin-only
586
+ * (`WORKFLOW_ADMIN_ROLE`); unlike `reactivate` it also applies to a running
587
+ * instance.
588
+ */
589
+ export async function overrideWorkflow(client, def, recordKey, patch, subject, locale) {
590
+ if (!isWorkflowAdmin(subject)) {
591
+ throw new SchemaError('workflow.transition.denied', { object: def.name, role: subject?.roles.join(',') ?? '', action: 'override' }, locale);
592
+ }
593
+ const now = new Date();
594
+ const actor = subject?.id ?? 'system';
595
+ const inst = await loadInstance(client, def.name, recordKey);
596
+ if (inst === undefined) {
597
+ throw new SchemaError('workflow.transition.notAllowed', { object: def.name, action: 'override' }, locale);
598
+ }
599
+ const wf = await resolveDefinition(client, def, inst.workflow_hash, locale);
600
+ const step = await loadActiveStep(client, inst.current_step_id);
601
+ const ctx = { def, recordKey, wf, now, locale, prevStepId: step?.id ?? null };
602
+ if (patch.node !== undefined) {
603
+ const idx = wf.nodes.findIndex((n) => n.id === patch.node);
604
+ if (idx < 0)
605
+ throw new SchemaError('workflow.node.unknown', { object: def.name, node: patch.node }, locale);
606
+ if (step !== undefined) {
607
+ await cancelOpenWorkitems(client, step.id, now);
608
+ await closeStep(client, step.id, 'finished', null, now);
609
+ }
610
+ const entered = await enterNode(client, ctx, idx);
611
+ if ('finished' in entered) {
612
+ await updateInstance(client, def.name, recordKey, { state: 'finished', approval: 'approved', finished_at: now, current_step_id: null });
613
+ await mirrorSide(client, def.name, recordKey, 'finished', actor, now);
614
+ return { state: 'finished' };
615
+ }
616
+ await updateInstance(client, def.name, recordKey, { state: 'running', current_step_id: entered.stepId, approval: null, finished_at: null });
617
+ await mirrorSide(client, def.name, recordKey, 'running', actor, now);
618
+ return { state: 'running', nodeId: entered.nodeId };
619
+ }
620
+ if (patch.state === 'canceled' || patch.state === 'finished') {
621
+ if (step !== undefined) {
622
+ await cancelOpenWorkitems(client, step.id, now);
623
+ await closeStep(client, step.id, patch.state === 'canceled' ? 'canceled' : 'finished', patch.state === 'canceled' ? 'canceled' : 'approved', now);
624
+ }
625
+ await updateInstance(client, def.name, recordKey, {
626
+ state: patch.state,
627
+ approval: patch.state === 'finished' ? 'approved' : 'rejected',
628
+ finished_at: now,
629
+ current_step_id: null,
630
+ });
631
+ await mirrorSide(client, def.name, recordKey, patch.state, actor, now);
632
+ return { state: patch.state };
633
+ }
634
+ throw new SchemaError('workflow.transition.notAllowed', { object: def.name, action: 'override' }, locale);
635
+ }
636
+ //# sourceMappingURL=workflow.js.map