@owlmeans/planning 0.1.18-rc.2 → 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 (228) hide show
  1. package/README.md +69 -26
  2. package/agent-meta/manifest.json +2 -2
  3. package/agent-meta/skills/planning/SKILL.md +157 -45
  4. package/build/aliases/types.d.ts +49 -0
  5. package/build/aliases/types.d.ts.map +1 -0
  6. package/build/aliases/types.js +2 -0
  7. package/build/aliases/types.js.map +1 -0
  8. package/build/aliases.d.ts +4 -0
  9. package/build/aliases.d.ts.map +1 -0
  10. package/build/aliases.js +27 -0
  11. package/build/aliases.js.map +1 -0
  12. package/build/consts.d.ts +23 -34
  13. package/build/consts.d.ts.map +1 -1
  14. package/build/consts.js +26 -25
  15. package/build/consts.js.map +1 -1
  16. package/build/entrypoints/types.d.ts +96 -0
  17. package/build/entrypoints/types.d.ts.map +1 -0
  18. package/build/entrypoints/types.js +2 -0
  19. package/build/entrypoints/types.js.map +1 -0
  20. package/build/entrypoints.d.ts +5 -1
  21. package/build/entrypoints.d.ts.map +1 -1
  22. package/build/entrypoints.js +17 -6
  23. package/build/entrypoints.js.map +1 -1
  24. package/build/errors.d.ts +41 -0
  25. package/build/errors.d.ts.map +1 -1
  26. package/build/errors.js +61 -0
  27. package/build/errors.js.map +1 -1
  28. package/build/helpers/apply/consts.local.d.ts +7 -0
  29. package/build/helpers/apply/consts.local.d.ts.map +1 -0
  30. package/build/helpers/apply/consts.local.js +9 -0
  31. package/build/helpers/apply/consts.local.js.map +1 -0
  32. package/build/helpers/apply/types.d.ts +32 -0
  33. package/build/helpers/apply/types.d.ts.map +1 -0
  34. package/build/helpers/apply/types.js +2 -0
  35. package/build/helpers/apply/types.js.map +1 -0
  36. package/build/helpers/apply.d.ts +5 -23
  37. package/build/helpers/apply.d.ts.map +1 -1
  38. package/build/helpers/apply.js +121 -143
  39. package/build/helpers/apply.js.map +1 -1
  40. package/build/helpers/card/types.d.ts +20 -0
  41. package/build/helpers/card/types.d.ts.map +1 -0
  42. package/build/helpers/card/types.js +2 -0
  43. package/build/helpers/card/types.js.map +1 -0
  44. package/build/helpers/card.d.ts +11 -7
  45. package/build/helpers/card.d.ts.map +1 -1
  46. package/build/helpers/card.js +41 -28
  47. package/build/helpers/card.js.map +1 -1
  48. package/build/helpers/changes/consts.local.d.ts +13 -0
  49. package/build/helpers/changes/consts.local.d.ts.map +1 -0
  50. package/build/helpers/changes/consts.local.js +13 -0
  51. package/build/helpers/changes/consts.local.js.map +1 -0
  52. package/build/helpers/changes/types.d.ts +58 -0
  53. package/build/helpers/changes/types.d.ts.map +1 -0
  54. package/build/helpers/changes/types.js +2 -0
  55. package/build/helpers/changes/types.js.map +1 -0
  56. package/build/helpers/changes.d.ts +11 -42
  57. package/build/helpers/changes.d.ts.map +1 -1
  58. package/build/helpers/changes.js +234 -251
  59. package/build/helpers/changes.js.map +1 -1
  60. package/build/helpers/code/types.d.ts +27 -0
  61. package/build/helpers/code/types.d.ts.map +1 -0
  62. package/build/helpers/code/types.js +2 -0
  63. package/build/helpers/code/types.js.map +1 -0
  64. package/build/helpers/code.d.ts +6 -17
  65. package/build/helpers/code.d.ts.map +1 -1
  66. package/build/helpers/code.js +39 -40
  67. package/build/helpers/code.js.map +1 -1
  68. package/build/helpers/index.d.ts +12 -0
  69. package/build/helpers/index.d.ts.map +1 -1
  70. package/build/helpers/index.js +2 -0
  71. package/build/helpers/index.js.map +1 -1
  72. package/build/helpers/query/types.d.ts +23 -0
  73. package/build/helpers/query/types.d.ts.map +1 -0
  74. package/build/helpers/query/types.js +2 -0
  75. package/build/helpers/query/types.js.map +1 -0
  76. package/build/helpers/query.d.ts +25 -17
  77. package/build/helpers/query.d.ts.map +1 -1
  78. package/build/helpers/query.js +108 -280
  79. package/build/helpers/query.js.map +1 -1
  80. package/build/helpers/scoped/types.d.ts +59 -0
  81. package/build/helpers/scoped/types.d.ts.map +1 -0
  82. package/build/helpers/scoped/types.js +2 -0
  83. package/build/helpers/scoped/types.js.map +1 -0
  84. package/build/helpers/scoped.d.ts +24 -0
  85. package/build/helpers/scoped.d.ts.map +1 -0
  86. package/build/helpers/scoped.js +197 -0
  87. package/build/helpers/scoped.js.map +1 -0
  88. package/build/helpers/specification/types.d.ts +24 -0
  89. package/build/helpers/specification/types.d.ts.map +1 -0
  90. package/build/helpers/specification/types.js +2 -0
  91. package/build/helpers/specification/types.js.map +1 -0
  92. package/build/helpers/specification.d.ts +9 -13
  93. package/build/helpers/specification.d.ts.map +1 -1
  94. package/build/helpers/specification.js +47 -44
  95. package/build/helpers/specification.js.map +1 -1
  96. package/build/helpers/status/types.d.ts +48 -0
  97. package/build/helpers/status/types.d.ts.map +1 -0
  98. package/build/helpers/status/types.js +2 -0
  99. package/build/helpers/status/types.js.map +1 -0
  100. package/build/helpers/status.d.ts +16 -29
  101. package/build/helpers/status.d.ts.map +1 -1
  102. package/build/helpers/status.js +77 -73
  103. package/build/helpers/status.js.map +1 -1
  104. package/build/helpers/types.local.d.ts +17 -0
  105. package/build/helpers/types.local.d.ts.map +1 -0
  106. package/build/helpers/types.local.js +2 -0
  107. package/build/helpers/types.local.js.map +1 -0
  108. package/build/helpers/validate/types.d.ts +30 -0
  109. package/build/helpers/validate/types.d.ts.map +1 -0
  110. package/build/helpers/validate/types.js +2 -0
  111. package/build/helpers/validate/types.js.map +1 -0
  112. package/build/helpers/validate.d.ts +8 -19
  113. package/build/helpers/validate.d.ts.map +1 -1
  114. package/build/helpers/validate.js +74 -79
  115. package/build/helpers/validate.js.map +1 -1
  116. package/build/helpers/wire/types.d.ts +28 -0
  117. package/build/helpers/wire/types.d.ts.map +1 -0
  118. package/build/helpers/wire/types.js +2 -0
  119. package/build/helpers/wire/types.js.map +1 -0
  120. package/build/helpers/wire.d.ts +4 -0
  121. package/build/helpers/wire.d.ts.map +1 -0
  122. package/build/helpers/wire.js +215 -0
  123. package/build/helpers/wire.js.map +1 -0
  124. package/build/i18n/be.json +5 -0
  125. package/build/i18n/de.json +5 -0
  126. package/build/i18n/en.json +5 -0
  127. package/build/i18n/es.json +5 -0
  128. package/build/i18n/fr.json +56 -0
  129. package/build/i18n/pl.json +5 -0
  130. package/build/i18n/ru.json +5 -0
  131. package/build/i18n/uk.json +5 -0
  132. package/build/i18n.js +5 -4
  133. package/build/i18n.js.map +1 -1
  134. package/build/index.d.ts +4 -0
  135. package/build/index.d.ts.map +1 -1
  136. package/build/index.js +2 -0
  137. package/build/index.js.map +1 -1
  138. package/build/models/index.d.ts +2 -3
  139. package/build/models/index.d.ts.map +1 -1
  140. package/build/models/index.js +1 -15
  141. package/build/models/index.js.map +1 -1
  142. package/build/models/model.d.ts +5 -0
  143. package/build/models/model.d.ts.map +1 -0
  144. package/build/models/model.js +16 -0
  145. package/build/models/model.js.map +1 -0
  146. package/build/models/project.d.ts +2 -1
  147. package/build/models/project.d.ts.map +1 -1
  148. package/build/models/project.js.map +1 -1
  149. package/build/models/specification.d.ts +2 -1
  150. package/build/models/specification.d.ts.map +1 -1
  151. package/build/models/specification.js.map +1 -1
  152. package/build/models/types.d.ts +69 -0
  153. package/build/models/types.d.ts.map +1 -0
  154. package/build/models/types.js +2 -0
  155. package/build/models/types.js.map +1 -0
  156. package/build/models/workcard.d.ts +2 -1
  157. package/build/models/workcard.d.ts.map +1 -1
  158. package/build/models/workcard.js +12 -12
  159. package/build/models/workcard.js.map +1 -1
  160. package/build/schemas.d.ts +10 -2
  161. package/build/schemas.d.ts.map +1 -1
  162. package/build/schemas.js +87 -1
  163. package/build/schemas.js.map +1 -1
  164. package/build/types.d.ts +199 -148
  165. package/build/types.d.ts.map +1 -1
  166. package/build/utils.d.ts +6 -0
  167. package/build/utils.d.ts.map +1 -0
  168. package/build/utils.js +6 -0
  169. package/build/utils.js.map +1 -0
  170. package/package.json +11 -11
  171. package/src/aliases/types.ts +38 -0
  172. package/src/aliases.ts +31 -0
  173. package/src/consts.ts +26 -25
  174. package/src/entrypoints/types.ts +68 -0
  175. package/src/entrypoints.ts +34 -14
  176. package/src/errors.ts +71 -0
  177. package/src/helpers/apply/consts.local.ts +10 -0
  178. package/src/helpers/apply/types.ts +32 -0
  179. package/src/helpers/apply.ts +135 -152
  180. package/src/helpers/card/types.ts +20 -0
  181. package/src/helpers/card.ts +59 -33
  182. package/src/helpers/changes/consts.local.ts +17 -0
  183. package/src/helpers/changes/types.ts +66 -0
  184. package/src/helpers/changes.ts +267 -280
  185. package/src/helpers/code/types.ts +31 -0
  186. package/src/helpers/code.ts +52 -48
  187. package/src/helpers/index.ts +13 -0
  188. package/src/helpers/query/types.ts +26 -0
  189. package/src/helpers/query.ts +144 -314
  190. package/src/helpers/scoped/types.ts +64 -0
  191. package/src/helpers/scoped.ts +257 -0
  192. package/src/helpers/specification/types.ts +26 -0
  193. package/src/helpers/specification.ts +69 -51
  194. package/src/helpers/status/types.ts +46 -0
  195. package/src/helpers/status.ts +117 -93
  196. package/src/helpers/types.local.ts +18 -0
  197. package/src/helpers/validate/types.ts +30 -0
  198. package/src/helpers/validate.ts +84 -77
  199. package/src/helpers/wire/types.ts +31 -0
  200. package/src/helpers/wire.ts +251 -0
  201. package/src/i18n/be.json +5 -0
  202. package/src/i18n/de.json +5 -0
  203. package/src/i18n/en.json +5 -0
  204. package/src/i18n/es.json +5 -0
  205. package/src/i18n/fr.json +56 -0
  206. package/src/i18n/pl.json +5 -0
  207. package/src/i18n/ru.json +5 -0
  208. package/src/i18n/uk.json +5 -0
  209. package/src/i18n.ts +6 -4
  210. package/src/index.ts +4 -0
  211. package/src/models/index.ts +2 -17
  212. package/src/models/model.ts +18 -0
  213. package/src/models/project.ts +2 -1
  214. package/src/models/specification.ts +2 -1
  215. package/src/models/types.ts +70 -0
  216. package/src/models/workcard.ts +14 -16
  217. package/src/schemas.ts +98 -2
  218. package/src/types.ts +207 -126
  219. package/src/utils.ts +9 -0
  220. package/tests/apply.spec.ts +95 -31
  221. package/tests/code.spec.ts +9 -9
  222. package/tests/entrypoints.spec.ts +18 -2
  223. package/tests/error-status.spec.ts +6 -1
  224. package/tests/models.spec.ts +16 -15
  225. package/tests/query.spec.ts +13 -15
  226. package/tests/schemas.spec.ts +8 -8
  227. package/tests/scoped.spec.ts +154 -0
  228. package/tests/status.spec.ts +31 -22
package/src/schemas.ts CHANGED
@@ -5,12 +5,14 @@ import type { ListResult } from '@owlmeans/resource'
5
5
  import {
6
6
  BODY_MAX, CAUSE_MAX, CODE_MAX, CodeScope, CodeStyle, CommitState, DESCRIPTION_MAX, IntrinsicPolicy,
7
7
  IntrinsicStatus, KEY_MAX, LABEL_MAX, MAX_COMMIT_POLL, MAX_LABELS, MAX_PARENTS, MAX_QUERY_LIST,
8
- QUERY_TEXT_MAX, REF_MAX, SpecificationFormat, TITLE_MAX, TransitionAction, TYPE_MAX, WorkcardKind,
8
+ PlanningSchemaKind, QUERY_TEXT_MAX, REF_MAX, SchemaOrigin, SchemaWriteMode, SpecificationFormat,
9
+ TITLE_MAX, TransitionAction, TYPE_MAX, WorkcardKind,
9
10
  } from './consts.js'
10
11
  import type {
11
12
  AnyTypeSchema, CodePolicy, CommitEvent, CommitFeedQuery, CommitQuery, CommitStatus, ExecuteRequest,
12
13
  PlanningSchemaBundle, ProjectTypeSchema, Relationship, RelationshipDraft, RelationshipQueryWire,
13
- RelationshipType, RevisionsQuery, Specification, SpecificationQueryWire, SpecificationRevision,
14
+ RelationshipType, RevisionsQuery, SchemaDefineRequest, SchemaKey, SchemaListQuery, ScopedSchemaBundle,
15
+ ScopedSchemaRecord, Specification, SpecificationQueryWire, SpecificationRevision,
14
16
  SpecificationRevisionList, SpecificationSlot, StatusDefinition, StatusFlowSchema,
15
17
  StatusTransitionRule, SummaryQueryWire, SummaryView, Transition, TransitionActor, TransitionCommit,
16
18
  TransitionExecution, TransitionParams, TransitionQueryWire, TransitionReceiptView, Workcard,
@@ -260,6 +262,7 @@ export const StatusFlowSchemaSchema = cast<StatusFlowSchema>({
260
262
  statuses: { type: 'array', minItems: 1, items: StatusDefinitionSchema },
261
263
  transitions: { type: 'array', items: StatusTransitionRuleSchema },
262
264
  label: { type: 'string', maxLength: TITLE_MAX, nullable: true },
265
+ overridable: { type: 'boolean', nullable: true },
263
266
  },
264
267
  required: ['id', 'version', 'statuses', 'transitions'],
265
268
  additionalProperties: false,
@@ -322,6 +325,7 @@ const typeProperties = {
322
325
  labels: { type: 'array', items: Label, nullable: true },
323
326
  code: { ...CodePolicySchema, nullable: true },
324
327
  label: { type: 'string', maxLength: TITLE_MAX, nullable: true },
328
+ overridable: { type: 'boolean', nullable: true },
325
329
  }
326
330
 
327
331
  const typeRequired = ['type', 'kind', 'version', 'fields', 'flows', 'specifications']
@@ -343,6 +347,7 @@ export const ProjectTypeSchemaSchema = cast<ProjectTypeSchema>({
343
347
  kind: { type: 'string', enum: [WorkcardKind.Project] },
344
348
  cardTypes: { type: 'array', items: TypeKey },
345
349
  projectTypes: { type: 'array', items: TypeKey, nullable: true },
350
+ scopedCardTypes: { type: 'boolean', nullable: true },
346
351
  },
347
352
  required: [...typeRequired, 'cardTypes'],
348
353
  additionalProperties: false,
@@ -356,6 +361,7 @@ export const AnyTypeSchemaSchema = cast<AnyTypeSchema>({
356
361
  kind: WorkcardKindSchema,
357
362
  cardTypes: { type: 'array', items: TypeKey, nullable: true },
358
363
  projectTypes: { type: 'array', items: TypeKey, nullable: true },
364
+ scopedCardTypes: { type: 'boolean', nullable: true },
359
365
  },
360
366
  required: typeRequired,
361
367
  additionalProperties: false,
@@ -372,6 +378,96 @@ export const PlanningSchemaBundleSchema = cast<PlanningSchemaBundle>({
372
378
  additionalProperties: false,
373
379
  })
374
380
 
381
+ // ─── Data-defined (scoped) schemas ───────────────────────────────────────────────────────────────
382
+
383
+ export const PlanningSchemaKindSchema = cast<PlanningSchemaKind>({ type: 'string', enum: Object.values(PlanningSchemaKind) })
384
+ export const SchemaOriginSchema = cast<SchemaOrigin>({ type: 'string', enum: Object.values(SchemaOrigin) })
385
+ export const SchemaWriteModeSchema = cast<SchemaWriteMode>({ type: 'string', enum: Object.values(SchemaWriteMode) })
386
+
387
+ export const ScopedSchemaRecordSchema = cast<ScopedSchemaRecord>({
388
+ type: 'object',
389
+ properties: {
390
+ id: OptionalId,
391
+ entityId: Id,
392
+ project: OptionalId,
393
+ kind: PlanningSchemaKindSchema,
394
+ key: TypeKey,
395
+ version: { type: 'number', minimum: 1 },
396
+ /** A card type or a flow — its own schema is applied by `assertTypeSchema` / `assertFlowSchema`. */
397
+ definition: OpenObject,
398
+ retired: { type: 'boolean', nullable: true },
399
+ rev: { type: 'number', minimum: 0, nullable: true },
400
+ createdAt: IsoDate,
401
+ updatedAt: OptionalIsoDate,
402
+ by: { ...TransitionActorSchema, nullable: true },
403
+ },
404
+ required: ['entityId', 'kind', 'key', 'version', 'definition', 'createdAt'],
405
+ additionalProperties: false,
406
+ })
407
+
408
+ export const SchemaKeySchema = cast<SchemaKey>({
409
+ type: 'object',
410
+ properties: { kind: PlanningSchemaKindSchema, key: TypeKey },
411
+ required: ['kind', 'key'],
412
+ additionalProperties: false,
413
+ })
414
+
415
+ const originMap = () => ({ type: 'object', additionalProperties: { type: 'string', enum: Object.values(SchemaOrigin) }, required: [] })
416
+ const keyList = () => ({ type: 'array', items: TypeKey })
417
+
418
+ export const ScopedSchemaBundleSchema = cast<ScopedSchemaBundle>({
419
+ type: 'object',
420
+ properties: {
421
+ version: { type: 'number', minimum: 1 },
422
+ types: { type: 'array', items: AnyTypeSchemaSchema },
423
+ flows: { type: 'array', items: StatusFlowSchemaSchema },
424
+ scope: {
425
+ type: 'object',
426
+ properties: { entityId: Id, project: OptionalId },
427
+ required: ['entityId'],
428
+ additionalProperties: false,
429
+ nullable: true,
430
+ },
431
+ revision: { type: 'number', minimum: 0, nullable: true },
432
+ origins: {
433
+ type: 'object',
434
+ properties: { types: originMap(), flows: originMap() },
435
+ required: ['types', 'flows'],
436
+ additionalProperties: false,
437
+ nullable: true,
438
+ },
439
+ retired: {
440
+ type: 'object',
441
+ properties: { types: keyList(), flows: keyList() },
442
+ required: ['types', 'flows'],
443
+ additionalProperties: false,
444
+ nullable: true,
445
+ },
446
+ },
447
+ required: ['version', 'types', 'flows'],
448
+ additionalProperties: false,
449
+ })
450
+
451
+ export const SchemaListQuerySchema = cast<SchemaListQuery>({
452
+ type: 'object',
453
+ properties: { project: OptionalId },
454
+ required: [],
455
+ additionalProperties: false,
456
+ })
457
+
458
+ export const SchemaDefineRequestSchema = cast<SchemaDefineRequest>({
459
+ type: 'object',
460
+ properties: {
461
+ project: OptionalId,
462
+ mode: nullable(SchemaWriteModeSchema),
463
+ types: { type: 'array', maxItems: MAX_QUERY_LIST, items: WorkcardTypeSchemaSchema, nullable: true },
464
+ flows: { type: 'array', maxItems: MAX_QUERY_LIST, items: StatusFlowSchemaSchema, nullable: true },
465
+ retire: { type: 'array', maxItems: MAX_QUERY_LIST, items: SchemaKeySchema, nullable: true },
466
+ },
467
+ required: [],
468
+ additionalProperties: false,
469
+ })
470
+
375
471
  // ─── Execution ───────────────────────────────────────────────────────────────────────────────────
376
472
 
377
473
  export const WorkcardDraftSchema = cast<WorkcardDraft>({
package/src/types.ts CHANGED
@@ -1,12 +1,11 @@
1
1
  import type { BasicConfig, BasicContext } from '@owlmeans/context'
2
- import type { EntrypointProtocol, OpenRequest, OpenValue } from '@owlmeans/entrypoint'
3
2
  import type { Criteria, ListOptions, ListResult, ResourceRecord } from '@owlmeans/resource'
4
- import type { RouteParent } from '@owlmeans/route'
5
3
  import type { AnySchema, ValidateFunction } from 'ajv'
6
4
  import type {
7
- CodeScope, CodeStyle, CommitState, IntrinsicPolicy, IntrinsicStatus, SpecificationFormat,
8
- TransitionAction, WorkcardKind,
5
+ CodeScope, CodeStyle, CommitState, IntrinsicPolicy, IntrinsicStatus, PlanningSchemaKind, SchemaOrigin,
6
+ SchemaWriteMode, SpecificationFormat, TransitionAction, WorkcardKind,
9
7
  } from './consts.js'
8
+ import type { WorkcardModel } from './models/types.js'
10
9
 
11
10
  // ─── Records ─────────────────────────────────────────────────────────────────────────────────────
12
11
 
@@ -121,9 +120,7 @@ export interface TransitionCommit {
121
120
  * Every key carries a NEW VALUE, never a delta. `fields` and `flows` merge shallowly into the
122
121
  * card's; every other key replaces. Clearing is `Transition.unset`.
123
122
  */
124
- export type WorkcardChanges =
125
- & Partial<Omit<Workcard, 'id' | 'kind' | 'type' | 'entityId' | 'seq' | 'head' | 'createdAt'>>
126
- & Partial<Pick<Specification, 'category' | 'format' | 'body' | 'ref' | 'revision' | 'version' | 'bodyChars'>>
123
+ export interface WorkcardChanges extends Partial<Omit<Workcard, 'id' | 'kind' | 'type' | 'entityId' | 'seq' | 'head' | 'createdAt'>>, Partial<Pick<Specification, 'category' | 'format' | 'body' | 'ref' | 'revision' | 'version' | 'bodyChars'>> {}
127
124
 
128
125
  /** The event. Append-only, never edited; folding every transition of a card in `seq` order IS the card. */
129
126
  export interface Transition extends ResourceRecord {
@@ -186,6 +183,11 @@ export interface StatusFlowSchema {
186
183
  statuses: StatusDefinition[]
187
184
  transitions: StatusTransitionRule[]
188
185
  label?: string
186
+ /**
187
+ * A code-registered flow is sealed against a data-defined override unless it says so. Meaningless
188
+ * on a data-defined flow: a project may override any organization-wide record.
189
+ */
190
+ overridable?: boolean
189
191
  }
190
192
 
191
193
  export interface SpecificationSlot {
@@ -243,12 +245,22 @@ export interface WorkcardTypeSchema {
243
245
  labels?: string[]
244
246
  code?: CodePolicy
245
247
  label?: string
248
+ /**
249
+ * A code-registered card type is sealed against a data-defined override unless it says so.
250
+ * Meaningless on a data-defined type: a project may override any organization-wide record.
251
+ */
252
+ overridable?: boolean
246
253
  }
247
254
 
248
255
  export interface ProjectTypeSchema extends Omit<WorkcardTypeSchema, 'kind'> {
249
256
  kind: WorkcardKind.Project
250
257
  cardTypes: string[]
251
258
  projectTypes?: string[]
259
+ /**
260
+ * The project admits cards of data-defined types (organization-wide or its own) beside the
261
+ * `cardTypes` it lists.
262
+ */
263
+ scopedCardTypes?: boolean
252
264
  }
253
265
 
254
266
  export type AnyTypeSchema = WorkcardTypeSchema | ProjectTypeSchema
@@ -278,6 +290,156 @@ export interface PlanningSchemaRegistry {
278
290
  load: (bundle: PlanningSchemaBundle) => void
279
291
  }
280
292
 
293
+ // ─── Data-defined (scoped) schemas ───────────────────────────────────────────────────────────────
294
+
295
+ /** The layer a record belongs to: an organization, and optionally one of its project cards. */
296
+ export interface SchemaScope {
297
+ entityId: string
298
+ /** A project card id; the organization-wide layer when omitted. */
299
+ project?: string
300
+ }
301
+
302
+ /**
303
+ * A card type or a status flow defined as data — organization-wide, or scoped to one project.
304
+ *
305
+ * `version` is the record's compare-and-set token and is also written into the declaration's own
306
+ * `version`: a write lands only at its layer's next version (1 for a new key).
307
+ */
308
+ export interface ScopedSchemaRecord extends ResourceRecord {
309
+ id?: string
310
+ entityId: string
311
+ /** A project card id; absent on an organization-wide record. */
312
+ project?: string
313
+ kind: PlanningSchemaKind
314
+ /** The type key or the flow id. */
315
+ key: string
316
+ version: number
317
+ /** A `WorkcardTypeSchema` of kind `card`, or a `StatusFlowSchema`. */
318
+ definition: WorkcardTypeSchema | StatusFlowSchema
319
+ /**
320
+ * Retired: offered for nothing new, still resolved for what already uses it. A retired record
321
+ * gives way to a live declaration of the same key in a lower layer.
322
+ */
323
+ retired?: boolean
324
+ /** The organization's schema revision this write landed at — assigned by the store. */
325
+ rev?: number
326
+ createdAt: string
327
+ updatedAt?: string
328
+ by?: TransitionActor
329
+ }
330
+
331
+ export interface ScopedSchemaWhere {
332
+ entityId: string
333
+ /** A project id — that project's layer; `null` — the organization-wide layer; omitted — every layer. */
334
+ project?: string | null
335
+ kind?: PlanningSchemaKind
336
+ key?: string | string[]
337
+ retired?: boolean
338
+ }
339
+
340
+ /**
341
+ * The optional port a store implements to hold data-defined types and flows. A store without it
342
+ * resolves every type and flow from the code registry alone.
343
+ */
344
+ export interface SchemaStore {
345
+ list: (where: ScopedSchemaWhere) => Promise<ScopedSchemaRecord[]>
346
+ /**
347
+ * Write one record — compare-and-set on `version`: the stored record of the same layer and key
348
+ * must be at `record.version - 1` (absent for version 1). Bumps the organization's revision.
349
+ *
350
+ * @throws {SchemaConflict}
351
+ */
352
+ put: (record: ScopedSchemaRecord) => Promise<ScopedSchemaRecord>
353
+ /** Remove a project's whole layer (its project was purged). Bumps the revision. */
354
+ purge: (where: { entityId: string, project: string }) => Promise<number>
355
+ /** The organization's monotonic schema revision — 0 before its first write. */
356
+ revision: (entityId: string) => Promise<number>
357
+ /** Hear of every write of an organization's records, from this process and — where the store can — others. */
358
+ watch?: (listener: (entityId: string) => void) => Unsubscribe
359
+ }
360
+
361
+ export interface SchemaKey {
362
+ kind: PlanningSchemaKind
363
+ key: string
364
+ }
365
+
366
+ /** What a scoped bundle adds, per kind: where each key resolved from, and which keys are retired. */
367
+ export interface ScopedSchemaOrigins {
368
+ types: Record<string, SchemaOrigin>
369
+ flows: Record<string, SchemaOrigin>
370
+ }
371
+
372
+ export interface ScopedSchemaRetired {
373
+ types: string[]
374
+ flows: string[]
375
+ }
376
+
377
+ /**
378
+ * A bundle resolved for one layer: the code registry, overlaid by the organization's records, then
379
+ * by the project's. Retired declarations stay in `types`/`flows` (existing cards still resolve them)
380
+ * and are listed in `retired`. Readers of the plain bundle ignore the extra keys.
381
+ */
382
+ export interface ScopedSchemaBundle extends PlanningSchemaBundle {
383
+ scope?: SchemaScope
384
+ /** The organization's schema revision the bundle was resolved at. */
385
+ revision?: number
386
+ origins?: ScopedSchemaOrigins
387
+ retired?: ScopedSchemaRetired
388
+ }
389
+
390
+ /** A read-only registry over one resolved layer. Its `register*` and `load` refuse. */
391
+ export interface ScopedSchemaRegistry extends PlanningSchemaRegistry {
392
+ scope: SchemaScope
393
+ revision: number
394
+ /** `undefined` for a key the layer does not resolve. */
395
+ originOf: (kind: PlanningSchemaKind, key: string) => SchemaOrigin | undefined
396
+ isRetired: (kind: PlanningSchemaKind, key: string) => boolean
397
+ bundle: () => ScopedSchemaBundle
398
+ }
399
+
400
+ /** Declarations written together — flows first, so a type may name a flow defined beside it. */
401
+ export interface SchemaDeclarations {
402
+ types?: WorkcardTypeSchema[]
403
+ flows?: StatusFlowSchema[]
404
+ }
405
+
406
+ export interface SchemaWriteOptions {
407
+ /** A project card id — that project's layer; the organization-wide layer when omitted. */
408
+ project?: string
409
+ }
410
+
411
+ /**
412
+ * Data-defined types and flows — present on a facade whose store implements
413
+ * {@link PlanningStore.schemas}. Only card types and flows are data-defined; projects and
414
+ * specifications always resolve in code.
415
+ */
416
+ export interface PlanningDefinitions {
417
+ /** The layer resolved: the organization-wide one, or a project's (which includes it). */
418
+ bundle: (project?: string) => Promise<ScopedSchemaBundle>
419
+ registry: (project?: string) => Promise<ScopedSchemaRegistry>
420
+ /** The records of one layer (`project: null` the organization's; omitted — every layer). */
421
+ records: (opts?: { project?: string | null, kind?: PlanningSchemaKind, retired?: boolean }) => Promise<ScopedSchemaRecord[]>
422
+ /**
423
+ * Compare-and-set: `type.version` must be the layer's next version (1 for a new key).
424
+ *
425
+ * @throws {SchemaConflict | SchemaSealed | SchemaInvalid | WorkcardNotFound}
426
+ */
427
+ putType: (type: WorkcardTypeSchema, opts?: SchemaWriteOptions) => Promise<ScopedSchemaRecord>
428
+ /** Compare-and-set, as {@link putType}. */
429
+ putFlow: (flow: StatusFlowSchema, opts?: SchemaWriteOptions) => Promise<ScopedSchemaRecord>
430
+ /** Every declaration at its layer's next version — flows first, then types. */
431
+ define: (declarations: SchemaDeclarations, opts?: SchemaWriteOptions) => Promise<ScopedSchemaRecord[]>
432
+ /** Only the keys the layer lacks, at version 1 — idempotent. */
433
+ seed: (declarations: SchemaDeclarations, opts?: SchemaWriteOptions) => Promise<ScopedSchemaRecord[]>
434
+ /**
435
+ * Retire a key at a layer. Existing cards keep resolving it; nothing new is created with it.
436
+ *
437
+ * @throws {SchemaInUse} a flow still resolved by a live type of an affected layer
438
+ * @throws {UnknownWorkcardType | UnknownStatusFlow} the layer holds no record of the key
439
+ */
440
+ retire: (kind: PlanningSchemaKind, key: string, opts?: SchemaWriteOptions) => Promise<ScopedSchemaRecord>
441
+ }
442
+
281
443
  // ─── Execution and receipts ──────────────────────────────────────────────────────────────────────
282
444
 
283
445
  export interface WorkcardDraft {
@@ -375,7 +537,7 @@ export interface CommitFilter {
375
537
  kind?: WorkcardKind
376
538
  }
377
539
 
378
- export type Unsubscribe = () => void
540
+ export interface Unsubscribe { (): void }
379
541
 
380
542
  export interface CommitSource {
381
543
  status: (transition: string) => Promise<CommitStatus>
@@ -389,7 +551,8 @@ export interface CommitSource {
389
551
  export interface TransitionWhere {
390
552
  entityId: string
391
553
  card?: string | string[]
392
- project?: string
554
+ /** One project, or any of several. */
555
+ project?: string | string[]
393
556
  sinceSeq?: number
394
557
  state?: CommitState
395
558
  action?: TransitionAction | TransitionAction[]
@@ -456,6 +619,8 @@ export interface RelationshipWhere {
456
619
  from?: string | string[]
457
620
  to?: string | string[]
458
621
  type?: string | string[]
622
+ /** The project an edge is filed under. A store that ignores it is narrowed by the facade. */
623
+ project?: string | string[]
459
624
  }
460
625
 
461
626
  export interface RelationshipStore {
@@ -482,6 +647,8 @@ export interface PlanningStore {
482
647
  specs?: SpecificationStore
483
648
  links?: RelationshipStore
484
649
  commits?: CommitSource
650
+ /** Data-defined types and flows. Without it every type and flow resolves in code. */
651
+ schemas?: SchemaStore
485
652
  }
486
653
 
487
654
  // ─── Queries ─────────────────────────────────────────────────────────────────────────────────────
@@ -613,6 +780,29 @@ export interface RevisionsQuery {
613
780
  limit?: number
614
781
  }
615
782
 
783
+ export interface SchemaListQuery {
784
+ /** A project card id — that project's layer; the organization-wide one when omitted. */
785
+ project?: string
786
+ }
787
+
788
+ /** The one write of data-defined types and flows over the wire. */
789
+ export interface SchemaDefineRequest {
790
+ /** A project card id — that project's layer; the organization-wide one when omitted. */
791
+ project?: string
792
+ /** `define` when omitted. */
793
+ mode?: SchemaWriteMode
794
+ types?: WorkcardTypeSchema[]
795
+ flows?: StatusFlowSchema[]
796
+ /** Keys retired at the layer after the declarations are written. */
797
+ retire?: SchemaKey[]
798
+ }
799
+
800
+ /** What a `schema.define` answers: the records it wrote, and the layer as it resolves afterwards. */
801
+ export interface SchemaDefineReply {
802
+ records: ScopedSchemaRecord[]
803
+ bundle: ScopedSchemaBundle
804
+ }
805
+
616
806
  // ─── Facade, scope, service, plugin seam ─────────────────────────────────────────────────────────
617
807
 
618
808
  export interface PlanningScope {
@@ -622,6 +812,12 @@ export interface PlanningScope {
622
812
  service?: string
623
813
  channel?: string
624
814
  actor?: TransitionActor
815
+ /**
816
+ * The only project cards this scope may see and write — the projects themselves and every card
817
+ * whose `parents` name one (a card's document through its card). Every project when omitted.
818
+ * Advisory on a client, where the server decides.
819
+ */
820
+ projects?: string[]
625
821
  }
626
822
 
627
823
  export interface PlanningFacade {
@@ -652,6 +848,8 @@ export interface PlanningFacade {
652
848
  commits: CommitSource
653
849
  execute: (exec: TransitionExecution, opts?: ExecuteOptions) => Promise<TransitionReceipt>
654
850
  model: <T extends Workcard = Workcard>(card: T | string) => Promise<WorkcardModel<T>>
851
+ /** Data-defined types and flows — present only where the store holds them. */
852
+ definitions?: PlanningDefinitions
655
853
  }
656
854
 
657
855
  export interface WithPlanningService {
@@ -717,120 +915,3 @@ export interface PlanningService {
717
915
  /** Runs the ordered `after` chain — called by the process that FOLDED the transition. */
718
916
  committed: (event: CommitEvent) => Promise<void>
719
917
  }
720
-
721
- // ─── Models ──────────────────────────────────────────────────────────────────────────────────────
722
-
723
- export interface ExecuteMeta {
724
- actor?: TransitionActor
725
- cause?: string
726
- key?: string
727
- expectSeq?: number | null
728
- }
729
-
730
- export type ModelExecuteOptions = ExecuteOptions & ExecuteMeta
731
-
732
- export interface SpecificationWriteOptions extends ModelExecuteOptions {
733
- format?: SpecificationFormat
734
- version?: number
735
- ref?: string
736
- /** The title a new document gets; the category when omitted. */
737
- title?: string
738
- /** The specification type; resolved from the slot and the registry when omitted. */
739
- type?: string
740
- }
741
-
742
- export interface WorkcardModel<T extends Workcard = Workcard> {
743
- record: T
744
- id: string
745
- kind: WorkcardKind
746
- type: string
747
- schema: () => AnyTypeSchema
748
- flow: (id?: string) => StatusFlowSchema
749
- statusOf: (flowId?: string) => string
750
- intrinsicOf: (flowId?: string) => IntrinsicStatus
751
- can: (transition: string, flowId?: string) => boolean
752
- available: (flowId?: string) => StatusTransitionRule[]
753
- pending: () => boolean
754
- transit: (transition: string, changes?: WorkcardChanges, opts?: ModelExecuteOptions & { flow?: string }) => Promise<TransitionReceipt>
755
- update: (changes: WorkcardChanges, opts?: ModelExecuteOptions & { unset?: string[] }) => Promise<TransitionReceipt>
756
- remove: (opts?: ModelExecuteOptions) => Promise<TransitionReceipt>
757
- link: (type: string, to: string, fields?: Record<string, unknown>, opts?: ModelExecuteOptions) => Promise<TransitionReceipt>
758
- unlink: (type: string, to: string, opts?: ModelExecuteOptions) => Promise<TransitionReceipt>
759
- children: (query?: Omit<WorkcardQuery, 'parent'>) => Promise<ListResult<Workcard>>
760
- relationships: (query?: RelationshipQuery) => Promise<ListResult<Relationship>>
761
- transitions: (query?: Omit<TransitionQuery, 'card'>) => Promise<ListResult<Transition>>
762
- specification: (category: string) => Promise<Specification | null>
763
- specifications: (query?: SpecificationQuery) => Promise<ListResult<Specification>>
764
- revisions: (category: string, limit?: number) => Promise<SpecificationRevision[]>
765
- /** Create the slot's document, or revise it when it already exists. */
766
- write: (category: string, body: string, opts?: SpecificationWriteOptions) => Promise<TransitionReceipt>
767
- reload: () => Promise<WorkcardModel<T>>
768
- }
769
-
770
- export interface ProjectModel extends WorkcardModel<Project> {
771
- cards: (query?: Omit<WorkcardQuery, 'within' | 'kind'>) => Promise<ListResult<Workcard>>
772
- projects: (query?: Omit<WorkcardQuery, 'within' | 'kind'>) => Promise<ListResult<Workcard>>
773
- summary: (query?: Omit<SummaryQuery, 'parents'>) => Promise<IntrinsicCounts>
774
- /** A `delete` of the project — the store removes everything under it. */
775
- purge: (opts?: ModelExecuteOptions) => Promise<TransitionReceipt>
776
- reload: () => Promise<ProjectModel>
777
- }
778
-
779
- export interface SpecificationModel extends WorkcardModel<Specification> {
780
- body: () => string | undefined
781
- revise: (body: string, opts?: ModelExecuteOptions & { version?: number, ref?: string }) => Promise<TransitionReceipt>
782
- history: (limit?: number) => Promise<SpecificationRevision[]>
783
- reload: () => Promise<SpecificationModel>
784
- }
785
-
786
- // ─── Protocol tree ───────────────────────────────────────────────────────────────────────────────
787
-
788
- export interface PlanningBaseOptions {
789
- /** The base alias every leaf alias derives from (`planningAliases`). */
790
- alias: string
791
- /** Defaults to `PLANNING_PATH`. */
792
- path?: string
793
- parent?: RouteParent
794
- service?: string
795
- }
796
-
797
- export interface PlanningProtocolOptions {
798
- base: PlanningBaseOptions
799
- /** The guard(s) the base carries; every HTTP leaf inherits them. */
800
- guards: string | readonly string[]
801
- gate?: { alias: string, params?: string | readonly string[] }
802
- /**
803
- * The socket base the commit feed hangs under. The feed inherits THAT base's guards; the
804
- * planning base when omitted.
805
- */
806
- socketBase?: RouteParent
807
- }
808
-
809
- export interface PlanningProtocols {
810
- base: EntrypointProtocol<OpenRequest, OpenValue>
811
- schema: {
812
- list: EntrypointProtocol<{}, PlanningSchemaBundle>
813
- }
814
- card: {
815
- list: EntrypointProtocol<{ query: WorkcardQueryWire }, ListResult<Workcard>>
816
- summary: EntrypointProtocol<{ query: SummaryQueryWire }, SummaryView>
817
- get: EntrypointProtocol<{ params: WorkcardParams }, Workcard>
818
- transitions: EntrypointProtocol<{ params: WorkcardParams, query: TransitionQueryWire }, ListResult<Transition>>
819
- specifications: EntrypointProtocol<{ params: WorkcardParams, query: SpecificationQueryWire }, ListResult<Specification>>
820
- }
821
- spec: {
822
- get: EntrypointProtocol<{ params: WorkcardParams }, Specification>
823
- revisions: EntrypointProtocol<{ params: WorkcardParams, query: RevisionsQuery }, SpecificationRevisionList>
824
- }
825
- link: {
826
- list: EntrypointProtocol<{ query: RelationshipQueryWire }, ListResult<Relationship>>
827
- }
828
- transition: {
829
- get: EntrypointProtocol<{ params: TransitionParams }, Transition>
830
- }
831
- execute: EntrypointProtocol<{ body: ExecuteRequest }, TransitionReceiptView>
832
- commit: {
833
- get: EntrypointProtocol<{ params: TransitionParams, query: CommitQuery }, CommitStatus>
834
- events: EntrypointProtocol<{ query: CommitFeedQuery }, CommitEvent>
835
- }
836
- }
package/src/utils.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { planningAliasHelper } from './aliases.js'
2
+ import type { PlanningAliases, PlanningDefinitionAliases } from './aliases/types.js'
3
+
4
+ /** @deprecated compat:factory-refactor — use `planningAliasHelper.planningAliases(…)` */
5
+ export const planningAliases = (base: string): PlanningAliases => planningAliasHelper.planningAliases(base)
6
+
7
+ /** @deprecated compat:factory-refactor — use `planningAliasHelper.planningDefinitionAliases(…)` */
8
+ export const planningDefinitionAliases = (base: string): PlanningDefinitionAliases =>
9
+ planningAliasHelper.planningDefinitionAliases(base)