@jini-ai/cms 0.3.11 → 0.4.0

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 (258) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/README.md +47 -19
  3. package/dist/content-types/agent-tools.d.ts +3 -56
  4. package/dist/content-types/agent-tools.js +22 -6
  5. package/dist/content-types/cleanup.d.ts +18 -13
  6. package/dist/content-types/cleanup.js +16 -11
  7. package/dist/content-types/errors.d.ts +57 -24
  8. package/dist/content-types/errors.js +56 -39
  9. package/dist/content-types/field-defs.d.ts +8 -4
  10. package/dist/content-types/field-defs.js +19 -14
  11. package/dist/content-types/index-provisioning.d.ts +61 -47
  12. package/dist/content-types/index-provisioning.js +90 -66
  13. package/dist/content-types/index.d.ts +4 -3
  14. package/dist/content-types/lifecycle-dispatch.d.ts +11 -5
  15. package/dist/content-types/lifecycle-dispatch.js +5 -4
  16. package/dist/content-types/lifecycle.d.ts +23 -18
  17. package/dist/content-types/lifecycle.js +71 -64
  18. package/dist/content-types/repo.memory.d.ts +5 -4
  19. package/dist/content-types/repo.memory.js +3 -2
  20. package/dist/content-types/tool-registrations.d.ts +6 -8
  21. package/dist/content-types/tool-registrations.js +24 -28
  22. package/dist/content-types/types.d.ts +17 -13
  23. package/dist/content-types/types.js +11 -5
  24. package/dist/content-types/write-service.d.ts +20 -22
  25. package/dist/content-types/write-service.js +78 -75
  26. package/dist/core/authorization.d.ts +15 -0
  27. package/dist/core/authorization.js +2 -0
  28. package/dist/core/commands/change-set.d.ts +15 -7
  29. package/dist/core/commands/command.d.ts +45 -26
  30. package/dist/core/commands/command.js +73 -63
  31. package/dist/core/entity-liveness.d.ts +11 -7
  32. package/dist/core/entity-liveness.js +5 -4
  33. package/dist/core/index.d.ts +12 -5
  34. package/dist/core/index.js +10 -4
  35. package/dist/core/ports.d.ts +25 -24
  36. package/dist/core/ports.js +1 -0
  37. package/dist/core/tools/args.d.ts +49 -0
  38. package/dist/core/tools/args.js +46 -0
  39. package/dist/core/tools/index.d.ts +3 -0
  40. package/dist/core/tools/index.js +3 -0
  41. package/dist/entries/agent-tools.d.ts +1 -73
  42. package/dist/entries/agent-tools.js +19 -13
  43. package/dist/entries/errors.d.ts +28 -14
  44. package/dist/entries/errors.js +17 -11
  45. package/dist/entries/field-validation.d.ts +5 -3
  46. package/dist/entries/field-validation.js +7 -5
  47. package/dist/entries/index.d.ts +2 -2
  48. package/dist/entries/lifecycle-dispatch.d.ts +5 -2
  49. package/dist/entries/lifecycle-dispatch.js +2 -1
  50. package/dist/entries/list.d.ts +4 -2
  51. package/dist/entries/list.js +4 -3
  52. package/dist/entries/repo.memory.d.ts +12 -10
  53. package/dist/entries/repo.memory.js +11 -10
  54. package/dist/entries/tool-registrations.d.ts +6 -8
  55. package/dist/entries/tool-registrations.js +42 -41
  56. package/dist/entries/types.d.ts +0 -7
  57. package/dist/entries/write-service.d.ts +28 -29
  58. package/dist/entries/write-service.js +114 -105
  59. package/dist/http/settings/cms-adapter.d.ts +20 -0
  60. package/dist/http/settings/cms-adapter.js +124 -0
  61. package/dist/http/settings/contracts.d.ts +135 -0
  62. package/dist/http/settings/contracts.js +2 -0
  63. package/dist/http/settings/http.d.ts +10 -0
  64. package/dist/http/settings/http.js +211 -0
  65. package/dist/http/settings/index.d.ts +5 -0
  66. package/dist/http/settings/index.js +4 -0
  67. package/dist/http/settings/shared.d.ts +68 -0
  68. package/dist/http/settings/shared.js +54 -0
  69. package/dist/http/settings/stream.d.ts +24 -0
  70. package/dist/http/settings/stream.js +147 -0
  71. package/dist/media/agent-tools.d.ts +1 -66
  72. package/dist/media/agent-tools.js +5 -1
  73. package/dist/media/blob-gc-lock.d.ts +6 -2
  74. package/dist/media/blob-gc-lock.js +4 -2
  75. package/dist/media/blob-gc.d.ts +64 -51
  76. package/dist/media/blob-gc.js +62 -52
  77. package/dist/media/blob-key.d.ts +1 -1
  78. package/dist/media/content-type-sniffer.d.ts +3 -1
  79. package/dist/media/content-type-sniffer.js +1 -1
  80. package/dist/media/html-attributes.d.ts +9 -5
  81. package/dist/media/html-attributes.js +8 -6
  82. package/dist/media/image-transformer.js +1 -1
  83. package/dist/media/image-transformer.sharp.d.ts +6 -0
  84. package/dist/media/image-transformer.sharp.js +12 -6
  85. package/dist/media/import/fetch-image.d.ts +24 -0
  86. package/dist/media/import/fetch-image.js +137 -0
  87. package/dist/media/import/index.d.ts +3 -0
  88. package/dist/media/import/index.js +3 -0
  89. package/dist/media/import/ports.d.ts +38 -0
  90. package/dist/media/index.d.ts +7 -1
  91. package/dist/media/index.js +1 -0
  92. package/dist/media/media-service.d.ts +14 -10
  93. package/dist/media/media-service.js +57 -52
  94. package/dist/media/ports.d.ts +3 -2
  95. package/dist/media/rendition-service.d.ts +3 -3
  96. package/dist/media/rendition-service.js +38 -37
  97. package/dist/media/repo.memory.d.ts +18 -7
  98. package/dist/media/repo.memory.js +12 -6
  99. package/dist/media/tool-registrations.d.ts +16 -15
  100. package/dist/media/tool-registrations.js +84 -72
  101. package/dist/media/transform-lock.d.ts +22 -12
  102. package/dist/media/transform-lock.js +14 -13
  103. package/dist/media/transform-registry.d.ts +3 -3
  104. package/dist/media/transform-registry.js +19 -18
  105. package/dist/media/transform-types.d.ts +8 -3
  106. package/dist/media/transform-types.js +10 -5
  107. package/dist/media/types.d.ts +21 -4
  108. package/dist/media/types.js +15 -2
  109. package/dist/navigation/agent-tools.d.ts +1 -80
  110. package/dist/navigation/agent-tools.js +15 -3
  111. package/dist/navigation/contracts.d.ts +1 -1
  112. package/dist/navigation/index.d.ts +2 -2
  113. package/dist/navigation/menu-service.d.ts +57 -40
  114. package/dist/navigation/menu-service.js +80 -69
  115. package/dist/navigation/ports.d.ts +1 -1
  116. package/dist/navigation/read-model.d.ts +3 -1
  117. package/dist/navigation/read-model.js +2 -2
  118. package/dist/navigation/reconcile.d.ts +2 -2
  119. package/dist/navigation/reconcile.js +2 -1
  120. package/dist/navigation/repo.memory.d.ts +7 -3
  121. package/dist/navigation/repo.memory.js +4 -2
  122. package/dist/navigation/resolver.d.ts +4 -1
  123. package/dist/navigation/resolver.js +1 -1
  124. package/dist/navigation/tool-registrations.d.ts +6 -8
  125. package/dist/navigation/tool-registrations.js +44 -42
  126. package/dist/navigation/types.d.ts +1 -1
  127. package/dist/presentation/presentation.d.ts +11 -3
  128. package/dist/presentation/presentation.js +13 -6
  129. package/dist/presentation/repo.memory.d.ts +6 -2
  130. package/dist/presentation/repo.memory.js +3 -2
  131. package/dist/settings/agent-tools.d.ts +2 -75
  132. package/dist/settings/agent-tools.js +49 -45
  133. package/dist/settings/agent-value-write-tools.d.ts +22 -0
  134. package/dist/settings/agent-value-write-tools.js +154 -0
  135. package/dist/settings/agent-writable-preferences.js +8 -20
  136. package/dist/settings/agent-write-denylist.d.ts +19 -0
  137. package/dist/settings/agent-write-denylist.js +15 -0
  138. package/dist/settings/change-feed.d.ts +11 -2
  139. package/dist/settings/change-feed.js +4 -4
  140. package/dist/settings/definitions-dispatch.d.ts +8 -3
  141. package/dist/settings/definitions-dispatch.js +5 -5
  142. package/dist/settings/dictionaries/index.d.ts +5 -2
  143. package/dist/settings/dictionaries/index.js +2 -2
  144. package/dist/settings/dictionaries/settings-dialog.ar.js +0 -1
  145. package/dist/settings/dictionaries/settings-dialog.bn.js +0 -1
  146. package/dist/settings/dictionaries/settings-dialog.de.js +0 -1
  147. package/dist/settings/dictionaries/settings-dialog.es.js +0 -1
  148. package/dist/settings/dictionaries/settings-dialog.fa.js +0 -1
  149. package/dist/settings/dictionaries/settings-dialog.fr.js +0 -1
  150. package/dist/settings/dictionaries/settings-dialog.hi.js +0 -1
  151. package/dist/settings/dictionaries/settings-dialog.hu.js +0 -1
  152. package/dist/settings/dictionaries/settings-dialog.id.js +0 -1
  153. package/dist/settings/dictionaries/settings-dialog.it.js +0 -1
  154. package/dist/settings/dictionaries/settings-dialog.ja.js +0 -1
  155. package/dist/settings/dictionaries/settings-dialog.ko.js +0 -1
  156. package/dist/settings/dictionaries/settings-dialog.pl.js +0 -1
  157. package/dist/settings/dictionaries/settings-dialog.pt-BR.js +0 -1
  158. package/dist/settings/dictionaries/settings-dialog.ru.js +0 -1
  159. package/dist/settings/dictionaries/settings-dialog.th.js +0 -1
  160. package/dist/settings/dictionaries/settings-dialog.tr.js +0 -1
  161. package/dist/settings/dictionaries/settings-dialog.uk.js +0 -1
  162. package/dist/settings/dictionaries/settings-dialog.ur.js +0 -1
  163. package/dist/settings/dictionaries/settings-dialog.zh-CN.js +0 -1
  164. package/dist/settings/dictionaries/settings-dialog.zh-TW.js +0 -1
  165. package/dist/settings/ensure-definitions.d.ts +5 -5
  166. package/dist/settings/errors.d.ts +7 -1
  167. package/dist/settings/errors.js +7 -1
  168. package/dist/settings/index.d.ts +4 -1
  169. package/dist/settings/index.js +1 -0
  170. package/dist/settings/ports.d.ts +6 -5
  171. package/dist/settings/principal-lookup.d.ts +9 -0
  172. package/dist/settings/principal-lookup.js +2 -0
  173. package/dist/settings/purge-service.d.ts +5 -4
  174. package/dist/settings/purge-service.js +3 -2
  175. package/dist/settings/settings.d.ts +22 -7
  176. package/dist/settings/settings.js +47 -26
  177. package/dist/settings/tool-registrations.d.ts +25 -32
  178. package/dist/settings/tool-registrations.js +66 -56
  179. package/dist/settings/types.d.ts +1 -1
  180. package/dist/settings/ui-tab-definitions.d.ts +1 -1
  181. package/dist/settings/write-service.d.ts +32 -26
  182. package/dist/settings/write-service.js +26 -20
  183. package/dist/taxonomy/agent-tools.d.ts +1 -66
  184. package/dist/taxonomy/agent-tools.js +25 -15
  185. package/dist/taxonomy/content-lookup.js +1 -1
  186. package/dist/taxonomy/index.d.ts +2 -2
  187. package/dist/taxonomy/merge-term.d.ts +7 -4
  188. package/dist/taxonomy/merge-term.js +7 -5
  189. package/dist/taxonomy/repo.memory.d.ts +42 -19
  190. package/dist/taxonomy/repo.memory.js +14 -12
  191. package/dist/taxonomy/validation-chain.d.ts +39 -18
  192. package/dist/taxonomy/validation-chain.js +35 -25
  193. package/dist/taxonomy/write-service.d.ts +103 -44
  194. package/dist/taxonomy/write-service.js +221 -179
  195. package/dist/trash/adapters/record-store.d.ts +52 -0
  196. package/dist/trash/adapters/record-store.js +36 -0
  197. package/dist/trash/cursor.d.ts +20 -0
  198. package/dist/trash/cursor.js +36 -0
  199. package/dist/trash/follow-ups.d.ts +76 -0
  200. package/dist/trash/follow-ups.js +46 -0
  201. package/dist/trash/index.d.ts +8 -0
  202. package/dist/trash/index.js +8 -0
  203. package/dist/trash/ports.d.ts +308 -0
  204. package/dist/trash/ports.js +2 -0
  205. package/dist/trash/repo.memory.d.ts +50 -0
  206. package/dist/trash/repo.memory.js +114 -0
  207. package/dist/trash/sweeper.d.ts +77 -0
  208. package/dist/trash/sweeper.js +127 -0
  209. package/dist/trash/write-service.d.ts +100 -0
  210. package/dist/trash/write-service.js +242 -0
  211. package/dist/workspace/agent-tools.d.ts +1 -59
  212. package/dist/workspace/agent-tools.js +27 -12
  213. package/dist/workspace/create.d.ts +31 -6
  214. package/dist/workspace/create.js +18 -5
  215. package/dist/workspace/delete.d.ts +18 -13
  216. package/dist/workspace/delete.js +20 -12
  217. package/dist/workspace/index.d.ts +1 -1
  218. package/dist/workspace/repo.memory.d.ts +19 -4
  219. package/dist/workspace/repo.memory.js +26 -4
  220. package/dist/workspace/tool-registrations.d.ts +2 -2
  221. package/dist/workspace/tool-registrations.js +13 -13
  222. package/dist/workspace/update.d.ts +6 -5
  223. package/dist/workspace/update.js +9 -8
  224. package/package.json +44 -38
  225. package/dist/identity/admin-crud-service.d.ts +0 -280
  226. package/dist/identity/admin-crud-service.js +0 -468
  227. package/dist/identity/agent-tool-input.d.ts +0 -58
  228. package/dist/identity/agent-tool-input.js +0 -126
  229. package/dist/identity/agent-tools.d.ts +0 -101
  230. package/dist/identity/agent-tools.js +0 -290
  231. package/dist/identity/auth-service.d.ts +0 -118
  232. package/dist/identity/auth-service.js +0 -170
  233. package/dist/identity/authorize.d.ts +0 -90
  234. package/dist/identity/authorize.js +0 -94
  235. package/dist/identity/grant-service.d.ts +0 -198
  236. package/dist/identity/grant-service.js +0 -361
  237. package/dist/identity/hasher.d.ts +0 -39
  238. package/dist/identity/hasher.js +0 -39
  239. package/dist/identity/index.d.ts +0 -62
  240. package/dist/identity/index.js +0 -54
  241. package/dist/identity/password-policy.d.ts +0 -57
  242. package/dist/identity/password-policy.js +0 -66
  243. package/dist/identity/permission-migrations.d.ts +0 -86
  244. package/dist/identity/permission-migrations.js +0 -67
  245. package/dist/identity/permissions.d.ts +0 -35
  246. package/dist/identity/permissions.js +0 -603
  247. package/dist/identity/ports.d.ts +0 -201
  248. package/dist/identity/repo.memory.d.ts +0 -164
  249. package/dist/identity/repo.memory.js +0 -224
  250. package/dist/identity/seed.d.ts +0 -54
  251. package/dist/identity/seed.js +0 -429
  252. package/dist/identity/tool-registrations.d.ts +0 -50
  253. package/dist/identity/tool-registrations.js +0 -419
  254. package/dist/identity/types.d.ts +0 -185
  255. package/dist/identity/types.js +0 -64
  256. package/dist/identity/username.d.ts +0 -12
  257. package/dist/identity/username.js +0 -14
  258. /package/dist/{identity → media/import}/ports.js +0 -0
@@ -25,52 +25,59 @@
25
25
  * their own repo lookups, so the ordering guarantee holds regardless of how a caller wires them.
26
26
  */
27
27
  export class TaxonomyNotApplicableError extends Error {
28
- constructor(message) {
28
+ constructor(requiredArgs, optionalArgs = {}) {
29
+ const { message } = requiredArgs;
29
30
  super(message);
30
31
  this.name = "TaxonomyNotApplicableError";
31
32
  }
32
33
  }
33
34
  export class WorkspaceMismatchError extends Error {
34
- constructor(message) {
35
+ constructor(requiredArgs, optionalArgs = {}) {
36
+ const { message } = requiredArgs;
35
37
  super(message);
36
38
  this.name = "WorkspaceMismatchError";
37
39
  }
38
40
  }
39
41
  export class ContentTypeMismatchError extends Error {
40
- constructor(message) {
42
+ constructor(requiredArgs, optionalArgs = {}) {
43
+ const { message } = requiredArgs;
41
44
  super(message);
42
45
  this.name = "ContentTypeMismatchError";
43
46
  }
44
47
  }
45
48
  export class TaxonomyNotHierarchicalError extends Error {
46
- constructor(message) {
49
+ constructor(requiredArgs, optionalArgs = {}) {
50
+ const { message } = requiredArgs;
47
51
  super(message);
48
52
  this.name = "TaxonomyNotHierarchicalError";
49
53
  }
50
54
  }
51
55
  export class ParentCrossTaxonomyError extends Error {
52
- constructor(message) {
56
+ constructor(requiredArgs, optionalArgs = {}) {
57
+ const { message } = requiredArgs;
53
58
  super(message);
54
59
  this.name = "ParentCrossTaxonomyError";
55
60
  }
56
61
  }
57
62
  export class TermNotFoundError extends Error {
58
- constructor(message) {
63
+ constructor(requiredArgs, optionalArgs = {}) {
64
+ const { message } = requiredArgs;
59
65
  super(message);
60
66
  this.name = "TermNotFoundError";
61
67
  }
62
68
  }
63
69
  export class HierarchyCycleDetectedError extends Error {
64
- constructor(message) {
70
+ constructor(requiredArgs, optionalArgs = {}) {
71
+ const { message } = requiredArgs;
65
72
  super(message);
66
73
  this.name = "HierarchyCycleDetectedError";
67
74
  }
68
75
  }
69
76
  /**
70
- * CIC U-002 — true if assigning `candidateParentId` as `termId`'s parent would create a cycle:
77
+ * — true if assigning `candidateParentId` as `termId`'s parent would create a cycle:
71
78
  * either immediate self-parenting, or `termId` appearing anywhere in `candidateParentId`'s own
72
79
  * ancestor chain. A full recursive walk, not a fixed-depth or immediate-parent-only comparison
73
- * (U-002-B1) — the exact shape a naive implementation gets wrong (a 3+-hop cycle is the
80
+ * — the exact shape a naive implementation gets wrong (a 3+-hop cycle is the
74
81
  * regression case this exists to catch).
75
82
  *
76
83
  * A `visited` guard bounds the walk even against a pre-existing malformed tree (defensive; no
@@ -79,6 +86,7 @@ export class HierarchyCycleDetectedError extends Error {
79
86
  *
80
87
  * @complexity O(depth) — one `getParentId` call per ancestor hop, each hop visited at most once.
81
88
  * @overallScore 100
89
+ * See docs/decisions/DR-005-ordered-taxonomy-validation.md.
82
90
  */
83
91
  export function wouldCreateCycle(required, _optional = {}) {
84
92
  const { termId, candidateParentId, tree } = required;
@@ -90,7 +98,7 @@ export function wouldCreateCycle(required, _optional = {}) {
90
98
  if (visited.has(current))
91
99
  return false; // malformed/self-looping ancestor data upstream of termId; not this call's cycle
92
100
  visited.add(current);
93
- const parent = tree.getParentId(current);
101
+ const parent = tree.getParentId({ termId: current });
94
102
  if (parent === termId)
95
103
  return true;
96
104
  current = parent;
@@ -98,55 +106,57 @@ export function wouldCreateCycle(required, _optional = {}) {
98
106
  return false;
99
107
  }
100
108
  /**
101
- * U-001-B1/ORD1/ORD2 — the content-join chain: allow-list, THEN workspace, THEN lens, in that
102
- * fixed order. A combined-failure case always reports the first-in-order failure (U-001-ORD1:
103
- * not-on-allow-list always wins over a simultaneous workspace mismatch; U-001-ORD2: a workspace
109
+ * /ORD1/ORD2 — the content-join chain: allow-list, THEN workspace, THEN lens, in that
110
+ * fixed order. A combined-failure case always reports the first-in-order failure (:
111
+ * not-on-allow-list always wins over a simultaneous workspace mismatch; : a workspace
104
112
  * mismatch always wins over a simultaneous lens mismatch).
105
113
  *
106
114
  * @complexity O(1) — three independent comparisons, no loop.
107
115
  * @overallScore 100
116
+ * See docs/decisions/DR-005-ordered-taxonomy-validation.md.
108
117
  */
109
118
  export function validateContentJoin(required, _optional = {}) {
110
119
  const { taxonomyId, isOnAllowList, callerWorkspaceId, resolvedTermWorkspaceId, resolvedContentWorkspaceId, suppliedContentType, resolvedContentKind, } = required;
111
120
  if (!isOnAllowList) {
112
- throw new TaxonomyNotApplicableError(`taxonomy '${taxonomyId}' is not on the allow-list for content type '${suppliedContentType}'`);
121
+ throw new TaxonomyNotApplicableError({ message: `taxonomy '${taxonomyId}' is not on the allow-list for content type '${suppliedContentType}'` });
113
122
  }
114
123
  if (resolvedTermWorkspaceId !== callerWorkspaceId || resolvedContentWorkspaceId !== callerWorkspaceId) {
115
- throw new WorkspaceMismatchError(`term/content workspace does not match the caller's workspace '${callerWorkspaceId}'`);
124
+ throw new WorkspaceMismatchError({ message: `term/content workspace does not match the caller's workspace '${callerWorkspaceId}'` });
116
125
  }
117
126
  if (resolvedContentKind !== suppliedContentType) {
118
- throw new ContentTypeMismatchError(`supplied content type '${suppliedContentType}' does not match the resolved row's own kind '${resolvedContentKind}'`);
127
+ throw new ContentTypeMismatchError({ message: `supplied content type '${suppliedContentType}' does not match the resolved row's own kind '${resolvedContentKind}'` });
119
128
  }
120
129
  }
121
130
  /**
122
- * U-001-B2/B3/ORD3 — the hierarchy chain: hierarchical-mode, THEN same-taxonomy (distinguishing
131
+ * /B3/ORD3 — the hierarchy chain: hierarchical-mode, THEN same-taxonomy (distinguishing
123
132
  * not-found from wrong-taxonomy), THEN cycle, in that fixed order. `null` `candidateParentId`
124
- * (no parent assignment attempted) always short-circuits to a pass regardless of mode (RT-012's
133
+ * (no parent assignment attempted) always short-circuits to a pass regardless of mode (
125
134
  * regression: a no-op parent write must never be rejected).
126
135
  *
127
- * The compound RT-001 regression this chain exists to prevent: a flat taxonomy's candidate parent
136
+ * The compound regression this chain exists to prevent: a flat taxonomy's candidate parent
128
137
  * that ALSO happens to exist in a different taxonomy must report `TAXONOMY_NOT_HIERARCHICAL`,
129
138
  * never `PARENT_CROSS_TAXONOMY` — hierarchical-mode is checked first and is decisive on its own.
130
139
  *
131
- * @complexity O(1) plus the injected `wouldCreateCycle` closure's own cost (U-002, only reached
140
+ * @complexity O(1) plus the injected `wouldCreateCycle` closure's own cost (only reached
132
141
  * once hierarchical-mode and same-taxonomy both pass).
133
142
  * @overallScore 100
143
+ * See docs/decisions/DR-005-ordered-taxonomy-validation.md.
134
144
  */
135
145
  export function validateHierarchyAssignment(required, _optional = {}) {
136
146
  const { taxonomyIsHierarchical, candidateParentId, resolvedParent, childTaxonomyId, wouldCreateCycle: checkCycle } = required;
137
147
  if (candidateParentId === null)
138
148
  return;
139
149
  if (!taxonomyIsHierarchical) {
140
- throw new TaxonomyNotHierarchicalError(`taxonomy '${childTaxonomyId}' is not hierarchical; parentId must be null`);
150
+ throw new TaxonomyNotHierarchicalError({ message: `taxonomy '${childTaxonomyId}' is not hierarchical; parentId must be null` });
141
151
  }
142
152
  if (resolvedParent === null || resolvedParent === "not-applicable") {
143
- throw new TermNotFoundError(`parent term '${candidateParentId}' was not found`);
153
+ throw new TermNotFoundError({ message: `parent term '${candidateParentId}' was not found` });
144
154
  }
145
155
  if (resolvedParent.taxonomyId !== childTaxonomyId) {
146
- throw new ParentCrossTaxonomyError(`parent term '${candidateParentId}' belongs to taxonomy '${resolvedParent.taxonomyId}', not '${childTaxonomyId}'`);
156
+ throw new ParentCrossTaxonomyError({ message: `parent term '${candidateParentId}' belongs to taxonomy '${resolvedParent.taxonomyId}', not '${childTaxonomyId}'` });
147
157
  }
148
- if (checkCycle(candidateParentId)) {
149
- throw new HierarchyCycleDetectedError(`assigning '${candidateParentId}' as parent would create a hierarchy cycle`);
158
+ if (checkCycle({ candidateParentId })) {
159
+ throw new HierarchyCycleDetectedError({ message: `assigning '${candidateParentId}' as parent would create a hierarchy cycle` });
150
160
  }
151
161
  }
152
162
  //# sourceMappingURL=validation-chain.js.map
@@ -1,3 +1,4 @@
1
+ import type { Clock, IdGenerator } from "@jini-ai/core/primitives";
1
2
  import type { TermListPort } from "./list.js";
2
3
  /**
3
4
  * @file The taxonomy write-service's ordinary (non-gated) mutations.
@@ -62,7 +63,9 @@ export interface Term {
62
63
  version: number;
63
64
  }
64
65
  export interface TaxonomyRepoPort {
65
- findById(id: string): Promise<{
66
+ findById({ id }: {
67
+ id: string;
68
+ }): Promise<{
66
69
  id: string;
67
70
  hierarchical: boolean;
68
71
  allowList?: string[] | undefined;
@@ -70,7 +73,9 @@ export interface TaxonomyRepoPort {
70
73
  insert(row: Taxonomy): Promise<unknown>;
71
74
  }
72
75
  export interface TermRepoPort {
73
- findById(id: string): Promise<{
76
+ findById({ id }: {
77
+ id: string;
78
+ }): Promise<{
74
79
  id: string;
75
80
  taxonomyId: string;
76
81
  name?: string | undefined;
@@ -102,9 +107,11 @@ export interface ContentLookupPort {
102
107
  kind: string;
103
108
  } | null>;
104
109
  }
105
- /** ADR-044: the content_types registry's per-type taxonomy allow-list for Collections entries
106
- * (parallel to, never folded into, TAXONOMY_ALLOWED_CONTENT_TYPES — see the decision note).
107
- * `null` = not a live registry type (not applicable). */
110
+ /** : the content_types registry's per-type taxonomy allow-list for Collections entries
111
+ * (parallel to, never folded into, TAXONOMY_ALLOWED_CONTENT_TYPES — see the decision note).
112
+ * `null` = not a live registry type (not applicable).
113
+ * See docs/decisions/DR-005-ordered-taxonomy-validation.md.
114
+ */
108
115
  export interface ContentTypeTaxonomyPolicyPort {
109
116
  taxonomiesFor(params: {
110
117
  contentType: string;
@@ -117,7 +124,9 @@ export interface ContentTypeTaxonomyPolicyPort {
117
124
  * an intentionally parallel (not layered) per-content-type policy carried by a host's own
118
125
  * `content_types` registry. */
119
126
  export declare const TAXONOMY_ALLOWED_CONTENT_TYPES: ReadonlySet<string>;
120
- export declare function isContentTypeOnAllowList(contentType: string): boolean;
127
+ export declare function isContentTypeOnAllowList(requiredArgs: {
128
+ contentType: string;
129
+ }, optionalArgs?: Record<string, never>): boolean;
121
130
  export interface TaxonomyRevisionRow {
122
131
  taxonomyId: string;
123
132
  /** `"delete"` added for `deleteTerm`/`deleteTaxonomy` below — unlike `mergeTerm`'s reuse of
@@ -132,16 +141,10 @@ export interface TaxonomyRevisionRow {
132
141
  export interface TaxonomyRevisionRepoPort {
133
142
  insert(row: TaxonomyRevisionRow): Promise<unknown>;
134
143
  }
135
- export interface ClockPort {
136
- nowIso(): string;
137
- }
138
- export interface IdGeneratorPort {
139
- newId(): string;
140
- }
141
144
  export interface WriteServiceDeps {
142
145
  authorize: AuthorizeFn;
143
- clock: ClockPort;
144
- idGen: IdGeneratorPort;
146
+ clock: Clock;
147
+ idGen: IdGenerator;
145
148
  taxonomies: TaxonomyRepoPort;
146
149
  terms: TermRepoPort;
147
150
  entryTerms: EntryTermRepoPort;
@@ -149,9 +152,13 @@ export interface WriteServiceDeps {
149
152
  /** `core/gated-mutations.stampWatermark`-shaped, injected — same-transaction stamp per mutation.
150
153
  * May be sync (SQLite) or async (PGlite/Postgres); every call site awaits it, so an async stamp
151
154
  * finishes, and its failure fails the write, before the mutation returns. */
152
- stampWatermark: (tx?: unknown) => Promise<void> | void;
155
+ stampWatermark: (required: Record<string, never>, optional?: {
156
+ tx?: unknown;
157
+ }) => Promise<void> | void;
153
158
  outbox: {
154
- enqueue: (event: unknown) => Promise<void>;
159
+ enqueue: ({ event }: {
160
+ event: unknown;
161
+ }) => Promise<void>;
155
162
  };
156
163
  /** The caller's own workspace — `validateContentJoin`'s `callerWorkspaceId` (Finding 1 fix). */
157
164
  workspaceId: string;
@@ -164,14 +171,20 @@ export interface WriteServiceDeps {
164
171
  contentTypeTaxonomyPolicy?: ContentTypeTaxonomyPolicyPort;
165
172
  }
166
173
  export declare class TaxonomyRecordNotFoundError extends Error {
167
- constructor(message: string);
174
+ constructor(requiredArgs: {
175
+ message: string;
176
+ }, optionalArgs?: Record<string, never>);
168
177
  }
169
178
  export declare class TermRecordNotFoundError extends Error {
170
- constructor(message: string);
179
+ constructor(requiredArgs: {
180
+ message: string;
181
+ }, optionalArgs?: Record<string, never>);
171
182
  }
172
183
  /** Finding 1 fix — the target of an `assignTerms` call does not resolve to any real content row. */
173
184
  export declare class ContentRecordNotFoundError extends Error {
174
- constructor(message: string);
185
+ constructor(requiredArgs: {
186
+ message: string;
187
+ }, optionalArgs?: Record<string, never>);
175
188
  }
176
189
  /**
177
190
  * J1 (plan-publish-all-types-2026-09-25.md) — `importTaxonomy`/`importTerm`'s optimistic-concurrency
@@ -182,7 +195,9 @@ export declare class ContentRecordNotFoundError extends Error {
182
195
  * "catch the one it actually called into" rule.
183
196
  */
184
197
  export declare class TaxonomyVersionConflictError extends Error {
185
- constructor(message: string);
198
+ constructor(requiredArgs: {
199
+ message: string;
200
+ }, optionalArgs?: Record<string, never>);
186
201
  }
187
202
  export interface CreateTaxonomyRequired {
188
203
  deps: WriteServiceDeps;
@@ -198,13 +213,17 @@ export interface CreateTermRequired {
198
213
  principalId: string;
199
214
  taxonomyId: string;
200
215
  name: string;
216
+ }
217
+ export interface CreateTermOptional {
201
218
  parentId?: string | null | undefined;
202
219
  }
203
- /** AC-03/AC-13/EC-04 — validates `parentId` via `validateHierarchyAssignment` before writing. A
220
+ /** — validates `parentId` via `validateHierarchyAssignment` before writing. A
204
221
  * freshly-created term has no descendants yet, so it structurally cannot be a cycle source; the
205
- * cycle check is therefore always a no-op (`() => false`) here, unlike a reparent of an existing
206
- * term (not yet built — no certified test in this slice exercises it). */
207
- export declare function createTerm(required: CreateTermRequired, _optional?: Record<string, never>): Promise<Term>;
222
+ * cycle check is therefore always a no-op (` => false`) here, unlike a reparent of an existing
223
+ * term (not yet built — no certified test in this slice exercises it).
224
+ * See docs/decisions/DR-005-ordered-taxonomy-validation.md.
225
+ */
226
+ export declare function createTerm(required: CreateTermRequired, optional?: CreateTermOptional): Promise<Term>;
208
227
  /**
209
228
  * Additive capability beyond the certified `TaxonomyRepoPort` — `findById`'s narrow return
210
229
  * (`{id, hierarchical, allowList?}`) doesn't carry `version`/`name`/`status`/`updatedAt`, which
@@ -212,7 +231,9 @@ export declare function createTerm(required: CreateTermRequired, _optional?: Rec
212
231
  * write an existing row back. Same beyond-the-certified-port precedent as `DeletableTaxonomyRepoPort`.
213
232
  */
214
233
  export interface ImportableTaxonomyRepoPort {
215
- findByIdFull(id: string): Promise<Taxonomy | null>;
234
+ findByIdFull({ id }: {
235
+ id: string;
236
+ }): Promise<Taxonomy | null>;
216
237
  update(row: Taxonomy): Promise<unknown>;
217
238
  }
218
239
  export interface ImportTaxonomyRequired {
@@ -249,7 +270,9 @@ export declare function importTaxonomy(required: ImportTaxonomyRequired, _option
249
270
  * `TermRepoPort` already has `update`, unlike taxonomies, so no additive `update` is needed here.
250
271
  */
251
272
  export interface ImportableTermRepoPort {
252
- findByIdFull(id: string): Promise<Term | null>;
273
+ findByIdFull({ id }: {
274
+ id: string;
275
+ }): Promise<Term | null>;
253
276
  }
254
277
  export interface ImportTermRequired {
255
278
  deps: WriteServiceDeps & {
@@ -260,10 +283,12 @@ export interface ImportTermRequired {
260
283
  id: string;
261
284
  taxonomyId: string;
262
285
  name: string;
263
- parentId?: string | null | undefined;
264
286
  /** Same three-way CAS contract as `importTaxonomy.expectedVersion`. */
265
287
  expectedVersion: number | undefined;
266
288
  }
289
+ export interface ImportTermOptional {
290
+ parentId?: string | null | undefined;
291
+ }
267
292
  /**
268
293
  * Slice J1 — the publish-content import chokepoint for `terms`. Address (name within
269
294
  * `(taxonomyId, parentId)`) uniqueness is the publish factory's own precheck, not this function's
@@ -277,16 +302,23 @@ export interface ImportTermRequired {
277
302
  * @complexity O(d) — one taxonomy lookup, one id lookup, one optional parent lookup, `d` ancestor
278
303
  * lookups (the candidate parent's depth), one insert-or-update, one revision append.
279
304
  */
280
- export declare function importTerm(required: ImportTermRequired, _optional?: Record<string, never>): Promise<Term>;
305
+ export declare function importTerm(required: ImportTermRequired, optional?: ImportTermOptional): Promise<Term>;
281
306
  export interface RenameTermRequired {
282
- deps: WriteServiceDeps;
307
+ deps: WriteServiceDeps & {
308
+ /** Required shared transaction. All repos, the watermark and outbox
309
+ * must share the store/connection opened by this port. */
310
+ transaction: TransactionalRepoPort["transaction"];
311
+ };
283
312
  principalId: string;
284
313
  termId: string;
285
314
  newName: string;
286
315
  }
287
- /** AC-15/AC-19/AC-25/REQ-12/REQ-17 — same-tx rename + revision (carrying the pre-rename state) +
288
- * watermark + outbox. `authorize()` runs before the term lookup, so a denied caller produces zero
289
- * side effects of any kind. */
316
+ /** — same-tx rename + revision (carrying the pre-rename state) +
317
+ * watermark + outbox. `authorize` runs before the term lookup, so a denied caller produces zero
318
+ * side effects of any kind. A missing transaction capability fails closed before any lookup
319
+ * or write; a caller must supply a real shared transaction for durable atomicity.
320
+ * See docs/decisions/DR-005-ordered-taxonomy-validation.md.
321
+ */
290
322
  export declare function renameTerm(required: RenameTermRequired, _optional?: Record<string, never>): Promise<Term>;
291
323
  export interface AssignTermsRequired {
292
324
  deps: WriteServiceDeps;
@@ -315,14 +347,16 @@ export interface UnassignTermsRequired {
315
347
  contentId: string;
316
348
  termIds: string[];
317
349
  }
318
- /** SPEC-018 REQ-07/REQ-13/REQ-14/REQ-17/REQ-22 — spec debt this codebase never built (the spec
350
+ /** — spec debt this codebase never built (the spec
319
351
  * always named "assign/unassign tools"; only `assignTerms` shipped). Same
320
352
  * authorize -> validateAssignmentTarget -> write -> stamp -> outbox chokepoint as `assignTerms`,
321
- * and — like `assignTerms` — never produces a `taxonomy_revisions` row (REQ-13/INV-05's disclosed
353
+ * and — like `assignTerms` — never produces a `taxonomy_revisions` row ( disclosed
322
354
  * narrowing applies equally to removal). Idempotent: unassigning a row that isn't there is a no-op,
323
- * not an error (`remove()`'s 0-vs-1 return is intentionally not surfaced to the caller). Chosen over
355
+ * not an error (`remove`'s 0-vs-1 return is intentionally not surfaced to the caller). Chosen over
324
356
  * a "set terms" replace call — see the taxonomy plan's "What the docs settle" #3 for why replace
325
- * risks silently erasing a concurrent assignment. */
357
+ * risks silently erasing a concurrent assignment.
358
+ * See docs/decisions/DR-005-ordered-taxonomy-validation.md.
359
+ */
326
360
  export declare function unassignTerms(required: UnassignTermsRequired, _optional?: Record<string, never>): Promise<void>;
327
361
  export interface EntryTermsCleanupPort {
328
362
  deleteByContent(params: {
@@ -343,8 +377,18 @@ export interface OnContentDeletedRequired {
343
377
  * `entry_terms` row that is inert on read; a periodic/boot reconciliation sweep — modeled by
344
378
  * re-invoking this same function for the orphan — is the backstop, never a hard failure). A
345
379
  * no-op for content with no
346
- * assigned terms, never an error. */
347
- export declare function onContentDeleted(required: OnContentDeletedRequired, _optional?: Record<string, never>): Promise<void>;
380
+ * assigned terms, never an error. Repository failures are warnings through the optional
381
+ * logger port; logger failure also cannot turn cleanup into a hard failure. Hosts should
382
+ * wire the logger for diagnostics; legacy callers without it remain silent. */
383
+ export declare function onContentDeleted(required: OnContentDeletedRequired, optional?: {
384
+ logger?: {
385
+ warn(required: {
386
+ message: string;
387
+ error: unknown;
388
+ event: OnContentDeletedRequired["event"];
389
+ }): void | Promise<void>;
390
+ };
391
+ }): Promise<void>;
348
392
  /**
349
393
  * Additive capabilities beyond the certified `TaxonomyRepoPort`/`TermRepoPort`/`EntryTermRepoPort`
350
394
  * — same beyond-the-certified-port precedent `MergeableEntryTermRepoPort` established in this
@@ -354,10 +398,14 @@ export declare function onContentDeleted(required: OnContentDeletedRequired, _op
354
398
  * SQLite adapter of its own — see this file's header and `repo.memory.ts`'s header for why).
355
399
  */
356
400
  export interface DeletableTaxonomyRepoPort {
357
- delete(id: string): Promise<void>;
401
+ delete({ id }: {
402
+ id: string;
403
+ }): Promise<void>;
358
404
  }
359
405
  export interface DeletableTermRepoPort {
360
- delete(id: string): Promise<void>;
406
+ delete({ id }: {
407
+ id: string;
408
+ }): Promise<void>;
361
409
  /** Direct-child count for `termId` as a parent. `deleteTerm` refuses to delete a term with
362
410
  * children still pointing `parentId` at it — that reference would otherwise dangle the moment
363
411
  * the parent row is gone, corrupting the hierarchy `validateHierarchyAssignment` polices on the
@@ -386,19 +434,28 @@ export interface AssignmentCountEntryTermRepoPort {
386
434
  * assigned" instead of a generic failure. */
387
435
  export declare class TermHasAssignedContentError extends Error {
388
436
  readonly assignedCount: number;
389
- constructor(message: string, assignedCount: number);
437
+ constructor(requiredArgs: {
438
+ message: string;
439
+ assignedCount: number;
440
+ }, _optionalArgs?: Record<string, never>);
390
441
  }
391
442
  /** See `DeletableTermRepoPort.countChildren`'s doc comment for why this guard exists. Carries
392
443
  * `childCount` for the same reason `TermHasAssignedContentError` carries `assignedCount`. */
393
444
  export declare class TermHasChildTermsError extends Error {
394
445
  readonly childCount: number;
395
- constructor(message: string, childCount: number);
446
+ constructor(requiredArgs: {
447
+ message: string;
448
+ childCount: number;
449
+ }, _optionalArgs?: Record<string, never>);
396
450
  }
397
451
  /** `deleteTaxonomy`'s content-assignment guard — `assignedCount` is the sum across every member
398
452
  * term, not a single term's count. */
399
453
  export declare class TaxonomyHasAssignedContentError extends Error {
400
454
  readonly assignedCount: number;
401
- constructor(message: string, assignedCount: number);
455
+ constructor(requiredArgs: {
456
+ message: string;
457
+ assignedCount: number;
458
+ }, _optionalArgs?: Record<string, never>);
402
459
  }
403
460
  /**
404
461
  * Opens/commits/rolls back one transaction around `fn` — the same shape and contract as this
@@ -426,7 +483,9 @@ export declare class TaxonomyHasAssignedContentError extends Error {
426
483
  * kind of backend they're running against.
427
484
  */
428
485
  export interface TransactionalRepoPort {
429
- transaction<T>(fn: () => Promise<T>): Promise<T>;
486
+ transaction<T>({ fn }: {
487
+ fn: () => Promise<T>;
488
+ }): Promise<T>;
430
489
  }
431
490
  export interface DeleteTermRequired {
432
491
  deps: WriteServiceDeps & {