@weave-kit/engine 0.4.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 (642) 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 +47 -7
  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/field-add.d.ts.map +1 -1
  102. package/dist/cli/commands/field-add.js +12 -6
  103. package/dist/cli/commands/field-add.js.map +1 -1
  104. package/dist/cli/commands/field-types.d.ts.map +1 -1
  105. package/dist/cli/commands/field-types.js +10 -1
  106. package/dist/cli/commands/field-types.js.map +1 -1
  107. package/dist/cli/commands/identity.d.ts +15 -0
  108. package/dist/cli/commands/identity.d.ts.map +1 -0
  109. package/dist/cli/commands/identity.js +115 -0
  110. package/dist/cli/commands/identity.js.map +1 -0
  111. package/dist/cli/commands/introspect.d.ts.map +1 -1
  112. package/dist/cli/commands/introspect.js +23 -0
  113. package/dist/cli/commands/introspect.js.map +1 -1
  114. package/dist/cli/commands/mcp-config.js +1 -1
  115. package/dist/cli/commands/mcp-config.js.map +1 -1
  116. package/dist/cli/commands/migrate.js +2 -2
  117. package/dist/cli/commands/migrate.js.map +1 -1
  118. package/dist/cli/commands/module.d.ts +2 -2
  119. package/dist/cli/commands/module.d.ts.map +1 -1
  120. package/dist/cli/commands/module.js +2 -2
  121. package/dist/cli/commands/module.js.map +1 -1
  122. package/dist/cli/commands/object-create.d.ts.map +1 -1
  123. package/dist/cli/commands/object-create.js +15 -15
  124. package/dist/cli/commands/object-create.js.map +1 -1
  125. package/dist/cli/commands/schema-map.d.ts.map +1 -1
  126. package/dist/cli/commands/schema-map.js +6 -0
  127. package/dist/cli/commands/schema-map.js.map +1 -1
  128. package/dist/cli/commands/workflow-close.d.ts +9 -0
  129. package/dist/cli/commands/workflow-close.d.ts.map +1 -0
  130. package/dist/cli/commands/workflow-close.js +48 -0
  131. package/dist/cli/commands/workflow-close.js.map +1 -0
  132. package/dist/cli/commands/workflow-migrate.d.ts +11 -0
  133. package/dist/cli/commands/workflow-migrate.d.ts.map +1 -0
  134. package/dist/cli/commands/workflow-migrate.js +120 -0
  135. package/dist/cli/commands/workflow-migrate.js.map +1 -0
  136. package/dist/cli/commands/workflow-open.d.ts +10 -0
  137. package/dist/cli/commands/workflow-open.d.ts.map +1 -0
  138. package/dist/cli/commands/workflow-open.js +112 -0
  139. package/dist/cli/commands/workflow-open.js.map +1 -0
  140. package/dist/cli/commands/workflow-starter.d.ts +10 -0
  141. package/dist/cli/commands/workflow-starter.d.ts.map +1 -0
  142. package/dist/cli/commands/workflow-starter.js +29 -0
  143. package/dist/cli/commands/workflow-starter.js.map +1 -0
  144. package/dist/cli/commands/workflow-switch.d.ts +10 -0
  145. package/dist/cli/commands/workflow-switch.d.ts.map +1 -0
  146. package/dist/cli/commands/workflow-switch.js +60 -0
  147. package/dist/cli/commands/workflow-switch.js.map +1 -0
  148. package/dist/cli/commands/workflow-upgrade.d.ts +12 -0
  149. package/dist/cli/commands/workflow-upgrade.d.ts.map +1 -0
  150. package/dist/cli/commands/workflow-upgrade.js +116 -0
  151. package/dist/cli/commands/workflow-upgrade.js.map +1 -0
  152. package/dist/cli/index.js +74 -3
  153. package/dist/cli/index.js.map +1 -1
  154. package/dist/cli/project-types/manifest.d.ts +25 -0
  155. package/dist/cli/project-types/manifest.d.ts.map +1 -0
  156. package/dist/cli/project-types/manifest.js +40 -0
  157. package/dist/cli/project-types/manifest.js.map +1 -0
  158. package/dist/cli/ready-screen.js +1 -1
  159. package/dist/cli/ready-screen.js.map +1 -1
  160. package/dist/cli/scaffold.d.ts.map +1 -1
  161. package/dist/cli/scaffold.js +21 -34
  162. package/dist/cli/scaffold.js.map +1 -1
  163. package/dist/cli/types/commands.d.ts +48 -0
  164. package/dist/cli/types/commands.d.ts.map +1 -1
  165. package/dist/cli/types/index.d.ts +1 -1
  166. package/dist/cli/types/index.d.ts.map +1 -1
  167. package/dist/cli/types/values.d.ts +9 -0
  168. package/dist/cli/types/values.d.ts.map +1 -1
  169. package/dist/cli/types/values.js +9 -0
  170. package/dist/cli/types/values.js.map +1 -1
  171. package/dist/core/api/error.d.ts.map +1 -1
  172. package/dist/core/api/error.js +7 -4
  173. package/dist/core/api/error.js.map +1 -1
  174. package/dist/core/audit/types.d.ts +4 -2
  175. package/dist/core/audit/types.d.ts.map +1 -1
  176. package/dist/core/audit/types.js +2 -0
  177. package/dist/core/audit/types.js.map +1 -1
  178. package/dist/core/formula/validate.d.ts.map +1 -1
  179. package/dist/core/formula/validate.js +6 -0
  180. package/dist/core/formula/validate.js.map +1 -1
  181. package/dist/core/i18n/ar.d.ts.map +1 -1
  182. package/dist/core/i18n/ar.js +59 -3
  183. package/dist/core/i18n/ar.js.map +1 -1
  184. package/dist/core/i18n/de.d.ts.map +1 -1
  185. package/dist/core/i18n/de.js +59 -3
  186. package/dist/core/i18n/de.js.map +1 -1
  187. package/dist/core/i18n/en.d.ts +60 -4
  188. package/dist/core/i18n/en.d.ts.map +1 -1
  189. package/dist/core/i18n/en.js +60 -4
  190. package/dist/core/i18n/en.js.map +1 -1
  191. package/dist/core/i18n/es.d.ts.map +1 -1
  192. package/dist/core/i18n/es.js +59 -3
  193. package/dist/core/i18n/es.js.map +1 -1
  194. package/dist/core/i18n/fr.d.ts.map +1 -1
  195. package/dist/core/i18n/fr.js +59 -3
  196. package/dist/core/i18n/fr.js.map +1 -1
  197. package/dist/core/i18n/hi.d.ts.map +1 -1
  198. package/dist/core/i18n/hi.js +59 -3
  199. package/dist/core/i18n/hi.js.map +1 -1
  200. package/dist/core/i18n/id.d.ts.map +1 -1
  201. package/dist/core/i18n/id.js +59 -3
  202. package/dist/core/i18n/id.js.map +1 -1
  203. package/dist/core/i18n/ja.d.ts.map +1 -1
  204. package/dist/core/i18n/ja.js +59 -3
  205. package/dist/core/i18n/ja.js.map +1 -1
  206. package/dist/core/i18n/ko.d.ts.map +1 -1
  207. package/dist/core/i18n/ko.js +59 -3
  208. package/dist/core/i18n/ko.js.map +1 -1
  209. package/dist/core/i18n/pt.d.ts.map +1 -1
  210. package/dist/core/i18n/pt.js +59 -3
  211. package/dist/core/i18n/pt.js.map +1 -1
  212. package/dist/core/i18n/ru.d.ts.map +1 -1
  213. package/dist/core/i18n/ru.js +59 -3
  214. package/dist/core/i18n/ru.js.map +1 -1
  215. package/dist/core/i18n/vi.d.ts.map +1 -1
  216. package/dist/core/i18n/vi.js +59 -3
  217. package/dist/core/i18n/vi.js.map +1 -1
  218. package/dist/core/i18n/zh-hant.d.ts.map +1 -1
  219. package/dist/core/i18n/zh-hant.js +59 -3
  220. package/dist/core/i18n/zh-hant.js.map +1 -1
  221. package/dist/core/i18n/zh.d.ts.map +1 -1
  222. package/dist/core/i18n/zh.js +60 -4
  223. package/dist/core/i18n/zh.js.map +1 -1
  224. package/dist/core/object/describe.d.ts +62 -3
  225. package/dist/core/object/describe.d.ts.map +1 -1
  226. package/dist/core/object/describe.js +81 -11
  227. package/dist/core/object/describe.js.map +1 -1
  228. package/dist/core/object/gen-types.d.ts.map +1 -1
  229. package/dist/core/object/gen-types.js +14 -1
  230. package/dist/core/object/gen-types.js.map +1 -1
  231. package/dist/core/object/graph.d.ts +3 -0
  232. package/dist/core/object/graph.d.ts.map +1 -1
  233. package/dist/core/object/graph.js +90 -14
  234. package/dist/core/object/graph.js.map +1 -1
  235. package/dist/core/object/index.d.ts +6 -2
  236. package/dist/core/object/index.d.ts.map +1 -1
  237. package/dist/core/object/index.js +5 -1
  238. package/dist/core/object/index.js.map +1 -1
  239. package/dist/core/object/migrations.d.ts.map +1 -1
  240. package/dist/core/object/migrations.js +45 -0
  241. package/dist/core/object/migrations.js.map +1 -1
  242. package/dist/core/object/parse.d.ts +7 -0
  243. package/dist/core/object/parse.d.ts.map +1 -1
  244. package/dist/core/object/parse.js +32 -1
  245. package/dist/core/object/parse.js.map +1 -1
  246. package/dist/core/object/record-key.d.ts +19 -0
  247. package/dist/core/object/record-key.d.ts.map +1 -0
  248. package/dist/core/object/record-key.js +100 -0
  249. package/dist/core/object/record-key.js.map +1 -0
  250. package/dist/core/object/registry.js +1 -1
  251. package/dist/core/object/registry.js.map +1 -1
  252. package/dist/core/object/schema-version.d.ts +1 -1
  253. package/dist/core/object/schema-version.js +1 -1
  254. package/dist/core/object/system-objects.d.ts +16 -0
  255. package/dist/core/object/system-objects.d.ts.map +1 -0
  256. package/dist/core/object/system-objects.js +72 -0
  257. package/dist/core/object/system-objects.js.map +1 -0
  258. package/dist/core/object/validate/constraints.d.ts +9 -0
  259. package/dist/core/object/validate/constraints.d.ts.map +1 -0
  260. package/dist/core/object/validate/constraints.js +45 -0
  261. package/dist/core/object/validate/constraints.js.map +1 -0
  262. package/dist/core/object/validate/field.d.ts.map +1 -1
  263. package/dist/core/object/validate/field.js +339 -66
  264. package/dist/core/object/validate/field.js.map +1 -1
  265. package/dist/core/object/validate/formulas.d.ts.map +1 -1
  266. package/dist/core/object/validate/formulas.js +6 -0
  267. package/dist/core/object/validate/formulas.js.map +1 -1
  268. package/dist/core/object/validate/object.d.ts +2 -0
  269. package/dist/core/object/validate/object.d.ts.map +1 -1
  270. package/dist/core/object/validate/object.js +54 -19
  271. package/dist/core/object/validate/object.js.map +1 -1
  272. package/dist/core/object/validate/permissions.d.ts.map +1 -1
  273. package/dist/core/object/validate/permissions.js +4 -0
  274. package/dist/core/object/validate/permissions.js.map +1 -1
  275. package/dist/core/object/validate/primitives.d.ts +0 -1
  276. package/dist/core/object/validate/primitives.d.ts.map +1 -1
  277. package/dist/core/object/validate/primitives.js +1 -2
  278. package/dist/core/object/validate/primitives.js.map +1 -1
  279. package/dist/core/object/validate/workflow.d.ts +10 -0
  280. package/dist/core/object/validate/workflow.d.ts.map +1 -0
  281. package/dist/core/object/validate/workflow.js +143 -0
  282. package/dist/core/object/validate/workflow.js.map +1 -0
  283. package/dist/core/object/workflow-hash.d.ts +10 -0
  284. package/dist/core/object/workflow-hash.d.ts.map +1 -0
  285. package/dist/core/object/workflow-hash.js +27 -0
  286. package/dist/core/object/workflow-hash.js.map +1 -0
  287. package/dist/core/object/workflow-migrations.d.ts +27 -0
  288. package/dist/core/object/workflow-migrations.d.ts.map +1 -0
  289. package/dist/core/object/workflow-migrations.js +125 -0
  290. package/dist/core/object/workflow-migrations.js.map +1 -0
  291. package/dist/core/provider/event/index.d.ts +1 -1
  292. package/dist/core/provider/event/index.d.ts.map +1 -1
  293. package/dist/core/provider/event/index.js.map +1 -1
  294. package/dist/core/provider/event/types.d.ts +17 -2
  295. package/dist/core/provider/event/types.d.ts.map +1 -1
  296. package/dist/core/provider/event/types.js +2 -1
  297. package/dist/core/provider/event/types.js.map +1 -1
  298. package/dist/core/provider/identity/directory.d.ts +90 -0
  299. package/dist/core/provider/identity/directory.d.ts.map +1 -0
  300. package/dist/core/provider/identity/directory.js +3 -0
  301. package/dist/core/provider/identity/directory.js.map +1 -0
  302. package/dist/core/provider/identity/index.d.ts +5 -1
  303. package/dist/core/provider/identity/index.d.ts.map +1 -1
  304. package/dist/core/provider/identity/index.js +2 -1
  305. package/dist/core/provider/identity/index.js.map +1 -1
  306. package/dist/core/provider/identity/source.d.ts +22 -0
  307. package/dist/core/provider/identity/source.d.ts.map +1 -0
  308. package/dist/core/provider/identity/source.js +3 -0
  309. package/dist/core/provider/identity/source.js.map +1 -0
  310. package/dist/core/provider/identity/types.d.ts +62 -7
  311. package/dist/core/provider/identity/types.d.ts.map +1 -1
  312. package/dist/core/provider/identity/types.js +13 -0
  313. package/dist/core/provider/identity/types.js.map +1 -1
  314. package/dist/core/proxy/types.d.ts +4 -4
  315. package/dist/core/proxy/types.d.ts.map +1 -1
  316. package/dist/core/rbac/authorize.d.ts +10 -9
  317. package/dist/core/rbac/authorize.d.ts.map +1 -1
  318. package/dist/core/rbac/authorize.js +23 -18
  319. package/dist/core/rbac/authorize.js.map +1 -1
  320. package/dist/core/rbac/details.d.ts +33 -0
  321. package/dist/core/rbac/details.d.ts.map +1 -0
  322. package/dist/core/rbac/details.js +74 -0
  323. package/dist/core/rbac/details.js.map +1 -0
  324. package/dist/core/rbac/fields.d.ts +2 -1
  325. package/dist/core/rbac/fields.d.ts.map +1 -1
  326. package/dist/core/rbac/fields.js +3 -2
  327. package/dist/core/rbac/fields.js.map +1 -1
  328. package/dist/core/rbac/index.d.ts +3 -2
  329. package/dist/core/rbac/index.d.ts.map +1 -1
  330. package/dist/core/rbac/index.js +2 -1
  331. package/dist/core/rbac/index.js.map +1 -1
  332. package/dist/core/rbac/resolve.d.ts +3 -1
  333. package/dist/core/rbac/resolve.d.ts.map +1 -1
  334. package/dist/core/rbac/resolve.js +17 -9
  335. package/dist/core/rbac/resolve.js.map +1 -1
  336. package/dist/core/rbac/rls.d.ts +6 -0
  337. package/dist/core/rbac/rls.d.ts.map +1 -1
  338. package/dist/core/rbac/rls.js +52 -7
  339. package/dist/core/rbac/rls.js.map +1 -1
  340. package/dist/core/rbac/rowScope.d.ts +13 -6
  341. package/dist/core/rbac/rowScope.d.ts.map +1 -1
  342. package/dist/core/rbac/rowScope.js +88 -16
  343. package/dist/core/rbac/rowScope.js.map +1 -1
  344. package/dist/core/rbac/types.d.ts +6 -7
  345. package/dist/core/rbac/types.d.ts.map +1 -1
  346. package/dist/core/script/types.d.ts +1 -1
  347. package/dist/core/script/types.d.ts.map +1 -1
  348. package/dist/core/storage/diff.d.ts +10 -2
  349. package/dist/core/storage/diff.d.ts.map +1 -1
  350. package/dist/core/storage/diff.js +40 -18
  351. package/dist/core/storage/diff.js.map +1 -1
  352. package/dist/core/storage/index.d.ts +7 -1
  353. package/dist/core/storage/index.d.ts.map +1 -1
  354. package/dist/core/storage/index.js +6 -1
  355. package/dist/core/storage/index.js.map +1 -1
  356. package/dist/core/storage/inspect.d.ts +12 -3
  357. package/dist/core/storage/inspect.d.ts.map +1 -1
  358. package/dist/core/storage/inspect.js +39 -22
  359. package/dist/core/storage/inspect.js.map +1 -1
  360. package/dist/core/storage/introspect.d.ts +9 -2
  361. package/dist/core/storage/introspect.d.ts.map +1 -1
  362. package/dist/core/storage/introspect.js +100 -43
  363. package/dist/core/storage/introspect.js.map +1 -1
  364. package/dist/core/storage/link-table.d.ts +47 -0
  365. package/dist/core/storage/link-table.d.ts.map +1 -0
  366. package/dist/core/storage/link-table.js +110 -0
  367. package/dist/core/storage/link-table.js.map +1 -0
  368. package/dist/core/storage/map.d.ts +14 -5
  369. package/dist/core/storage/map.d.ts.map +1 -1
  370. package/dist/core/storage/map.js +207 -39
  371. package/dist/core/storage/map.js.map +1 -1
  372. package/dist/core/storage/meta.d.ts +6 -3
  373. package/dist/core/storage/meta.d.ts.map +1 -1
  374. package/dist/core/storage/meta.js +9 -5
  375. package/dist/core/storage/meta.js.map +1 -1
  376. package/dist/core/storage/migrate.d.ts.map +1 -1
  377. package/dist/core/storage/migrate.js +144 -11
  378. package/dist/core/storage/migrate.js.map +1 -1
  379. package/dist/core/storage/record-key-sql.d.ts +19 -0
  380. package/dist/core/storage/record-key-sql.d.ts.map +1 -0
  381. package/dist/core/storage/record-key-sql.js +43 -0
  382. package/dist/core/storage/record-key-sql.js.map +1 -0
  383. package/dist/core/storage/record-meta.d.ts +68 -0
  384. package/dist/core/storage/record-meta.d.ts.map +1 -0
  385. package/dist/core/storage/record-meta.js +108 -0
  386. package/dist/core/storage/record-meta.js.map +1 -0
  387. package/dist/core/storage/report.d.ts +10 -0
  388. package/dist/core/storage/report.d.ts.map +1 -1
  389. package/dist/core/storage/report.js +31 -9
  390. package/dist/core/storage/report.js.map +1 -1
  391. package/dist/core/storage/sql-literals.d.ts +9 -0
  392. package/dist/core/storage/sql-literals.d.ts.map +1 -0
  393. package/dist/core/storage/sql-literals.js +13 -0
  394. package/dist/core/storage/sql-literals.js.map +1 -0
  395. package/dist/core/storage/system-tables.d.ts +44 -0
  396. package/dist/core/storage/system-tables.d.ts.map +1 -0
  397. package/dist/core/storage/system-tables.js +268 -0
  398. package/dist/core/storage/system-tables.js.map +1 -0
  399. package/dist/core/tools/policies.d.ts +2 -2
  400. package/dist/core/tools/policies.js +2 -2
  401. package/dist/core/tools/types.d.ts +6 -6
  402. package/dist/core/tools/types.d.ts.map +1 -1
  403. package/dist/core/tools/values.d.ts +5 -0
  404. package/dist/core/tools/values.d.ts.map +1 -1
  405. package/dist/core/tools/values.js +9 -1
  406. package/dist/core/tools/values.js.map +1 -1
  407. package/dist/core/types/currency.d.ts +9 -0
  408. package/dist/core/types/currency.d.ts.map +1 -0
  409. package/dist/core/types/currency.js +28 -0
  410. package/dist/core/types/currency.js.map +1 -0
  411. package/dist/core/types/field-type.d.ts +60 -6
  412. package/dist/core/types/field-type.d.ts.map +1 -1
  413. package/dist/core/types/field-type.js +19 -3
  414. package/dist/core/types/field-type.js.map +1 -1
  415. package/dist/core/types/fields.d.ts +118 -20
  416. package/dist/core/types/fields.d.ts.map +1 -1
  417. package/dist/core/types/index.d.ts +11 -9
  418. package/dist/core/types/index.d.ts.map +1 -1
  419. package/dist/core/types/index.js +5 -4
  420. package/dist/core/types/index.js.map +1 -1
  421. package/dist/core/types/object.d.ts +27 -2
  422. package/dist/core/types/object.d.ts.map +1 -1
  423. package/dist/core/types/permission.d.ts +5 -0
  424. package/dist/core/types/permission.d.ts.map +1 -1
  425. package/dist/core/types/primaryField.d.ts +6 -1
  426. package/dist/core/types/primaryField.d.ts.map +1 -1
  427. package/dist/core/types/primaryField.js +8 -1
  428. package/dist/core/types/primaryField.js.map +1 -1
  429. package/dist/core/types/registry.d.ts +6 -4
  430. package/dist/core/types/registry.d.ts.map +1 -1
  431. package/dist/core/types/registry.js +40 -30
  432. package/dist/core/types/registry.js.map +1 -1
  433. package/dist/core/types/values.d.ts +102 -27
  434. package/dist/core/types/values.d.ts.map +1 -1
  435. package/dist/core/types/values.js +68 -29
  436. package/dist/core/types/values.js.map +1 -1
  437. package/dist/core/types/workflow.d.ts +140 -0
  438. package/dist/core/types/workflow.d.ts.map +1 -0
  439. package/dist/core/types/workflow.js +49 -0
  440. package/dist/core/types/workflow.js.map +1 -0
  441. package/dist/index.d.ts +2 -0
  442. package/dist/index.d.ts.map +1 -1
  443. package/dist/index.js +5 -3
  444. package/dist/index.js.map +1 -1
  445. package/dist/infrastructure/event/bus.d.ts.map +1 -1
  446. package/dist/infrastructure/event/bus.js +14 -0
  447. package/dist/infrastructure/event/bus.js.map +1 -1
  448. package/dist/infrastructure/identity.d.ts +2 -2
  449. package/dist/infrastructure/identity.d.ts.map +1 -1
  450. package/dist/infrastructure/identity.js.map +1 -1
  451. package/dist/layout-format.d.ts +6 -6
  452. package/dist/layout-format.js +4 -4
  453. package/dist/runtime/data-access/builder.d.ts +15 -5
  454. package/dist/runtime/data-access/builder.d.ts.map +1 -1
  455. package/dist/runtime/data-access/builder.js +222 -30
  456. package/dist/runtime/data-access/builder.js.map +1 -1
  457. package/dist/runtime/data-access/details.d.ts.map +1 -1
  458. package/dist/runtime/data-access/details.js +7 -2
  459. package/dist/runtime/data-access/details.js.map +1 -1
  460. package/dist/runtime/data-access/formula.d.ts +11 -3
  461. package/dist/runtime/data-access/formula.d.ts.map +1 -1
  462. package/dist/runtime/data-access/formula.js +82 -19
  463. package/dist/runtime/data-access/formula.js.map +1 -1
  464. package/dist/runtime/data-access/index.d.ts +1 -1
  465. package/dist/runtime/data-access/index.d.ts.map +1 -1
  466. package/dist/runtime/data-access/index.js +1 -1
  467. package/dist/runtime/data-access/index.js.map +1 -1
  468. package/dist/runtime/data-access/link.d.ts +7 -0
  469. package/dist/runtime/data-access/link.d.ts.map +1 -0
  470. package/dist/runtime/data-access/link.js +80 -0
  471. package/dist/runtime/data-access/link.js.map +1 -0
  472. package/dist/runtime/data-access/query.d.ts +48 -3
  473. package/dist/runtime/data-access/query.d.ts.map +1 -1
  474. package/dist/runtime/data-access/query.js +399 -45
  475. package/dist/runtime/data-access/query.js.map +1 -1
  476. package/dist/runtime/data-access/rbac.d.ts.map +1 -1
  477. package/dist/runtime/data-access/rbac.js +134 -16
  478. package/dist/runtime/data-access/rbac.js.map +1 -1
  479. package/dist/runtime/data-access/seqno.d.ts +0 -2
  480. package/dist/runtime/data-access/seqno.d.ts.map +1 -1
  481. package/dist/runtime/data-access/seqno.js +0 -9
  482. package/dist/runtime/data-access/seqno.js.map +1 -1
  483. package/dist/runtime/data-access/sql-executor.d.ts +13 -3
  484. package/dist/runtime/data-access/sql-executor.d.ts.map +1 -1
  485. package/dist/runtime/data-access/sql-executor.js +20 -14
  486. package/dist/runtime/data-access/sql-executor.js.map +1 -1
  487. package/dist/runtime/data-access/sql-gate.d.ts +4 -4
  488. package/dist/runtime/data-access/sql-gate.d.ts.map +1 -1
  489. package/dist/runtime/data-access/sql-gate.js +5 -5
  490. package/dist/runtime/data-access/sql-gate.js.map +1 -1
  491. package/dist/runtime/data-access/tx.d.ts +1 -1
  492. package/dist/runtime/data-access/tx.js +1 -1
  493. package/dist/runtime/data-access/types.d.ts +31 -3
  494. package/dist/runtime/data-access/types.d.ts.map +1 -1
  495. package/dist/runtime/data-access/validate.d.ts.map +1 -1
  496. package/dist/runtime/data-access/validate.js +186 -39
  497. package/dist/runtime/data-access/validate.js.map +1 -1
  498. package/dist/runtime/data-access/workflow.d.ts +146 -0
  499. package/dist/runtime/data-access/workflow.d.ts.map +1 -0
  500. package/dist/runtime/data-access/workflow.js +636 -0
  501. package/dist/runtime/data-access/workflow.js.map +1 -0
  502. package/dist/runtime/engine.d.ts +89 -14
  503. package/dist/runtime/engine.d.ts.map +1 -1
  504. package/dist/runtime/engine.js +123 -26
  505. package/dist/runtime/engine.js.map +1 -1
  506. package/dist/runtime/fieldtypes/loader.d.ts.map +1 -1
  507. package/dist/runtime/fieldtypes/loader.js +84 -2
  508. package/dist/runtime/fieldtypes/loader.js.map +1 -1
  509. package/dist/runtime/git/guardrailSource.d.ts +1 -1
  510. package/dist/runtime/git/index.d.ts +4 -2
  511. package/dist/runtime/git/index.d.ts.map +1 -1
  512. package/dist/runtime/git/index.js +2 -1
  513. package/dist/runtime/git/index.js.map +1 -1
  514. package/dist/runtime/git/layoutSource.d.ts +1 -1
  515. package/dist/runtime/git/loader.d.ts.map +1 -1
  516. package/dist/runtime/git/loader.js +18 -6
  517. package/dist/runtime/git/loader.js.map +1 -1
  518. package/dist/runtime/git/pageCatalog.d.ts +1 -1
  519. package/dist/runtime/git/schemaChange.d.ts +22 -0
  520. package/dist/runtime/git/schemaChange.d.ts.map +1 -1
  521. package/dist/runtime/git/schemaChange.js +28 -2
  522. package/dist/runtime/git/schemaChange.js.map +1 -1
  523. package/dist/runtime/git/schemaSource.d.ts +1 -1
  524. package/dist/runtime/git/sourceFile.d.ts +1 -1
  525. package/dist/runtime/git/sourceFile.js +1 -1
  526. package/dist/runtime/git/sourceTransaction.d.ts +1 -1
  527. package/dist/runtime/git/workflowSource.d.ts +40 -0
  528. package/dist/runtime/git/workflowSource.d.ts.map +1 -0
  529. package/dist/runtime/git/workflowSource.js +45 -0
  530. package/dist/runtime/git/workflowSource.js.map +1 -0
  531. package/dist/runtime/identity/admin.d.ts +18 -0
  532. package/dist/runtime/identity/admin.d.ts.map +1 -0
  533. package/dist/runtime/identity/admin.js +27 -0
  534. package/dist/runtime/identity/admin.js.map +1 -0
  535. package/dist/runtime/identity/directory.d.ts +12 -0
  536. package/dist/runtime/identity/directory.d.ts.map +1 -0
  537. package/dist/runtime/identity/directory.js +22 -0
  538. package/dist/runtime/identity/directory.js.map +1 -0
  539. package/dist/runtime/identity/index.d.ts +11 -0
  540. package/dist/runtime/identity/index.d.ts.map +1 -0
  541. package/dist/runtime/identity/index.js +8 -0
  542. package/dist/runtime/identity/index.js.map +1 -0
  543. package/dist/runtime/identity/resolve.d.ts +10 -0
  544. package/dist/runtime/identity/resolve.d.ts.map +1 -0
  545. package/dist/runtime/identity/resolve.js +16 -0
  546. package/dist/runtime/identity/resolve.js.map +1 -0
  547. package/dist/runtime/identity/sources/function.d.ts +10 -0
  548. package/dist/runtime/identity/sources/function.d.ts.map +1 -0
  549. package/dist/runtime/identity/sources/function.js +9 -0
  550. package/dist/runtime/identity/sources/function.js.map +1 -0
  551. package/dist/runtime/identity/sources/pg.d.ts +42 -0
  552. package/dist/runtime/identity/sources/pg.d.ts.map +1 -0
  553. package/dist/runtime/identity/sources/pg.js +121 -0
  554. package/dist/runtime/identity/sources/pg.js.map +1 -0
  555. package/dist/runtime/identity/store.d.ts +27 -0
  556. package/dist/runtime/identity/store.d.ts.map +1 -0
  557. package/dist/runtime/identity/store.js +139 -0
  558. package/dist/runtime/identity/store.js.map +1 -0
  559. package/dist/runtime/identity/sync.d.ts +34 -0
  560. package/dist/runtime/identity/sync.d.ts.map +1 -0
  561. package/dist/runtime/identity/sync.js +149 -0
  562. package/dist/runtime/identity/sync.js.map +1 -0
  563. package/dist/runtime/metadata/cache.d.ts +0 -2
  564. package/dist/runtime/metadata/cache.d.ts.map +1 -1
  565. package/dist/runtime/metadata/cache.js +0 -11
  566. package/dist/runtime/metadata/cache.js.map +1 -1
  567. package/dist/runtime/metadata/index.d.ts +1 -1
  568. package/dist/runtime/metadata/index.d.ts.map +1 -1
  569. package/dist/runtime/metadata/index.js +1 -1
  570. package/dist/runtime/metadata/index.js.map +1 -1
  571. package/dist/runtime/record-meta/index.d.ts +2 -0
  572. package/dist/runtime/record-meta/index.d.ts.map +1 -0
  573. package/dist/runtime/record-meta/index.js +2 -0
  574. package/dist/runtime/record-meta/index.js.map +1 -0
  575. package/dist/runtime/record-meta/store.d.ts +43 -0
  576. package/dist/runtime/record-meta/store.d.ts.map +1 -0
  577. package/dist/runtime/record-meta/store.js +88 -0
  578. package/dist/runtime/record-meta/store.js.map +1 -0
  579. package/dist/runtime/sql-analyzer/index.d.ts.map +1 -1
  580. package/dist/runtime/sql-analyzer/index.js +59 -0
  581. package/dist/runtime/sql-analyzer/index.js.map +1 -1
  582. package/dist/runtime/tools/executor.d.ts +11 -11
  583. package/dist/runtime/tools/executor.d.ts.map +1 -1
  584. package/dist/runtime/tools/executor.js +6 -6
  585. package/dist/runtime/tools/executor.js.map +1 -1
  586. package/dist/runtime/tools/index.d.ts +2 -0
  587. package/dist/runtime/tools/index.d.ts.map +1 -1
  588. package/dist/runtime/tools/index.js +1 -0
  589. package/dist/runtime/tools/index.js.map +1 -1
  590. package/dist/runtime/tools/policies.d.ts +22 -5
  591. package/dist/runtime/tools/policies.d.ts.map +1 -1
  592. package/dist/runtime/tools/policies.js +42 -12
  593. package/dist/runtime/tools/policies.js.map +1 -1
  594. package/dist/runtime/tunnel/connector.d.ts +1 -1
  595. package/dist/runtime/tunnel/forwarder.js +1 -1
  596. package/dist/runtime/tunnel/framing.d.ts +1 -1
  597. package/dist/runtime/tunnel/server.d.ts +1 -1
  598. package/dist/subsystems/approvals/index.d.ts +4 -4
  599. package/dist/subsystems/approvals/index.d.ts.map +1 -1
  600. package/dist/subsystems/approvals/index.js +5 -6
  601. package/dist/subsystems/approvals/index.js.map +1 -1
  602. package/dist/subsystems/approvals/store.d.ts +1 -3
  603. package/dist/subsystems/approvals/store.d.ts.map +1 -1
  604. package/dist/subsystems/approvals/store.js +1 -16
  605. package/dist/subsystems/approvals/store.js.map +1 -1
  606. package/dist/subsystems/audit/index.d.ts +1 -1
  607. package/dist/subsystems/audit/index.d.ts.map +1 -1
  608. package/dist/subsystems/audit/index.js +2 -3
  609. package/dist/subsystems/audit/index.js.map +1 -1
  610. package/dist/subsystems/audit/store.d.ts +0 -2
  611. package/dist/subsystems/audit/store.d.ts.map +1 -1
  612. package/dist/subsystems/audit/store.js +0 -21
  613. package/dist/subsystems/audit/store.js.map +1 -1
  614. package/dist/subsystems/quota/store.d.ts +9 -0
  615. package/dist/subsystems/quota/store.d.ts.map +1 -1
  616. package/dist/subsystems/quota/store.js +0 -8
  617. package/dist/subsystems/quota/store.js.map +1 -1
  618. package/dist/subsystems/script/backend/isolated-vm.js +1 -1
  619. package/dist/subsystems/script/backend/types.d.ts +2 -2
  620. package/dist/subsystems/script/backend/types.d.ts.map +1 -1
  621. package/dist/subsystems/script/bridge.d.ts +1 -1
  622. package/dist/subsystems/script/bridge.d.ts.map +1 -1
  623. package/dist/subsystems/script/bridge.js +6 -4
  624. package/dist/subsystems/script/bridge.js.map +1 -1
  625. package/dist/subsystems/script/dispatcher.d.ts.map +1 -1
  626. package/dist/subsystems/script/dispatcher.js +3 -1
  627. package/dist/subsystems/script/dispatcher.js.map +1 -1
  628. package/dist/subsystems/workflow/index.d.ts +4 -0
  629. package/dist/subsystems/workflow/index.d.ts.map +1 -0
  630. package/dist/subsystems/workflow/index.js +3 -0
  631. package/dist/subsystems/workflow/index.js.map +1 -0
  632. package/dist/subsystems/workflow/scheduler.d.ts +27 -0
  633. package/dist/subsystems/workflow/scheduler.d.ts.map +1 -0
  634. package/dist/subsystems/workflow/scheduler.js +109 -0
  635. package/dist/subsystems/workflow/scheduler.js.map +1 -0
  636. package/dist/subsystems/workflow/store.d.ts +10 -0
  637. package/dist/subsystems/workflow/store.d.ts.map +1 -0
  638. package/dist/subsystems/workflow/store.js +44 -0
  639. package/dist/subsystems/workflow/store.js.map +1 -0
  640. package/dist/version.d.ts +1 -1
  641. package/dist/version.js +1 -1
  642. package/package.json +7 -3
@@ -1,14 +1,22 @@
1
- import { SchemaError, primaryKeyOf } from '../../core/index.js';
2
- import { DETAILS_COLUMNS, FIELD_TYPES } from '../../core/index.js';
1
+ import { SchemaError, primaryFieldsOf, encodeRecordKey, decodeRecordKey, canonicalizePrimaryValue } from '../../core/index.js';
2
+ import { DETAILS_COLUMNS, FIELD_TYPES, isSideTableVirtualField, RECORD_META_ID_FIELD, recordKeySql, recordMetaTableName } from '../../core/index.js';
3
3
  import { AUDIT_ACTOR_TYPES, DATA_ACTIONS } from '../../core/audit/index.js';
4
4
  import { NOOP_SCRIPT_DISPATCHER, SCRIPT_HOOKS } from '../../core/index.js';
5
+ import { evaluateTransition } from '../tools/policies.js';
5
6
  import { buildCountSql, buildFindSql, scopeSuffix } from './builder.js';
6
7
  import { deleteDetailsChildren, insertDetails } from './details.js';
8
+ import { insertLinks, replaceLinks } from './link.js';
9
+ import { runWorkflowTransition, getWorkflowStatus, acquireWorkflowLock, releaseWorkflowLock, getWorkflowHistory, getWorkflowTodos, overrideWorkflow, } from './workflow.js';
7
10
  import { computeFormulas } from './formula.js';
8
- import { ensureSeqTable, generateSeqNo } from './seqno.js';
11
+ import { generateSeqNo } from './seqno.js';
9
12
  import { validateRecord } from './validate.js';
10
13
  import { WRITE_MODES } from './values.js';
14
+ import { upsertRecordMeta, deleteRecordMeta } from '../record-meta/index.js';
11
15
  const q = (id) => `"${id}"`;
16
+ /** cross-object formula authorization derived from the request context */
17
+ function formulaAuth(ctx) {
18
+ return { subject: ctx.subject, roles: ctx.subject?.roles ?? [], locale: ctx.locale };
19
+ }
12
20
  /** PG error 42703 = undefined_column: a query referenced a column that doesn't exist */
13
21
  function isUndefinedColumn(error) {
14
22
  return typeof error === 'object' && error !== null && error.code === '42703';
@@ -21,6 +29,21 @@ function undefinedColumnOf(error) {
21
29
  const m = /column "([^"]+)" of relation/.exec(message);
22
30
  return m?.[1];
23
31
  }
32
+ /** PG error 23505 = unique_violation: a unique constraint (column or object constraint) was hit */
33
+ function isUniqueViolation(error) {
34
+ return typeof error === 'object' && error !== null && error.code === '23505';
35
+ }
36
+ /** readable field list behind a unique violation (from the detail `Key (a, b)=(...)`) */
37
+ function uniqueFieldsOf(error) {
38
+ const detail = error?.detail;
39
+ if (typeof detail === 'string') {
40
+ const m = /Key \(([^)]+)\)/.exec(detail);
41
+ if (m?.[1] !== undefined)
42
+ return m[1];
43
+ }
44
+ const constraint = error?.constraint;
45
+ return typeof constraint === 'string' ? constraint : '?';
46
+ }
24
47
  /**
25
48
  * Run a SQL statement against an object's table, mapping PG `undefined_column`
26
49
  * (42703) — a schema/DB drift (schema declares a field the table lacks) — to an
@@ -35,6 +58,9 @@ async function runTableQuery(q, objectName, sql, params, locale) {
35
58
  const field = undefinedColumnOf(error);
36
59
  throw new SchemaError('data.schemaDrift', { object: objectName, field: field ?? '' }, locale);
37
60
  }
61
+ if (isUniqueViolation(error)) {
62
+ throw new SchemaError('data.unique', { object: objectName, fields: uniqueFieldsOf(error) }, locale);
63
+ }
38
64
  throw error;
39
65
  }
40
66
  }
@@ -64,7 +90,7 @@ function scriptUserOf(ctx) {
64
90
  return {
65
91
  id: ctx.subject?.id ?? 'system',
66
92
  roles: ctx.subject?.roles ?? [],
67
- teamId: ctx.subject?.teamId,
93
+ departmentId: ctx.subject?.departmentId,
68
94
  };
69
95
  }
70
96
  const PARENT_COLUMNS = new Set([
@@ -84,7 +110,99 @@ function requireDef(ctx, objectName) {
84
110
  return def;
85
111
  }
86
112
  function bctx(ctx, objectName) {
87
- return { object: objectName, locale: ctx.locale, allowParentCols: isDetailsChild(ctx.registry, objectName) };
113
+ return {
114
+ object: objectName,
115
+ locale: ctx.locale,
116
+ allowParentCols: isDetailsChild(ctx.registry, objectName),
117
+ lookup: ctx.registry,
118
+ ...(ctx.subject === undefined ? {} : { subject: ctx.subject }),
119
+ };
120
+ }
121
+ /** hidden select column carrying the SQL-computed record_key for a fetched row */
122
+ const META_KEY_COL = '__weave_record_key';
123
+ /** select expression for the SQL-computed record_key (lossless for temporal keys) */
124
+ function recordKeySelect(def) {
125
+ return `${recordKeySql(def, (name) => q(name))} AS ${q(META_KEY_COL)}`;
126
+ }
127
+ /** the record_key of a row, from its declared primary fields (declaration order) */
128
+ function recordKeyOfRow(def, record) {
129
+ return encodeRecordKey(primaryFieldsOf(def).map((f) => canonicalizePrimaryValue(record[f.name])));
130
+ }
131
+ /** declared primary field names, in declaration order */
132
+ function primaryNames(def) {
133
+ return primaryFieldsOf(def).map((f) => f.name);
134
+ }
135
+ /** decode an external id (the record_key, for single and composite keys alike) into primary values */
136
+ function pkValuesOf(def, id, ctx) {
137
+ const names = primaryNames(def);
138
+ let values;
139
+ try {
140
+ values = decodeRecordKey(id);
141
+ }
142
+ catch {
143
+ throw new SchemaError('recordKey.invalid', { key: id }, ctx.locale);
144
+ }
145
+ if (values.length !== names.length) {
146
+ throw new SchemaError('recordKey.invalid', { key: id }, ctx.locale);
147
+ }
148
+ return values;
149
+ }
150
+ /** primary-key filter object for `find` (declared names zipped with values) */
151
+ function pkFilter(def, values) {
152
+ const filter = {};
153
+ primaryNames(def).forEach((name, i) => {
154
+ filter[name] = values[i];
155
+ });
156
+ return filter;
157
+ }
158
+ /** `"a" = $1 AND "b" = $2` predicate for the primary names, starting at `startIndex` */
159
+ function pkWhereSql(def, startIndex) {
160
+ return primaryNames(def)
161
+ .map((name, i) => `${q(name)} = $${startIndex + i}`)
162
+ .join(' AND ');
163
+ }
164
+ /** the external id of a record: always its record_key (single and composite keys alike) */
165
+ function externalIdOf(def, record) {
166
+ return recordKeyOfRow(def, record);
167
+ }
168
+ /** true when the query references a side-table virtual field (`weave_*` minus the derived `weave_id`) */
169
+ function needsSideTable(opts) {
170
+ if ((opts.fields ?? []).some((f) => isSideTableVirtualField(f)))
171
+ return true;
172
+ if ((opts.sort ?? []).some((s) => isSideTableVirtualField(s.field)))
173
+ return true;
174
+ const filter = opts.filter;
175
+ if (filter !== undefined) {
176
+ for (const [key, value] of Object.entries(filter)) {
177
+ if (key === '$or') {
178
+ if (Array.isArray(value) &&
179
+ value.some((group) => group !== null &&
180
+ typeof group === 'object' &&
181
+ Object.keys(group).some((k) => isSideTableVirtualField(k)))) {
182
+ return true;
183
+ }
184
+ }
185
+ else if (isSideTableVirtualField(key)) {
186
+ return true;
187
+ }
188
+ }
189
+ }
190
+ return false;
191
+ }
192
+ /**
193
+ * Narrow `ToolDataAccess` over this data-access for guardrail policies: a policy
194
+ * calls `ctx.dataAccess.find(obj, opts, { subject? })` with no pool/registry, so
195
+ * those are injected from the execution context (mirrors the tool executor's
196
+ * wrapper; `...c` lets a policy override the subject per call).
197
+ */
198
+ function toolDataAccessOver(inner, base) {
199
+ return {
200
+ find: (n, o, c) => inner.find(n, o, { ...base, ...c }),
201
+ findOne: (n, id, c) => inner.findOne(n, id, { ...base, ...c }),
202
+ create: (n, d, c) => inner.create(n, d, { ...base, ...c }),
203
+ update: (n, id, changes, c) => inner.update(n, id, changes, { ...base, ...c }),
204
+ delete: (n, id, c) => inner.delete(n, id, { ...base, ...c }),
205
+ };
88
206
  }
89
207
  /**
90
208
  * Serialize a value for binding to a DB column. pg (node-postgres) auto-stringifies
@@ -93,7 +211,10 @@ function bctx(ctx, objectName) {
93
211
  * (arrays/objects/numbers/booleans) to valid JSON text. `null` stays SQL NULL.
94
212
  */
95
213
  function dbJsonValue(field, value) {
96
- if (field !== undefined && field.type === FIELD_TYPES.JSON && value !== null && typeof value !== 'string') {
214
+ if (field !== undefined &&
215
+ (field.type === FIELD_TYPES.JSON || field.type === FIELD_TYPES.JSONB) &&
216
+ value !== null &&
217
+ typeof value !== 'string') {
97
218
  return JSON.stringify(value);
98
219
  }
99
220
  return value;
@@ -102,17 +223,26 @@ function dbJsonValue(field, value) {
102
223
  export class DefaultObjectDataAccess {
103
224
  audit;
104
225
  script;
105
- /** M10 diff replay: attach before/after row snapshots to update/delete audit events */
226
+ /** audit diff replay: attach before/after row snapshots to update/delete audit events */
106
227
  replay;
107
- /** M12 live events: publish committed writes to the bus (undefined = zero overhead) */
228
+ /** live events: publish committed writes to the bus (undefined = zero overhead) */
108
229
  events;
109
230
  /** objects currently dispatching onLoad — skips re-entrant onLoad (a hook re-reading the same object) */
110
231
  onLoadInFlight = new Set();
232
+ /** guardrail policies shared with the open-contract (empty = no policy gate on transitions) */
233
+ policies;
234
+ /** approval queue used when a policy or a transition requires approval */
235
+ approvals;
236
+ /** workflow timer handle: re-arm/cancel a record's `onTimeout` on state changes */
237
+ workflowTimers;
111
238
  constructor(options = {}) {
112
239
  this.audit = options.audit;
113
240
  this.script = options.script ?? NOOP_SCRIPT_DISPATCHER;
114
241
  this.replay = options.replay ?? false;
115
242
  this.events = options.events;
243
+ this.policies = options.policies ?? [];
244
+ this.approvals = options.approvals;
245
+ this.workflowTimers = options.workflowTimers;
116
246
  }
117
247
  /**
118
248
  * Run the read hook (`onLoad`) over a fetched batch. The hook receives the
@@ -150,13 +280,14 @@ export class DefaultObjectDataAccess {
150
280
  * hook failure → the surrounding transaction rolls back. Returns the
151
281
  * possibly-modified changes from beforeUpdate (undefined = keep original).
152
282
  */
153
- async runBeforeHook(hook, objectName, record, changes, ctx) {
283
+ async runBeforeHook(hook, objectName, record, changes, ctx, extra) {
154
284
  if (!this.script.has(objectName, hook))
155
285
  return undefined;
156
286
  const result = await this.script.dispatch(objectName, hook, {
157
287
  record,
158
288
  changes,
159
289
  user: scriptUserOf(ctx),
290
+ ...(extra ?? {}),
160
291
  });
161
292
  return result.changes;
162
293
  }
@@ -165,7 +296,7 @@ export class DefaultObjectDataAccess {
165
296
  * committed, so a hook failure is a non-fatal warning: recorded to audit and
166
297
  * delivered via `ctx.onWarnings`, never rethrown.
167
298
  */
168
- async runAfterHook(hook, action, objectName, record, changes, ctx, warnings, objectId) {
299
+ async runAfterHook(hook, action, objectName, record, changes, ctx, warnings, objectId, extra) {
169
300
  if (!this.script.has(objectName, hook))
170
301
  return;
171
302
  try {
@@ -173,6 +304,7 @@ export class DefaultObjectDataAccess {
173
304
  record,
174
305
  changes,
175
306
  user: scriptUserOf(ctx),
307
+ ...(extra ?? {}),
176
308
  });
177
309
  }
178
310
  catch (error) {
@@ -189,26 +321,33 @@ export class DefaultObjectDataAccess {
189
321
  async find(objectName, opts, ctx) {
190
322
  const def = requireDef(ctx, objectName);
191
323
  const q = ctx.client ?? ctx.pool;
192
- const { sql, params } = buildFindSql(def, opts, bctx(ctx, objectName), ctx.rowScope, opts.exclude);
324
+ // `weave_*` virtual fields live in the engine side table; when referenced,
325
+ // LEFT JOIN it and select/filter/sort them in SQL (never customer columns)
326
+ const meta = needsSideTable(opts) ? { table: recordMetaTableName(def.name) } : undefined;
327
+ const buildCtx = { ...bctx(ctx, objectName), ...(meta === undefined ? {} : { meta }) };
328
+ const { sql, params } = buildFindSql(def, opts, buildCtx, ctx.rowScope, opts.exclude);
193
329
  const { rows } = await runTableQuery(q, objectName, sql, params, ctx.locale);
194
- const { sql: countSql, params: countParams } = buildCountSql(def, opts, bctx(ctx, objectName), ctx.rowScope);
330
+ const { sql: countSql, params: countParams } = buildCountSql(def, opts, buildCtx, ctx.rowScope);
195
331
  const { rows: countRows } = await runTableQuery(q, objectName, countSql, countParams, ctx.locale);
196
332
  const loaded = await this.runOnLoad(objectName, rows, ctx);
197
333
  return { rows: loaded, total: countRows[0].total };
198
334
  }
199
335
  async findOne(objectName, id, ctx) {
200
336
  const def = requireDef(ctx, objectName);
201
- const pk = primaryKeyOf(def);
202
- if (pk === undefined) {
337
+ if (primaryNames(def).length === 0) {
203
338
  throw new SchemaError('data.recordNotFound', { object: objectName, id }, ctx.locale);
204
339
  }
205
- const result = await this.find(objectName, { filter: { [pk]: id }, limit: 1 }, ctx);
340
+ // project every declared column plus the derived `weave_id` (the record's
341
+ // external id) so a fetched record is self-identifying
342
+ const cols = def.fields.filter((f) => f.type !== FIELD_TYPES.DETAILS).map((f) => f.name);
343
+ if (isDetailsChild(ctx.registry, objectName))
344
+ cols.push(...PARENT_COLUMNS);
345
+ const result = await this.find(objectName, { filter: pkFilter(def, pkValuesOf(def, id, ctx)), limit: 1, fields: [...cols, RECORD_META_ID_FIELD] }, ctx);
206
346
  return result.rows[0] ?? null;
207
347
  }
208
348
  async create(objectName, data, ctx) {
209
349
  const def = requireDef(ctx, objectName);
210
- const pk = primaryKeyOf(def);
211
- if (pk === undefined) {
350
+ if (primaryNames(def).length === 0) {
212
351
  throw new SchemaError('data.recordNotFound', { object: objectName }, ctx.locale);
213
352
  }
214
353
  let client;
@@ -243,14 +382,16 @@ export class DefaultObjectDataAccess {
243
382
  if (payload[field.name] !== undefined)
244
383
  continue;
245
384
  record[field.name] =
246
- (field.type === FIELD_TYPES.DATETIME || field.type === FIELD_TYPES.DATE) && raw.default === 'now'
385
+ (field.type === FIELD_TYPES.DATE ||
386
+ field.type === FIELD_TYPES.TIMESTAMP ||
387
+ field.type === FIELD_TYPES.TIMESTAMPTZ) &&
388
+ raw.default === 'now'
247
389
  ? now.toISOString()
248
390
  : raw.default;
249
391
  }
250
392
  Object.assign(record, payload);
251
393
  const seqFields = def.fields.filter((f) => f.type === FIELD_TYPES.SEQ_NO);
252
394
  if (seqFields.length > 0) {
253
- await ensureSeqTable(client);
254
395
  for (const f of seqFields)
255
396
  record[f.name] = await generateSeqNo(client, def.name, f, now);
256
397
  }
@@ -261,29 +402,37 @@ export class DefaultObjectDataAccess {
261
402
  record[DETAILS_COLUMNS.PARENT_IDX] = res.rows[0].n;
262
403
  }
263
404
  const cols = [
264
- ...def.fields.filter((f) => f.type !== FIELD_TYPES.DETAILS).map((f) => f.name),
405
+ ...def.fields
406
+ .filter((f) => f.type !== FIELD_TYPES.DETAILS && f.type !== FIELD_TYPES.MULTI_RELATION)
407
+ .map((f) => f.name),
265
408
  ...(child ? [...PARENT_COLUMNS] : []),
266
409
  ];
267
410
  const fieldByName = new Map(def.fields.map((f) => [f.name, f]));
268
411
  const values = cols.map((c) => dbJsonValue(fieldByName.get(c), record[c] ?? null));
269
412
  const placeholders = cols.map((_, i) => `$${i + 1}`).join(', ');
270
- await runTableQuery(client, def.name, `INSERT INTO ${q(def.name)} (${cols.map(q).join(', ')}) VALUES (${placeholders})`, values, ctx.locale);
271
- await insertDetails(client, def, record[pk], payload, ctx.registry, ctx.locale);
413
+ const insertRes = await runTableQuery(client, def.name, `INSERT INTO ${q(def.name)} (${cols.map(q).join(', ')}) VALUES (${placeholders}) RETURNING ${recordKeySql(def, q)} AS ${q(META_KEY_COL)}`, values, ctx.locale);
414
+ const metaKey = String(insertRes.rows[0]?.[META_KEY_COL] ?? '');
415
+ const externalId = metaKey;
416
+ record[RECORD_META_ID_FIELD] = externalId;
417
+ await insertDetails(client, def, externalId, payload, ctx.registry, ctx.locale);
418
+ await insertLinks(client, def, primaryFieldsOf(def).map((f) => record[f.name]), payload, ctx.registry, ctx.locale);
272
419
  // compute formula fields AFTER children exist (aggregates see them), then persist
273
- await computeFormulas(def, record, client, ctx.registry, now);
420
+ await computeFormulas(def, record, client, ctx.registry, now, externalId, formulaAuth(ctx));
274
421
  const formulaCols = def.fields
275
422
  .filter((f) => f.formula !== undefined)
276
423
  .map((f) => f.name);
277
424
  if (formulaCols.length > 0) {
278
425
  const setSql = formulaCols.map((c, i) => `${q(c)} = $${i + 1}`).join(', ');
279
426
  const formulaValues = formulaCols.map((c) => record[c] ?? null);
280
- await runTableQuery(client, def.name, `UPDATE ${q(def.name)} SET ${setSql} WHERE ${q(pk)} = $${formulaCols.length + 1}`, [...formulaValues, record[pk]], ctx.locale);
427
+ const pkValues = pkValuesOf(def, externalId, ctx);
428
+ await runTableQuery(client, def.name, `UPDATE ${q(def.name)} SET ${setSql} WHERE ${pkWhereSql(def, formulaCols.length + 1)}`, [...formulaValues, ...pkValues], ctx.locale);
281
429
  }
430
+ await this.writeRecordMeta(client, def, metaKey, ctx, now, true);
282
431
  if (owned)
283
432
  await client.query('COMMIT');
284
- auditWrite(this.audit, ctx, DATA_ACTIONS.CREATE, objectName, String(record[pk] ?? ''), record);
285
- this.events?.publishRecordChange('created', objectName, String(record[pk] ?? ''));
286
- await this.runAfterHook(SCRIPT_HOOKS.AFTER_UPDATE, DATA_ACTIONS.CREATE, objectName, record, payload, ctx, warnings, String(record[pk] ?? ''));
433
+ auditWrite(this.audit, ctx, DATA_ACTIONS.CREATE, objectName, externalId, record);
434
+ this.events?.publishRecordChange('created', objectName, externalId);
435
+ await this.runAfterHook(SCRIPT_HOOKS.AFTER_UPDATE, DATA_ACTIONS.CREATE, objectName, record, payload, ctx, warnings, externalId);
287
436
  if (warnings.length > 0)
288
437
  ctx.onWarnings?.(warnings);
289
438
  const loaded = await this.runOnLoad(objectName, [record], ctx);
@@ -292,7 +441,10 @@ export class DefaultObjectDataAccess {
292
441
  catch (err) {
293
442
  if (owned)
294
443
  await client.query('ROLLBACK');
295
- auditWrite(this.audit, ctx, DATA_ACTIONS.CREATE, objectName, data[pk] === undefined ? undefined : String(data[pk]), data, err);
444
+ const failedId = primaryNames(def).every((n) => data[n] !== undefined)
445
+ ? externalIdOf(def, data)
446
+ : undefined;
447
+ auditWrite(this.audit, ctx, DATA_ACTIONS.CREATE, objectName, failedId, data, err);
296
448
  throw err;
297
449
  }
298
450
  finally {
@@ -302,10 +454,10 @@ export class DefaultObjectDataAccess {
302
454
  }
303
455
  async update(objectName, id, changes, ctx) {
304
456
  const def = requireDef(ctx, objectName);
305
- const pk = primaryKeyOf(def);
306
- if (pk === undefined) {
457
+ if (primaryNames(def).length === 0) {
307
458
  throw new SchemaError('data.recordNotFound', { object: objectName, id }, ctx.locale);
308
459
  }
460
+ const pkValues = pkValuesOf(def, id, ctx);
309
461
  let client;
310
462
  let owned = false;
311
463
  if (ctx.client !== undefined) {
@@ -320,21 +472,31 @@ export class DefaultObjectDataAccess {
320
472
  if (owned)
321
473
  await client.query('BEGIN');
322
474
  await validateRecord(def, changes, WRITE_MODES.UPDATE, { pool: client, registry: ctx.registry, locale: ctx.locale });
323
- const { sql, params } = buildFindSql(def, { filter: { [pk]: id }, limit: 1 }, bctx(ctx, objectName), ctx.rowScope);
475
+ const { sql, params } = buildFindSql(def, { filter: pkFilter(def, pkValues), limit: 1 }, bctx(ctx, objectName), ctx.rowScope, undefined, [recordKeySelect(def)]);
324
476
  const { rows } = await runTableQuery(client, objectName, sql, params, ctx.locale);
325
- const existing = rows[0];
326
- if (existing === undefined) {
477
+ const raw = rows[0];
478
+ if (raw === undefined) {
327
479
  throw new SchemaError('data.recordNotFound', { object: objectName, id }, ctx.locale);
328
480
  }
481
+ const metaKey = String(raw[META_KEY_COL] ?? '');
482
+ const existing = { ...raw };
483
+ delete existing[META_KEY_COL];
329
484
  // validate → beforeUpdate; hooks see the pre-update record and may rewrite changes
330
485
  await this.runBeforeHook(SCRIPT_HOOKS.VALIDATE, objectName, existing, changes, ctx);
331
486
  let payload = changes;
332
487
  const before = await this.runBeforeHook(SCRIPT_HOOKS.BEFORE_UPDATE, objectName, existing, changes, ctx);
333
488
  if (before !== undefined)
334
489
  payload = before;
490
+ // primary keys are immutable: reject any attempt to change them (drift-free record_key)
491
+ for (const name of primaryNames(def)) {
492
+ if (payload[name] !== undefined) {
493
+ throw new SchemaError('object.primary.mutable', { object: objectName, field: name }, ctx.locale);
494
+ }
495
+ }
335
496
  const now = new Date();
336
497
  const record = { ...existing, ...payload };
337
- await computeFormulas(def, record, client, ctx.registry, now);
498
+ record[RECORD_META_ID_FIELD] = metaKey;
499
+ await computeFormulas(def, record, client, ctx.registry, now, metaKey, formulaAuth(ctx));
338
500
  const settable = new Set();
339
501
  for (const key of Object.keys(payload)) {
340
502
  if (isDetailsChild(ctx.registry, def.name) && PARENT_COLUMNS.has(key)) {
@@ -342,21 +504,25 @@ export class DefaultObjectDataAccess {
342
504
  continue;
343
505
  }
344
506
  const field = def.fields.find((f) => f.name === key);
345
- if (field !== undefined && field.type !== FIELD_TYPES.DETAILS)
507
+ if (field !== undefined && field.type !== FIELD_TYPES.DETAILS && field.type !== FIELD_TYPES.MULTI_RELATION) {
346
508
  settable.add(key);
509
+ }
347
510
  }
348
511
  for (const field of def.fields) {
349
512
  if (field.formula !== undefined)
350
513
  settable.add(field.name);
351
514
  }
352
- settable.delete(pk);
515
+ for (const name of primaryNames(def))
516
+ settable.delete(name);
353
517
  if (settable.size > 0) {
354
518
  const cols = [...settable];
355
519
  const setSql = cols.map((c, i) => `${q(c)} = $${i + 1}`).join(', ');
356
- const scope = ctx.rowScope !== undefined ? scopeSuffix(ctx.rowScope, cols.length + 1) : undefined;
520
+ const scope = ctx.rowScope !== undefined ? scopeSuffix(ctx.rowScope, cols.length + pkValues.length) : undefined;
357
521
  const values = cols.map((c) => dbJsonValue(def.fields.find((f) => f.name === c), record[c] ?? null));
358
- await runTableQuery(client, objectName, `UPDATE ${q(def.name)} SET ${setSql} WHERE ${q(pk)} = $${cols.length + 1}${scope !== undefined ? ` AND (${scope.sql})` : ''}`, [...values, id, ...(scope?.params ?? [])], ctx.locale);
522
+ await runTableQuery(client, objectName, `UPDATE ${q(def.name)} SET ${setSql} WHERE ${pkWhereSql(def, cols.length + 1)}${scope !== undefined ? ` AND (${scope.sql})` : ''}`, [...values, ...pkValues, ...(scope?.params ?? [])], ctx.locale);
359
523
  }
524
+ await this.writeRecordMeta(client, def, metaKey, ctx, now, false);
525
+ await replaceLinks(client, def, pkValues, payload, ctx.registry, ctx.locale);
360
526
  if (owned)
361
527
  await client.query('COMMIT');
362
528
  auditWrite(this.audit, ctx, DATA_ACTIONS.UPDATE, objectName, id, payload, undefined, this.replay ? existing : undefined, this.replay ? record : undefined);
@@ -378,12 +544,195 @@ export class DefaultObjectDataAccess {
378
544
  client.release();
379
545
  }
380
546
  }
547
+ /**
548
+ * Fire a workflow action against the three-layer runtime (instance/step/
549
+ * workitem). Runs in one transaction: the instance row is locked, the current
550
+ * step's workitems are quorum-evaluated, the new step/workitems are opened and
551
+ * the side-table status mirror is updated. The customer row is never touched.
552
+ */
553
+ async transition(objectName, id, action, ctx, payload) {
554
+ const def = requireDef(ctx, objectName);
555
+ if (def.workflow === undefined) {
556
+ throw new SchemaError('workflow.transition.unknown', { object: objectName, action }, ctx.locale);
557
+ }
558
+ if (primaryNames(def).length === 0) {
559
+ throw new SchemaError('data.recordNotFound', { object: objectName, id }, ctx.locale);
560
+ }
561
+ const pkValues = pkValuesOf(def, id, ctx);
562
+ let client;
563
+ let owned = false;
564
+ if (ctx.client !== undefined) {
565
+ client = ctx.client;
566
+ }
567
+ else {
568
+ owned = true;
569
+ client = await ctx.pool.connect();
570
+ }
571
+ try {
572
+ if (owned)
573
+ await client.query('BEGIN');
574
+ // the customer record must exist (transitions never create records)
575
+ const { sql, params } = buildFindSql(def, { filter: pkFilter(def, pkValues), limit: 1 }, bctx(ctx, objectName), undefined, undefined, [recordKeySelect(def)]);
576
+ const found = await runTableQuery(client, objectName, sql, params, ctx.locale);
577
+ if (found.rows[0] === undefined) {
578
+ throw new SchemaError('data.recordNotFound', { object: objectName, id }, ctx.locale);
579
+ }
580
+ // guardrail policy + approval gate (shared policy set with the open contract):
581
+ // a policy self-filters on `workflow.transition.<object>.<action>`; a node may
582
+ // also declare `requiresApproval`. deny → error; requireApproval → pending.
583
+ const currentNode = await getWorkflowStatus(client, def, id, ctx.subject);
584
+ const nodeDef = currentNode.node === undefined ? undefined : def.workflow.nodes.find((n) => n.id === currentNode.node);
585
+ const requireApproval = nodeDef?.requiresApproval === true;
586
+ if (this.policies.length > 0 || requireApproval) {
587
+ const actorId = ctx.subject?.id ?? 'system';
588
+ const guardrailCtx = {
589
+ actor: { key: actorId, label: actorId, onBehalfOf: actorId },
590
+ subject: ctx.subject ?? { id: 'system', roles: [] },
591
+ action: `workflow.transition.${def.name}.${action}`,
592
+ args: { object: def.name, id, action },
593
+ dataAccess: toolDataAccessOver(this, {
594
+ pool: ctx.pool,
595
+ registry: ctx.registry,
596
+ ...(ctx.locale === undefined ? {} : { locale: ctx.locale }),
597
+ ...(ctx.client === undefined ? {} : { client: ctx.client }),
598
+ ...(ctx.subject === undefined ? {} : { subject: ctx.subject }),
599
+ }),
600
+ };
601
+ const gate = await evaluateTransition(this.policies, this.approvals, guardrailCtx, requireApproval);
602
+ if (gate.kind === 'deny') {
603
+ throw new SchemaError(gate.code, { object: objectName, action, reason: gate.reason ?? '' }, ctx.locale);
604
+ }
605
+ if (gate.kind === 'pending') {
606
+ throw new SchemaError('workflow.transition.pending', { object: objectName, action, approvalKey: gate.approvalKey }, ctx.locale);
607
+ }
608
+ }
609
+ const outcome = await runWorkflowTransition(client, def, id, action, ctx.subject, payload, ctx.locale);
610
+ if (owned)
611
+ await client.query('COMMIT');
612
+ auditWrite(this.audit, ctx, DATA_ACTIONS.TRANSITION, objectName, id, {
613
+ action,
614
+ node: outcome.toNodeId ?? null,
615
+ from: outcome.fromNodeId ?? null,
616
+ ...(def.workflowHash === undefined ? {} : { workflowHash: def.workflowHash }),
617
+ });
618
+ this.events?.publishRecordChange('updated', objectName, id);
619
+ this.events?.publishRecordTransitioned(objectName, id, outcome.fromNodeId ?? '', outcome.toNodeId ?? '', action, def.workflow.version, def.workflowHash);
620
+ if (outcome.nodeId !== undefined) {
621
+ await this.workflowTimers?.sync(objectName, id, outcome.nodeId).catch(() => { });
622
+ }
623
+ else {
624
+ await this.workflowTimers?.cancel(objectName, id).catch(() => { });
625
+ }
626
+ const updated = await this.findOne(objectName, id, ctx);
627
+ const transitionInfo = { from: outcome.fromNodeId ?? '', to: outcome.toNodeId ?? '' };
628
+ const warnings = [];
629
+ if (updated !== null) {
630
+ await this.runAfterHook(SCRIPT_HOOKS.ON_EXIT, DATA_ACTIONS.TRANSITION, objectName, updated, {}, ctx, warnings, id, { transition: transitionInfo, state: outcome.fromNodeId });
631
+ await this.runAfterHook(SCRIPT_HOOKS.ON_ENTER, DATA_ACTIONS.TRANSITION, objectName, updated, {}, ctx, warnings, id, { transition: transitionInfo, state: outcome.toNodeId });
632
+ await this.runAfterHook(SCRIPT_HOOKS.AFTER_TRANSITION, DATA_ACTIONS.TRANSITION, objectName, updated, {}, ctx, warnings, id, { transition: transitionInfo, state: outcome.toNodeId });
633
+ }
634
+ if (warnings.length > 0)
635
+ ctx.onWarnings?.(warnings);
636
+ return updated;
637
+ }
638
+ catch (err) {
639
+ if (owned)
640
+ await client.query('ROLLBACK');
641
+ auditWrite(this.audit, ctx, DATA_ACTIONS.TRANSITION, objectName, id, { action }, err);
642
+ throw err;
643
+ }
644
+ finally {
645
+ if (owned)
646
+ client.release();
647
+ }
648
+ }
649
+ /**
650
+ * Read a record's workflow status (state/node/actions/own workitems).
651
+ */
652
+ async workflowStatus(objectName, id, ctx) {
653
+ const def = requireDef(ctx, objectName);
654
+ if (def.workflow === undefined) {
655
+ throw new SchemaError('workflow.transition.unknown', { object: objectName, action: 'status' }, ctx.locale);
656
+ }
657
+ return getWorkflowStatus(ctx.client ?? ctx.pool, def, id, ctx.subject);
658
+ }
659
+ /** Acquire/renew the caller's presence lock on the current step (TTL lease). */
660
+ async acquireWorkflowLock(objectName, id, ctx) {
661
+ const def = requireDef(ctx, objectName);
662
+ return acquireWorkflowLock(ctx.pool, def, id, ctx.subject, ctx.locale);
663
+ }
664
+ /** Release the caller's presence lock. */
665
+ async releaseWorkflowLock(objectName, id, ctx) {
666
+ const def = requireDef(ctx, objectName);
667
+ await releaseWorkflowLock(ctx.pool, def, id, ctx.subject);
668
+ }
669
+ /** Read a record's workflow history (steps + workitems). */
670
+ async workflowHistory(objectName, id, ctx) {
671
+ const def = requireDef(ctx, objectName);
672
+ if (def.workflow === undefined) {
673
+ throw new SchemaError('workflow.transition.unknown', { object: objectName, action: 'history' }, ctx.locale);
674
+ }
675
+ return getWorkflowHistory(ctx.client ?? ctx.pool, def, id);
676
+ }
677
+ /** The subject's pending workitems across all objects. */
678
+ async workflowTodos(ctx) {
679
+ return getWorkflowTodos(ctx.pool, ctx.subject);
680
+ }
681
+ /** Admin override: jump the record to a node or terminate the instance. */
682
+ async overrideWorkflow(objectName, id, patch, ctx) {
683
+ const def = requireDef(ctx, objectName);
684
+ if (def.workflow === undefined) {
685
+ throw new SchemaError('workflow.transition.unknown', { object: objectName, action: 'override' }, ctx.locale);
686
+ }
687
+ let client;
688
+ let owned = false;
689
+ if (ctx.client !== undefined) {
690
+ client = ctx.client;
691
+ }
692
+ else {
693
+ owned = true;
694
+ client = await ctx.pool.connect();
695
+ }
696
+ try {
697
+ if (owned)
698
+ await client.query('BEGIN');
699
+ const result = await overrideWorkflow(client, def, id, patch, ctx.subject, ctx.locale);
700
+ if (owned)
701
+ await client.query('COMMIT');
702
+ if (result.nodeId !== undefined) {
703
+ await this.workflowTimers?.sync(objectName, id, result.nodeId).catch(() => { });
704
+ }
705
+ else {
706
+ await this.workflowTimers?.cancel(objectName, id).catch(() => { });
707
+ }
708
+ return result;
709
+ }
710
+ catch (err) {
711
+ if (owned)
712
+ await client.query('ROLLBACK');
713
+ throw err;
714
+ }
715
+ finally {
716
+ if (owned)
717
+ client.release();
718
+ }
719
+ }
720
+ /**
721
+ * Upsert a record's sparse metadata side-table row (status/owner/timestamps)
722
+ * inside the caller's transaction. `created` also stamps the creation facts.
723
+ */
724
+ async writeRecordMeta(client, def, key, ctx, now, created) {
725
+ const actor = ctx.subject?.id ?? 'system';
726
+ await upsertRecordMeta(client, def.name, key, created
727
+ ? { createdBy: actor, modifiedBy: actor, createdTime: now, modifiedTime: now }
728
+ : { modifiedBy: actor, modifiedTime: now });
729
+ }
381
730
  async delete(objectName, id, ctx) {
382
731
  const def = requireDef(ctx, objectName);
383
- const pk = primaryKeyOf(def);
384
- if (pk === undefined) {
732
+ if (primaryNames(def).length === 0) {
385
733
  throw new SchemaError('data.recordNotFound', { object: objectName, id }, ctx.locale);
386
734
  }
735
+ const pkValues = pkValuesOf(def, id, ctx);
387
736
  let client;
388
737
  let owned = false;
389
738
  if (ctx.client !== undefined) {
@@ -397,22 +746,27 @@ export class DefaultObjectDataAccess {
397
746
  try {
398
747
  if (owned)
399
748
  await client.query('BEGIN');
400
- const { sql, params } = buildFindSql(def, { filter: { [pk]: id }, limit: 1 }, bctx(ctx, objectName), ctx.rowScope);
749
+ const { sql, params } = buildFindSql(def, { filter: pkFilter(def, pkValues), limit: 1 }, bctx(ctx, objectName), ctx.rowScope, undefined, [recordKeySelect(def)]);
401
750
  const { rows } = await runTableQuery(client, objectName, sql, params, ctx.locale);
402
- const existing = rows[0];
403
- if (existing === undefined) {
751
+ const raw = rows[0];
752
+ if (raw === undefined) {
404
753
  throw new SchemaError('data.recordNotFound', { object: objectName, id }, ctx.locale);
405
754
  }
755
+ const metaKey = String(raw[META_KEY_COL] ?? '');
756
+ const existing = { ...raw };
757
+ delete existing[META_KEY_COL];
406
758
  await this.runBeforeHook(SCRIPT_HOOKS.BEFORE_DELETE, objectName, existing, {}, ctx);
407
759
  await deleteDetailsChildren(client, def, id, ctx.registry);
408
- const scope = ctx.rowScope !== undefined ? scopeSuffix(ctx.rowScope, 1) : undefined;
409
- const res = await runTableQuery(client, objectName, `DELETE FROM ${q(def.name)} WHERE ${q(pk)} = $1${scope !== undefined ? ` AND (${scope.sql})` : ''}`, [id, ...(scope?.params ?? [])], ctx.locale);
760
+ const scope = ctx.rowScope !== undefined ? scopeSuffix(ctx.rowScope, pkValues.length) : undefined;
761
+ const res = await runTableQuery(client, objectName, `DELETE FROM ${q(def.name)} WHERE ${pkWhereSql(def, 1)}${scope !== undefined ? ` AND (${scope.sql})` : ''}`, [...pkValues, ...(scope?.params ?? [])], ctx.locale);
410
762
  if (res.rowCount === 0)
411
763
  throw new SchemaError('data.recordNotFound', { object: objectName, id }, ctx.locale);
764
+ await deleteRecordMeta(client, def.name, metaKey);
412
765
  if (owned)
413
766
  await client.query('COMMIT');
414
767
  auditWrite(this.audit, ctx, DATA_ACTIONS.DELETE, objectName, id, undefined, undefined, this.replay ? existing : undefined);
415
768
  this.events?.publishRecordChange('deleted', objectName, id);
769
+ await this.workflowTimers?.cancel(objectName, id).catch(() => { });
416
770
  await this.runAfterHook(SCRIPT_HOOKS.AFTER_DELETE, DATA_ACTIONS.DELETE, objectName, existing, {}, ctx, warnings, id);
417
771
  if (warnings.length > 0)
418
772
  ctx.onWarnings?.(warnings);