@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
@@ -0,0 +1,7 @@
1
+ import { PlanningSchemaKind, type AssigneeTypeSchema, type StatusFlowSchema, type WorkcardTypeSchema } from '@owlmeans/planning'
2
+
3
+ export interface Planned {
4
+ kind: PlanningSchemaKind
5
+ key: string
6
+ definition: WorkcardTypeSchema | StatusFlowSchema | AssigneeTypeSchema
7
+ }
package/src/types.ts CHANGED
@@ -1,11 +1,10 @@
1
1
  import type { BasicConfig, BasicContext, LazyService } from '@owlmeans/context'
2
2
  import type { AbstractRequest } from '@owlmeans/entrypoint'
3
- import type {
4
- AnyTypeSchema, PlanningPlugin, PlanningScope, PlanningService, PlanningStore, StatusFlowSchema,
5
- WithPlanningService,
6
- } from '@owlmeans/planning'
3
+ import type { AssigneeTypeSchema, AnyTypeSchema, PlanningAppDeclarations, PlanningPlugin, PlanningScope, PlanningService, PlanningStore, StatusFlowSchema, WithPlanningService, PlanningSchemaRegistry, SchemaStore, ScopedSchemaRegistry, CommitEvent, PlanningExecContext, PlanningHookContext, TransitionExecution, WorkcardDraft } from '@owlmeans/planning'
7
4
  import type { ApiServerAppend } from '@owlmeans/server-api'
8
5
  import type { ServerConfig, ServerContext } from '@owlmeans/server-context'
6
+ import type { StoreRoute } from './store/types.js'
7
+
9
8
 
10
9
  export interface Config extends ServerConfig { }
11
10
 
@@ -15,8 +14,11 @@ export interface PlanningServiceOptions {
15
14
  /** The default store — every type no plugin owns. An in-memory store when omitted. */
16
15
  store?: PlanningStore
17
16
  plugins?: PlanningPlugin[]
18
- /** Schemas registered before any plugin's. */
19
- schemas?: { types?: AnyTypeSchema[], flows?: StatusFlowSchema[] }
17
+ /**
18
+ * Schemas registered before any plugin's; `app` is the first source every plugin's `schemas.app`
19
+ * is merged over.
20
+ */
21
+ schemas?: { types?: AnyTypeSchema[], flows?: StatusFlowSchema[], assigneeTypes?: AssigneeTypeSchema[], app?: PlanningAppDeclarations }
20
22
  /** Run the `after` chain in this process. Default `true`. */
21
23
  hooks?: boolean
22
24
  /** Card ids when the store mints none. */
@@ -37,6 +39,53 @@ export interface PlanningScopeExtractor {
37
39
  (req: AbstractRequest, ctx: BasicContext<BasicConfig>): Partial<PlanningScope> | Promise<Partial<PlanningScope>>
38
40
  }
39
41
 
42
+ /**
43
+ * A grant: `true` for everything the request can see, a list for those project cards only (the
44
+ * parent of a created project, the deleted project, the schema layer).
45
+ */
46
+ export type PlanningGrant = boolean | string[]
47
+
48
+ export interface PlanningAccessGrants {
49
+ /** Create a project — at the root only with `true`; a list names the parent projects. */
50
+ manageAssignees?: boolean
51
+ manageTeams?: boolean
52
+ createProjects?: PlanningGrant
53
+ /** Delete a project — a list names the projects. */
54
+ deleteProjects?: PlanningGrant
55
+ /** Write data-defined types and flows — the organization-wide layer only with `true`. */
56
+ defineSchemas?: PlanningGrant
57
+ }
58
+
59
+ /** What a hosting application decides about one request. */
60
+ export interface PlanningAccess {
61
+ /** The organization the request acts in — the only source of it once a resolver is given. */
62
+ entityId: string
63
+ /** Narrows every read and write to these project cards. Every project when omitted. */
64
+ projects?: string[]
65
+ /**
66
+ * The project cards the request may WRITE in: `execute` on a card, specification or link inside
67
+ * one of them (the same rule a narrowed read admits — the project, the cards whose `parents` name
68
+ * it, a specification through its parent card), and `schema.define` of a project layer. A project
69
+ * outside `projects` is still unreachable. Omitted — writes reach every project `projects` admits;
70
+ * present — anything else is refused with `PlanningForbidden` (403). Creating a project is
71
+ * `grants.createProjects`' alone; the organization-wide schema layer is `grants.defineSchemas`'.
72
+ */
73
+ writes?: string[]
74
+ /**
75
+ * Gates the writes above. Omitted — nothing is gated; present — a flag it leaves out is refused
76
+ * with `PlanningForbidden`.
77
+ */
78
+ grants?: PlanningAccessGrants
79
+ }
80
+
81
+ /**
82
+ * Resolves a request's access. A throw is the request's answer (an `AuthForbidden` answers 403
83
+ * like any other guard refusal).
84
+ */
85
+ export interface PlanningAccessResolver {
86
+ (req: AbstractRequest, ctx: BasicContext<BasicConfig>): Promise<PlanningAccess>
87
+ }
88
+
40
89
  export interface PlanningHandlerOptions {
41
90
  /** The planning service alias. `PLANNING_SERVICE` when omitted. */
42
91
  service?: string
@@ -45,4 +94,88 @@ export interface PlanningHandlerOptions {
45
94
  /** The longest single long poll, in seconds — clamps `commit.get`'s `wait` and `execute`'s `timeout`. */
46
95
  maxPoll?: number
47
96
  scope?: PlanningScopeExtractor
97
+ /**
98
+ * The hosting application's access decision per request. Without it the organization is the
99
+ * request's own (`requireEntityKey`) and nothing is narrowed or gated.
100
+ */
101
+ access?: PlanningAccessResolver
102
+ }
103
+
104
+ export interface SchemaViewsOptions {
105
+ /** The code registry every layer starts from. */
106
+ code: () => PlanningSchemaRegistry
107
+ /** Bumps whenever the code registry changes (a plugin's `use`). */
108
+ version: () => number
109
+ /** The schema port, when the store has one. */
110
+ port: () => SchemaStore | undefined
111
+ /** How many resolved layers are kept. */
112
+ limit?: number
113
+ }
114
+
115
+ export interface SchemaViews {
116
+ /** The code registry itself without a port; the resolved layer with one. */
117
+ of: (entityId: string, project?: string) => Promise<PlanningSchemaRegistry>
118
+ /** @throws {PlanningUnsupported} without a port */
119
+ scoped: (entityId: string, project?: string) => Promise<ScopedSchemaRegistry>
120
+ }
121
+
122
+ export interface ProjectionOptions {
123
+ /** The planning service alias. */
124
+ service?: string
125
+ /** The store the queue folds — the service's default store when omitted. */
126
+ store?: (service: PlanningService) => PlanningStore
127
+ /** Where events go — the store's commit hub `publish` when it has one. */
128
+ publish?: (event: CommitEvent) => Promise<void>
129
+ }
130
+
131
+ export interface PluginRegistry {
132
+ /**
133
+ * Register, or replace the plugin of the same `name`. Its schemas are contributed now; the
134
+ * application's declarations are re-merged from the service's own and every plugin's, in plugin
135
+ * order (`appSchemaHelper.merge`), so a replaced plugin's declarations leave with it.
136
+ *
137
+ * @throws {SchemaInvalid} a malformed `schemas.app` — the plugin is not registered
138
+ */
139
+ use: (plugin: PlanningPlugin) => void
140
+ /** Every plugin, `order` ascending (registration order among equals). */
141
+ plugins: () => PlanningPlugin[]
142
+ /** The owning plugins that supply a store, in plugin order, each store resolved once. */
143
+ routes: (ctx?: BasicContext<BasicConfig>) => StoreRoute[]
144
+ /** The first owning plugin's store for a type, else `fallback`. */
145
+ storeFor: (type: string | undefined, fallback: PlanningStore, ctx?: BasicContext<BasicConfig>) => PlanningStore
146
+ /** The first plugin answering a code wins. */
147
+ mintCode: (
148
+ draft: WorkcardDraft, taken: (code: string) => Promise<boolean>, contextOf: (plugin: PlanningPlugin) => PlanningExecContext
149
+ ) => Promise<string | undefined>
150
+ /** The `before` chain; answers the execution the chain left. */
151
+ before: (
152
+ exec: TransitionExecution, contextOf: (plugin: PlanningPlugin) => PlanningExecContext
153
+ ) => Promise<TransitionExecution>
154
+ /** The `after` chain; a failing hook is logged and the chain goes on. */
155
+ after: (event: CommitEvent, contextOf: (plugin: PlanningPlugin) => PlanningHookContext) => Promise<void>
156
+ /** Bumps on every `use` — what a cached composite store is keyed by. */
157
+ version: () => number
158
+ }
159
+
160
+ export interface PlanningServiceApi extends Pick<PlanningService, 'use' | 'plugins' | 'schemas' | 'store' | 'for' | 'committed'> {}
161
+
162
+ /** What the facade and the executor reach the service through. */
163
+ export interface PlanningRuntime {
164
+ service: () => PlanningService
165
+ registry: PluginRegistry
166
+ options: PlanningServiceOptions
167
+ context: () => BasicContext<BasicConfig> | undefined
168
+ /** The composite store reads and commits go through. */
169
+ reader: () => PlanningStore
170
+ /** Every distinct store: the default one first, then each plugin's. */
171
+ stores: () => PlanningStore[]
172
+ /** The default store's data-defined schema port, when it has one. */
173
+ schemaStore: () => SchemaStore | undefined
174
+ /**
175
+ * The registry a card of this organization (and project) resolves through. Without a schema
176
+ * port it is the service's code registry itself — the very same object.
177
+ */
178
+ schemasFor: (entityId: string, project?: string) => Promise<PlanningSchemaRegistry>
179
+ /** The resolved layer. @throws {PlanningUnsupported} without a schema port */
180
+ scopedSchemas: (entityId: string, project?: string) => Promise<ScopedSchemaRegistry>
48
181
  }
@@ -0,0 +1,30 @@
1
+ import type { Workcard } from '@owlmeans/planning'
2
+ import type { PlanningAccess, PlanningAccessGrants } from '../../types.js'
3
+
4
+ /** The write rules of one resolved {@link PlanningAccess} — no access at all gates nothing. */
5
+ export interface PlanningAccessModel {
6
+ readonly record: PlanningAccess | undefined
7
+ /**
8
+ * Refuse a write the access does not grant. No access, or access without `grants`, gates nothing;
9
+ * a `grants` object refuses every flag it leaves out. `true` grants everything; a list grants the
10
+ * project ids it names — `target` is the project the write is about (`undefined` for the
11
+ * organization's root, which only `true` reaches).
12
+ *
13
+ * @throws {PlanningForbidden}
14
+ */
15
+ assertGranted: (grant: keyof PlanningAccessGrants, target?: string) => void
16
+ /**
17
+ * A card the access's `writes` admits — the rule a narrowed read admits, over `writes`: a project
18
+ * it names, or a card whose `parents` name one. A specification is admitted through its parent card
19
+ * by the caller. No `writes` admits everything.
20
+ */
21
+ writableIn: (card: Pick<Workcard, 'id' | 'parents'>) => boolean
22
+ /**
23
+ * Refuse a write into a project the access's `writes` leaves out. No `writes` refuses nothing;
24
+ * `target` is the project the write is in (`undefined` for the organization's root, which a set
25
+ * `writes` never admits).
26
+ *
27
+ * @throws {PlanningForbidden}
28
+ */
29
+ assertWrites: (target?: string) => void
30
+ }
@@ -0,0 +1,33 @@
1
+ import { PlanningForbidden, type Workcard } from '@owlmeans/planning'
2
+ import type { PlanningAccess, PlanningAccessGrants } from '../types.js'
3
+ import type { PlanningAccessModel } from './access/types.js'
4
+
5
+ export const makePlanningAccessModel = (access: PlanningAccess | undefined): PlanningAccessModel => {
6
+ const assertGranted = (grant: keyof PlanningAccessGrants, target?: string): void => {
7
+ if (access?.grants == null) {
8
+ return
9
+ }
10
+ const granted = access.grants[grant]
11
+ if (granted === true || (Array.isArray(granted) && target != null && granted.includes(target))) {
12
+ return
13
+ }
14
+ throw new PlanningForbidden(`${grant}:${target ?? 'root'}`)
15
+ }
16
+
17
+ const writableIn = (card: Pick<Workcard, 'id' | 'parents'>): boolean => {
18
+ const writes = access?.writes
19
+ if (writes == null) {
20
+ return true
21
+ }
22
+ return (card.id != null && writes.includes(card.id)) || card.parents.some(parent => writes.includes(parent))
23
+ }
24
+
25
+ const assertWrites = (target?: string): void => {
26
+ if (access?.writes == null || (target != null && access.writes.includes(target))) {
27
+ return
28
+ }
29
+ throw new PlanningForbidden(`writes:${target ?? 'root'}`)
30
+ }
31
+
32
+ return { record: access, assertGranted, writableIn, assertWrites }
33
+ }
@@ -0,0 +1,21 @@
1
+ import type { WorkcardNotFound, Workcard, PlanningReply } from '@owlmeans/planning'
2
+
3
+ /** What every handler answers with when a record is not the caller's: absence, never a refusal. */
4
+ export interface GuardHelper {
5
+ notFoundOf: (id: string) => WorkcardNotFound
6
+ /**
7
+ * A record of another entity is absent, not forbidden.
8
+ *
9
+ * @throws {WorkcardNotFound}
10
+ */
11
+ assertScope: <T extends Pick<Workcard, 'entityId'>>(record: T | null | undefined, scope: { entityId: string }, id: string) => T
12
+ /**
13
+ * Run a handler body so that a scope mismatch leaves as `WorkcardNotFound` — telling "not yours"
14
+ * apart from "does not exist" is what turns an id space into an enumeration oracle.
15
+ */
16
+ concealed: <T>(run: () => Promise<T>) => Promise<T>
17
+ /** Conceal scope failures and project storage metadata out of a public reply. */
18
+ reply: <T>(run: () => Promise<T>) => Promise<PlanningReply<T>>
19
+ /** Seconds as the wire sends them, clamped to `[0, max]`. */
20
+ clampSeconds: (value: unknown, max: number) => number
21
+ }
@@ -1,40 +1,53 @@
1
- import { PlanningScopeMismatch, WorkcardNotFound } from '@owlmeans/planning'
1
+ import { planningReplyHelper, PlanningScopeMismatch, WorkcardNotFound } from '@owlmeans/planning'
2
2
  import type { Workcard } from '@owlmeans/planning'
3
+ import type { GuardHelper } from './guard/types.js'
3
4
 
4
- export const notFoundOf = (id: string): WorkcardNotFound => new WorkcardNotFound(id)
5
+ export const createGuardHelper = (): GuardHelper => {
6
+ const notFoundOf = (id: string): WorkcardNotFound => new WorkcardNotFound(id)
5
7
 
6
- /**
7
- * A record of another entity is absent, not forbidden.
8
- *
9
- * @throws {WorkcardNotFound}
10
- */
11
- export const assertScope = <T extends Pick<Workcard, 'entityId'>>(
12
- record: T | null | undefined, scope: { entityId: string }, id: string
13
- ): T => {
14
- if (record == null || record.entityId !== scope.entityId) {
15
- throw notFoundOf(id)
8
+ const assertScope = <T extends Pick<Workcard, 'entityId'>>(
9
+ record: T | null | undefined, scope: { entityId: string }, id: string
10
+ ): T => {
11
+ if (record == null || record.entityId !== scope.entityId) {
12
+ throw notFoundOf(id)
13
+ }
14
+ return record
16
15
  }
17
- return record
18
- }
19
16
 
20
- /**
21
- * Run a handler body so that a scope mismatch leaves as `WorkcardNotFound` — telling "not yours"
22
- * apart from "does not exist" is what turns an id space into an enumeration oracle.
23
- */
24
- export const concealed = async <T>(run: () => Promise<T>): Promise<T> => {
25
- try {
26
- return await run()
27
- } catch (error) {
28
- if (error instanceof PlanningScopeMismatch
29
- || (error as { type?: string } | null)?.type === PlanningScopeMismatch.typeName) {
30
- throw new WorkcardNotFound()
17
+ const concealed = async <T>(run: () => Promise<T>): Promise<T> => {
18
+ try {
19
+ return await run()
20
+ } catch (error) {
21
+ if (error instanceof PlanningScopeMismatch
22
+ || (error as { type?: string } | null)?.type === PlanningScopeMismatch.typeName) {
23
+ throw new WorkcardNotFound()
24
+ }
25
+ throw error
31
26
  }
32
- throw error
33
27
  }
34
- }
35
28
 
36
- /** Seconds as the wire sends them, clamped to `[0, max]`. */
37
- export const clampSeconds = (value: unknown, max: number): number => {
38
- const number = typeof value === 'number' ? value : Number(value ?? 0)
39
- return Number.isFinite(number) ? Math.min(Math.max(number, 0), max) : 0
29
+ const clampSeconds = (value: unknown, max: number): number => {
30
+ const number = typeof value === 'number' ? value : Number(value ?? 0)
31
+ return Number.isFinite(number) ? Math.min(Math.max(number, 0), max) : 0
32
+ }
33
+
34
+ return { notFoundOf, assertScope, concealed, clampSeconds,
35
+ reply: async run => planningReplyHelper.project(await concealed(run)),
36
+ }
40
37
  }
38
+
39
+ export const guardHelper = createGuardHelper()
40
+
41
+ /** @deprecated compat:factory-refactor — use `guardHelper.notFoundOf(…)` */
42
+ export const notFoundOf = (id: string): WorkcardNotFound => guardHelper.notFoundOf(id)
43
+
44
+ /** @deprecated compat:factory-refactor — use `guardHelper.assertScope(…)` */
45
+ export const assertScope = <T extends Pick<Workcard, 'entityId'>>(
46
+ record: T | null | undefined, scope: { entityId: string }, id: string
47
+ ): T => guardHelper.assertScope<T>(record, scope, id)
48
+
49
+ /** @deprecated compat:factory-refactor — use `guardHelper.concealed(…)` */
50
+ export const concealed = async <T>(run: () => Promise<T>): Promise<T> => await guardHelper.concealed<T>(run)
51
+
52
+ /** @deprecated compat:factory-refactor — use `guardHelper.clampSeconds(…)` */
53
+ export const clampSeconds = (value: unknown, max: number): number => guardHelper.clampSeconds(value, max)
@@ -0,0 +1,28 @@
1
+ import type { AbstractRequest } from '@owlmeans/entrypoint'
2
+ import type { PlanningFacade, PlanningScope, PlanningService } from '@owlmeans/planning'
3
+ import type { PlanningHandlerOptions } from '../../types.js'
4
+ import type { HandlerScope } from '../types.js'
5
+
6
+ /** The planning service of one context, as a request handler reaches it. */
7
+ export interface PlanningHandlerHelper {
8
+ planningServiceOf: (opts?: Pick<PlanningHandlerOptions, 'service'>) => PlanningService
9
+ /**
10
+ * The facade a handler works through, and the access it was resolved under.
11
+ *
12
+ * Without `opts.access` it is exactly the request's scope plus what `opts.scope` derives. With it,
13
+ * the resolver names the organization and the visible projects; a throw from the resolver is the
14
+ * request's error.
15
+ */
16
+ handlerScopeOf: (req: AbstractRequest, opts?: PlanningHandlerOptions) => Promise<HandlerScope>
17
+ /** The facade a handler works through: the request's scope plus what `opts.scope` derives. */
18
+ handlerFacade: (req: AbstractRequest, opts?: PlanningHandlerOptions) => Promise<PlanningFacade>
19
+ /**
20
+ * The facade a hand-written handler works through: the request's entity and subject, plus `extra`
21
+ * (a `channel`) — never an entity from the request body.
22
+ *
23
+ * @throws {AuthorizationError} when the request carries no organization
24
+ */
25
+ planningFor: (
26
+ req: AbstractRequest, extra?: Partial<PlanningScope>, opts?: Pick<PlanningHandlerOptions, 'service'>
27
+ ) => PlanningFacade
28
+ }
@@ -0,0 +1,35 @@
1
+ import { memoHelper, type BasicConfig, type BasicContext } from '@owlmeans/context'
2
+ import type { AbstractRequest } from '@owlmeans/entrypoint'
3
+ import { PLANNING_SERVICE, type PlanningFacade, type PlanningScope, type PlanningService } from '@owlmeans/planning'
4
+ import type { PlanningHandlerOptions, PlanningHostService } from '../types.js'
5
+ import type { PlanningHandlerHelper } from './handler/types.js'
6
+ import { makeRequestScope } from './request.js'
7
+ import type { HandlerScope } from './types.js'
8
+
9
+ export const makePlanningHandlerHelper = (ctx: BasicContext<BasicConfig>): PlanningHandlerHelper => {
10
+ const planningServiceOf = (opts?: Pick<PlanningHandlerOptions, 'service'>): PlanningService =>
11
+ ctx.service<PlanningHostService>(opts?.service ?? PLANNING_SERVICE)
12
+
13
+ const handlerScopeOf = async (req: AbstractRequest, opts?: PlanningHandlerOptions): Promise<HandlerScope> => {
14
+ const planningService = planningServiceOf(opts)
15
+ const extra = await opts?.scope?.(req, ctx)
16
+ if (opts?.access == null) {
17
+ return { facade: planningService.for(makeRequestScope(req).scopeOf(extra ?? undefined)) }
18
+ }
19
+ const access = await opts.access(req, ctx)
20
+
21
+ return { facade: planningService.for(makeRequestScope(req).accessScopeOf(access, extra ?? undefined)), access }
22
+ }
23
+
24
+ const handlerFacade = async (req: AbstractRequest, opts?: PlanningHandlerOptions): Promise<PlanningFacade> =>
25
+ (await handlerScopeOf(req, opts)).facade
26
+
27
+ const planningFor = (
28
+ req: AbstractRequest, extra?: Partial<PlanningScope>, opts?: Pick<PlanningHandlerOptions, 'service'>
29
+ ): PlanningFacade => planningServiceOf(opts).for(makeRequestScope(req).scopeOf(extra))
30
+
31
+ return { planningServiceOf, handlerScopeOf, handlerFacade, planningFor }
32
+ }
33
+
34
+ /** The handler helper of a context — one per context. */
35
+ export const planningHandlerOf = memoHelper.oncePer(makePlanningHandlerHelper)
@@ -1,2 +1,11 @@
1
+ export type * from './types.js'
2
+ export type * from './access/types.js'
3
+ export type * from './guard/types.js'
4
+ export type * from './handler/types.js'
5
+ export type * from './request/types.js'
6
+
7
+ export * from './access.js'
1
8
  export * from './guard.js'
9
+ export * from './handler.js'
10
+ export * from './request.js'
2
11
  export * from './scope.js'
@@ -0,0 +1,23 @@
1
+ import type { PlanningScope, TransitionActor } from '@owlmeans/planning'
2
+ import type { PlanningAccess } from '../../types.js'
3
+
4
+ /** One request's identity as planning reads it — built at the top of a handler, never stored. */
5
+ export interface RequestScope {
6
+ /** The authenticated subject of a request, as a transition names it. */
7
+ actorOf: () => TransitionActor
8
+ /**
9
+ * The scope a request reads and writes as.
10
+ *
11
+ * `entityId` is `requireEntityKey(req)` — the resolved organization id, never a value from the
12
+ * body or the query — and `extra` cannot replace it; `extra` adds what the deployment derives
13
+ * (a `channel`, a `service`). The actor is the authenticated subject plus that channel.
14
+ *
15
+ * @throws {AuthorizationError} when the request carries no organization
16
+ */
17
+ scopeOf: (extra?: Partial<PlanningScope>) => PlanningScope
18
+ /**
19
+ * The scope of a request under a resolved {@link PlanningAccess}: the organization is the
20
+ * resolver's — never the token's, never `extra`'s — and `projects` narrows it.
21
+ */
22
+ accessScopeOf: (access: PlanningAccess, extra?: Partial<PlanningScope>) => PlanningScope
23
+ }
@@ -0,0 +1,40 @@
1
+
2
+ import type { AbstractRequest } from '@owlmeans/entrypoint'
3
+ import type { PlanningScope, TransitionActor } from '@owlmeans/planning'
4
+ import type { PlanningAccess } from '../types.js'
5
+ import type { RequestScope } from './request/types.js'
6
+ import { makeEntityScope } from '@owlmeans/auth-common'
7
+
8
+ const clean = <T extends object>(record: T): T =>
9
+ Object.fromEntries(Object.entries(record).filter(([, value]) => value != null && value !== '')) as T
10
+
11
+ export const makeRequestScope = (req: AbstractRequest): RequestScope => {
12
+ const actorOf = (): TransitionActor => clean({
13
+ profileId: req.auth?.profileId,
14
+ userId: req.auth?.userId,
15
+ })
16
+
17
+ const scopeWith = (entityId: string, extra?: Partial<PlanningScope>): PlanningScope => {
18
+ const subject = actorOf()
19
+ const channel = extra?.channel ?? extra?.actor?.channel
20
+
21
+ return clean({
22
+ ...extra,
23
+ ...subject,
24
+ entityId,
25
+ channel,
26
+ actor: clean({ ...extra?.actor, ...subject, channel }),
27
+ }) as PlanningScope
28
+ }
29
+
30
+ const scopeOf = (extra?: Partial<PlanningScope>): PlanningScope => scopeWith(makeEntityScope(req).requireEntityKey(), extra)
31
+
32
+ const accessScopeOf = (access: PlanningAccess, extra?: Partial<PlanningScope>): PlanningScope => {
33
+ const { projects: _projects, entityId: _entityId, ...rest } = extra ?? {}
34
+ const scope = scopeWith(access.entityId, rest)
35
+
36
+ return access.projects != null ? { ...scope, projects: [...access.projects] } : scope
37
+ }
38
+
39
+ return { actorOf, scopeOf, accessScopeOf }
40
+ }
@@ -1,51 +1,48 @@
1
- import { requireEntityKey } from '@owlmeans/auth-common'
2
1
  import type { BasicConfig, BasicContext } from '@owlmeans/context'
3
2
  import type { AbstractRequest } from '@owlmeans/entrypoint'
4
- import { PLANNING_SERVICE } from '@owlmeans/planning'
5
- import type { PlanningFacade, PlanningScope, PlanningService, TransitionActor } from '@owlmeans/planning'
6
- import type { PlanningHandlerOptions, PlanningHostService } from '../types.js'
7
-
8
- const clean = <T extends object>(record: T): T =>
9
- Object.fromEntries(Object.entries(record).filter(([, value]) => value != null && value !== '')) as T
10
-
11
- /** The authenticated subject of a request, as a transition names it. */
12
- export const actorOf = (req: AbstractRequest): TransitionActor => clean({
13
- profileId: req.auth?.profileId,
14
- userId: req.auth?.userId,
15
- })
16
-
17
- /**
18
- * The scope a request reads and writes as.
19
- *
20
- * `entityId` is `requireEntityKey(req)` — the resolved organization id, never a value from the
21
- * body or the query — and `extra` cannot replace it; `extra` adds what the deployment derives
22
- * (a `channel`, a `service`). The actor is the authenticated subject plus that channel.
23
- *
24
- * @throws {AuthorizationError} when the request carries no organization
25
- */
26
- export const scopeOf = (req: AbstractRequest, extra?: Partial<PlanningScope>): PlanningScope => {
27
- const entityId = requireEntityKey(req)
28
- const subject = actorOf(req)
29
- const channel = extra?.channel ?? extra?.actor?.channel
30
-
31
- return clean({
32
- ...extra,
33
- ...subject,
34
- entityId,
35
- channel,
36
- actor: clean({ ...extra?.actor, ...subject, channel }),
37
- }) as PlanningScope
38
- }
3
+ import type { PlanningFacade, PlanningScope, PlanningService, TransitionActor, Workcard } from '@owlmeans/planning'
4
+ import type { PlanningAccess, PlanningAccessGrants, PlanningHandlerOptions } from '../types.js'
5
+ import { makePlanningAccessModel } from './access.js'
6
+ import { planningHandlerOf } from './handler.js'
7
+ import { makeRequestScope } from './request.js'
8
+ import type { HandlerScope } from './types.js'
39
9
 
10
+ /** @deprecated compat:factory-refactor — use `makeRequestScope(req).actorOf()` */
11
+ export const actorOf = (req: AbstractRequest): TransitionActor => makeRequestScope(req).actorOf()
12
+
13
+ /** @deprecated compat:factory-refactor — use `makeRequestScope(req).scopeOf(…)` */
14
+ export const scopeOf = (req: AbstractRequest, extra?: Partial<PlanningScope>): PlanningScope =>
15
+ makeRequestScope(req).scopeOf(extra)
16
+
17
+ /** @deprecated compat:factory-refactor — use `makeRequestScope(req).accessScopeOf(…)` */
18
+ export const accessScopeOf = (
19
+ req: AbstractRequest, access: PlanningAccess, extra?: Partial<PlanningScope>
20
+ ): PlanningScope => makeRequestScope(req).accessScopeOf(access, extra)
21
+
22
+ /** @deprecated compat:factory-refactor — use `planningHandlerOf(ctx).planningServiceOf(…)` */
40
23
  export const planningServiceOf = (
41
24
  ctx: BasicContext<BasicConfig>, opts?: Pick<PlanningHandlerOptions, 'service'>
42
- ): PlanningService => ctx.service<PlanningHostService>(opts?.service ?? PLANNING_SERVICE)
25
+ ): PlanningService => planningHandlerOf(ctx).planningServiceOf(opts)
43
26
 
44
- /** The facade a handler works through: the request's scope plus what `opts.scope` derives. */
27
+ /** @deprecated compat:factory-refactor — use `planningHandlerOf(ctx).handlerScopeOf(…)` */
28
+ export const handlerScopeOf = async (
29
+ ctx: BasicContext<BasicConfig>, req: AbstractRequest, opts?: PlanningHandlerOptions
30
+ ): Promise<HandlerScope> => await planningHandlerOf(ctx).handlerScopeOf(req, opts)
31
+
32
+ /** @deprecated compat:factory-refactor — use `planningHandlerOf(ctx).handlerFacade(…)` */
45
33
  export const handlerFacade = async (
46
34
  ctx: BasicContext<BasicConfig>, req: AbstractRequest, opts?: PlanningHandlerOptions
47
- ): Promise<PlanningFacade> => {
48
- const extra = await opts?.scope?.(req, ctx)
35
+ ): Promise<PlanningFacade> => await planningHandlerOf(ctx).handlerFacade(req, opts)
36
+
37
+ /** @deprecated compat:factory-refactor — use `makePlanningAccessModel(access).assertGranted(…)` */
38
+ export const assertGranted = (
39
+ access: PlanningAccess | undefined, grant: keyof PlanningAccessGrants, target?: string
40
+ ): void => makePlanningAccessModel(access).assertGranted(grant, target)
41
+
42
+ /** @deprecated compat:factory-refactor — use `makePlanningAccessModel(access).writableIn(…)` */
43
+ export const writableIn = (access: PlanningAccess | undefined, card: Pick<Workcard, 'id' | 'parents'>): boolean =>
44
+ makePlanningAccessModel(access).writableIn(card)
49
45
 
50
- return planningServiceOf(ctx, opts).for(scopeOf(req, extra ?? undefined))
51
- }
46
+ /** @deprecated compat:factory-refactor — use `makePlanningAccessModel(access).assertWrites(…)` */
47
+ export const assertWrites = (access: PlanningAccess | undefined, target?: string): void =>
48
+ makePlanningAccessModel(access).assertWrites(target)
@@ -0,0 +1,8 @@
1
+ import type { PlanningFacade } from '@owlmeans/planning'
2
+ import type { PlanningAccess } from '../types.js'
3
+
4
+ export interface HandlerScope {
5
+ facade: PlanningFacade
6
+ /** The resolver's answer, when the handler options carry one. */
7
+ access?: PlanningAccess
8
+ }