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

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 (173) hide show
  1. package/README.md +2 -2
  2. package/agent-meta/manifest.json +2 -2
  3. package/agent-meta/skills/server-planning/SKILL.md +1 -1
  4. package/build/actions/cards.d.ts +3 -5
  5. package/build/actions/cards.d.ts.map +1 -1
  6. package/build/actions/cards.js +1 -1
  7. package/build/actions/cards.js.map +1 -1
  8. package/build/actions/schemas.d.ts +3 -5
  9. package/build/actions/schemas.d.ts.map +1 -1
  10. package/build/actions/schemas.js.map +1 -1
  11. package/build/actions/specs.d.ts +2 -4
  12. package/build/actions/specs.d.ts.map +1 -1
  13. package/build/actions/specs.js.map +1 -1
  14. package/build/actions/types.d.ts +4 -0
  15. package/build/actions/types.d.ts.map +1 -0
  16. package/build/actions/types.js +2 -0
  17. package/build/actions/types.js.map +1 -0
  18. package/build/actions/watch.d.ts.map +1 -1
  19. package/build/actions/watch.js +4 -2
  20. package/build/actions/watch.js.map +1 -1
  21. package/build/conformance/cases.d.ts +2 -17
  22. package/build/conformance/cases.d.ts.map +1 -1
  23. package/build/conformance/cases.js +3 -2
  24. package/build/conformance/cases.js.map +1 -1
  25. package/build/conformance/consts.d.ts +19 -0
  26. package/build/conformance/consts.d.ts.map +1 -0
  27. package/build/conformance/consts.js +42 -0
  28. package/build/conformance/consts.js.map +1 -0
  29. package/build/conformance/fixtures.d.ts +1 -18
  30. package/build/conformance/fixtures.d.ts.map +1 -1
  31. package/build/conformance/fixtures.js +3 -41
  32. package/build/conformance/fixtures.js.map +1 -1
  33. package/build/conformance/index.d.ts +2 -0
  34. package/build/conformance/index.d.ts.map +1 -1
  35. package/build/conformance/index.js +1 -0
  36. package/build/conformance/index.js.map +1 -1
  37. package/build/conformance/types.d.ts +18 -0
  38. package/build/conformance/types.d.ts.map +1 -0
  39. package/build/conformance/types.js +2 -0
  40. package/build/conformance/types.js.map +1 -0
  41. package/build/definitions.d.ts +2 -18
  42. package/build/definitions.d.ts.map +1 -1
  43. package/build/definitions.js +1 -1
  44. package/build/definitions.js.map +1 -1
  45. package/build/executor/changes.d.ts +2 -2
  46. package/build/executor/changes.d.ts.map +1 -1
  47. package/build/executor/changes.js.map +1 -1
  48. package/build/executor/code.d.ts +3 -3
  49. package/build/executor/code.d.ts.map +1 -1
  50. package/build/executor/code.js +1 -1
  51. package/build/executor/code.js.map +1 -1
  52. package/build/executor/consts.local.d.ts +5 -0
  53. package/build/executor/consts.local.d.ts.map +1 -0
  54. package/build/executor/consts.local.js +6 -0
  55. package/build/executor/consts.local.js.map +1 -0
  56. package/build/executor/creator.d.ts +1 -1
  57. package/build/executor/creator.d.ts.map +1 -1
  58. package/build/executor/creator.js +1 -2
  59. package/build/executor/creator.js.map +1 -1
  60. package/build/executor/resolve.d.ts +23 -28
  61. package/build/executor/resolve.d.ts.map +1 -1
  62. package/build/executor/resolve.js +9 -7
  63. package/build/executor/resolve.js.map +1 -1
  64. package/build/executor/types.d.ts +24 -0
  65. package/build/executor/types.d.ts.map +1 -0
  66. package/build/executor/types.js +2 -0
  67. package/build/executor/types.js.map +1 -0
  68. package/build/executor/validate.d.ts +3 -3
  69. package/build/executor/validate.d.ts.map +1 -1
  70. package/build/executor/validate.js +4 -4
  71. package/build/executor/validate.js.map +1 -1
  72. package/build/executor.d.ts +2 -2
  73. package/build/executor.d.ts.map +1 -1
  74. package/build/executor.js +6 -6
  75. package/build/executor.js.map +1 -1
  76. package/build/facade.d.ts +2 -2
  77. package/build/facade.d.ts.map +1 -1
  78. package/build/facade.js +1 -1
  79. package/build/facade.js.map +1 -1
  80. package/build/projection.d.ts +2 -10
  81. package/build/projection.d.ts.map +1 -1
  82. package/build/projection.js +1 -1
  83. package/build/projection.js.map +1 -1
  84. package/build/queue/consts.d.ts +5 -0
  85. package/build/queue/consts.d.ts.map +1 -0
  86. package/build/queue/consts.js +5 -0
  87. package/build/queue/consts.js.map +1 -0
  88. package/build/queue/index.d.ts +4 -16
  89. package/build/queue/index.d.ts.map +1 -1
  90. package/build/queue/index.js +2 -4
  91. package/build/queue/index.js.map +1 -1
  92. package/build/queue/types.d.ts +13 -0
  93. package/build/queue/types.d.ts.map +1 -0
  94. package/build/queue/types.js +2 -0
  95. package/build/queue/types.js.map +1 -0
  96. package/build/registry.d.ts +2 -21
  97. package/build/registry.d.ts.map +1 -1
  98. package/build/registry.js +3 -1
  99. package/build/registry.js.map +1 -1
  100. package/build/service.d.ts +3 -25
  101. package/build/service.d.ts.map +1 -1
  102. package/build/service.js.map +1 -1
  103. package/build/store/commits.d.ts.map +1 -1
  104. package/build/store/commits.js +3 -1
  105. package/build/store/commits.js.map +1 -1
  106. package/build/store/consts.local.d.ts +2 -0
  107. package/build/store/consts.local.d.ts.map +1 -0
  108. package/build/store/consts.local.js +2 -0
  109. package/build/store/consts.local.js.map +1 -0
  110. package/build/store/fold.d.ts +1 -2
  111. package/build/store/fold.d.ts.map +1 -1
  112. package/build/store/fold.js +6 -4
  113. package/build/store/fold.js.map +1 -1
  114. package/build/store/memory.d.ts.map +1 -1
  115. package/build/store/memory.js +0 -0
  116. package/build/store/memory.js.map +1 -1
  117. package/build/store/types.local.d.ts +3 -0
  118. package/build/store/types.local.d.ts.map +1 -0
  119. package/build/store/types.local.js +2 -0
  120. package/build/store/types.local.js.map +1 -0
  121. package/build/types.d.ts +65 -1
  122. package/build/types.d.ts.map +1 -1
  123. package/build/types.local.d.ts +7 -0
  124. package/build/types.local.d.ts.map +1 -0
  125. package/build/types.local.js +2 -0
  126. package/build/types.local.js.map +1 -0
  127. package/build/utils/index.d.ts +1 -0
  128. package/build/utils/index.d.ts.map +1 -1
  129. package/build/utils/scope.d.ts +2 -6
  130. package/build/utils/scope.d.ts.map +1 -1
  131. package/build/utils/scope.js.map +1 -1
  132. package/build/utils/types.d.ts +8 -0
  133. package/build/utils/types.d.ts.map +1 -0
  134. package/build/utils/types.js +2 -0
  135. package/build/utils/types.js.map +1 -0
  136. package/package.json +21 -20
  137. package/src/actions/cards.ts +2 -6
  138. package/src/actions/schemas.ts +2 -6
  139. package/src/actions/specs.ts +1 -2
  140. package/src/actions/types.ts +4 -0
  141. package/src/actions/watch.ts +5 -2
  142. package/src/conformance/cases.ts +4 -29
  143. package/src/conformance/consts.ts +44 -0
  144. package/src/conformance/fixtures.ts +3 -50
  145. package/src/conformance/index.ts +2 -0
  146. package/src/conformance/types.ts +20 -0
  147. package/src/definitions.ts +3 -35
  148. package/src/executor/changes.ts +2 -6
  149. package/src/executor/code.ts +3 -9
  150. package/src/executor/consts.local.ts +8 -0
  151. package/src/executor/creator.ts +2 -5
  152. package/src/executor/resolve.ts +13 -39
  153. package/src/executor/types.ts +25 -0
  154. package/src/executor/validate.ts +7 -16
  155. package/src/executor.ts +9 -13
  156. package/src/facade.ts +2 -9
  157. package/src/projection.ts +4 -14
  158. package/src/queue/consts.ts +5 -0
  159. package/src/queue/index.ts +6 -21
  160. package/src/queue/types.ts +14 -0
  161. package/src/registry.ts +5 -29
  162. package/src/service.ts +3 -32
  163. package/src/store/commits.ts +5 -4
  164. package/src/store/consts.local.ts +1 -0
  165. package/src/store/fold.ts +7 -10
  166. package/src/store/memory.ts +0 -0
  167. package/src/store/types.local.ts +3 -0
  168. package/src/types.local.ts +7 -0
  169. package/src/types.ts +76 -4
  170. package/src/utils/index.ts +1 -0
  171. package/src/utils/scope.ts +2 -8
  172. package/src/utils/types.ts +8 -0
  173. package/tests/plugins.spec.ts +4 -3
@@ -1,3 +1,4 @@
1
+ import { logger } from '@owlmeans/log'
1
2
  import { PLANNING_COMMIT_EVENT } from '@owlmeans/planning'
2
3
  import type { CommitEvent, CommitFeedQuery, PlanningProtocols } from '@owlmeans/planning'
3
4
  import { connection } from '@owlmeans/server-socket'
@@ -6,6 +7,8 @@ import { MessageType } from '@owlmeans/socket'
6
7
  import type { Context, PlanningHandlerOptions } from '../types.js'
7
8
  import { handlerFacade } from '../utils/index.js'
8
9
 
10
+ const log = logger('planning:watch')
11
+
9
12
  const text = (value: unknown): string | undefined =>
10
13
  value == null || value === '' ? undefined : `${value}`
11
14
 
@@ -32,7 +35,7 @@ export const watchCommits = (
32
35
  const enriched = event.record !== undefined ? event : { ...event, record: await facade.cards.load(event.card) }
33
36
  await conn.notify(frame, enriched)
34
37
  } catch (e) {
35
- console.error('Planning commit notify error:', e)
38
+ log.warn('Planning commit notify failed', e)
36
39
  }
37
40
  }, filter)
38
41
 
@@ -45,7 +48,7 @@ export const watchCommits = (
45
48
  try {
46
49
  unsubscribe()
47
50
  } catch (e) {
48
- console.error('Planning commit unsubscribe error:', e)
51
+ log.warn('Planning commit unsubscribe failed', e)
49
52
  }
50
53
  }
51
54
  })
@@ -1,35 +1,10 @@
1
1
  import { uuid } from '@owlmeans/basic-ids'
2
- import {
3
- applyTransition, CardTypeNotAllowed, CommitState, IntrinsicStatus, PlanningError, PlanningSchemaKind,
4
- RelationshipRefused, SchemaConflict, SchemaInUse, SchemaInvalid, SchemaOrigin, SchemaSealed, SpecificationFormat,
5
- TransitionAction, UnknownWorkcardType, WorkcardConflict, WorkcardKind, WorkcardNotFound,
6
- } from '@owlmeans/planning'
7
- import type {
8
- CommitEvent, PlanningFacade, PlanningService, PlanningStore, StatusFlowSchema, Transition, TransitionExecution,
9
- Unsubscribe, Workcard, WorkcardQuery, WorkcardTypeSchema,
10
- } from '@owlmeans/planning'
2
+ import { applyTransition, CardTypeNotAllowed, CommitState, IntrinsicStatus, PlanningError, PlanningSchemaKind, RelationshipRefused, SchemaConflict, SchemaInUse, SchemaInvalid, SchemaOrigin, SchemaSealed, SpecificationFormat, TransitionAction, UnknownWorkcardType, WorkcardConflict, WorkcardKind, WorkcardNotFound, type CommitEvent, type PlanningFacade, type PlanningStore, type StatusFlowSchema, type Transition, type TransitionExecution, type Unsubscribe, type Workcard, type WorkcardQuery, type WorkcardTypeSchema } from '@owlmeans/planning'
11
3
  import { creatorOf } from '../executor/creator.js'
12
4
  import { check, rejects, same, sameSet } from './assert.js'
13
- import { BOOK_TYPE, LIBRARY, PERIODICAL_TYPE, createBook, createBranch, transit } from './fixtures.js'
14
-
15
- /** What a case runs against: a planning service over the store under test. */
16
- export interface ConformanceSubject {
17
- /** A service with `planningConformancePlugin` registered and a strictly increasing clock. */
18
- service: PlanningService
19
- /** The store under test — the service's default store. */
20
- store: PlanningStore
21
- /** A facade of one organization, acting as a signed-in person. */
22
- facade: (entityId: string) => PlanningFacade
23
- }
24
-
25
- /** A capability a store may implement; a case that needs one is skipped for a store without it. */
26
- export type ConformanceCapability = 'schemas'
27
-
28
- export interface ConformanceCase {
29
- name: string
30
- needs?: ConformanceCapability[]
31
- run: (subject: ConformanceSubject) => Promise<void>
32
- }
5
+ import { createBook, createBranch, transit } from './fixtures.js'
6
+ import { BOOK_TYPE, LIBRARY, PERIODICAL_TYPE } from './consts.js'
7
+ import type { ConformanceCase } from './types.js'
33
8
 
34
9
  /** A fresh organization per case, so cases never see each other's cards on a shared database. */
35
10
  const organization = (): string => `conformance-${uuid()}`
@@ -0,0 +1,44 @@
1
+ import { type WorkcardTypeSchema, CodeScope, CodeStyle, SpecificationFormat, WorkcardKind } from '@owlmeans/planning'
2
+
3
+ /**
4
+ * The conformance vocabulary: a lending library. Branches (projects) hold books and periodicals
5
+ * (cards); a book runs a circulation flow and a review flow; documents are pages.
6
+ */
7
+ export const LIBRARY = Object.freeze({
8
+ branch: 'library:branch',
9
+ room: 'library:reading-room',
10
+ book: 'library:book',
11
+ periodical: 'library:periodical',
12
+ page: 'library:page',
13
+ circulation: 'library:circulation',
14
+ review: 'library:review',
15
+ branchLife: 'library:branch-life',
16
+ pageLife: 'library:page-life',
17
+ })
18
+
19
+ export const BOOK_TYPE: WorkcardTypeSchema = {
20
+ type: LIBRARY.book,
21
+ kind: WorkcardKind.Card,
22
+ version: 1,
23
+ fields: {
24
+ type: 'object',
25
+ properties: { genre: { type: 'string', enum: ['poetry', 'history', 'fiction'] }, signed: { type: 'boolean' } },
26
+ additionalProperties: false,
27
+ },
28
+ flows: [LIBRARY.circulation, LIBRARY.review],
29
+ specifications: [{ category: 'summary', format: SpecificationFormat.Json, revisioned: true, keepRevisions: 3 }],
30
+ relationships: [{ name: 'sequel-of', to: [LIBRARY.book], single: true }, { name: 'shelved-near' }],
31
+ labels: ['rare', 'new', 'signed'],
32
+ code: { prefix: 'B-', style: CodeStyle.Random, length: 5, uppercase: true, uniqueWithin: CodeScope.Parent },
33
+ }
34
+
35
+ export const PERIODICAL_TYPE: WorkcardTypeSchema = {
36
+ type: LIBRARY.periodical,
37
+ kind: WorkcardKind.Card,
38
+ version: 1,
39
+ overridable: true,
40
+ label: 'Periodical',
41
+ fields: { type: 'object', additionalProperties: true },
42
+ flows: [LIBRARY.circulation],
43
+ specifications: [],
44
+ }
@@ -1,26 +1,6 @@
1
- import {
2
- CodeScope, CodeStyle, IntrinsicStatus, SpecificationFormat, TransitionAction, WorkcardKind,
3
- } from '@owlmeans/planning'
4
- import type {
5
- AnyTypeSchema, PlanningFacade, PlanningPlugin, StatusFlowSchema, TransitionReceipt, Workcard,
6
- WorkcardTypeSchema,
7
- } from '@owlmeans/planning'
8
-
9
- /**
10
- * The conformance vocabulary: a lending library. Branches (projects) hold books and periodicals
11
- * (cards); a book runs a circulation flow and a review flow; documents are pages.
12
- */
13
- export const LIBRARY = Object.freeze({
14
- branch: 'library:branch',
15
- room: 'library:reading-room',
16
- book: 'library:book',
17
- periodical: 'library:periodical',
18
- page: 'library:page',
19
- circulation: 'library:circulation',
20
- review: 'library:review',
21
- branchLife: 'library:branch-life',
22
- pageLife: 'library:page-life',
23
- })
1
+ // owlmeans-structure: allow-file the conformance fixtures are one declarative data set together with the plugin that serves it
2
+ import { CodeScope, CodeStyle, IntrinsicStatus, SpecificationFormat, TransitionAction, WorkcardKind, type AnyTypeSchema, type PlanningFacade, type PlanningPlugin, type StatusFlowSchema, type TransitionReceipt, type Workcard } from '@owlmeans/planning'
3
+ import { BOOK_TYPE, LIBRARY, PERIODICAL_TYPE } from './consts.js'
24
4
 
25
5
  const flows: StatusFlowSchema[] = [
26
6
  {
@@ -64,33 +44,6 @@ const flows: StatusFlowSchema[] = [
64
44
  },
65
45
  ]
66
46
 
67
- export const BOOK_TYPE: WorkcardTypeSchema = {
68
- type: LIBRARY.book,
69
- kind: WorkcardKind.Card,
70
- version: 1,
71
- fields: {
72
- type: 'object',
73
- properties: { genre: { type: 'string', enum: ['poetry', 'history', 'fiction'] }, signed: { type: 'boolean' } },
74
- additionalProperties: false,
75
- },
76
- flows: [LIBRARY.circulation, LIBRARY.review],
77
- specifications: [{ category: 'summary', format: SpecificationFormat.Json, revisioned: true, keepRevisions: 3 }],
78
- relationships: [{ name: 'sequel-of', to: [LIBRARY.book], single: true }, { name: 'shelved-near' }],
79
- labels: ['rare', 'new', 'signed'],
80
- code: { prefix: 'B-', style: CodeStyle.Random, length: 5, uppercase: true, uniqueWithin: CodeScope.Parent },
81
- }
82
-
83
- export const PERIODICAL_TYPE: WorkcardTypeSchema = {
84
- type: LIBRARY.periodical,
85
- kind: WorkcardKind.Card,
86
- version: 1,
87
- overridable: true,
88
- label: 'Periodical',
89
- fields: { type: 'object', additionalProperties: true },
90
- flows: [LIBRARY.circulation],
91
- specifications: [],
92
- }
93
-
94
47
  const types: AnyTypeSchema[] = [
95
48
  {
96
49
  type: LIBRARY.branch,
@@ -6,4 +6,6 @@
6
6
  */
7
7
  export * from './assert.js'
8
8
  export * from './cases.js'
9
+ export type * from './types.js'
9
10
  export * from './fixtures.js'
11
+ export * from './consts.js'
@@ -0,0 +1,20 @@
1
+ import type { PlanningFacade, PlanningService, PlanningStore } from '@owlmeans/planning'
2
+
3
+ /** What a case runs against: a planning service over the store under test. */
4
+ export interface ConformanceSubject {
5
+ /** A service with `planningConformancePlugin` registered and a strictly increasing clock. */
6
+ service: PlanningService
7
+ /** The store under test — the service's default store. */
8
+ store: PlanningStore
9
+ /** A facade of one organization, acting as a signed-in person. */
10
+ facade: (entityId: string) => PlanningFacade
11
+ }
12
+
13
+ /** A capability a store may implement; a case that needs one is skipped for a store without it. */
14
+ export type ConformanceCapability = 'schemas'
15
+
16
+ export interface ConformanceCase {
17
+ name: string
18
+ needs?: ConformanceCapability[]
19
+ run: (subject: ConformanceSubject) => Promise<void>
20
+ }
@@ -1,37 +1,11 @@
1
- import {
2
- assertFlowSchema, assertOverridable, assertTypeSchema, flowInUse, isProject, PlanningSchemaKind,
3
- PlanningUnsupported, resolveScopedBundle, SchemaConflict, SchemaInUse, scopedRegistryOf,
4
- UnknownStatusFlow, UnknownWorkcardType, WorkcardNotFound,
5
- } from '@owlmeans/planning'
6
- import type {
7
- PlanningDefinitions, PlanningFacade, PlanningSchemaRegistry, SchemaDeclarations, SchemaStore,
8
- SchemaWriteOptions, ScopedSchemaRecord, ScopedSchemaRegistry, StatusFlowSchema, TransitionExecution,
9
- Unsubscribe, WorkcardTypeSchema,
10
- } from '@owlmeans/planning'
1
+ import { assertFlowSchema, assertOverridable, assertTypeSchema, flowInUse, isProject, PlanningSchemaKind, PlanningUnsupported, resolveScopedBundle, SchemaConflict, SchemaInUse, scopedRegistryOf, UnknownStatusFlow, UnknownWorkcardType, WorkcardNotFound, type PlanningDefinitions, type PlanningFacade, type PlanningSchemaRegistry, type SchemaDeclarations, type SchemaStore, type SchemaWriteOptions, type ScopedSchemaRecord, type ScopedSchemaRegistry, type StatusFlowSchema, type TransitionExecution, type Unsubscribe, type WorkcardTypeSchema } from '@owlmeans/planning'
11
2
  import { DEFAULT_SCHEMA_VIEWS } from './consts.js'
12
3
  import { actorOf } from './executor/changes.js'
13
- import type { PlanningRuntime } from './service.js'
4
+ import type { PlanningRuntime, SchemaViews, SchemaViewsOptions } from './types.js'
5
+ import type { Planned } from './types.local.js'
14
6
 
15
7
  const isoNow = (): string => new Date().toISOString()
16
8
 
17
- export interface SchemaViewsOptions {
18
- /** The code registry every layer starts from. */
19
- code: () => PlanningSchemaRegistry
20
- /** Bumps whenever the code registry changes (a plugin's `use`). */
21
- version: () => number
22
- /** The schema port, when the store has one. */
23
- port: () => SchemaStore | undefined
24
- /** How many resolved layers are kept. */
25
- limit?: number
26
- }
27
-
28
- export interface SchemaViews {
29
- /** The code registry itself without a port; the resolved layer with one. */
30
- of: (entityId: string, project?: string) => Promise<PlanningSchemaRegistry>
31
- /** @throws {PlanningUnsupported} without a port */
32
- scoped: (entityId: string, project?: string) => Promise<ScopedSchemaRegistry>
33
- }
34
-
35
9
  /**
36
10
  * The resolved layers of one planning service, cached per (organization, project) and keyed by the
37
11
  * organization's schema revision and the code registry's version — a write anywhere, in any
@@ -98,12 +72,6 @@ export const makeSchemaViews = (opts: SchemaViewsOptions): SchemaViews => {
98
72
  }
99
73
  }
100
74
 
101
- interface Planned {
102
- kind: PlanningSchemaKind
103
- key: string
104
- definition: WorkcardTypeSchema | StatusFlowSchema
105
- }
106
-
107
75
  const planOf = (declarations: SchemaDeclarations): Planned[] => [
108
76
  ...(declarations.flows ?? []).map(flow => ({ kind: PlanningSchemaKind.Flow, key: flow.id, definition: flow })),
109
77
  ...(declarations.types ?? []).map(type => ({ kind: PlanningSchemaKind.Type, key: type.type, definition: type })),
@@ -1,9 +1,5 @@
1
- import { CommitState, computeChanges, isEmptyChange, TransitionAction } from '@owlmeans/planning'
2
- import type {
3
- ChangeSet, PlanningSchemaRegistry, PlanningScope, RelationshipDraft, Transition, TransitionActor,
4
- TransitionExecution, WorkcardDraft,
5
- } from '@owlmeans/planning'
6
- import type { Resolved } from './resolve.js'
1
+ import { CommitState, computeChanges, isEmptyChange, TransitionAction, type ChangeSet, type PlanningSchemaRegistry, type PlanningScope, type RelationshipDraft, type Transition, type TransitionActor, type TransitionExecution, type WorkcardDraft } from '@owlmeans/planning'
2
+ import type { Resolved } from './types.js'
7
3
 
8
4
  const clean = <T extends object>(record: T): T =>
9
5
  Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined)) as T
@@ -1,13 +1,7 @@
1
- import {
2
- CODE_MINT_ATTEMPTS, CodeScope, CodeStyle, CodeTaken, mintCode, TransitionAction,
3
- } from '@owlmeans/planning'
4
- import type {
5
- CodePolicy, PlanningExecContext, PlanningPlugin, PlanningScope, TransitionExecution, WorkcardDraft,
6
- } from '@owlmeans/planning'
1
+ import { CODE_MINT_ATTEMPTS, CodeScope, CodeStyle, CodeTaken, mintCode, TransitionAction, type CodePolicy, type PlanningExecContext, type PlanningPlugin, type PlanningScope, type TransitionExecution, type WorkcardDraft, type Workcard } from '@owlmeans/planning'
7
2
  import type { Criteria } from '@owlmeans/resource'
8
- import type { Workcard } from '@owlmeans/planning'
9
- import type { PluginRegistry } from '../registry.js'
10
- import type { Resolved } from './resolve.js'
3
+ import type { PluginRegistry } from '../types.js'
4
+ import type { Resolved } from './types.js'
11
5
 
12
6
  /** The criteria a code must be unique within — the policy's scope, `parent` when there is none. */
13
7
  const scopeCriteria = (
@@ -0,0 +1,8 @@
1
+ import { TransitionAction } from '@owlmeans/planning'
2
+
3
+ /** The field a create's draft writes once and nothing moves afterwards. */
4
+ export const CREATOR = 'createdBy'
5
+
6
+ export const TRIMMED = ['title', 'description', 'code'] as const
7
+
8
+ export const ACTIONS = new Set<string>(Object.values(TransitionAction))
@@ -1,11 +1,8 @@
1
- import { PlanningError, TransitionAction } from '@owlmeans/planning'
2
- import type { PlanningScope, TransitionExecution } from '@owlmeans/planning'
1
+ import { PlanningError, TransitionAction, type PlanningScope, type TransitionExecution } from '@owlmeans/planning'
2
+ import { CREATOR } from './consts.local.js'
3
3
 
4
4
  const named = (value?: string | null): value is string => value != null && value !== ''
5
5
 
6
- /** The field a create's draft writes once and nothing moves afterwards. */
7
- const CREATOR = 'createdBy'
8
-
9
6
  /**
10
7
  * The subject a create made under `scope` is stamped with as its `createdBy`: the scope's
11
8
  * `profileId`, else its `userId`, else the same two of its `actor` — the authenticated subject an
@@ -1,35 +1,7 @@
1
- import {
2
- CardTypeNotAllowed, isProject, normalizeParents, ParentNotFound, PlanningError, PlanningSchemaKind,
3
- PlanningScopeMismatch, primaryFlowOf, projectOf, SchemaOrigin, slotOf, TransitionAction, UnknownStatusFlow,
4
- UnknownWorkcardType, WorkcardKind, WorkcardNotFound,
5
- } from '@owlmeans/planning'
6
- import type {
7
- AnyTypeSchema, PlanningFacade, PlanningSchemaRegistry, PlanningStore, ProjectTypeSchema,
8
- ScopedSchemaRegistry, Specification, SpecificationSlot, StatusFlowSchema, TransitionExecution, Workcard,
9
- WorkcardDraft,
10
- } from '@owlmeans/planning'
11
- import type { PlanningRuntime } from '../service.js'
12
-
13
- /** Everything the steps after resolution read about an execution. */
14
- export interface Resolved {
15
- create: boolean
16
- /** The existing card (not a create). */
17
- card?: Workcard
18
- type: AnyTypeSchema
19
- flowId: string
20
- flow: StatusFlowSchema
21
- /** The primary parent, when it resolves. */
22
- parent?: Workcard
23
- /** The slot a specification belongs to. */
24
- slot?: SpecificationSlot
25
- /** The store the type is written to. */
26
- store: PlanningStore
27
- /**
28
- * The registry every later step reads: the service's code registry itself, or — where the store
29
- * holds data-defined schemas — the resolved layer of the card's project.
30
- */
31
- schemas: PlanningSchemaRegistry
32
- }
1
+ import { CardTypeNotAllowed, isProject, normalizeParents, ParentNotFound, PlanningError, PlanningSchemaKind, PlanningScopeMismatch, primaryFlowOf, projectOf, SchemaOrigin, slotOf, TransitionAction, UnknownStatusFlow, UnknownWorkcardType, WorkcardKind, WorkcardNotFound, type AnyTypeSchema, type PlanningFacade, type PlanningSchemaRegistry, type ProjectTypeSchema, type ScopedSchemaRegistry, type Specification, type TransitionExecution, type Workcard, type WorkcardDraft } from '@owlmeans/planning'
2
+ import type { PlanningRuntime } from '../types.js'
3
+ import { TRIMMED } from './consts.local.js'
4
+ import type { Resolved } from './types.js'
33
5
 
34
6
  const isScoped = (schemas: PlanningSchemaRegistry): schemas is ScopedSchemaRegistry =>
35
7
  typeof (schemas as Partial<ScopedSchemaRegistry>).originOf === 'function'
@@ -45,8 +17,6 @@ const dataDefined = (schemas: PlanningSchemaRegistry | undefined, type: string):
45
17
 
46
18
  const trimmed = (value: unknown): unknown => typeof value === 'string' ? value.trim() : value
47
19
 
48
- const TRIMMED = ['title', 'description', 'code'] as const
49
-
50
20
  const trim = <T extends object>(record: T | undefined): T | undefined => {
51
21
  if (record == null) {
52
22
  return record
@@ -64,7 +34,7 @@ const trim = <T extends object>(record: T | undefined): T | undefined => {
64
34
  * Step 1: a deep copy with trimmed text, `parents ∋ parent` on a draft, and no duplicate `unset`
65
35
  * paths. The caller's object is never touched.
66
36
  */
67
- export const normalizeExecution = (input: TransitionExecution): TransitionExecution => {
37
+ const normalizeExecution = (input: TransitionExecution): TransitionExecution => {
68
38
  const exec = structuredClone(input) as TransitionExecution
69
39
  if (exec.card != null && typeof exec.card === 'object') {
70
40
  const draft = trim(exec.card) as WorkcardDraft
@@ -87,7 +57,7 @@ export const normalizeExecution = (input: TransitionExecution): TransitionExecut
87
57
  *
88
58
  * @throws {CardTypeNotAllowed}
89
59
  */
90
- export const assertChildAllowed = (
60
+ const assertChildAllowed = (
91
61
  runtime: PlanningRuntime, parent: Workcard, kind: WorkcardKind, type: string, view?: PlanningSchemaRegistry
92
62
  ): void => {
93
63
  if (kind === WorkcardKind.Specification) {
@@ -108,7 +78,7 @@ export const assertChildAllowed = (
108
78
  }
109
79
 
110
80
  /** The layer a parent project admits data-defined children through — `undefined` without a schema port. */
111
- export const childViewOf = async (
81
+ const childViewOf = async (
112
82
  runtime: PlanningRuntime, entityId: string, parent: Workcard
113
83
  ): Promise<PlanningSchemaRegistry | undefined> =>
114
84
  runtime.schemaStore() == null || !isProject(parent) ? undefined : await runtime.schemasFor(entityId, parent.id)
@@ -119,7 +89,7 @@ export const childViewOf = async (
119
89
  * @throws {WorkcardNotFound | PlanningScopeMismatch | UnknownWorkcardType | UnknownStatusFlow}
120
90
  * @throws {ParentNotFound | CardTypeNotAllowed | PlanningError}
121
91
  */
122
- export const resolveExecution = async (
92
+ const resolveExecution = async (
123
93
  runtime: PlanningRuntime, facade: PlanningFacade, exec: TransitionExecution
124
94
  ): Promise<Resolved> => {
125
95
  const service = runtime.service()
@@ -232,7 +202,7 @@ export const resolveExecution = async (
232
202
  }
233
203
 
234
204
  /** The project a transition is filed under: a project's own id, else its parent's project. */
235
- export const projectFor = (resolved: Resolved, exec: TransitionExecution, cardId: string): string | undefined => {
205
+ const projectFor = (resolved: Resolved, exec: TransitionExecution, cardId: string): string | undefined => {
236
206
  if (resolved.card != null) {
237
207
  return isProject(resolved.card) ? resolved.card.id : projectOf(resolved.card, resolved.parent)
238
208
  }
@@ -242,3 +212,7 @@ export const projectFor = (resolved: Resolved, exec: TransitionExecution, cardId
242
212
  }
243
213
  return projectOf({ kind: draft.kind, parent: draft.parent, parents: draft.parents ?? [] } as unknown as Workcard, resolved.parent)
244
214
  }
215
+
216
+ export const createResolveHelper = () => ({ normalizeExecution, assertChildAllowed, childViewOf, resolveExecution, projectFor })
217
+
218
+ export const resolveHelper = createResolveHelper()
@@ -0,0 +1,25 @@
1
+ import type { AnyTypeSchema, PlanningSchemaRegistry, PlanningStore, SpecificationSlot, StatusFlowSchema, Workcard } from '@owlmeans/planning'
2
+ import type { createResolveHelper } from './resolve.js'
3
+
4
+ /** Everything the steps after resolution read about an execution. */
5
+ export interface Resolved {
6
+ create: boolean
7
+ /** The existing card (not a create). */
8
+ card?: Workcard
9
+ type: AnyTypeSchema
10
+ flowId: string
11
+ flow: StatusFlowSchema
12
+ /** The primary parent, when it resolves. */
13
+ parent?: Workcard
14
+ /** The slot a specification belongs to. */
15
+ slot?: SpecificationSlot
16
+ /** The store the type is written to. */
17
+ store: PlanningStore
18
+ /**
19
+ * The registry every later step reads: the service's code registry itself, or — where the store
20
+ * holds data-defined schemas — the resolved layer of the card's project.
21
+ */
22
+ schemas: PlanningSchemaRegistry
23
+ }
24
+
25
+ export type ResolveHelper = ReturnType<typeof createResolveHelper>
@@ -1,18 +1,9 @@
1
- import {
2
- applyUnset, assertMutable, BODY_MAX, CODE_MAX, DESCRIPTION_MAX, IllegalTransition,
3
- LabelNotAllowed, MAX_LABELS, MAX_PARENTS, mergeFields, normalizeParents, ParentNotFound, PlanningError,
4
- RelationshipRefused, ruleOf, SpecificationRevisionConflict, SpecificationSlotUnknown, slotOf, TITLE_MAX,
5
- TransitionAction, validateFields, validateSpecificationBody, WorkcardKind,
6
- } from '@owlmeans/planning'
7
- import type {
8
- PlanningFacade, RelationshipDraft, Specification, TransitionExecution, WorkcardDraft,
9
- } from '@owlmeans/planning'
10
- import type { PlanningRuntime } from '../service.js'
1
+ import { applyUnset, assertMutable, BODY_MAX, CODE_MAX, DESCRIPTION_MAX, IllegalTransition, LabelNotAllowed, MAX_LABELS, MAX_PARENTS, mergeFields, normalizeParents, ParentNotFound, PlanningError, RelationshipRefused, ruleOf, SpecificationRevisionConflict, SpecificationSlotUnknown, slotOf, TITLE_MAX, TransitionAction, validateFields, validateSpecificationBody, WorkcardKind, type PlanningFacade, type RelationshipDraft, type Specification, type TransitionExecution, type WorkcardDraft } from '@owlmeans/planning'
2
+ import type { PlanningRuntime } from '../types.js'
11
3
  import { assertCreatorFixed } from './creator.js'
12
- import { assertChildAllowed, childViewOf } from './resolve.js'
13
- import type { Resolved } from './resolve.js'
14
-
15
- const ACTIONS = new Set<string>(Object.values(TransitionAction))
4
+ import type { Resolved } from './types.js'
5
+ import { ACTIONS } from './consts.local.js'
6
+ import { resolveHelper } from './resolve.js'
16
7
 
17
8
  const malformed = (what: string): PlanningError => new PlanningError(`malformed:${what}`)
18
9
 
@@ -128,8 +119,8 @@ const assertParentMove = async (
128
119
  if (found == null) {
129
120
  throw new ParentNotFound(id)
130
121
  }
131
- assertChildAllowed(
132
- runtime, found, resolved.card!.kind, resolved.card!.type, await childViewOf(runtime, facade.scope.entityId, found)
122
+ resolveHelper.assertChildAllowed(
123
+ runtime, found, resolved.card!.kind, resolved.card!.type, await resolveHelper.childViewOf(runtime, facade.scope.entityId, found)
133
124
  )
134
125
  }
135
126
  }
package/src/executor.ts CHANGED
@@ -1,18 +1,14 @@
1
1
  import { uuid } from '@owlmeans/basic-ids'
2
2
  import type { BasicConfig, BasicContext } from '@owlmeans/context'
3
- import { PlanningError, PlanningUnsupported, WorkcardConflict } from '@owlmeans/planning'
4
- import type {
5
- ExecuteOptions, PlanningExecContext, PlanningFacade, PlanningPlugin, PlanningStore, Transition,
6
- TransitionExecution, TransitionReceipt,
7
- } from '@owlmeans/planning'
3
+ import { PlanningError, PlanningUnsupported, WorkcardConflict, type ExecuteOptions, type PlanningExecContext, type PlanningFacade, type PlanningPlugin, type PlanningStore, type Transition, type TransitionExecution, type TransitionReceipt } from '@owlmeans/planning'
8
4
  import { changeSetOf, transitionOf } from './executor/changes.js'
9
5
  import { assignCode } from './executor/code.js'
10
6
  import { withCreator } from './executor/creator.js'
11
7
  import { makeReceipt } from './executor/receipt.js'
12
- import { normalizeExecution, projectFor, resolveExecution } from './executor/resolve.js'
13
- import type { Resolved } from './executor/resolve.js'
8
+ import type { Resolved } from './executor/types.js'
14
9
  import { validateExecution } from './executor/validate.js'
15
- import type { PlanningRuntime } from './service.js'
10
+ import type { PlanningRuntime } from './types.js'
11
+ import { resolveHelper } from './executor/resolve.js'
16
12
 
17
13
  export { assertCreatorFixed, creatorOf, withCreator } from './executor/creator.js'
18
14
 
@@ -83,7 +79,7 @@ export const executeTransition = async (
83
79
  const scope = facade.scope
84
80
  const at = (runtime.options.now ?? isoNow)()
85
81
 
86
- let exec = withCreator(normalizeExecution(input), scope)
82
+ let exec = withCreator(resolveHelper.normalizeExecution(input), scope)
87
83
 
88
84
  if (scope.entityId == null || scope.entityId === '') {
89
85
  throw new PlanningError('malformed:scope-without-entity')
@@ -96,12 +92,12 @@ export const executeTransition = async (
96
92
  }
97
93
  }
98
94
 
99
- let resolved = await resolveExecution(runtime, facade, exec)
95
+ let resolved = await resolveHelper.resolveExecution(runtime, facade, exec)
100
96
 
101
97
  const before = identityOf(exec)
102
- exec = normalizeExecution(await runtime.registry.before(exec, execContextOf(runtime, facade, resolved)))
98
+ exec = resolveHelper.normalizeExecution(await runtime.registry.before(exec, execContextOf(runtime, facade, resolved)))
103
99
  if (identityOf(exec) !== before) {
104
- resolved = await resolveExecution(runtime, facade, exec)
100
+ resolved = await resolveHelper.resolveExecution(runtime, facade, exec)
105
101
  }
106
102
 
107
103
  await validateExecution(runtime, facade, exec, resolved)
@@ -130,7 +126,7 @@ export const executeTransition = async (
130
126
 
131
127
  const transition = transitionOf({
132
128
  exec, resolved, scope, set, cardId, seq, at,
133
- project: projectFor(resolved, exec, cardId),
129
+ project: resolveHelper.projectFor(resolved, exec, cardId),
134
130
  })
135
131
 
136
132
  let appended: Transition
package/src/facade.ts CHANGED
@@ -1,15 +1,8 @@
1
- import {
2
- criteriaOf, currentSpecification, isProject, isSpecification, linkWhereOf, listOptionsOf, modelOf, projectOf,
3
- PlanningUnsupported, specCriteriaOf, transitionWhereOf, WorkcardKind, WorkcardNotFound,
4
- } from '@owlmeans/planning'
5
- import type {
6
- CommitEvent, CommitSource, PlanningFacade, PlanningScope, Relationship, Specification, Transition,
7
- Workcard, WorkcardModel, WorkcardQuery,
8
- } from '@owlmeans/planning'
1
+ import { criteriaOf, currentSpecification, isProject, isSpecification, linkWhereOf, listOptionsOf, modelOf, projectOf, PlanningUnsupported, specCriteriaOf, transitionWhereOf, WorkcardKind, WorkcardNotFound, type CommitEvent, type CommitSource, type PlanningFacade, type PlanningScope, type Relationship, type Specification, type Transition, type Workcard, type WorkcardModel, type WorkcardQuery } from '@owlmeans/planning'
9
2
  import type { Criteria } from '@owlmeans/resource'
10
3
  import { makeDefinitions } from './definitions.js'
11
4
  import { executeTransition } from './executor.js'
12
- import type { PlanningRuntime } from './service.js'
5
+ import type { PlanningRuntime } from './types.js'
13
6
  import { wantsSpecifications } from './store/memory.js'
14
7
  import type { CommitHub } from './store/types.js'
15
8
 
package/src/projection.ts CHANGED
@@ -1,22 +1,12 @@
1
1
  import type { BasicConfig, BasicContext } from '@owlmeans/context'
2
- import { PLANNING_SERVICE } from '@owlmeans/planning'
3
- import type { CommitEvent, PlanningService, PlanningStore } from '@owlmeans/planning'
4
- import { PLANNING_PROJECT_JOB, PLANNING_PROJECTION_QUEUE } from './queue/index.js'
5
- import type { ProjectionRequest } from './queue/index.js'
2
+ import { PLANNING_SERVICE, type PlanningService, type PlanningStore } from '@owlmeans/planning'
3
+ import { PLANNING_PROJECT_JOB, PLANNING_PROJECTION_QUEUE } from './queue/consts.js'
4
+ import type { ProjectionRequest } from './queue/types.js'
6
5
  import type { JobProcessor, QueueHooks } from '@owlmeans/queue'
7
6
  import { failPending, foldPending } from './store/fold.js'
8
- import type { PlanningHostService } from './types.js'
7
+ import type { PlanningHostService, ProjectionOptions } from './types.js'
9
8
  import type { CommitHub, FoldResult } from './store/types.js'
10
9
 
11
- export interface ProjectionOptions {
12
- /** The planning service alias. */
13
- service?: string
14
- /** The store the queue folds — the service's default store when omitted. */
15
- store?: (service: PlanningService) => PlanningStore
16
- /** Where events go — the store's commit hub `publish` when it has one. */
17
- publish?: (event: CommitEvent) => Promise<void>
18
- }
19
-
20
10
  const serviceOf = (ctx: BasicContext<BasicConfig>, opts?: ProjectionOptions): PlanningService =>
21
11
  ctx.service<PlanningHostService>(opts?.service ?? PLANNING_SERVICE)
22
12
 
@@ -0,0 +1,5 @@
1
+ /** The server-side queue used to project planning transitions. */
2
+ export const PLANNING_PROJECTION_QUEUE = 'planning-projection'
3
+
4
+ /** The processor name accepted by the planning projection queue. */
5
+ export const PLANNING_PROJECT_JOB = 'planning:project'
@@ -1,25 +1,10 @@
1
- import { declareQueue } from '@owlmeans/queue'
2
- import type { Config, JobOptions, QueueWorkerOptions } from '@owlmeans/queue'
3
-
4
- /** The server-side queue used to project planning transitions. */
5
- export const PLANNING_PROJECTION_QUEUE = 'planning-projection'
6
-
7
- /** The processor name accepted by the planning projection queue. */
8
- export const PLANNING_PROJECT_JOB = 'planning:project'
9
-
10
- /** What one projection job folds. */
11
- export interface ProjectionRequest {
12
- cardId: string
13
- entityId: string
14
- /** The transition that requested projection; it is a hint rather than a fold bound. */
15
- transition?: string
16
- }
17
-
18
- export interface PlanningQueueOptions {
19
- worker?: QueueWorkerOptions
20
- defaults?: JobOptions
21
- }
1
+ import { declareQueue, type Config } from '@owlmeans/queue'
2
+ import { PLANNING_PROJECT_JOB, PLANNING_PROJECTION_QUEUE } from './consts.js'
3
+ import type { PlanningQueueOptions } from './types.js'
22
4
 
23
5
  /** Declare the shared projection address; each process separately chooses whether to listen. */
24
6
  export const declarePlanningQueue = <C extends Config>(cfg: C, opts?: PlanningQueueOptions): C =>
25
7
  declareQueue(cfg, PLANNING_PROJECTION_QUEUE, [PLANNING_PROJECT_JOB], opts)
8
+
9
+ export { PLANNING_PROJECTION_QUEUE, PLANNING_PROJECT_JOB } from './consts.js'
10
+ export type { PlanningQueueOptions, ProjectionRequest } from './types.js'
@@ -0,0 +1,14 @@
1
+ import type { JobOptions, QueueWorkerOptions } from '@owlmeans/queue'
2
+
3
+ /** What one projection job folds. */
4
+ export interface ProjectionRequest {
5
+ cardId: string
6
+ entityId: string
7
+ /** The transition that requested projection; it is a hint rather than a fold bound. */
8
+ transition?: string
9
+ }
10
+
11
+ export interface PlanningQueueOptions {
12
+ worker?: QueueWorkerOptions
13
+ defaults?: JobOptions
14
+ }