@owlmeans/server-planning 0.1.18-rc.21 → 0.1.18-rc.22

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 (314) hide show
  1. package/README.md +24 -17
  2. package/agent-meta/manifest.json +2 -2
  3. package/agent-meta/skills/server-planning/SKILL.md +28 -28
  4. package/build/actions/apply-schema-request.d.ts +8 -0
  5. package/build/actions/apply-schema-request.d.ts.map +1 -0
  6. package/build/actions/apply-schema-request.js +31 -0
  7. package/build/actions/apply-schema-request.js.map +1 -0
  8. package/build/actions/commit.d.ts +3 -3
  9. package/build/actions/commit.d.ts.map +1 -1
  10. package/build/actions/commit.js +5 -4
  11. package/build/actions/commit.js.map +1 -1
  12. package/build/actions/define-schemas.d.ts +13 -0
  13. package/build/actions/define-schemas.d.ts.map +1 -0
  14. package/build/actions/define-schemas.js +28 -0
  15. package/build/actions/define-schemas.js.map +1 -0
  16. package/build/actions/execute.d.ts +8 -28
  17. package/build/actions/execute.d.ts.map +1 -1
  18. package/build/actions/execute.js +17 -101
  19. package/build/actions/execute.js.map +1 -1
  20. package/build/actions/execution/types.d.ts +34 -0
  21. package/build/actions/execution/types.d.ts.map +1 -0
  22. package/build/actions/execution/types.js +2 -0
  23. package/build/actions/execution/types.js.map +1 -0
  24. package/build/actions/execution.d.ts +4 -0
  25. package/build/actions/execution.d.ts.map +1 -0
  26. package/build/actions/execution.js +79 -0
  27. package/build/actions/execution.js.map +1 -0
  28. package/build/actions/get-card.d.ts +6 -0
  29. package/build/actions/get-card.d.ts.map +1 -0
  30. package/build/actions/get-card.js +9 -0
  31. package/build/actions/get-card.js.map +1 -0
  32. package/build/actions/get-specification.d.ts +6 -0
  33. package/build/actions/get-specification.d.ts.map +1 -0
  34. package/build/actions/get-specification.js +9 -0
  35. package/build/actions/get-specification.js.map +1 -0
  36. package/build/actions/index.d.ts +12 -3
  37. package/build/actions/index.d.ts.map +1 -1
  38. package/build/actions/index.js +11 -3
  39. package/build/actions/index.js.map +1 -1
  40. package/build/actions/links.d.ts +3 -3
  41. package/build/actions/links.d.ts.map +1 -1
  42. package/build/actions/links.js +6 -5
  43. package/build/actions/links.js.map +1 -1
  44. package/build/actions/list-card-specifications.d.ts +6 -0
  45. package/build/actions/list-card-specifications.d.ts.map +1 -0
  46. package/build/actions/list-card-specifications.js +11 -0
  47. package/build/actions/list-card-specifications.js.map +1 -0
  48. package/build/actions/list-card-transitions.d.ts +6 -0
  49. package/build/actions/list-card-transitions.d.ts.map +1 -0
  50. package/build/actions/list-card-transitions.js +11 -0
  51. package/build/actions/list-card-transitions.js.map +1 -0
  52. package/build/actions/list-cards.d.ts +6 -0
  53. package/build/actions/list-cards.d.ts.map +1 -0
  54. package/build/actions/list-cards.js +10 -0
  55. package/build/actions/list-cards.js.map +1 -0
  56. package/build/actions/list-schemas.d.ts +13 -0
  57. package/build/actions/list-schemas.d.ts.map +1 -0
  58. package/build/actions/list-schemas.js +20 -0
  59. package/build/actions/list-schemas.js.map +1 -0
  60. package/build/actions/{specs.d.ts → list-specification-revisions.d.ts} +1 -3
  61. package/build/actions/list-specification-revisions.d.ts.map +1 -0
  62. package/build/actions/list-specification-revisions.js +10 -0
  63. package/build/actions/list-specification-revisions.js.map +1 -0
  64. package/build/actions/summarize-cards.d.ts +6 -0
  65. package/build/actions/summarize-cards.d.ts.map +1 -0
  66. package/build/actions/summarize-cards.js +11 -0
  67. package/build/actions/summarize-cards.js.map +1 -0
  68. package/build/actions/transitions.d.ts +3 -3
  69. package/build/actions/transitions.d.ts.map +1 -1
  70. package/build/actions/transitions.js +4 -3
  71. package/build/actions/transitions.js.map +1 -1
  72. package/build/actions/types.d.ts +5 -3
  73. package/build/actions/types.d.ts.map +1 -1
  74. package/build/actions/watch.d.ts +2 -2
  75. package/build/actions/watch.d.ts.map +1 -1
  76. package/build/actions/watch.js +2 -2
  77. package/build/actions/watch.js.map +1 -1
  78. package/build/conformance/assert/types.d.ts +19 -0
  79. package/build/conformance/assert/types.d.ts.map +1 -0
  80. package/build/conformance/assert/types.js +2 -0
  81. package/build/conformance/assert/types.js.map +1 -0
  82. package/build/conformance/assert.d.ts +8 -13
  83. package/build/conformance/assert.d.ts.map +1 -1
  84. package/build/conformance/assert.js +41 -43
  85. package/build/conformance/assert.js.map +1 -1
  86. package/build/conformance/cases.d.ts.map +1 -1
  87. package/build/conformance/cases.js +86 -67
  88. package/build/conformance/cases.js.map +1 -1
  89. package/build/conformance/clock.d.ts +6 -0
  90. package/build/conformance/clock.d.ts.map +1 -0
  91. package/build/conformance/clock.js +12 -0
  92. package/build/conformance/clock.js.map +1 -0
  93. package/build/conformance/consts.d.ts +3 -1
  94. package/build/conformance/consts.d.ts.map +1 -1
  95. package/build/conformance/consts.js +84 -1
  96. package/build/conformance/consts.js.map +1 -1
  97. package/build/conformance/errors.d.ts +5 -0
  98. package/build/conformance/errors.d.ts.map +1 -0
  99. package/build/conformance/errors.js +8 -0
  100. package/build/conformance/errors.js.map +1 -0
  101. package/build/conformance/fixtures/types.d.ts +13 -0
  102. package/build/conformance/fixtures/types.d.ts.map +1 -0
  103. package/build/conformance/fixtures/types.js +2 -0
  104. package/build/conformance/fixtures/types.js.map +1 -0
  105. package/build/conformance/fixtures.d.ts +8 -8
  106. package/build/conformance/fixtures.d.ts.map +1 -1
  107. package/build/conformance/fixtures.js +24 -107
  108. package/build/conformance/fixtures.js.map +1 -1
  109. package/build/conformance/index.d.ts +3 -0
  110. package/build/conformance/index.d.ts.map +1 -1
  111. package/build/conformance/index.js +1 -0
  112. package/build/conformance/index.js.map +1 -1
  113. package/build/definitions.d.ts.map +1 -1
  114. package/build/definitions.js +9 -9
  115. package/build/definitions.js.map +1 -1
  116. package/build/executor/changes/types.d.ts +36 -0
  117. package/build/executor/changes/types.d.ts.map +1 -0
  118. package/build/executor/changes/types.js +2 -0
  119. package/build/executor/changes/types.js.map +1 -0
  120. package/build/executor/changes.d.ts +3 -30
  121. package/build/executor/changes.d.ts.map +1 -1
  122. package/build/executor/changes.js +42 -51
  123. package/build/executor/changes.js.map +1 -1
  124. package/build/executor/code/types.d.ts +17 -0
  125. package/build/executor/code/types.d.ts.map +1 -0
  126. package/build/executor/code/types.js +2 -0
  127. package/build/executor/code/types.js.map +1 -0
  128. package/build/executor/code.d.ts +3 -14
  129. package/build/executor/code.d.ts.map +1 -1
  130. package/build/executor/code.js +50 -54
  131. package/build/executor/code.js.map +1 -1
  132. package/build/executor/creator/types.d.ts +33 -0
  133. package/build/executor/creator/types.d.ts.map +1 -0
  134. package/build/executor/creator/types.js +2 -0
  135. package/build/executor/creator/types.js.map +1 -0
  136. package/build/executor/creator.d.ts +6 -25
  137. package/build/executor/creator.d.ts.map +1 -1
  138. package/build/executor/creator.js +26 -41
  139. package/build/executor/creator.js.map +1 -1
  140. package/build/executor/resolve/types.d.ts +30 -0
  141. package/build/executor/resolve/types.d.ts.map +1 -0
  142. package/build/executor/resolve/types.js +2 -0
  143. package/build/executor/resolve/types.js.map +1 -0
  144. package/build/executor/resolve.d.ts +4 -41
  145. package/build/executor/resolve.d.ts.map +1 -1
  146. package/build/executor/resolve.js +142 -157
  147. package/build/executor/resolve.js.map +1 -1
  148. package/build/executor/types.d.ts +0 -2
  149. package/build/executor/types.d.ts.map +1 -1
  150. package/build/executor/validate.d.ts +1 -1
  151. package/build/executor/validate.d.ts.map +1 -1
  152. package/build/executor/validate.js +16 -15
  153. package/build/executor/validate.js.map +1 -1
  154. package/build/executor.d.ts +4 -3
  155. package/build/executor.d.ts.map +1 -1
  156. package/build/executor.js +18 -17
  157. package/build/executor.js.map +1 -1
  158. package/build/facade.d.ts.map +1 -1
  159. package/build/facade.js +16 -16
  160. package/build/facade.js.map +1 -1
  161. package/build/helper.d.ts +1 -6
  162. package/build/helper.d.ts.map +1 -1
  163. package/build/helper.js +3 -8
  164. package/build/helper.js.map +1 -1
  165. package/build/projection.d.ts +2 -0
  166. package/build/projection.d.ts.map +1 -1
  167. package/build/projection.js +6 -4
  168. package/build/projection.js.map +1 -1
  169. package/build/queue/declare.d.ts +5 -0
  170. package/build/queue/declare.d.ts.map +1 -0
  171. package/build/queue/declare.js +5 -0
  172. package/build/queue/declare.js.map +1 -0
  173. package/build/queue/index.d.ts +1 -4
  174. package/build/queue/index.d.ts.map +1 -1
  175. package/build/queue/index.js +1 -4
  176. package/build/queue/index.js.map +1 -1
  177. package/build/store/composite.d.ts.map +1 -1
  178. package/build/store/composite.js +2 -2
  179. package/build/store/composite.js.map +1 -1
  180. package/build/store/fold/types.d.ts +43 -0
  181. package/build/store/fold/types.d.ts.map +1 -0
  182. package/build/store/fold/types.js +2 -0
  183. package/build/store/fold/types.js.map +1 -0
  184. package/build/store/fold.d.ts +7 -30
  185. package/build/store/fold.d.ts.map +1 -1
  186. package/build/store/fold.js +185 -203
  187. package/build/store/fold.js.map +1 -1
  188. package/build/store/index.d.ts +1 -0
  189. package/build/store/index.d.ts.map +1 -1
  190. package/build/store/index.js.map +1 -1
  191. package/build/store/memory.d.ts.map +1 -1
  192. package/build/store/memory.js +0 -0
  193. package/build/store/memory.js.map +1 -1
  194. package/build/store/types.local.d.ts +3 -1
  195. package/build/store/types.local.d.ts.map +1 -1
  196. package/build/types.d.ts +2 -1
  197. package/build/types.d.ts.map +1 -1
  198. package/build/utils/access/types.d.ts +30 -0
  199. package/build/utils/access/types.d.ts.map +1 -0
  200. package/build/utils/access/types.js +2 -0
  201. package/build/utils/access/types.js.map +1 -0
  202. package/build/utils/access.d.ts +4 -0
  203. package/build/utils/access.d.ts.map +1 -0
  204. package/build/utils/access.js +28 -0
  205. package/build/utils/access.js.map +1 -0
  206. package/build/utils/guard/types.d.ts +21 -0
  207. package/build/utils/guard/types.d.ts.map +1 -0
  208. package/build/utils/guard/types.js +2 -0
  209. package/build/utils/guard/types.js.map +1 -0
  210. package/build/utils/guard.d.ts +7 -10
  211. package/build/utils/guard.d.ts.map +1 -1
  212. package/build/utils/guard.js +33 -31
  213. package/build/utils/guard.js.map +1 -1
  214. package/build/utils/handler/types.d.ts +26 -0
  215. package/build/utils/handler/types.d.ts.map +1 -0
  216. package/build/utils/handler/types.js +2 -0
  217. package/build/utils/handler/types.js.map +1 -0
  218. package/build/utils/handler.d.ts +6 -0
  219. package/build/utils/handler.d.ts.map +1 -0
  220. package/build/utils/handler.js +21 -0
  221. package/build/utils/handler.js.map +1 -0
  222. package/build/utils/index.d.ts +8 -1
  223. package/build/utils/index.d.ts.map +1 -1
  224. package/build/utils/index.js +3 -0
  225. package/build/utils/index.js.map +1 -1
  226. package/build/utils/request/types.d.ts +23 -0
  227. package/build/utils/request/types.d.ts.map +1 -0
  228. package/build/utils/request/types.js +2 -0
  229. package/build/utils/request/types.js.map +1 -0
  230. package/build/utils/request.d.ts +4 -0
  231. package/build/utils/request.d.ts.map +1 -0
  232. package/build/utils/request.js +27 -0
  233. package/build/utils/request.js.map +1 -0
  234. package/build/utils/scope.d.ts +10 -43
  235. package/build/utils/scope.d.ts.map +1 -1
  236. package/build/utils/scope.js +21 -99
  237. package/build/utils/scope.js.map +1 -1
  238. package/package.json +18 -18
  239. package/src/actions/apply-schema-request.ts +35 -0
  240. package/src/actions/commit.ts +7 -5
  241. package/src/actions/define-schemas.ts +34 -0
  242. package/src/actions/execute.ts +30 -115
  243. package/src/actions/execution/types.ts +34 -0
  244. package/src/actions/execution.ts +96 -0
  245. package/src/actions/get-card.ts +14 -0
  246. package/src/actions/get-specification.ts +14 -0
  247. package/src/actions/index.ts +13 -3
  248. package/src/actions/links.ts +8 -6
  249. package/src/actions/list-card-specifications.ts +15 -0
  250. package/src/actions/list-card-transitions.ts +15 -0
  251. package/src/actions/list-cards.ts +14 -0
  252. package/src/actions/list-schemas.ts +29 -0
  253. package/src/actions/{specs.ts → list-specification-revisions.ts} +4 -11
  254. package/src/actions/summarize-cards.ts +15 -0
  255. package/src/actions/transitions.ts +6 -4
  256. package/src/actions/types.ts +4 -3
  257. package/src/actions/watch.ts +4 -3
  258. package/src/conformance/assert/types.ts +16 -0
  259. package/src/conformance/assert.ts +49 -41
  260. package/src/conformance/cases.ts +88 -67
  261. package/src/conformance/clock.ts +11 -0
  262. package/src/conformance/consts.ts +87 -1
  263. package/src/conformance/errors.ts +7 -0
  264. package/src/conformance/fixtures/types.ts +11 -0
  265. package/src/conformance/fixtures.ts +32 -107
  266. package/src/conformance/index.ts +3 -0
  267. package/src/definitions.ts +9 -9
  268. package/src/executor/changes/types.ts +38 -0
  269. package/src/executor/changes.ts +48 -63
  270. package/src/executor/code/types.ts +23 -0
  271. package/src/executor/code.ts +60 -61
  272. package/src/executor/creator/types.ts +33 -0
  273. package/src/executor/creator.ts +33 -41
  274. package/src/executor/resolve/types.ts +30 -0
  275. package/src/executor/resolve.ts +153 -167
  276. package/src/executor/types.ts +0 -3
  277. package/src/executor/validate.ts +17 -16
  278. package/src/executor.ts +20 -17
  279. package/src/facade.ts +16 -16
  280. package/src/helper.ts +3 -8
  281. package/src/projection.ts +8 -4
  282. package/src/queue/declare.ts +7 -0
  283. package/src/queue/index.ts +1 -8
  284. package/src/store/composite.ts +2 -2
  285. package/src/store/fold/types.ts +44 -0
  286. package/src/store/fold.ts +209 -212
  287. package/src/store/index.ts +1 -0
  288. package/src/store/memory.ts +0 -0
  289. package/src/store/types.local.ts +1 -1
  290. package/src/types.ts +1 -1
  291. package/src/utils/access/types.ts +30 -0
  292. package/src/utils/access.ts +33 -0
  293. package/src/utils/guard/types.ts +19 -0
  294. package/src/utils/guard.ts +41 -30
  295. package/src/utils/handler/types.ts +28 -0
  296. package/src/utils/handler.ts +35 -0
  297. package/src/utils/index.ts +9 -1
  298. package/src/utils/request/types.ts +23 -0
  299. package/src/utils/request.ts +40 -0
  300. package/src/utils/scope.ts +25 -108
  301. package/tests/creator.spec.ts +18 -18
  302. package/build/actions/cards.d.ts +0 -14
  303. package/build/actions/cards.d.ts.map +0 -1
  304. package/build/actions/cards.js +0 -32
  305. package/build/actions/cards.js.map +0 -1
  306. package/build/actions/schemas.d.ts +0 -28
  307. package/build/actions/schemas.d.ts.map +0 -1
  308. package/build/actions/schemas.js +0 -69
  309. package/build/actions/schemas.js.map +0 -1
  310. package/build/actions/specs.d.ts.map +0 -1
  311. package/build/actions/specs.js +0 -14
  312. package/build/actions/specs.js.map +0 -1
  313. package/src/actions/cards.ts +0 -48
  314. package/src/actions/schemas.ts +0 -87
@@ -1,40 +1,51 @@
1
1
  import { 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 }
40
35
  }
36
+
37
+ export const guardHelper = createGuardHelper()
38
+
39
+ /** @deprecated compat:factory-refactor — use `guardHelper.notFoundOf(…)` */
40
+ export const notFoundOf = (id: string): WorkcardNotFound => guardHelper.notFoundOf(id)
41
+
42
+ /** @deprecated compat:factory-refactor — use `guardHelper.assertScope(…)` */
43
+ export const assertScope = <T extends Pick<Workcard, 'entityId'>>(
44
+ record: T | null | undefined, scope: { entityId: string }, id: string
45
+ ): T => guardHelper.assertScope<T>(record, scope, id)
46
+
47
+ /** @deprecated compat:factory-refactor — use `guardHelper.concealed(…)` */
48
+ export const concealed = async <T>(run: () => Promise<T>): Promise<T> => await guardHelper.concealed<T>(run)
49
+
50
+ /** @deprecated compat:factory-refactor — use `guardHelper.clampSeconds(…)` */
51
+ 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,3 +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'
3
- export type * from './types.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,131 +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, PlanningForbidden, type PlanningFacade, type PlanningScope, type PlanningService, type TransitionActor, type Workcard } from '@owlmeans/planning'
5
- import type {
6
- PlanningAccess, PlanningAccessGrants, PlanningHandlerOptions, PlanningHostService,
7
- } from '../types.js'
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
8
  import type { HandlerScope } from './types.js'
9
9
 
10
- const clean = <T extends object>(record: T): T =>
11
- Object.fromEntries(Object.entries(record).filter(([, value]) => value != null && value !== '')) as T
10
+ /** @deprecated compat:factory-refactor — use `makeRequestScope(req).actorOf()` */
11
+ export const actorOf = (req: AbstractRequest): TransitionActor => makeRequestScope(req).actorOf()
12
12
 
13
- /** The authenticated subject of a request, as a transition names it. */
14
- export const actorOf = (req: AbstractRequest): TransitionActor => clean({
15
- profileId: req.auth?.profileId,
16
- userId: req.auth?.userId,
17
- })
18
-
19
- const scopeWith = (req: AbstractRequest, entityId: string, extra?: Partial<PlanningScope>): PlanningScope => {
20
- const subject = actorOf(req)
21
- const channel = extra?.channel ?? extra?.actor?.channel
22
-
23
- return clean({
24
- ...extra,
25
- ...subject,
26
- entityId,
27
- channel,
28
- actor: clean({ ...extra?.actor, ...subject, channel }),
29
- }) as PlanningScope
30
- }
31
-
32
- /**
33
- * The scope a request reads and writes as.
34
- *
35
- * `entityId` is `requireEntityKey(req)` — the resolved organization id, never a value from the
36
- * body or the query — and `extra` cannot replace it; `extra` adds what the deployment derives
37
- * (a `channel`, a `service`). The actor is the authenticated subject plus that channel.
38
- *
39
- * @throws {AuthorizationError} when the request carries no organization
40
- */
13
+ /** @deprecated compat:factory-refactor — use `makeRequestScope(req).scopeOf(…)` */
41
14
  export const scopeOf = (req: AbstractRequest, extra?: Partial<PlanningScope>): PlanningScope =>
42
- scopeWith(req, requireEntityKey(req), extra)
15
+ makeRequestScope(req).scopeOf(extra)
43
16
 
44
- /**
45
- * The scope of a request under a resolved {@link PlanningAccess}: the organization is the
46
- * resolver's — never the token's, never `extra`'s — and `projects` narrows it.
47
- */
17
+ /** @deprecated compat:factory-refactor — use `makeRequestScope(req).accessScopeOf(…)` */
48
18
  export const accessScopeOf = (
49
19
  req: AbstractRequest, access: PlanningAccess, extra?: Partial<PlanningScope>
50
- ): PlanningScope => {
51
- const { projects: _projects, entityId: _entityId, ...rest } = extra ?? {}
52
- const scope = scopeWith(req, access.entityId, rest)
53
-
54
- return access.projects != null ? { ...scope, projects: [...access.projects] } : scope
55
- }
20
+ ): PlanningScope => makeRequestScope(req).accessScopeOf(access, extra)
56
21
 
22
+ /** @deprecated compat:factory-refactor — use `planningHandlerOf(ctx).planningServiceOf(…)` */
57
23
  export const planningServiceOf = (
58
24
  ctx: BasicContext<BasicConfig>, opts?: Pick<PlanningHandlerOptions, 'service'>
59
- ): PlanningService => ctx.service<PlanningHostService>(opts?.service ?? PLANNING_SERVICE)
25
+ ): PlanningService => planningHandlerOf(ctx).planningServiceOf(opts)
60
26
 
61
- /**
62
- * The facade a handler works through, and the access it was resolved under.
63
- *
64
- * Without `opts.access` it is exactly the request's scope plus what `opts.scope` derives. With it,
65
- * the resolver names the organization and the visible projects; a throw from the resolver is the
66
- * request's error.
67
- */
27
+ /** @deprecated compat:factory-refactor — use `planningHandlerOf(ctx).handlerScopeOf(…)` */
68
28
  export const handlerScopeOf = async (
69
29
  ctx: BasicContext<BasicConfig>, req: AbstractRequest, opts?: PlanningHandlerOptions
70
- ): Promise<HandlerScope> => {
71
- const extra = await opts?.scope?.(req, ctx)
72
- if (opts?.access == null) {
73
- return { facade: planningServiceOf(ctx, opts).for(scopeOf(req, extra ?? undefined)) }
74
- }
75
- const access = await opts.access(req, ctx)
76
-
77
- return { facade: planningServiceOf(ctx, opts).for(accessScopeOf(req, access, extra ?? undefined)), access }
78
- }
30
+ ): Promise<HandlerScope> => await planningHandlerOf(ctx).handlerScopeOf(req, opts)
79
31
 
80
- /** The facade a handler works through: the request's scope plus what `opts.scope` derives. */
32
+ /** @deprecated compat:factory-refactor — use `planningHandlerOf(ctx).handlerFacade(…)` */
81
33
  export const handlerFacade = async (
82
34
  ctx: BasicContext<BasicConfig>, req: AbstractRequest, opts?: PlanningHandlerOptions
83
- ): Promise<PlanningFacade> => (await handlerScopeOf(ctx, req, opts)).facade
35
+ ): Promise<PlanningFacade> => await planningHandlerOf(ctx).handlerFacade(req, opts)
84
36
 
85
- /**
86
- * Refuse a write the access does not grant. No access, or access without `grants`, gates nothing;
87
- * a `grants` object refuses every flag it leaves out. `true` grants everything; a list grants the
88
- * project ids it names — `target` is the project the write is about (`undefined` for the
89
- * organization's root, which only `true` reaches).
90
- *
91
- * @throws {PlanningForbidden}
92
- */
37
+ /** @deprecated compat:factory-refactor — use `makePlanningAccessModel(access).assertGranted(…)` */
93
38
  export const assertGranted = (
94
39
  access: PlanningAccess | undefined, grant: keyof PlanningAccessGrants, target?: string
95
- ): void => {
96
- if (access?.grants == null) {
97
- return
98
- }
99
- const granted = access.grants[grant]
100
- if (granted === true || (Array.isArray(granted) && target != null && granted.includes(target))) {
101
- return
102
- }
103
- throw new PlanningForbidden(`${grant}:${target ?? 'root'}`)
104
- }
40
+ ): void => makePlanningAccessModel(access).assertGranted(grant, target)
105
41
 
106
- /**
107
- * A card the access's `writes` admits — the rule a narrowed read admits, over `writes`: a project
108
- * it names, or a card whose `parents` name one. A specification is admitted through its parent card
109
- * by the caller. No `writes` admits everything.
110
- */
111
- export const writableIn = (access: PlanningAccess | undefined, card: Pick<Workcard, 'id' | 'parents'>): boolean => {
112
- const writes = access?.writes
113
- if (writes == null) {
114
- return true
115
- }
116
- return (card.id != null && writes.includes(card.id)) || card.parents.some(parent => writes.includes(parent))
117
- }
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)
118
45
 
119
- /**
120
- * Refuse a write into a project the access's `writes` leaves out. No `writes` refuses nothing;
121
- * `target` is the project the write is in (`undefined` for the organization's root, which a set
122
- * `writes` never admits).
123
- *
124
- * @throws {PlanningForbidden}
125
- */
126
- export const assertWrites = (access: PlanningAccess | undefined, target?: string): void => {
127
- if (access?.writes == null || (target != null && access.writes.includes(target))) {
128
- return
129
- }
130
- throw new PlanningForbidden(`writes:${target ?? 'root'}`)
131
- }
46
+ /** @deprecated compat:factory-refactor — use `makePlanningAccessModel(access).assertWrites(…)` */
47
+ export const assertWrites = (access: PlanningAccess | undefined, target?: string): void =>
48
+ makePlanningAccessModel(access).assertWrites(target)
@@ -1,9 +1,9 @@
1
1
  import { describe, expect, test } from 'bun:test'
2
2
  import { CommitState, makePlanningProtocols, PlanningError, TransitionAction, WorkcardKind } from '@owlmeans/planning'
3
3
  import type { PlanningFacade, Transition, TransitionExecution, WorkcardChanges, WorkcardDraft } from '@owlmeans/planning'
4
- import { executePlanning, wireExecution } from '../src/actions/index.js'
5
- import { assertCreatorFixed, creatorOf, withCreator } from '../src/executor.js'
4
+ import { executePlanning, executionHelper } from '../src/actions/index.js'
6
5
  import { createProject, createTask, ENTITY, invoke, makeTestPlanning, PROFILE, PROJECT, session, TASK } from './context.js'
6
+ import { creatorHelper } from '../src/executor.js'
7
7
 
8
8
  const tree = makePlanningProtocols({ base: { alias: 'test:planning' }, guards: 'test-guard' })
9
9
 
@@ -101,21 +101,21 @@ describe('@owlmeans/server-planning — a create\'s createdBy', () => {
101
101
  test('wireExecution still answers the execution the executor will run', () => {
102
102
  const body = { card: { kind: WorkcardKind.Project, type: PROJECT, title: 'W', createdBy: 'intruder' }, action: TransitionAction.Create }
103
103
 
104
- expect(draftOf(wireExecution(body, { entityId: ENTITY, profileId: PROFILE, userId: 'user-1' })).createdBy).toBe(PROFILE)
105
- expect(draftOf(wireExecution(body, { entityId: ENTITY, userId: 'user-1' })).createdBy).toBe('user-1')
106
- expect(draftOf(wireExecution(body, { entityId: ENTITY })).createdBy).toBeUndefined()
104
+ expect(draftOf(executionHelper.wireExecution(body, { entityId: ENTITY, profileId: PROFILE, userId: 'user-1' })).createdBy).toBe(PROFILE)
105
+ expect(draftOf(executionHelper.wireExecution(body, { entityId: ENTITY, userId: 'user-1' })).createdBy).toBe('user-1')
106
+ expect(draftOf(executionHelper.wireExecution(body, { entityId: ENTITY })).createdBy).toBeUndefined()
107
107
  })
108
108
 
109
109
  test('creatorOf and withCreator', () => {
110
- expect(creatorOf({ entityId: ENTITY, profileId: 'p', userId: 'u', actor: { profileId: 'a' } })).toBe('p')
111
- expect(creatorOf({ entityId: ENTITY, profileId: '', userId: 'u' })).toBe('u')
112
- expect(creatorOf({ entityId: ENTITY, actor: { userId: 'au', service: 's' } })).toBe('au')
113
- expect(creatorOf({ entityId: ENTITY, service: 's' })).toBeUndefined()
110
+ expect(creatorHelper.creatorOf({ entityId: ENTITY, profileId: 'p', userId: 'u', actor: { profileId: 'a' } })).toBe('p')
111
+ expect(creatorHelper.creatorOf({ entityId: ENTITY, profileId: '', userId: 'u' })).toBe('u')
112
+ expect(creatorHelper.creatorOf({ entityId: ENTITY, actor: { userId: 'au', service: 's' } })).toBe('au')
113
+ expect(creatorHelper.creatorOf({ entityId: ENTITY, service: 's' })).toBeUndefined()
114
114
 
115
115
  const update: TransitionExecution = { card: 'card-1', action: TransitionAction.Update, changes: { title: 'T' } }
116
- expect(withCreator(update, { entityId: ENTITY, profileId: 'p' })).toBe(update)
116
+ expect(creatorHelper.withCreator(update, { entityId: ENTITY, profileId: 'p' })).toBe(update)
117
117
  const blank: TransitionExecution = { card: { kind: WorkcardKind.Project, type: PROJECT, title: 'T', createdBy: '' }, action: TransitionAction.Create }
118
- expect(draftOf(withCreator(blank, { entityId: ENTITY, profileId: 'p' })).createdBy).toBe('p')
118
+ expect(draftOf(creatorHelper.withCreator(blank, { entityId: ENTITY, profileId: 'p' })).createdBy).toBe('p')
119
119
  })
120
120
  })
121
121
 
@@ -246,12 +246,12 @@ describe('@owlmeans/server-planning — createdBy never moves after the create',
246
246
  test('assertCreatorFixed', () => {
247
247
  const draft = { kind: WorkcardKind.Project, type: PROJECT, title: 'T', createdBy: 'owner' }
248
248
 
249
- expect(() => assertCreatorFixed({ card: draft, action: TransitionAction.Create })).not.toThrow()
250
- expect(() => assertCreatorFixed({ card: 'c', action: TransitionAction.Update, changes: { title: 'T', createdBy: undefined } })).not.toThrow()
251
- expect(() => assertCreatorFixed({ card: 'c', action: TransitionAction.Update, unset: ['fields.createdBy'] })).not.toThrow()
252
- expect(() => assertCreatorFixed({ card: 'c', action: TransitionAction.Update, changes: { fields: { createdBy: 'x' } } })).not.toThrow()
253
- expect(() => assertCreatorFixed({ card: 'c', action: TransitionAction.Update, changes: { createdBy: 'x' } })).toThrow('planning:immutable:createdBy')
254
- expect(() => assertCreatorFixed({ card: 'c', action: TransitionAction.Delete, unset: ['createdBy'] })).toThrow('planning:immutable:createdBy')
255
- expect(() => assertCreatorFixed({ card: draft, action: TransitionAction.Create, changes: { createdBy: 'x' } })).toThrow('planning:immutable:createdBy')
249
+ expect(() => creatorHelper.assertCreatorFixed({ card: draft, action: TransitionAction.Create })).not.toThrow()
250
+ expect(() => creatorHelper.assertCreatorFixed({ card: 'c', action: TransitionAction.Update, changes: { title: 'T', createdBy: undefined } })).not.toThrow()
251
+ expect(() => creatorHelper.assertCreatorFixed({ card: 'c', action: TransitionAction.Update, unset: ['fields.createdBy'] })).not.toThrow()
252
+ expect(() => creatorHelper.assertCreatorFixed({ card: 'c', action: TransitionAction.Update, changes: { fields: { createdBy: 'x' } } })).not.toThrow()
253
+ expect(() => creatorHelper.assertCreatorFixed({ card: 'c', action: TransitionAction.Update, changes: { createdBy: 'x' } })).toThrow('planning:immutable:createdBy')
254
+ expect(() => creatorHelper.assertCreatorFixed({ card: 'c', action: TransitionAction.Delete, unset: ['createdBy'] })).toThrow('planning:immutable:createdBy')
255
+ expect(() => creatorHelper.assertCreatorFixed({ card: draft, action: TransitionAction.Create, changes: { createdBy: 'x' } })).toThrow('planning:immutable:createdBy')
256
256
  })
257
257
  })
@@ -1,14 +0,0 @@
1
- import { type PlanningProtocols } from '@owlmeans/planning';
2
- import type { PlanningHandlerOptions } from '../types.js';
3
- import type { RequestHandler } from './types.js';
4
- /** Cards of the caller's entity; the query arrives in its wire shape and is decoded here. */
5
- export declare const listCards: (protocol: PlanningProtocols['card']['list'], opts?: PlanningHandlerOptions) => RequestHandler;
6
- /** Intrinsic counts of DIRECT children per parent. */
7
- export declare const summarizeCards: (protocol: PlanningProtocols['card']['summary'], opts?: PlanningHandlerOptions) => RequestHandler;
8
- /** @throws {WorkcardNotFound} for an absent card and for another entity's alike */
9
- export declare const getCard: (protocol: PlanningProtocols['card']['get'], opts?: PlanningHandlerOptions) => RequestHandler;
10
- /** One card's log. */
11
- export declare const listCardTransitions: (protocol: PlanningProtocols['card']['transitions'], opts?: PlanningHandlerOptions) => RequestHandler;
12
- /** One card's specifications — the current document per category unless `all`. */
13
- export declare const listCardSpecifications: (protocol: PlanningProtocols['card']['specifications'], opts?: PlanningHandlerOptions) => RequestHandler;
14
- //# sourceMappingURL=cards.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cards.d.ts","sourceRoot":"","sources":["../../src/actions/cards.ts"],"names":[],"mappings":"AACA,OAAO,EAA4F,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACrJ,OAAO,KAAK,EAAW,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAElE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,6FAA6F;AAC7F,eAAO,MAAM,SAAS,aAAc,iBAAiB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,SAAS,sBAAsB,KAAG,cAKlG,CAAA;AAEL,sDAAsD;AACtD,eAAO,MAAM,cAAc,aAAc,iBAAiB,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,sBAAsB,KAAG,cAM1G,CAAA;AAEL,mFAAmF;AACnF,eAAO,MAAM,OAAO,aAAc,iBAAiB,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,SAAS,sBAAsB,KAAG,cAK/F,CAAA;AAEL,sBAAsB;AACtB,eAAO,MAAM,mBAAmB,aAAc,iBAAiB,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,SAAS,sBAAsB,KAAG,cAMnH,CAAA;AAEL,kFAAkF;AAClF,eAAO,MAAM,sBAAsB,aAAc,iBAAiB,CAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,SAAS,sBAAsB,KAAG,cAMzH,CAAA"}
@@ -1,32 +0,0 @@
1
- import { handlers } from '@owlmeans/server-api';
2
- import { decodeSpecificationQuery, decodeSummaryQuery, decodeTransitionQuery, decodeWorkcardQuery } from '@owlmeans/planning';
3
- import { concealed, handlerFacade } from '../utils/index.js';
4
- /** Cards of the caller's entity; the query arrives in its wire shape and is decoded here. */
5
- export const listCards = (protocol, opts) => handlers().request(protocol, async (req, ctx) => concealed(async () => {
6
- const facade = await handlerFacade(ctx, req, opts);
7
- return await facade.cards.list(decodeWorkcardQuery(req.query));
8
- }));
9
- /** Intrinsic counts of DIRECT children per parent. */
10
- export const summarizeCards = (protocol, opts) => handlers().request(protocol, async (req, ctx) => concealed(async () => {
11
- const facade = await handlerFacade(ctx, req, opts);
12
- const { parents, ...query } = decodeSummaryQuery(req.query);
13
- return await facade.cards.summary(parents, query);
14
- }));
15
- /** @throws {WorkcardNotFound} for an absent card and for another entity's alike */
16
- export const getCard = (protocol, opts) => handlers().request(protocol, async (req, ctx) => concealed(async () => {
17
- const facade = await handlerFacade(ctx, req, opts);
18
- return await facade.cards.get(`${req.params.id}`);
19
- }));
20
- /** One card's log. */
21
- export const listCardTransitions = (protocol, opts) => handlers().request(protocol, async (req, ctx) => concealed(async () => {
22
- const facade = await handlerFacade(ctx, req, opts);
23
- const card = await facade.cards.get(`${req.params.id}`);
24
- return await facade.transitions.list({ ...decodeTransitionQuery(req.query), card: card.id });
25
- }));
26
- /** One card's specifications — the current document per category unless `all`. */
27
- export const listCardSpecifications = (protocol, opts) => handlers().request(protocol, async (req, ctx) => concealed(async () => {
28
- const facade = await handlerFacade(ctx, req, opts);
29
- const card = await facade.cards.get(`${req.params.id}`);
30
- return await facade.specifications.list(card.id, decodeSpecificationQuery(req.query));
31
- }));
32
- //# sourceMappingURL=cards.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cards.js","sourceRoot":"","sources":["../../src/actions/cards.ts"],"names":[],"mappings":"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"}
@@ -1,28 +0,0 @@
1
- import { type PlanningDefinitions, type PlanningProtocols, type SchemaDefineReply, type SchemaDefineRequest } from '@owlmeans/planning';
2
- import type { PlanningHandlerOptions } from '../types.js';
3
- import type { RequestHandler } from './types.js';
4
- /**
5
- * The schema bundle — what a client loads to answer `can()` with no round trip. Scoped like every
6
- * other leaf (no organization, no bundle). Where the store holds data-defined schemas it is the
7
- * resolved layer of the organization, or of the project the `project` query names (a project this
8
- * scope can see); otherwise the service's code bundle.
9
- *
10
- * @throws {WorkcardNotFound} for a project this scope cannot see
11
- */
12
- export declare const listSchemas: (protocol: PlanningProtocols['schema']['list'], opts?: PlanningHandlerOptions) => RequestHandler;
13
- /**
14
- * Apply one `schema.define` request to a facade's definitions: the declarations in the request's
15
- * mode (flows before types), then the retirements — answering what was written and the layer as it
16
- * resolves afterwards.
17
- */
18
- export declare const applySchemaRequest: (definitions: PlanningDefinitions, request: SchemaDefineRequest) => Promise<SchemaDefineReply>;
19
- /**
20
- * The write of data-defined types and flows. A project layer needs the project in the access's
21
- * `writes` when the resolver answers it; then `grants.defineSchemas` gates when the resolver answers
22
- * grants (the organization-wide layer needs `true`, a project layer its id).
23
- *
24
- * @throws {PlanningUnsupported} where the store holds no data-defined schemas
25
- * @throws {PlanningForbidden | SchemaConflict | SchemaSealed | SchemaInvalid | SchemaInUse | WorkcardNotFound}
26
- */
27
- export declare const defineSchemas: (protocol: NonNullable<PlanningProtocols['schema']['define']>, opts?: PlanningHandlerOptions) => RequestHandler;
28
- //# sourceMappingURL=schemas.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/actions/schemas.ts"],"names":[],"mappings":"AACA,OAAO,EAAwC,KAAK,mBAAmB,EAAE,KAAK,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,KAAK,mBAAmB,EAAoD,MAAM,oBAAoB,CAAA;AAC/N,OAAO,KAAK,EAAW,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAElE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAKhD;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,aACZ,iBAAiB,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,sBAAsB,KAC3E,cAQE,CAAA;AAEL;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,gBAChB,mBAAmB,WAAW,mBAAmB,KAC7D,OAAO,CAAC,iBAAiB,CAyB3B,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,aACd,WAAW,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,sBAAsB,KAC1F,cAaE,CAAA"}
@@ -1,69 +0,0 @@
1
- import { handlers } from '@owlmeans/server-api';
2
- import { PlanningUnsupported, SchemaWriteMode } from '@owlmeans/planning';
3
- import { assertGranted, assertWrites, concealed, handlerScopeOf } from '../utils/index.js';
4
- const text = (value) => value == null || value === '' ? undefined : `${Array.isArray(value) ? value[0] : value}`;
5
- /**
6
- * The schema bundle — what a client loads to answer `can()` with no round trip. Scoped like every
7
- * other leaf (no organization, no bundle). Where the store holds data-defined schemas it is the
8
- * resolved layer of the organization, or of the project the `project` query names (a project this
9
- * scope can see); otherwise the service's code bundle.
10
- *
11
- * @throws {WorkcardNotFound} for a project this scope cannot see
12
- */
13
- export const listSchemas = (protocol, opts) => handlers().request(protocol, async (req, ctx) => concealed(async () => {
14
- const { facade } = await handlerScopeOf(ctx, req, opts);
15
- if (facade.definitions == null) {
16
- return facade.schemas.bundle();
17
- }
18
- return await facade.definitions.bundle(text(req.query?.project));
19
- }));
20
- /**
21
- * Apply one `schema.define` request to a facade's definitions: the declarations in the request's
22
- * mode (flows before types), then the retirements — answering what was written and the layer as it
23
- * resolves afterwards.
24
- */
25
- export const applySchemaRequest = async (definitions, request) => {
26
- const layer = request.project != null ? { project: request.project } : {};
27
- const declarations = { types: request.types ?? [], flows: request.flows ?? [] };
28
- const records = [];
29
- switch (request.mode ?? SchemaWriteMode.Define) {
30
- case SchemaWriteMode.Put:
31
- for (const flow of declarations.flows) {
32
- records.push(await definitions.putFlow(flow, layer));
33
- }
34
- for (const type of declarations.types) {
35
- records.push(await definitions.putType(type, layer));
36
- }
37
- break;
38
- case SchemaWriteMode.Seed:
39
- records.push(...await definitions.seed(declarations, layer));
40
- break;
41
- default:
42
- records.push(...await definitions.define(declarations, layer));
43
- }
44
- for (const key of request.retire ?? []) {
45
- records.push(await definitions.retire(key.kind, key.key, layer));
46
- }
47
- return { records, bundle: await definitions.bundle(request.project) };
48
- };
49
- /**
50
- * The write of data-defined types and flows. A project layer needs the project in the access's
51
- * `writes` when the resolver answers it; then `grants.defineSchemas` gates when the resolver answers
52
- * grants (the organization-wide layer needs `true`, a project layer its id).
53
- *
54
- * @throws {PlanningUnsupported} where the store holds no data-defined schemas
55
- * @throws {PlanningForbidden | SchemaConflict | SchemaSealed | SchemaInvalid | SchemaInUse | WorkcardNotFound}
56
- */
57
- export const defineSchemas = (protocol, opts) => handlers().request(protocol, async (req, ctx) => concealed(async () => {
58
- const { facade, access } = await handlerScopeOf(ctx, req, opts);
59
- const request = (req.body ?? {});
60
- if (facade.definitions == null) {
61
- throw new PlanningUnsupported('definitions');
62
- }
63
- if (request.project != null) {
64
- assertWrites(access, request.project);
65
- }
66
- assertGranted(access, 'defineSchemas', request.project);
67
- return await applySchemaRequest(facade.definitions, request);
68
- }));
69
- //# sourceMappingURL=schemas.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/actions/schemas.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"specs.d.ts","sourceRoot":"","sources":["../../src/actions/specs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC3D,OAAO,KAAK,EAAW,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAElE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,iCAAiC;AACjC,eAAO,MAAM,gBAAgB,aAAc,iBAAiB,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,SAAS,sBAAsB,KAAG,cAKxG,CAAA;AAEL,iEAAiE;AACjE,eAAO,MAAM,0BAA0B,aAAc,iBAAiB,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,SAAS,sBAAsB,KAAG,cAMxH,CAAA"}