@owlmeans/server-planning 0.1.18-rc.8 → 0.1.18

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 (438) hide show
  1. package/README.md +92 -19
  2. package/agent-meta/manifest.json +105 -4
  3. package/agent-meta/skills/server-planning/SKILL.md +89 -138
  4. package/agent-meta/skills/server-planning/parts/auxiliary.md +54 -0
  5. package/agent-meta/skills/server-planning/parts/executor.md +82 -0
  6. package/agent-meta/skills/server-planning/parts/schemas.md +26 -0
  7. package/agent-meta/skills/server-planning/parts/serving.md +88 -0
  8. package/agent-meta/skills/server-planning/parts/stores.md +91 -0
  9. package/build/actions/apply-schema-request.d.ts +8 -0
  10. package/build/actions/apply-schema-request.d.ts.map +1 -0
  11. package/build/actions/apply-schema-request.js +33 -0
  12. package/build/actions/apply-schema-request.js.map +1 -0
  13. package/build/actions/commit.d.ts +3 -3
  14. package/build/actions/commit.d.ts.map +1 -1
  15. package/build/actions/commit.js +5 -4
  16. package/build/actions/commit.js.map +1 -1
  17. package/build/actions/define-schemas.d.ts +13 -0
  18. package/build/actions/define-schemas.d.ts.map +1 -0
  19. package/build/actions/define-schemas.js +28 -0
  20. package/build/actions/define-schemas.js.map +1 -0
  21. package/build/actions/execute.d.ts +11 -10
  22. package/build/actions/execute.d.ts.map +1 -1
  23. package/build/actions/execute.js +17 -27
  24. package/build/actions/execute.js.map +1 -1
  25. package/build/actions/execution/types.d.ts +34 -0
  26. package/build/actions/execution/types.d.ts.map +1 -0
  27. package/build/actions/execution/types.js +2 -0
  28. package/build/actions/execution/types.js.map +1 -0
  29. package/build/actions/execution.d.ts +4 -0
  30. package/build/actions/execution.d.ts.map +1 -0
  31. package/build/actions/execution.js +88 -0
  32. package/build/actions/execution.js.map +1 -0
  33. package/build/actions/get-card.d.ts +6 -0
  34. package/build/actions/get-card.d.ts.map +1 -0
  35. package/build/actions/get-card.js +9 -0
  36. package/build/actions/get-card.js.map +1 -0
  37. package/build/actions/get-specification.d.ts +6 -0
  38. package/build/actions/get-specification.d.ts.map +1 -0
  39. package/build/actions/get-specification.js +9 -0
  40. package/build/actions/get-specification.js.map +1 -0
  41. package/build/actions/index.d.ts +12 -3
  42. package/build/actions/index.d.ts.map +1 -1
  43. package/build/actions/index.js +11 -3
  44. package/build/actions/index.js.map +1 -1
  45. package/build/actions/links.d.ts +3 -3
  46. package/build/actions/links.d.ts.map +1 -1
  47. package/build/actions/links.js +6 -5
  48. package/build/actions/links.js.map +1 -1
  49. package/build/actions/list-card-specifications.d.ts +6 -0
  50. package/build/actions/list-card-specifications.d.ts.map +1 -0
  51. package/build/actions/list-card-specifications.js +11 -0
  52. package/build/actions/list-card-specifications.js.map +1 -0
  53. package/build/actions/list-card-transitions.d.ts +6 -0
  54. package/build/actions/list-card-transitions.d.ts.map +1 -0
  55. package/build/actions/list-card-transitions.js +11 -0
  56. package/build/actions/list-card-transitions.js.map +1 -0
  57. package/build/actions/list-cards.d.ts +6 -0
  58. package/build/actions/list-cards.d.ts.map +1 -0
  59. package/build/actions/list-cards.js +10 -0
  60. package/build/actions/list-cards.js.map +1 -0
  61. package/build/actions/list-schemas.d.ts +13 -0
  62. package/build/actions/list-schemas.d.ts.map +1 -0
  63. package/build/actions/list-schemas.js +20 -0
  64. package/build/actions/list-schemas.js.map +1 -0
  65. package/build/actions/list-specification-revisions.d.ts +6 -0
  66. package/build/actions/list-specification-revisions.d.ts.map +1 -0
  67. package/build/actions/list-specification-revisions.js +10 -0
  68. package/build/actions/list-specification-revisions.js.map +1 -0
  69. package/build/actions/resources.d.ts +5 -0
  70. package/build/actions/resources.d.ts.map +1 -0
  71. package/build/actions/resources.js +111 -0
  72. package/build/actions/resources.js.map +1 -0
  73. package/build/actions/summarize-cards.d.ts +6 -0
  74. package/build/actions/summarize-cards.d.ts.map +1 -0
  75. package/build/actions/summarize-cards.js +11 -0
  76. package/build/actions/summarize-cards.js.map +1 -0
  77. package/build/actions/transitions.d.ts +3 -3
  78. package/build/actions/transitions.d.ts.map +1 -1
  79. package/build/actions/transitions.js +4 -3
  80. package/build/actions/transitions.js.map +1 -1
  81. package/build/actions/types.d.ts +6 -0
  82. package/build/actions/types.d.ts.map +1 -0
  83. package/build/actions/types.js +2 -0
  84. package/build/actions/types.js.map +1 -0
  85. package/build/actions/watch.d.ts +2 -2
  86. package/build/actions/watch.d.ts.map +1 -1
  87. package/build/actions/watch.js +8 -6
  88. package/build/actions/watch.js.map +1 -1
  89. package/build/conformance/assert/types.d.ts +19 -0
  90. package/build/conformance/assert/types.d.ts.map +1 -0
  91. package/build/conformance/assert/types.js +2 -0
  92. package/build/conformance/assert/types.js.map +1 -0
  93. package/build/conformance/assert.d.ts +15 -0
  94. package/build/conformance/assert.d.ts.map +1 -0
  95. package/build/conformance/assert.js +52 -0
  96. package/build/conformance/assert.js.map +1 -0
  97. package/build/conformance/cases.d.ts +7 -0
  98. package/build/conformance/cases.d.ts.map +1 -0
  99. package/build/conformance/cases.js +544 -0
  100. package/build/conformance/cases.js.map +1 -0
  101. package/build/conformance/clock.d.ts +6 -0
  102. package/build/conformance/clock.d.ts.map +1 -0
  103. package/build/conformance/clock.js +12 -0
  104. package/build/conformance/clock.js.map +1 -0
  105. package/build/conformance/consts.d.ts +30 -0
  106. package/build/conformance/consts.d.ts.map +1 -0
  107. package/build/conformance/consts.js +159 -0
  108. package/build/conformance/consts.js.map +1 -0
  109. package/build/conformance/errors.d.ts +5 -0
  110. package/build/conformance/errors.d.ts.map +1 -0
  111. package/build/conformance/errors.js +8 -0
  112. package/build/conformance/errors.js.map +1 -0
  113. package/build/conformance/fixtures/types.d.ts +13 -0
  114. package/build/conformance/fixtures/types.d.ts.map +1 -0
  115. package/build/conformance/fixtures/types.js +2 -0
  116. package/build/conformance/fixtures/types.js.map +1 -0
  117. package/build/conformance/fixtures.d.ts +14 -0
  118. package/build/conformance/fixtures.d.ts.map +1 -0
  119. package/build/conformance/fixtures.js +26 -0
  120. package/build/conformance/fixtures.js.map +1 -0
  121. package/build/conformance/index.d.ts +15 -0
  122. package/build/conformance/index.d.ts.map +1 -0
  123. package/build/conformance/index.js +12 -0
  124. package/build/conformance/index.js.map +1 -0
  125. package/build/conformance/resources.d.ts +4 -0
  126. package/build/conformance/resources.d.ts.map +1 -0
  127. package/build/conformance/resources.js +228 -0
  128. package/build/conformance/resources.js.map +1 -0
  129. package/build/conformance/types.d.ts +18 -0
  130. package/build/conformance/types.d.ts.map +1 -0
  131. package/build/conformance/types.js +2 -0
  132. package/build/conformance/types.js.map +1 -0
  133. package/build/consts.d.ts +5 -0
  134. package/build/consts.d.ts.map +1 -1
  135. package/build/consts.js +5 -0
  136. package/build/consts.js.map +1 -1
  137. package/build/definitions.d.ts +18 -0
  138. package/build/definitions.d.ts.map +1 -0
  139. package/build/definitions.js +225 -0
  140. package/build/definitions.js.map +1 -0
  141. package/build/executor/changes/types.d.ts +36 -0
  142. package/build/executor/changes/types.d.ts.map +1 -0
  143. package/build/executor/changes/types.js +2 -0
  144. package/build/executor/changes/types.js.map +1 -0
  145. package/build/executor/changes.d.ts +3 -30
  146. package/build/executor/changes.d.ts.map +1 -1
  147. package/build/executor/changes.js +42 -51
  148. package/build/executor/changes.js.map +1 -1
  149. package/build/executor/code/types.d.ts +17 -0
  150. package/build/executor/code/types.d.ts.map +1 -0
  151. package/build/executor/code/types.js +2 -0
  152. package/build/executor/code/types.js.map +1 -0
  153. package/build/executor/code.d.ts +3 -14
  154. package/build/executor/code.d.ts.map +1 -1
  155. package/build/executor/code.js +50 -54
  156. package/build/executor/code.js.map +1 -1
  157. package/build/executor/consts.local.d.ts +5 -0
  158. package/build/executor/consts.local.d.ts.map +1 -0
  159. package/build/executor/consts.local.js +6 -0
  160. package/build/executor/consts.local.js.map +1 -0
  161. package/build/executor/creator/types.d.ts +33 -0
  162. package/build/executor/creator/types.d.ts.map +1 -0
  163. package/build/executor/creator/types.js +2 -0
  164. package/build/executor/creator/types.js.map +1 -0
  165. package/build/executor/creator.d.ts +11 -0
  166. package/build/executor/creator.d.ts.map +1 -0
  167. package/build/executor/creator.js +32 -0
  168. package/build/executor/creator.js.map +1 -0
  169. package/build/executor/resolve/types.d.ts +30 -0
  170. package/build/executor/resolve/types.d.ts.map +1 -0
  171. package/build/executor/resolve/types.js +2 -0
  172. package/build/executor/resolve/types.js.map +1 -0
  173. package/build/executor/resolve.d.ts +5 -34
  174. package/build/executor/resolve.d.ts.map +1 -1
  175. package/build/executor/resolve.js +169 -110
  176. package/build/executor/resolve.js.map +1 -1
  177. package/build/executor/types.d.ts +23 -0
  178. package/build/executor/types.d.ts.map +1 -0
  179. package/build/executor/types.js +2 -0
  180. package/build/executor/types.js.map +1 -0
  181. package/build/executor/validate.d.ts +6 -5
  182. package/build/executor/validate.d.ts.map +1 -1
  183. package/build/executor/validate.js +38 -27
  184. package/build/executor/validate.js.map +1 -1
  185. package/build/executor.d.ts +11 -7
  186. package/build/executor.d.ts.map +1 -1
  187. package/build/executor.js +27 -21
  188. package/build/executor.js.map +1 -1
  189. package/build/facade.d.ts +20 -2
  190. package/build/facade.d.ts.map +1 -1
  191. package/build/facade.js +144 -22
  192. package/build/facade.js.map +1 -1
  193. package/build/helper.d.ts +5 -9
  194. package/build/helper.d.ts.map +1 -1
  195. package/build/helper.js +12 -11
  196. package/build/helper.js.map +1 -1
  197. package/build/hierarchy/types.d.ts +20 -0
  198. package/build/hierarchy/types.d.ts.map +1 -0
  199. package/build/hierarchy/types.js +2 -0
  200. package/build/hierarchy/types.js.map +1 -0
  201. package/build/hierarchy.d.ts +5 -0
  202. package/build/hierarchy.d.ts.map +1 -0
  203. package/build/hierarchy.js +133 -0
  204. package/build/hierarchy.js.map +1 -0
  205. package/build/index.d.ts +1 -0
  206. package/build/index.d.ts.map +1 -1
  207. package/build/index.js +1 -0
  208. package/build/index.js.map +1 -1
  209. package/build/invariants/types.d.ts +6 -0
  210. package/build/invariants/types.d.ts.map +1 -0
  211. package/build/invariants/types.js +2 -0
  212. package/build/invariants/types.js.map +1 -0
  213. package/build/invariants.d.ts +5 -0
  214. package/build/invariants.d.ts.map +1 -0
  215. package/build/invariants.js +126 -0
  216. package/build/invariants.js.map +1 -0
  217. package/build/projection.d.ts +4 -10
  218. package/build/projection.d.ts.map +1 -1
  219. package/build/projection.js +7 -5
  220. package/build/projection.js.map +1 -1
  221. package/build/queue/consts.d.ts +5 -0
  222. package/build/queue/consts.d.ts.map +1 -0
  223. package/build/queue/consts.js +5 -0
  224. package/build/queue/consts.js.map +1 -0
  225. package/build/queue/declare.d.ts +5 -0
  226. package/build/queue/declare.d.ts.map +1 -0
  227. package/build/queue/declare.js +5 -0
  228. package/build/queue/declare.js.map +1 -0
  229. package/build/queue/index.d.ts +3 -18
  230. package/build/queue/index.d.ts.map +1 -1
  231. package/build/queue/index.js +2 -7
  232. package/build/queue/index.js.map +1 -1
  233. package/build/queue/types.d.ts +13 -0
  234. package/build/queue/types.d.ts.map +1 -0
  235. package/build/queue/types.js +2 -0
  236. package/build/queue/types.js.map +1 -0
  237. package/build/registry.d.ts +5 -22
  238. package/build/registry.d.ts.map +1 -1
  239. package/build/registry.js +16 -10
  240. package/build/registry.js.map +1 -1
  241. package/build/resources.d.ts +5 -0
  242. package/build/resources.d.ts.map +1 -0
  243. package/build/resources.js +287 -0
  244. package/build/resources.js.map +1 -0
  245. package/build/service.d.ts +3 -16
  246. package/build/service.d.ts.map +1 -1
  247. package/build/service.js +12 -0
  248. package/build/service.js.map +1 -1
  249. package/build/store/commits.d.ts.map +1 -1
  250. package/build/store/commits.js +3 -1
  251. package/build/store/commits.js.map +1 -1
  252. package/build/store/composite.d.ts +1 -0
  253. package/build/store/composite.d.ts.map +1 -1
  254. package/build/store/composite.js +7 -2
  255. package/build/store/composite.js.map +1 -1
  256. package/build/store/consts.local.d.ts +2 -0
  257. package/build/store/consts.local.d.ts.map +1 -0
  258. package/build/store/consts.local.js +2 -0
  259. package/build/store/consts.local.js.map +1 -0
  260. package/build/store/fold/types.d.ts +43 -0
  261. package/build/store/fold/types.d.ts.map +1 -0
  262. package/build/store/fold/types.js +2 -0
  263. package/build/store/fold/types.js.map +1 -0
  264. package/build/store/fold.d.ts +8 -30
  265. package/build/store/fold.d.ts.map +1 -1
  266. package/build/store/fold.js +190 -198
  267. package/build/store/fold.js.map +1 -1
  268. package/build/store/index.d.ts +1 -0
  269. package/build/store/index.d.ts.map +1 -1
  270. package/build/store/index.js.map +1 -1
  271. package/build/store/memory.d.ts +12 -0
  272. package/build/store/memory.d.ts.map +1 -1
  273. package/build/store/memory.js +0 -0
  274. package/build/store/memory.js.map +1 -1
  275. package/build/store/types.d.ts +15 -1
  276. package/build/store/types.d.ts.map +1 -1
  277. package/build/store/types.local.d.ts +5 -0
  278. package/build/store/types.local.d.ts.map +1 -0
  279. package/build/store/types.local.js +2 -0
  280. package/build/store/types.local.js.map +1 -0
  281. package/build/types.d.ts +126 -2
  282. package/build/types.d.ts.map +1 -1
  283. package/build/types.local.d.ts +7 -0
  284. package/build/types.local.d.ts.map +1 -0
  285. package/build/types.local.js +2 -0
  286. package/build/types.local.js.map +1 -0
  287. package/build/utils/access/types.d.ts +30 -0
  288. package/build/utils/access/types.d.ts.map +1 -0
  289. package/build/utils/access/types.js +2 -0
  290. package/build/utils/access/types.js.map +1 -0
  291. package/build/utils/access.d.ts +4 -0
  292. package/build/utils/access.d.ts.map +1 -0
  293. package/build/utils/access.js +28 -0
  294. package/build/utils/access.js.map +1 -0
  295. package/build/utils/guard/types.d.ts +23 -0
  296. package/build/utils/guard/types.d.ts.map +1 -0
  297. package/build/utils/guard/types.js +2 -0
  298. package/build/utils/guard/types.js.map +1 -0
  299. package/build/utils/guard.d.ts +7 -10
  300. package/build/utils/guard.d.ts.map +1 -1
  301. package/build/utils/guard.js +36 -32
  302. package/build/utils/guard.js.map +1 -1
  303. package/build/utils/handler/types.d.ts +26 -0
  304. package/build/utils/handler/types.d.ts.map +1 -0
  305. package/build/utils/handler/types.js +2 -0
  306. package/build/utils/handler/types.js.map +1 -0
  307. package/build/utils/handler.d.ts +6 -0
  308. package/build/utils/handler.d.ts.map +1 -0
  309. package/build/utils/handler.js +21 -0
  310. package/build/utils/handler.js.map +1 -0
  311. package/build/utils/index.d.ts +8 -0
  312. package/build/utils/index.d.ts.map +1 -1
  313. package/build/utils/index.js +3 -0
  314. package/build/utils/index.js.map +1 -1
  315. package/build/utils/request/types.d.ts +23 -0
  316. package/build/utils/request/types.d.ts.map +1 -0
  317. package/build/utils/request/types.js +2 -0
  318. package/build/utils/request/types.js.map +1 -0
  319. package/build/utils/request.d.ts +4 -0
  320. package/build/utils/request.d.ts.map +1 -0
  321. package/build/utils/request.js +27 -0
  322. package/build/utils/request.js.map +1 -0
  323. package/build/utils/scope.d.ts +17 -13
  324. package/build/utils/scope.d.ts.map +1 -1
  325. package/build/utils/scope.js +21 -35
  326. package/build/utils/scope.js.map +1 -1
  327. package/build/utils/types.d.ts +8 -0
  328. package/build/utils/types.d.ts.map +1 -0
  329. package/build/utils/types.js +2 -0
  330. package/build/utils/types.js.map +1 -0
  331. package/package.json +30 -22
  332. package/src/actions/apply-schema-request.ts +36 -0
  333. package/src/actions/commit.ts +7 -5
  334. package/src/actions/define-schemas.ts +34 -0
  335. package/src/actions/execute.ts +32 -34
  336. package/src/actions/execution/types.ts +34 -0
  337. package/src/actions/execution.ts +100 -0
  338. package/src/actions/get-card.ts +14 -0
  339. package/src/actions/get-specification.ts +14 -0
  340. package/src/actions/index.ts +13 -3
  341. package/src/actions/links.ts +8 -6
  342. package/src/actions/list-card-specifications.ts +15 -0
  343. package/src/actions/list-card-transitions.ts +15 -0
  344. package/src/actions/list-cards.ts +14 -0
  345. package/src/actions/list-schemas.ts +29 -0
  346. package/src/actions/list-specification-revisions.ts +15 -0
  347. package/src/actions/resources.ts +79 -0
  348. package/src/actions/summarize-cards.ts +15 -0
  349. package/src/actions/transitions.ts +6 -4
  350. package/src/actions/types.ts +5 -0
  351. package/src/actions/watch.ts +11 -7
  352. package/src/conformance/assert/types.ts +16 -0
  353. package/src/conformance/assert.ts +67 -0
  354. package/src/conformance/cases.ts +631 -0
  355. package/src/conformance/clock.ts +11 -0
  356. package/src/conformance/consts.ts +165 -0
  357. package/src/conformance/errors.ts +7 -0
  358. package/src/conformance/fixtures/types.ts +11 -0
  359. package/src/conformance/fixtures.ts +46 -0
  360. package/src/conformance/index.ts +14 -0
  361. package/src/conformance/resources.ts +227 -0
  362. package/src/conformance/types.ts +20 -0
  363. package/src/consts.ts +6 -0
  364. package/src/definitions.ts +264 -0
  365. package/src/executor/changes/types.ts +38 -0
  366. package/src/executor/changes.ts +49 -68
  367. package/src/executor/code/types.ts +23 -0
  368. package/src/executor/code.ts +62 -69
  369. package/src/executor/consts.local.ts +8 -0
  370. package/src/executor/creator/types.ts +33 -0
  371. package/src/executor/creator.ts +43 -0
  372. package/src/executor/resolve/types.ts +30 -0
  373. package/src/executor/resolve.ts +181 -139
  374. package/src/executor/types.ts +23 -0
  375. package/src/executor/validate.ts +40 -38
  376. package/src/executor.ts +33 -27
  377. package/src/facade.ts +132 -29
  378. package/src/helper.ts +12 -11
  379. package/src/hierarchy/types.ts +20 -0
  380. package/src/hierarchy.ts +113 -0
  381. package/src/index.ts +1 -0
  382. package/src/invariants/types.ts +6 -0
  383. package/src/invariants.ts +106 -0
  384. package/src/projection.ts +12 -18
  385. package/src/queue/consts.ts +5 -0
  386. package/src/queue/declare.ts +7 -0
  387. package/src/queue/index.ts +3 -25
  388. package/src/queue/types.ts +14 -0
  389. package/src/registry.ts +18 -36
  390. package/src/resources.ts +256 -0
  391. package/src/service.ts +16 -20
  392. package/src/store/commits.ts +5 -4
  393. package/src/store/composite.ts +7 -2
  394. package/src/store/consts.local.ts +1 -0
  395. package/src/store/fold/types.ts +44 -0
  396. package/src/store/fold.ts +214 -212
  397. package/src/store/index.ts +1 -0
  398. package/src/store/memory.ts +0 -0
  399. package/src/store/types.local.ts +3 -0
  400. package/src/store/types.ts +16 -1
  401. package/src/types.local.ts +7 -0
  402. package/src/types.ts +139 -6
  403. package/src/utils/access/types.ts +30 -0
  404. package/src/utils/access.ts +33 -0
  405. package/src/utils/guard/types.ts +21 -0
  406. package/src/utils/guard.ts +44 -31
  407. package/src/utils/handler/types.ts +28 -0
  408. package/src/utils/handler.ts +35 -0
  409. package/src/utils/index.ts +9 -0
  410. package/src/utils/request/types.ts +23 -0
  411. package/src/utils/request.ts +40 -0
  412. package/src/utils/scope.ts +39 -42
  413. package/src/utils/types.ts +8 -0
  414. package/tests/access.spec.ts +160 -0
  415. package/tests/app.spec.ts +112 -0
  416. package/tests/conformance.spec.ts +47 -0
  417. package/tests/create-example.spec.ts +202 -0
  418. package/tests/creator.spec.ts +257 -0
  419. package/tests/entrypoints.spec.ts +5 -0
  420. package/tests/memory-store.spec.ts +52 -0
  421. package/tests/narrowing.spec.ts +94 -0
  422. package/tests/plugins.spec.ts +4 -3
  423. package/tests/writes.spec.ts +140 -0
  424. package/build/actions/cards.d.ts +0 -16
  425. package/build/actions/cards.d.ts.map +0 -1
  426. package/build/actions/cards.js +0 -32
  427. package/build/actions/cards.js.map +0 -1
  428. package/build/actions/schemas.d.ts +0 -6
  429. package/build/actions/schemas.d.ts.map +0 -1
  430. package/build/actions/schemas.js +0 -9
  431. package/build/actions/schemas.js.map +0 -1
  432. package/build/actions/specs.d.ts +0 -10
  433. package/build/actions/specs.d.ts.map +0 -1
  434. package/build/actions/specs.js +0 -14
  435. package/build/actions/specs.js.map +0 -1
  436. package/src/actions/cards.ts +0 -52
  437. package/src/actions/schemas.ts +0 -15
  438. package/src/actions/specs.ts +0 -23
@@ -1,9 +1,10 @@
1
- import { CommitFailed, CommitState, CommitTimeout, DEFAULT_COMMIT_TIMEOUT, WorkcardNotFound } from '@owlmeans/planning'
2
- import type { CommitEvent, CommitFilter, CommitStatus, Unsubscribe, Workcard } from '@owlmeans/planning'
1
+ import { logger } from '@owlmeans/log'
2
+ import { CommitFailed, CommitState, CommitTimeout, DEFAULT_COMMIT_TIMEOUT, WorkcardNotFound, type CommitEvent, type CommitFilter, type CommitStatus, type Unsubscribe, type Workcard } from '@owlmeans/planning'
3
3
  import { COMMIT_POLL_LADDER, DEFAULT_COMMIT_MEMORY } from '../consts.js'
4
4
  import type { CommitHub, CommitHubOptions } from './types.js'
5
+ import type { Listener } from './types.local.js'
5
6
 
6
- type Listener = (event: CommitEvent) => void | Promise<void>
7
+ const log = logger('planning:store')
7
8
 
8
9
  const matches = (event: CommitEvent, filter?: CommitFilter): boolean =>
9
10
  filter == null || (
@@ -58,7 +59,7 @@ export const makeCommitHub = (options: CommitHubOptions): CommitHub => {
58
59
  const results = await Promise.allSettled(targets.map(async entry => await entry.listener(event)))
59
60
  results.forEach(result => {
60
61
  if (result.status === 'rejected') {
61
- console.error('planning: commit listener failed:', result.reason)
62
+ log.error('Planning commit listener failed', { transition: event.transition, error: result.reason })
62
63
  }
63
64
  })
64
65
  },
@@ -3,9 +3,9 @@ import type {
3
3
  CommitSource, PlanningStore, ProjectionStore, Relationship, RelationshipStore, SpecificationStore,
4
4
  TransitionStore, Unsubscribe, Workcard,
5
5
  } from '@owlmeans/planning'
6
- import { applyQuery } from '@owlmeans/resource'
7
6
  import type { Criteria, ListResult } from '@owlmeans/resource'
8
7
  import type { CommitHub, StoreRoute } from './types.js'
8
+ import { recordQueryHelper } from '@owlmeans/resource'
9
9
 
10
10
  const firstOf = async <S, T>(
11
11
  stores: S[], read: (store: S) => Promise<T | null | undefined> | undefined
@@ -29,6 +29,7 @@ const sum = async <S>(stores: S[], run: (store: S) => Promise<number>): Promise<
29
29
  * then each owner; a list whose criteria names one owned type (or several owned by one store) goes
30
30
  * there, and every other list is the default store's — a cross-type query is answered by the
31
31
  * default store alone, never merged. Relationship lists and commit subscriptions span every store.
32
+ * The data-defined schema port is the default store's.
32
33
  */
33
34
  export const makeCompositeStore = (routes: StoreRoute[], fallback: PlanningStore): PlanningStore => {
34
35
  const all = [...new Set([fallback, ...routes.map(route => route.store)])]
@@ -121,7 +122,7 @@ export const makeCompositeStore = (routes: StoreRoute[], fallback: PlanningStore
121
122
  list: async (where, opts) => {
122
123
  const results = await Promise.all(linked.map(store => store.links!.list(where, { size: 0 })))
123
124
  const items = results.flatMap((result: ListResult<Relationship>) => result.items)
124
- return applyQuery(items, undefined, opts)
125
+ return recordQueryHelper.applyQuery(items, undefined, opts)
125
126
  },
126
127
  put: link => (fallback.links ?? linked[0].links!).put(link),
127
128
  drop: where => sum(linked, store => store.links!.drop(where)),
@@ -162,10 +163,14 @@ export const makeCompositeStore = (routes: StoreRoute[], fallback: PlanningStore
162
163
  return {
163
164
  alias: `composite:${fallback.alias ?? 'default'}`,
164
165
  newId: fallback.newId,
166
+ unit: fallback.unit,
167
+ assignees: fallback.assignees, teams: fallback.teams, comments: fallback.comments, mentions: fallback.mentions,
165
168
  cards,
166
169
  ...(transitions != null ? { transitions } : {}),
167
170
  ...(specs != null ? { specs } : {}),
168
171
  ...(links != null ? { links } : {}),
169
172
  ...(commits != null ? { commits } : {}),
173
+ // Data-defined schemas are the default store's alone: a layer describes the whole organization.
174
+ ...(fallback.schemas != null ? { schemas: fallback.schemas } : {}),
170
175
  }
171
176
  }
@@ -0,0 +1 @@
1
+ export const CONTENT_KEYS = ['body', 'ref', 'format', 'version'] as const
@@ -0,0 +1,44 @@
1
+ import type { CommitEvent, CommitState, PlanningStore, SpecificationRevision, Transition, Workcard } from '@owlmeans/planning'
2
+ import type { FoldOptions, FoldResult } from '../types.js'
3
+
4
+ /** The projection body every store reuses: the fold of a card's pending log, and what it publishes. */
5
+ export interface FoldHelper {
6
+ /** The event a settled transition publishes. `record` is in-process only — strip it before a bus. */
7
+ commitEventOf: (
8
+ transition: Transition, state: CommitState, at: string, extra?: { error?: string, record?: Workcard | null }
9
+ ) => CommitEvent
10
+ /**
11
+ * Fold every pending transition of one card — the projection body every store reuses.
12
+ *
13
+ * Transitions are read in `seq` order past the card's own `seq`, and only `pending` ones are
14
+ * applied, each with `applyHelper.applyTransition` and nothing else. Per transition: write the
15
+ * record (a `delete` drops it with its own documents, a project `delete` purges everything under it), fold its
16
+ * relationships, mark it `committed`, `publish` the event, then run `onCommitted` — so the `after`
17
+ * chain runs in THIS process, exactly once per committed transition. A transition that cannot be
18
+ * folded is marked `failed` with the reason and a failed event is published, and the fold goes PAST
19
+ * it: the card's `seq` advances to the failed transition with every other value as it was, so the
20
+ * next transition applies normally. Nothing is removed from the log. A create that fails leaves no
21
+ * card to advance, so what follows it fails too; a store that refuses the advancing write itself
22
+ * stops the fold there and reports `followUp`, leaving the rest pending for a retry.
23
+ *
24
+ * The caller owns single flight: two folds of one card running at once would both publish. A
25
+ * transactional store passes `unit`, which wraps each transition's writes (a savepoint), so a write
26
+ * the database refuses is undone whole before the fold marks the transition failed.
27
+ *
28
+ * @throws {PlanningUnsupported} for a store without a transition log
29
+ */
30
+ foldPending: (store: PlanningStore, cardId: string, entityId: string, opts?: FoldOptions) => Promise<FoldResult>
31
+ /**
32
+ * Mark every pending transition of a card `failed` and publish a failed event for each — what a
33
+ * queued store does when its projection job is dead, or waiters hang until their timeout.
34
+ */
35
+ failPending: (
36
+ store: PlanningStore, cardId: string, entityId: string, reason: string, opts?: Pick<FoldOptions, 'publish' | 'now'>
37
+ ) => Promise<number>
38
+ /**
39
+ * A specification's history, replayed from its log: one entry per create and per committed
40
+ * content change, newest first. The fold is `applyHelper.applyTransition` itself, so an entry's
41
+ * `body` is the body AT that revision even when the transition changed only `ref`.
42
+ */
43
+ revisionsFromLog: (log: Transition[], limit?: number) => SpecificationRevision[]
44
+ }
package/src/store/fold.ts CHANGED
@@ -1,10 +1,10 @@
1
- import {
2
- applyRelationship, applyTransition, CommitState, isProject, PlanningUnsupported, TransitionAction,
3
- } from '@owlmeans/planning'
4
- import type {
5
- CommitEvent, PlanningStore, Relationship, SpecificationRevision, Transition, Workcard,
6
- } from '@owlmeans/planning'
1
+ import { logger } from '@owlmeans/log'
2
+ import { applyHelper, cardHelper, CommitState, PlanningUnsupported, TransitionAction, type CommitEvent, type PlanningStore, type Relationship, type SpecificationRevision, type Transition, type Workcard } from '@owlmeans/planning'
3
+ import type { FoldHelper } from './fold/types.js'
7
4
  import type { FoldOptions, FoldResult } from './types.js'
5
+ import { CONTENT_KEYS } from './consts.local.js'
6
+
7
+ const log = logger('planning:store')
8
8
 
9
9
  const isoNow = (): string => new Date().toISOString()
10
10
 
@@ -14,244 +14,246 @@ const clean = <T extends object>(record: T): T =>
14
14
  const errorText = (error: unknown): string =>
15
15
  error instanceof Error ? error.message : `${error}`
16
16
 
17
- const safely = async (label: string, run: () => Promise<void> | void | undefined): Promise<void> => {
18
- try {
19
- await run()
20
- } catch (error) {
21
- console.error(`planning: ${label} failed:`, error)
17
+ export const createFoldHelper = (): FoldHelper => {
18
+ const safely = async (label: string, run: () => Promise<void> | void | undefined): Promise<void> => {
19
+ try {
20
+ await run()
21
+ } catch (error) {
22
+ log.error('Planning store step failed', { step: label, error })
23
+ }
22
24
  }
23
- }
24
25
 
25
- /** The event a settled transition publishes. `record` is in-process only — strip it before a bus. */
26
- export const commitEventOf = (
27
- transition: Transition, state: CommitState, at: string, extra?: { error?: string, record?: Workcard | null }
28
- ): CommitEvent => clean({
29
- transition: transition.id!,
30
- card: transition.card,
31
- entityId: transition.entityId,
32
- project: transition.project,
33
- kind: transition.kind,
34
- type: transition.type,
35
- seq: transition.seq,
36
- action: transition.action,
37
- state,
38
- at,
39
- error: extra?.error,
40
- record: extra?.record,
41
- })
26
+ const commitEventOf = (
27
+ transition: Transition, state: CommitState, at: string, extra?: { error?: string, record?: Workcard | null }
28
+ ): CommitEvent => clean({
29
+ transition: transition.id!,
30
+ card: transition.card,
31
+ entityId: transition.entityId,
32
+ project: transition.project,
33
+ kind: transition.kind,
34
+ type: transition.type,
35
+ seq: transition.seq,
36
+ action: transition.action,
37
+ state,
38
+ at,
39
+ error: extra?.error,
40
+ record: extra?.record,
41
+ })
42
42
 
43
- const bearsRelationships = (transition: Transition): boolean =>
44
- transition.action === TransitionAction.Link
45
- || transition.action === TransitionAction.Unlink
46
- || transition.action === TransitionAction.Delete
47
- || (transition.action === TransitionAction.Create && (transition.links?.length ?? 0) > 0)
43
+ const bearsRelationships = (transition: Transition): boolean =>
44
+ transition.action === TransitionAction.Link
45
+ || transition.action === TransitionAction.Unlink
46
+ || transition.action === TransitionAction.Delete
47
+ || (transition.action === TransitionAction.Create && (transition.links?.length ?? 0) > 0)
48
48
 
49
- const foldRelationships = async (store: PlanningStore, transition: Transition): Promise<void> => {
50
- const links = store.links
51
- if (links == null || !bearsRelationships(transition)) {
52
- return
53
- }
54
- const where = { entityId: transition.entityId }
55
- const [outgoing, incoming] = await Promise.all([
56
- links.list({ ...where, from: transition.card }, { size: 0 }),
57
- links.list({ ...where, to: transition.card }, { size: 0 }),
58
- ])
59
- const before = [...new Map([...outgoing.items, ...incoming.items].map(link => [link.id, link])).values()]
60
- const after = applyRelationship(before, transition)
61
- const kept = new Set(after.filter(link => link.id != null).map(link => link.id))
49
+ const foldRelationships = async (store: PlanningStore, transition: Transition): Promise<void> => {
50
+ const links = store.links
51
+ if (links == null || !bearsRelationships(transition)) {
52
+ return
53
+ }
54
+ const where = { entityId: transition.entityId }
55
+ const [outgoing, incoming] = await Promise.all([
56
+ links.list({ ...where, from: transition.card }, { size: 0 }),
57
+ links.list({ ...where, to: transition.card }, { size: 0 }),
58
+ ])
59
+ const before = [...new Map([...outgoing.items, ...incoming.items].map(link => [link.id, link])).values()]
60
+ const after = applyHelper.applyRelationship(before, transition)
61
+ const kept = new Set(after.filter(link => link.id != null).map(link => link.id))
62
62
 
63
- for (const link of before) {
64
- if (link.id != null && !kept.has(link.id)) {
65
- await links.drop({ entityId: transition.entityId, id: link.id })
63
+ for (const link of before) {
64
+ if (link.id != null && !kept.has(link.id)) {
65
+ await links.drop({ entityId: transition.entityId, id: link.id })
66
+ }
66
67
  }
67
- }
68
- for (const link of after) {
69
- if (link.id == null) {
70
- await links.put(link as Relationship)
68
+ for (const link of after) {
69
+ if (link.id == null) {
70
+ await links.put(link as Relationship)
71
+ }
71
72
  }
72
73
  }
73
- }
74
74
 
75
- const writeFold = async (
76
- store: PlanningStore, before: Workcard | null, after: Workcard | null, transition: Transition
77
- ): Promise<void> => {
78
- if (transition.action === TransitionAction.Delete) {
79
- if (before != null && isProject(before)) {
80
- // A project takes everything under it, its own log included — the hub remembers the commit.
81
- await store.cards.purge(transition.card, transition.entityId)
75
+ const writeFold = async (
76
+ store: PlanningStore, before: Workcard | null, after: Workcard | null, transition: Transition
77
+ ): Promise<void> => {
78
+ await store.validateProjection?.(before, after, transition)
79
+ if (transition.action === TransitionAction.Delete) {
80
+ if (before != null && cardHelper.isProject(before)) {
81
+ // A project takes everything under it, its own log included — the hub remembers the commit.
82
+ await store.cards.purge(transition.card, transition.entityId)
83
+ return
84
+ }
85
+ await foldRelationships(store, transition)
86
+ await store.cards.drop(transition.card, transition.entityId)
82
87
  return
83
88
  }
89
+ if (after != null) {
90
+ await store.cards.put(after)
91
+ await store.projectReferences?.(after, transition)
92
+ }
84
93
  await foldRelationships(store, transition)
85
- await store.cards.drop(transition.card, transition.entityId)
86
- return
87
- }
88
- if (after != null) {
89
- await store.cards.put(after)
90
94
  }
91
- await foldRelationships(store, transition)
92
- }
93
-
94
- /**
95
- * Fold every pending transition of one card — the projection body every store reuses.
96
- *
97
- * Transitions are read in `seq` order past the card's own `seq`, and only `pending` ones are
98
- * applied, each with `applyTransition` and nothing else. Per transition: write the record (a
99
- * `delete` drops it, a project `delete` purges everything under it), fold its relationships, mark
100
- * it `committed`, `publish` the event, then run `onCommitted` — so the `after` chain runs in THIS
101
- * process, exactly once per committed transition. A transition that cannot be folded is marked
102
- * `failed` with the reason and a failed event is published, and the fold goes PAST it: the card's
103
- * `seq` advances to the failed transition with every other value as it was, so the next
104
- * transition applies normally. Nothing is removed from the log. A create that fails leaves no card
105
- * to advance, so what follows it fails too; a store that refuses the advancing write itself stops
106
- * the fold there and reports `followUp`, leaving the rest pending for a retry.
107
- *
108
- * The caller owns single flight: two folds of one card running at once would both publish.
109
- *
110
- * @throws {PlanningUnsupported} for a store without a transition log
111
- */
112
- export const foldPending = async (
113
- store: PlanningStore, cardId: string, entityId: string, opts: FoldOptions = {}
114
- ): Promise<FoldResult> => {
115
- const transitions = store.transitions
116
- if (transitions == null) {
117
- throw new PlanningUnsupported(`fold:${store.alias ?? 'store'}`)
118
- }
119
- const now = opts.now ?? isoNow
120
-
121
- let card = await store.cards.get(cardId, entityId)
122
- const listed = await transitions.list(
123
- { entityId, card: cardId, sinceSeq: card?.seq ?? 0, state: CommitState.Pending },
124
- { sort: ['seq'], size: opts.limit ?? 0 }
125
- )
126
95
 
127
- let folded = 0
128
- let failed = 0
129
- for (const transition of listed.items) {
130
- if (transition.commit.state !== CommitState.Pending || transition.id == null) {
131
- continue
96
+ const foldPending = async (
97
+ store: PlanningStore, cardId: string, entityId: string, opts: FoldOptions = {}
98
+ ): Promise<FoldResult> => {
99
+ const transitions = store.transitions
100
+ if (transitions == null) {
101
+ throw new PlanningUnsupported(`fold:${store.alias ?? 'store'}`)
132
102
  }
133
- await opts.touch?.()
134
- const at = now()
103
+ const now = opts.now ?? isoNow
135
104
 
136
- let next: Workcard | null
137
- try {
138
- next = applyTransition(card, transition)
139
- if (card != null && next === card) {
140
- // Already applied by another folder, which owns its commit and its event.
105
+ let card = await store.cards.get(cardId, entityId)
106
+ const listed = await transitions.list(
107
+ { entityId, card: cardId, sinceSeq: card?.seq ?? 0, state: CommitState.Pending },
108
+ { sort: ['seq'], size: opts.limit ?? 0 }
109
+ )
110
+
111
+ let folded = 0
112
+ let failed = 0
113
+ for (const transition of listed.items) {
114
+ if (transition.commit.state !== CommitState.Pending || transition.id == null) {
141
115
  continue
142
116
  }
143
- await writeFold(store, card, next, transition)
144
- } catch (error) {
145
- failed++
146
- const message = errorText(error)
147
- if (card != null && transition.seq > card.seq) {
148
- // Fold PAST it: the record keeps its previous values and only its cursor moves, so the
149
- // next transition still applies. The card is re-written whole, which also undoes a write
150
- // that got half way before it threw.
151
- const skipped: Workcard = { ...card, seq: transition.seq, head: Math.max(card.head ?? card.seq, transition.seq) }
152
- try {
153
- await store.cards.put(skipped)
154
- card = skipped
155
- } catch (advance) {
156
- // The store itself refuses writes: leave the rest pending for a retry rather than
157
- // failing every later transition as out of order.
158
- console.error(`planning: cannot advance ${cardId} past failed seq ${transition.seq}:`, advance)
159
- await safely('commit failure', () => transitions.commit(transition.id!, { state: CommitState.Failed, at, error: message }))
160
- await safely('publish', () => opts.publish?.(commitEventOf(transition, CommitState.Failed, at, { error: message })))
161
- return { card, folded, failed, followUp: true }
117
+ await opts.touch?.()
118
+ const at = now()
119
+
120
+ let next: Workcard | null
121
+ try {
122
+ next = applyHelper.applyTransition(card, transition)
123
+ if (card != null && next === card) {
124
+ // Already applied by another folder, which owns its commit and its event.
125
+ continue
162
126
  }
127
+ const before = card
128
+ const after = next
129
+ await (opts.unit != null
130
+ ? opts.unit(async () => { await writeFold(store, before, after, transition) })
131
+ : writeFold(store, before, after, transition))
132
+ } catch (error) {
133
+ failed++
134
+ const message = errorText(error)
135
+ if (card != null && transition.seq > card.seq) {
136
+ // Fold PAST it: the record keeps its previous values and only its cursor moves, so the
137
+ // next transition still applies. The card is re-written whole, which also undoes a write
138
+ // that got half way before it threw.
139
+ const skipped: Workcard = { ...card, seq: transition.seq, head: Math.max(card.head ?? card.seq, transition.seq) }
140
+ try {
141
+ await store.cards.put(skipped)
142
+ card = skipped
143
+ } catch (advance) {
144
+ // The store itself refuses writes: leave the rest pending for a retry rather than
145
+ // failing every later transition as out of order.
146
+ log.error('Planning cannot advance a card past a failed transition', { cardId, seq: transition.seq, error: advance })
147
+ await safely('commit failure', () => transitions.commit(transition.id!, { state: CommitState.Failed, at, error: message }))
148
+ await safely('publish', () => opts.publish?.(commitEventOf(transition, CommitState.Failed, at, { error: message })))
149
+ return { card, folded, failed, followUp: true }
150
+ }
151
+ }
152
+ await safely('commit failure', () => transitions.commit(transition.id!, { state: CommitState.Failed, at, error: message }))
153
+ const event = commitEventOf(transition, CommitState.Failed, at, { error: message })
154
+ await safely('publish', () => opts.publish?.(event))
155
+ continue
163
156
  }
164
- await safely('commit failure', () => transitions.commit(transition.id!, { state: CommitState.Failed, at, error: message }))
165
- const event = commitEventOf(transition, CommitState.Failed, at, { error: message })
157
+
158
+ card = next
159
+ folded++
160
+ await safely('commit', () => transitions.commit(transition.id!, { state: CommitState.Committed, at }))
161
+ const event = commitEventOf(transition, CommitState.Committed, at, { record: next })
166
162
  await safely('publish', () => opts.publish?.(event))
167
- continue
163
+ await safely('onCommitted', () => opts.onCommitted?.(event))
168
164
  }
169
165
 
170
- card = next
171
- folded++
172
- await safely('commit', () => transitions.commit(transition.id!, { state: CommitState.Committed, at }))
173
- const event = commitEventOf(transition, CommitState.Committed, at, { record: next })
174
- await safely('publish', () => opts.publish?.(event))
175
- await safely('onCommitted', () => opts.onCommitted?.(event))
166
+ return { card, folded, failed, followUp: listed.total > listed.items.length }
176
167
  }
177
168
 
178
- return { card, folded, failed, followUp: listed.total > listed.items.length }
179
- }
169
+ const failPending = async (
170
+ store: PlanningStore, cardId: string, entityId: string, reason: string,
171
+ opts: Pick<FoldOptions, 'publish' | 'now'> = {}
172
+ ): Promise<number> => {
173
+ const transitions = store.transitions
174
+ if (transitions == null) {
175
+ return 0
176
+ }
177
+ const at = (opts.now ?? isoNow)()
178
+ const pending = await transitions.list({ entityId, card: cardId, state: CommitState.Pending }, { sort: ['seq'], size: 0 })
179
+ for (const transition of pending.items) {
180
+ if (transition.id == null) {
181
+ continue
182
+ }
183
+ await transitions.commit(transition.id, { state: CommitState.Failed, at, error: reason })
184
+ const event = commitEventOf(transition, CommitState.Failed, at, { error: reason })
185
+ await safely('publish', () => opts.publish?.(event))
186
+ }
180
187
 
181
- /**
182
- * Mark every pending transition of a card `failed` and publish a failed event for each — what a
183
- * queued store does when its projection job is dead, or waiters hang until their timeout.
184
- */
185
- export const failPending = async (
186
- store: PlanningStore, cardId: string, entityId: string, reason: string,
187
- opts: Pick<FoldOptions, 'publish' | 'now'> = {}
188
- ): Promise<number> => {
189
- const transitions = store.transitions
190
- if (transitions == null) {
191
- return 0
188
+ return pending.items.length
192
189
  }
193
- const at = (opts.now ?? isoNow)()
194
- const pending = await transitions.list({ entityId, card: cardId, state: CommitState.Pending }, { sort: ['seq'], size: 0 })
195
- for (const transition of pending.items) {
196
- if (transition.id == null) {
197
- continue
190
+
191
+ const revisionsFromLog = (log: Transition[], limit?: number): SpecificationRevision[] => {
192
+ const ordered = log.filter(transition => transition.commit.state !== CommitState.Pending)
193
+ .sort((left, right) => left.seq - right.seq)
194
+
195
+ const entries: SpecificationRevision[] = []
196
+ let state: Workcard | null = null
197
+ for (const transition of ordered) {
198
+ if (transition.commit.state === CommitState.Failed) {
199
+ // The fold went past it; so does the replay.
200
+ if (state != null && transition.seq > state.seq) {
201
+ state = { ...(state as Workcard), seq: transition.seq }
202
+ }
203
+ continue
204
+ }
205
+ try {
206
+ state = applyHelper.applyTransition(state, transition)
207
+ } catch {
208
+ break
209
+ }
210
+ if (state == null) {
211
+ break
212
+ }
213
+ const changed = transition.action === TransitionAction.Create
214
+ || CONTENT_KEYS.some(key => (transition.changes as Record<string, unknown>)[key] !== undefined
215
+ || transition.unset?.includes(key) === true)
216
+ if (!changed) {
217
+ continue
218
+ }
219
+ const spec = state as Workcard & { body?: string, ref?: string, bodyChars?: number, version?: number, revision?: number }
220
+ entries.push(clean({
221
+ revision: spec.revision ?? entries.length + 1,
222
+ body: spec.body,
223
+ ref: spec.ref,
224
+ bodyChars: spec.bodyChars,
225
+ version: spec.version,
226
+ at: transition.at,
227
+ by: transition.actor,
228
+ transition: transition.id!,
229
+ }))
198
230
  }
199
- await transitions.commit(transition.id, { state: CommitState.Failed, at, error: reason })
200
- const event = commitEventOf(transition, CommitState.Failed, at, { error: reason })
201
- await safely('publish', () => opts.publish?.(event))
231
+
232
+ const newest = entries.reverse()
233
+ return limit != null && limit > 0 ? newest.slice(0, limit) : newest
202
234
  }
203
235
 
204
- return pending.items.length
236
+ return { commitEventOf, foldPending, failPending, revisionsFromLog }
205
237
  }
206
238
 
207
- const CONTENT_KEYS = ['body', 'ref', 'format', 'version'] as const
239
+ export const foldHelper = createFoldHelper()
208
240
 
209
- /**
210
- * A specification's history, replayed from its log: one entry per create and per committed
211
- * content change, newest first. The fold is `applyTransition` itself, so an entry's `body` is the
212
- * body AT that revision even when the transition changed only `ref`.
213
- */
214
- export const revisionsFromLog = (log: Transition[], limit?: number): SpecificationRevision[] => {
215
- const ordered = log.filter(transition => transition.commit.state !== CommitState.Pending)
216
- .sort((left, right) => left.seq - right.seq)
241
+ /** @deprecated compat:factory-refactor — use `foldHelper.commitEventOf(…)` */
242
+ export const commitEventOf = (
243
+ transition: Transition, state: CommitState, at: string, extra?: { error?: string, record?: Workcard | null }
244
+ ): CommitEvent => foldHelper.commitEventOf(transition, state, at, extra)
217
245
 
218
- const entries: SpecificationRevision[] = []
219
- let state: Workcard | null = null
220
- for (const transition of ordered) {
221
- if (transition.commit.state === CommitState.Failed) {
222
- // The fold went past it; so does the replay.
223
- if (state != null && transition.seq > state.seq) {
224
- state = { ...(state as Workcard), seq: transition.seq }
225
- }
226
- continue
227
- }
228
- try {
229
- state = applyTransition(state, transition)
230
- } catch {
231
- break
232
- }
233
- if (state == null) {
234
- break
235
- }
236
- const changed = transition.action === TransitionAction.Create
237
- || CONTENT_KEYS.some(key => (transition.changes as Record<string, unknown>)[key] !== undefined
238
- || transition.unset?.includes(key) === true)
239
- if (!changed) {
240
- continue
241
- }
242
- const spec = state as Workcard & { body?: string, ref?: string, bodyChars?: number, version?: number, revision?: number }
243
- entries.push(clean({
244
- revision: spec.revision ?? entries.length + 1,
245
- body: spec.body,
246
- ref: spec.ref,
247
- bodyChars: spec.bodyChars,
248
- version: spec.version,
249
- at: transition.at,
250
- by: transition.actor,
251
- transition: transition.id!,
252
- }))
253
- }
246
+ /** @deprecated compat:factory-refactor — use `foldHelper.foldPending(…)` */
247
+ export const foldPending = async (
248
+ store: PlanningStore, cardId: string, entityId: string, opts: FoldOptions = {}
249
+ ): Promise<FoldResult> => await foldHelper.foldPending(store, cardId, entityId, opts)
254
250
 
255
- const newest = entries.reverse()
256
- return limit != null && limit > 0 ? newest.slice(0, limit) : newest
257
- }
251
+ /** @deprecated compat:factory-refactor — use `foldHelper.failPending(…)` */
252
+ export const failPending = async (
253
+ store: PlanningStore, cardId: string, entityId: string, reason: string,
254
+ opts: Pick<FoldOptions, 'publish' | 'now'> = {}
255
+ ): Promise<number> => await foldHelper.failPending(store, cardId, entityId, reason, opts)
256
+
257
+ /** @deprecated compat:factory-refactor — use `foldHelper.revisionsFromLog(…)` */
258
+ export const revisionsFromLog = (log: Transition[], limit?: number): SpecificationRevision[] =>
259
+ foldHelper.revisionsFromLog(log, limit)
@@ -1,4 +1,5 @@
1
1
  export type * from './types.js'
2
+ export type * from './fold/types.js'
2
3
 
3
4
  export * from './commits.js'
4
5
  export * from './composite.js'
Binary file
@@ -0,0 +1,3 @@
1
+ import type { CommitEvent } from '@owlmeans/planning'
2
+
3
+ export interface Listener { (event: CommitEvent): void | Promise<void> }
@@ -1,6 +1,7 @@
1
1
  import type {
2
2
  CommitEvent, CommitSource, CommitStatus, PlanningStore, ProjectionStore, Relationship,
3
- RelationshipStore, SpecificationStore, Transition, TransitionStore, Workcard,
3
+ RelationshipStore, SchemaStore, ScopedSchemaRecord, SpecificationStore, Transition, TransitionStore,
4
+ Workcard,
4
5
  } from '@owlmeans/planning'
5
6
 
6
7
  /** What a folding store calls for every committed transition — the service's `committed`. */
@@ -49,6 +50,11 @@ export interface FoldOptions {
49
50
  limit?: number
50
51
  /** Called between transitions — a queue processor renews its lock here. */
51
52
  touch?: () => Promise<void>
53
+ /**
54
+ * Runs one transition's store writes as a unit — a transactional store opens a savepoint here, so
55
+ * a write the database refuses leaves nothing of that transition behind and the fold goes past it.
56
+ */
57
+ unit?: <R>(run: () => Promise<R>) => Promise<R>
52
58
  }
53
59
 
54
60
  export interface FoldResult {
@@ -63,6 +69,8 @@ export interface MemoryPlanningStoreSeed {
63
69
  cards?: Workcard[]
64
70
  links?: Relationship[]
65
71
  transitions?: Transition[]
72
+ /** Data-defined type and flow records — kept only by a store built with `schemas: true`. */
73
+ schemas?: ScopedSchemaRecord[]
66
74
  }
67
75
 
68
76
  export interface MemoryPlanningStoreOptions {
@@ -74,6 +82,11 @@ export interface MemoryPlanningStoreOptions {
74
82
  /** The commit listener used until a service binds its own. */
75
83
  onCommitted?: CommitListener
76
84
  alias?: string
85
+ /**
86
+ * Hold data-defined types and flows (the `schemas` port). Off by default: a store without it
87
+ * resolves every type and flow from the code registry, exactly as before.
88
+ */
89
+ schemas?: boolean
77
90
  }
78
91
 
79
92
  export interface MemoryPlanningStore extends BindablePlanningStore {
@@ -82,6 +95,8 @@ export interface MemoryPlanningStore extends BindablePlanningStore {
82
95
  specs: SpecificationStore
83
96
  links: RelationshipStore
84
97
  commits: CommitHub
98
+ /** Present when the store was built with `schemas: true`. */
99
+ schemas?: SchemaStore
85
100
  bind: (committed: CommitListener) => void
86
101
  /** Fold what is pending — for one card, or for every card with a pending transition. */
87
102
  flush: (card?: string) => Promise<void>