@jini-ai/cms 0.3.10 → 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 +106 -45
  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,24 +141,24 @@ 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;
148
151
  revisions: TaxonomyRevisionRepoPort;
149
- /** `core/gated-mutations.stampWatermark`-shaped, injected — same-transaction stamp per mutation. */
150
- stampWatermark: (tx?: unknown) => void;
152
+ /** `core/gated-mutations.stampWatermark`-shaped, injected — same-transaction stamp per mutation.
153
+ * May be sync (SQLite) or async (PGlite/Postgres); every call site awaits it, so an async stamp
154
+ * finishes, and its failure fails the write, before the mutation returns. */
155
+ stampWatermark: (required: Record<string, never>, optional?: {
156
+ tx?: unknown;
157
+ }) => Promise<void> | void;
151
158
  outbox: {
152
- enqueue: (event: unknown) => Promise<void>;
159
+ enqueue: ({ event }: {
160
+ event: unknown;
161
+ }) => Promise<void>;
153
162
  };
154
163
  /** The caller's own workspace — `validateContentJoin`'s `callerWorkspaceId` (Finding 1 fix). */
155
164
  workspaceId: string;
@@ -162,14 +171,20 @@ export interface WriteServiceDeps {
162
171
  contentTypeTaxonomyPolicy?: ContentTypeTaxonomyPolicyPort;
163
172
  }
164
173
  export declare class TaxonomyRecordNotFoundError extends Error {
165
- constructor(message: string);
174
+ constructor(requiredArgs: {
175
+ message: string;
176
+ }, optionalArgs?: Record<string, never>);
166
177
  }
167
178
  export declare class TermRecordNotFoundError extends Error {
168
- constructor(message: string);
179
+ constructor(requiredArgs: {
180
+ message: string;
181
+ }, optionalArgs?: Record<string, never>);
169
182
  }
170
183
  /** Finding 1 fix — the target of an `assignTerms` call does not resolve to any real content row. */
171
184
  export declare class ContentRecordNotFoundError extends Error {
172
- constructor(message: string);
185
+ constructor(requiredArgs: {
186
+ message: string;
187
+ }, optionalArgs?: Record<string, never>);
173
188
  }
174
189
  /**
175
190
  * J1 (plan-publish-all-types-2026-09-25.md) — `importTaxonomy`/`importTerm`'s optimistic-concurrency
@@ -180,7 +195,9 @@ export declare class ContentRecordNotFoundError extends Error {
180
195
  * "catch the one it actually called into" rule.
181
196
  */
182
197
  export declare class TaxonomyVersionConflictError extends Error {
183
- constructor(message: string);
198
+ constructor(requiredArgs: {
199
+ message: string;
200
+ }, optionalArgs?: Record<string, never>);
184
201
  }
185
202
  export interface CreateTaxonomyRequired {
186
203
  deps: WriteServiceDeps;
@@ -196,13 +213,17 @@ export interface CreateTermRequired {
196
213
  principalId: string;
197
214
  taxonomyId: string;
198
215
  name: string;
216
+ }
217
+ export interface CreateTermOptional {
199
218
  parentId?: string | null | undefined;
200
219
  }
201
- /** AC-03/AC-13/EC-04 — validates `parentId` via `validateHierarchyAssignment` before writing. A
220
+ /** — validates `parentId` via `validateHierarchyAssignment` before writing. A
202
221
  * freshly-created term has no descendants yet, so it structurally cannot be a cycle source; the
203
- * cycle check is therefore always a no-op (`() => false`) here, unlike a reparent of an existing
204
- * term (not yet built — no certified test in this slice exercises it). */
205
- 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>;
206
227
  /**
207
228
  * Additive capability beyond the certified `TaxonomyRepoPort` — `findById`'s narrow return
208
229
  * (`{id, hierarchical, allowList?}`) doesn't carry `version`/`name`/`status`/`updatedAt`, which
@@ -210,7 +231,9 @@ export declare function createTerm(required: CreateTermRequired, _optional?: Rec
210
231
  * write an existing row back. Same beyond-the-certified-port precedent as `DeletableTaxonomyRepoPort`.
211
232
  */
212
233
  export interface ImportableTaxonomyRepoPort {
213
- findByIdFull(id: string): Promise<Taxonomy | null>;
234
+ findByIdFull({ id }: {
235
+ id: string;
236
+ }): Promise<Taxonomy | null>;
214
237
  update(row: Taxonomy): Promise<unknown>;
215
238
  }
216
239
  export interface ImportTaxonomyRequired {
@@ -247,7 +270,9 @@ export declare function importTaxonomy(required: ImportTaxonomyRequired, _option
247
270
  * `TermRepoPort` already has `update`, unlike taxonomies, so no additive `update` is needed here.
248
271
  */
249
272
  export interface ImportableTermRepoPort {
250
- findByIdFull(id: string): Promise<Term | null>;
273
+ findByIdFull({ id }: {
274
+ id: string;
275
+ }): Promise<Term | null>;
251
276
  }
252
277
  export interface ImportTermRequired {
253
278
  deps: WriteServiceDeps & {
@@ -258,10 +283,12 @@ export interface ImportTermRequired {
258
283
  id: string;
259
284
  taxonomyId: string;
260
285
  name: string;
261
- parentId?: string | null | undefined;
262
286
  /** Same three-way CAS contract as `importTaxonomy.expectedVersion`. */
263
287
  expectedVersion: number | undefined;
264
288
  }
289
+ export interface ImportTermOptional {
290
+ parentId?: string | null | undefined;
291
+ }
265
292
  /**
266
293
  * Slice J1 — the publish-content import chokepoint for `terms`. Address (name within
267
294
  * `(taxonomyId, parentId)`) uniqueness is the publish factory's own precheck, not this function's
@@ -275,16 +302,23 @@ export interface ImportTermRequired {
275
302
  * @complexity O(d) — one taxonomy lookup, one id lookup, one optional parent lookup, `d` ancestor
276
303
  * lookups (the candidate parent's depth), one insert-or-update, one revision append.
277
304
  */
278
- export declare function importTerm(required: ImportTermRequired, _optional?: Record<string, never>): Promise<Term>;
305
+ export declare function importTerm(required: ImportTermRequired, optional?: ImportTermOptional): Promise<Term>;
279
306
  export interface RenameTermRequired {
280
- 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
+ };
281
312
  principalId: string;
282
313
  termId: string;
283
314
  newName: string;
284
315
  }
285
- /** AC-15/AC-19/AC-25/REQ-12/REQ-17 — same-tx rename + revision (carrying the pre-rename state) +
286
- * watermark + outbox. `authorize()` runs before the term lookup, so a denied caller produces zero
287
- * 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
+ */
288
322
  export declare function renameTerm(required: RenameTermRequired, _optional?: Record<string, never>): Promise<Term>;
289
323
  export interface AssignTermsRequired {
290
324
  deps: WriteServiceDeps;
@@ -313,14 +347,16 @@ export interface UnassignTermsRequired {
313
347
  contentId: string;
314
348
  termIds: string[];
315
349
  }
316
- /** 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
317
351
  * always named "assign/unassign tools"; only `assignTerms` shipped). Same
318
352
  * authorize -> validateAssignmentTarget -> write -> stamp -> outbox chokepoint as `assignTerms`,
319
- * 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
320
354
  * narrowing applies equally to removal). Idempotent: unassigning a row that isn't there is a no-op,
321
- * 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
322
356
  * a "set terms" replace call — see the taxonomy plan's "What the docs settle" #3 for why replace
323
- * risks silently erasing a concurrent assignment. */
357
+ * risks silently erasing a concurrent assignment.
358
+ * See docs/decisions/DR-005-ordered-taxonomy-validation.md.
359
+ */
324
360
  export declare function unassignTerms(required: UnassignTermsRequired, _optional?: Record<string, never>): Promise<void>;
325
361
  export interface EntryTermsCleanupPort {
326
362
  deleteByContent(params: {
@@ -341,8 +377,18 @@ export interface OnContentDeletedRequired {
341
377
  * `entry_terms` row that is inert on read; a periodic/boot reconciliation sweep — modeled by
342
378
  * re-invoking this same function for the orphan — is the backstop, never a hard failure). A
343
379
  * no-op for content with no
344
- * assigned terms, never an error. */
345
- 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>;
346
392
  /**
347
393
  * Additive capabilities beyond the certified `TaxonomyRepoPort`/`TermRepoPort`/`EntryTermRepoPort`
348
394
  * — same beyond-the-certified-port precedent `MergeableEntryTermRepoPort` established in this
@@ -352,10 +398,14 @@ export declare function onContentDeleted(required: OnContentDeletedRequired, _op
352
398
  * SQLite adapter of its own — see this file's header and `repo.memory.ts`'s header for why).
353
399
  */
354
400
  export interface DeletableTaxonomyRepoPort {
355
- delete(id: string): Promise<void>;
401
+ delete({ id }: {
402
+ id: string;
403
+ }): Promise<void>;
356
404
  }
357
405
  export interface DeletableTermRepoPort {
358
- delete(id: string): Promise<void>;
406
+ delete({ id }: {
407
+ id: string;
408
+ }): Promise<void>;
359
409
  /** Direct-child count for `termId` as a parent. `deleteTerm` refuses to delete a term with
360
410
  * children still pointing `parentId` at it — that reference would otherwise dangle the moment
361
411
  * the parent row is gone, corrupting the hierarchy `validateHierarchyAssignment` polices on the
@@ -384,19 +434,28 @@ export interface AssignmentCountEntryTermRepoPort {
384
434
  * assigned" instead of a generic failure. */
385
435
  export declare class TermHasAssignedContentError extends Error {
386
436
  readonly assignedCount: number;
387
- constructor(message: string, assignedCount: number);
437
+ constructor(requiredArgs: {
438
+ message: string;
439
+ assignedCount: number;
440
+ }, _optionalArgs?: Record<string, never>);
388
441
  }
389
442
  /** See `DeletableTermRepoPort.countChildren`'s doc comment for why this guard exists. Carries
390
443
  * `childCount` for the same reason `TermHasAssignedContentError` carries `assignedCount`. */
391
444
  export declare class TermHasChildTermsError extends Error {
392
445
  readonly childCount: number;
393
- constructor(message: string, childCount: number);
446
+ constructor(requiredArgs: {
447
+ message: string;
448
+ childCount: number;
449
+ }, _optionalArgs?: Record<string, never>);
394
450
  }
395
451
  /** `deleteTaxonomy`'s content-assignment guard — `assignedCount` is the sum across every member
396
452
  * term, not a single term's count. */
397
453
  export declare class TaxonomyHasAssignedContentError extends Error {
398
454
  readonly assignedCount: number;
399
- constructor(message: string, assignedCount: number);
455
+ constructor(requiredArgs: {
456
+ message: string;
457
+ assignedCount: number;
458
+ }, _optionalArgs?: Record<string, never>);
400
459
  }
401
460
  /**
402
461
  * Opens/commits/rolls back one transaction around `fn` — the same shape and contract as this
@@ -424,7 +483,9 @@ export declare class TaxonomyHasAssignedContentError extends Error {
424
483
  * kind of backend they're running against.
425
484
  */
426
485
  export interface TransactionalRepoPort {
427
- transaction<T>(fn: () => Promise<T>): Promise<T>;
486
+ transaction<T>({ fn }: {
487
+ fn: () => Promise<T>;
488
+ }): Promise<T>;
428
489
  }
429
490
  export interface DeleteTermRequired {
430
491
  deps: WriteServiceDeps & {