@jini-ai/cms 0.3.11 → 0.4.1

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 (262) 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 +27 -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/core/tools/registration-kit.d.ts +0 -346
  226. package/dist/core/tools/registration-kit.js +0 -426
  227. package/dist/identity/admin-crud-service.d.ts +0 -280
  228. package/dist/identity/admin-crud-service.js +0 -468
  229. package/dist/identity/agent-tool-input.d.ts +0 -58
  230. package/dist/identity/agent-tool-input.js +0 -126
  231. package/dist/identity/agent-tools.d.ts +0 -101
  232. package/dist/identity/agent-tools.js +0 -290
  233. package/dist/identity/auth-service.d.ts +0 -118
  234. package/dist/identity/auth-service.js +0 -170
  235. package/dist/identity/authorize.d.ts +0 -90
  236. package/dist/identity/authorize.js +0 -94
  237. package/dist/identity/grant-service.d.ts +0 -198
  238. package/dist/identity/grant-service.js +0 -361
  239. package/dist/identity/hasher.d.ts +0 -39
  240. package/dist/identity/hasher.js +0 -39
  241. package/dist/identity/index.d.ts +0 -62
  242. package/dist/identity/index.js +0 -54
  243. package/dist/identity/password-policy.d.ts +0 -57
  244. package/dist/identity/password-policy.js +0 -66
  245. package/dist/identity/permission-migrations.d.ts +0 -86
  246. package/dist/identity/permission-migrations.js +0 -67
  247. package/dist/identity/permissions.d.ts +0 -35
  248. package/dist/identity/permissions.js +0 -603
  249. package/dist/identity/ports.d.ts +0 -201
  250. package/dist/identity/repo.memory.d.ts +0 -164
  251. package/dist/identity/repo.memory.js +0 -224
  252. package/dist/identity/seed.d.ts +0 -54
  253. package/dist/identity/seed.js +0 -429
  254. package/dist/identity/tool-registrations.d.ts +0 -50
  255. package/dist/identity/tool-registrations.js +0 -419
  256. package/dist/identity/types.d.ts +0 -185
  257. package/dist/identity/types.js +0 -64
  258. package/dist/identity/username.d.ts +0 -12
  259. package/dist/identity/username.js +0 -14
  260. package/dist/server/index.d.ts +0 -28
  261. package/dist/server/index.js +0 -28
  262. /package/dist/{identity → media/import}/ports.js +0 -0
@@ -1,111 +1,117 @@
1
+ import { nowIso as kernelNowIso } from "@jini-ai/core/primitives";
1
2
  import { ContentTypeLifecycleError, ContentTypeNotFoundError, ForbiddenError, VersionConflictError } from "./errors.js";
2
3
  async function resolveActiveOrDeprecated(repo, workspaceId, key) {
3
4
  const current = await repo.findByKey({ workspaceId, key });
4
5
  if (!current) {
5
- return { ok: false, error: new ContentTypeNotFoundError(`content type '${key}' was not found in workspace '${workspaceId}'`) };
6
+ return { ok: false, error: new ContentTypeNotFoundError({ message: `content type '${key}' was not found in workspace '${workspaceId}'` }) };
6
7
  }
7
8
  return { ok: true, value: current };
8
9
  }
9
10
  /**
10
- * AC-13/AC-19 — flips an active type to `deprecated` (blocks only NEW entry creation, REQ-10) and
11
- * enqueues `content_type.deprecated` in the same call. Rejected unconditionally (INV-06) if the
11
+ * — flips an active type to `deprecated` (blocks only NEW entry creation) and
12
+ * enqueues `content_type.deprecated` in the same call. Rejected unconditionally if the
12
13
  * type is already `tombstone` — deprecate can never be used to "step back" out of tombstone.
13
14
  *
14
15
  * @complexity O(1) plus one repo read, one same-tx write pair, and one outbox enqueue.
15
16
  * @overallScore 100
17
+ * See docs/decisions/DR-002-content-lifecycle-and-cleanup.md.
16
18
  */
17
19
  export async function deprecateContentType(required) {
18
20
  const { deps, input } = required;
19
- const authResult = await deps.authorize({ principalId: input.actorId, permission: "admin.collections.manage", workspaceId: input.workspaceId, entityType: "content-type" });
21
+ const authResult = await deps.authorize({ principalId: input.actorId, permission: "admin.collections.manage", workspaceId: input.workspaceId }, { entityType: "content-type" });
20
22
  if (!authResult.allowed) {
21
- return { ok: false, error: new ForbiddenError(`principal '${input.actorId}' cannot deprecate content type '${input.key}' (${authResult.reason})`) };
23
+ return { ok: false, error: new ForbiddenError({ message: `principal '${input.actorId}' cannot deprecate content type '${input.key}' (${authResult.reason})` }) };
22
24
  }
23
25
  const resolved = await resolveActiveOrDeprecated(deps.repo, input.workspaceId, input.key);
24
26
  if (!resolved.ok)
25
27
  return resolved;
26
28
  const current = resolved.value;
27
29
  if (current.status === "tombstone") {
28
- return { ok: false, error: new ContentTypeLifecycleError(`content type '${input.key}' is tombstoned; INV-06 forbids any transition out of tombstone`) };
30
+ // See docs/decisions/DR-002-content-lifecycle-and-cleanup.md for the invariant behind this refusal; keep external identifiers out of caller-facing messages.
31
+ return { ok: false, error: new ContentTypeLifecycleError({ message: `content type '${input.key}' is tombstoned; no transition out of tombstone is allowed` }) };
29
32
  }
30
33
  if (input.expectedVersion !== current.version) {
31
- return { ok: false, error: new VersionConflictError(`expected version ${input.expectedVersion} for content type '${input.key}', found ${current.version}`) };
34
+ return { ok: false, error: new VersionConflictError({ message: `expected version ${input.expectedVersion} for content type '${input.key}', found ${current.version}` }) };
32
35
  }
33
- const now = deps.clock.nowIso();
36
+ const now = kernelNowIso({ clock: deps.clock });
34
37
  const updated = { ...current, status: "deprecated", version: current.version + 1 };
35
- await deps.repo.transaction(async () => {
36
- await deps.repo.save(updated);
37
- await deps.repo.appendRevision({
38
- contentTypeKey: input.key,
39
- workspaceId: input.workspaceId,
40
- op: "field-change",
41
- stateJson: updated,
42
- actorId: input.actorId,
43
- principalKind: input.principalKind ?? null,
44
- delegatedByWorkspaceId: null,
45
- delegatedById: null,
46
- recordedAt: now,
47
- });
48
- });
38
+ await deps.repo.transaction({ fn: async () => {
39
+ await deps.repo.save(updated);
40
+ await deps.repo.appendRevision({
41
+ contentTypeKey: input.key,
42
+ workspaceId: input.workspaceId,
43
+ op: "field-change",
44
+ stateJson: updated,
45
+ actorId: input.actorId,
46
+ principalKind: input.principalKind ?? null,
47
+ delegatedByWorkspaceId: null,
48
+ delegatedById: null,
49
+ recordedAt: now,
50
+ });
51
+ } });
49
52
  await deps.outbox.enqueue({ name: "content_type.deprecated", payload: { workspaceId: input.workspaceId, key: input.key } });
50
53
  return { ok: true, value: { contentType: updated } };
51
54
  }
52
55
  /**
53
- * AC-13 — flips a `deprecated` (or already-`active`, a no-op-shaped success) type back to
54
- * `active`. Rejected unconditionally (AC-14/INV-06) against a tombstoned row.
56
+ * — flips a `deprecated` (or already-`active`, a no-op-shaped success) type back to
57
+ * `active`. Rejected unconditionally against a tombstoned row.
55
58
  *
56
59
  * @complexity O(1) plus one repo read and one same-tx write pair.
57
60
  * @overallScore 100
61
+ * See docs/decisions/DR-002-content-lifecycle-and-cleanup.md.
58
62
  */
59
63
  export async function reactivateContentType(required) {
60
64
  const { deps, input } = required;
61
- const authResult = await deps.authorize({ principalId: input.actorId, permission: "admin.collections.manage", workspaceId: input.workspaceId, entityType: "content-type" });
65
+ const authResult = await deps.authorize({ principalId: input.actorId, permission: "admin.collections.manage", workspaceId: input.workspaceId }, { entityType: "content-type" });
62
66
  if (!authResult.allowed) {
63
- return { ok: false, error: new ForbiddenError(`principal '${input.actorId}' cannot reactivate content type '${input.key}' (${authResult.reason})`) };
67
+ return { ok: false, error: new ForbiddenError({ message: `principal '${input.actorId}' cannot reactivate content type '${input.key}' (${authResult.reason})` }) };
64
68
  }
65
69
  const resolved = await resolveActiveOrDeprecated(deps.repo, input.workspaceId, input.key);
66
70
  if (!resolved.ok)
67
71
  return resolved;
68
72
  const current = resolved.value;
69
73
  if (current.status === "tombstone") {
70
- return { ok: false, error: new ContentTypeLifecycleError(`content type '${input.key}' is tombstoned; INV-06 forbids any transition out of tombstone`) };
74
+ // See docs/decisions/DR-002-content-lifecycle-and-cleanup.md for the invariant behind this refusal; keep external identifiers out of caller-facing messages.
75
+ return { ok: false, error: new ContentTypeLifecycleError({ message: `content type '${input.key}' is tombstoned; no transition out of tombstone is allowed` }) };
71
76
  }
72
77
  if (input.expectedVersion !== current.version) {
73
- return { ok: false, error: new VersionConflictError(`expected version ${input.expectedVersion} for content type '${input.key}', found ${current.version}`) };
78
+ return { ok: false, error: new VersionConflictError({ message: `expected version ${input.expectedVersion} for content type '${input.key}', found ${current.version}` }) };
74
79
  }
75
- const now = deps.clock.nowIso();
80
+ const now = kernelNowIso({ clock: deps.clock });
76
81
  const updated = { ...current, status: "active", version: current.version + 1 };
77
- await deps.repo.transaction(async () => {
78
- await deps.repo.save(updated);
79
- await deps.repo.appendRevision({
80
- contentTypeKey: input.key,
81
- workspaceId: input.workspaceId,
82
- op: "field-change",
83
- stateJson: updated,
84
- actorId: input.actorId,
85
- principalKind: input.principalKind ?? null,
86
- delegatedByWorkspaceId: null,
87
- delegatedById: null,
88
- recordedAt: now,
89
- });
90
- });
82
+ await deps.repo.transaction({ fn: async () => {
83
+ await deps.repo.save(updated);
84
+ await deps.repo.appendRevision({
85
+ contentTypeKey: input.key,
86
+ workspaceId: input.workspaceId,
87
+ op: "field-change",
88
+ stateJson: updated,
89
+ actorId: input.actorId,
90
+ principalKind: input.principalKind ?? null,
91
+ delegatedByWorkspaceId: null,
92
+ delegatedById: null,
93
+ recordedAt: now,
94
+ });
95
+ } });
91
96
  return { ok: true, value: { contentType: updated } };
92
97
  }
93
98
  /**
94
- * AC-17/AC-20/EC-09 — the one-way terminal transition into `tombstone`. Must be entered from
99
+ * — the one-way terminal transition into `tombstone`. Must be entered from
95
100
  * `deprecated` (any other status, including an already-tombstoned row, is rejected with the same
96
- * "must deprecate first" guard — EC-09/INV-06 collapse to one check). Tears down every queryable-
101
+ * "must deprecate first" guard — collapse to one check). Tears down every queryable-
97
102
  * field index the type ever provisioned BEFORE persisting the status flip, and enqueues
98
103
  * `content_type.tombstoned` in the same call.
99
104
  *
100
105
  * @complexity O(1) plus one repo read, one index-teardown call, one same-tx write pair, and one
101
106
  * outbox enqueue.
102
107
  * @overallScore 100
108
+ * See docs/decisions/DR-002-content-lifecycle-and-cleanup.md.
103
109
  */
104
110
  export async function tombstoneContentType(required) {
105
111
  const { deps, input } = required;
106
- const authResult = await deps.authorize({ principalId: input.actorId, permission: "admin.collections.manage", workspaceId: input.workspaceId, entityType: "content-type" });
112
+ const authResult = await deps.authorize({ principalId: input.actorId, permission: "admin.collections.manage", workspaceId: input.workspaceId }, { entityType: "content-type" });
107
113
  if (!authResult.allowed) {
108
- return { ok: false, error: new ForbiddenError(`principal '${input.actorId}' cannot tombstone content type '${input.key}' (${authResult.reason})`) };
114
+ return { ok: false, error: new ForbiddenError({ message: `principal '${input.actorId}' cannot tombstone content type '${input.key}' (${authResult.reason})` }) };
109
115
  }
110
116
  const resolved = await resolveActiveOrDeprecated(deps.repo, input.workspaceId, input.key);
111
117
  if (!resolved.ok)
@@ -114,29 +120,30 @@ export async function tombstoneContentType(required) {
114
120
  if (current.status !== "deprecated") {
115
121
  return {
116
122
  ok: false,
117
- error: new ContentTypeLifecycleError(`content type '${input.key}' must be 'deprecated' before it can be tombstoned (EC-09); current status is '${current.status}'`),
123
+ // See docs/decisions/DR-002-content-lifecycle-and-cleanup.md for the invariant behind this refusal; keep external identifiers out of caller-facing messages.
124
+ error: new ContentTypeLifecycleError({ message: `content type '${input.key}' must be 'deprecated' before it can be tombstoned; current status is '${current.status}'` }),
118
125
  };
119
126
  }
120
127
  if (input.expectedVersion !== current.version) {
121
- return { ok: false, error: new VersionConflictError(`expected version ${input.expectedVersion} for content type '${input.key}', found ${current.version}`) };
128
+ return { ok: false, error: new VersionConflictError({ message: `expected version ${input.expectedVersion} for content type '${input.key}', found ${current.version}` }) };
122
129
  }
123
- const now = deps.clock.nowIso();
130
+ const now = kernelNowIso({ clock: deps.clock });
124
131
  const updated = { ...current, status: "tombstone", tombstonedAt: now, version: current.version + 1 };
125
132
  await deps.indexProvisioner.tearDownAllIndexesForContentType({ workspaceId: input.workspaceId, contentTypeKey: input.key });
126
- await deps.repo.transaction(async () => {
127
- await deps.repo.save(updated);
128
- await deps.repo.appendRevision({
129
- contentTypeKey: input.key,
130
- workspaceId: input.workspaceId,
131
- op: "field-change",
132
- stateJson: updated,
133
- actorId: input.actorId,
134
- principalKind: input.principalKind ?? null,
135
- delegatedByWorkspaceId: null,
136
- delegatedById: null,
137
- recordedAt: now,
138
- });
139
- });
133
+ await deps.repo.transaction({ fn: async () => {
134
+ await deps.repo.save(updated);
135
+ await deps.repo.appendRevision({
136
+ contentTypeKey: input.key,
137
+ workspaceId: input.workspaceId,
138
+ op: "field-change",
139
+ stateJson: updated,
140
+ actorId: input.actorId,
141
+ principalKind: input.principalKind ?? null,
142
+ delegatedByWorkspaceId: null,
143
+ delegatedById: null,
144
+ recordedAt: now,
145
+ });
146
+ } });
140
147
  await deps.outbox.enqueue({ name: "content_type.tombstoned", payload: { workspaceId: input.workspaceId, key: input.key } });
141
148
  return { ok: true, value: { contentType: updated } };
142
149
  }
@@ -1,3 +1,4 @@
1
+ import type { Clock } from "@jini-ai/core/primitives";
1
2
  import type { ContentTypeRepoPort, ContentTypeRevisionInput, IndexProvisionerPort, OutboxPort } from "./write-service.js";
2
3
  import type { TeardownIndexProvisionerPort } from "./lifecycle.js";
3
4
  import type { ContentTypeListPort } from "./list.js";
@@ -32,7 +33,9 @@ export declare class InMemoryContentTypeRepo implements ContentTypeRepoPort, Con
32
33
  workspaceId: string;
33
34
  key: string;
34
35
  }): Promise<ContentTypeRecord | null>;
35
- transaction<T>(fn: () => Promise<T>): Promise<T>;
36
+ transaction<T>({ fn }: {
37
+ fn: () => Promise<T>;
38
+ }): Promise<T>;
36
39
  listByWorkspace(params: {
37
40
  workspaceId: string;
38
41
  }): Promise<ContentTypeRecord[]>;
@@ -59,9 +62,7 @@ export declare function toContentTypeOutbox(deps: {
59
62
  payload: Record<string, unknown>;
60
63
  }): Promise<void>;
61
64
  };
62
- clock: {
63
- nowIso(): string;
64
- };
65
+ clock: Clock;
65
66
  idGen: {
66
67
  newId(): string;
67
68
  };
@@ -1,3 +1,4 @@
1
+ import { nowIso as kernelNowIso } from "@jini-ai/core/primitives";
1
2
  /**
2
3
  * @file In-memory adapters for the `content-types` package's write/list ports (port/adapter rule-of-two
3
4
  * "one being built now" half). Backs `server/app.ts`'s hermetic test/dev composition AND, until a
@@ -36,7 +37,7 @@ export class InMemoryContentTypeRepo {
36
37
  const row = this.rows.get(InMemoryContentTypeRepo.key(params.workspaceId, params.key));
37
38
  return row ? { ...row } : null;
38
39
  }
39
- async transaction(fn) {
40
+ async transaction({ fn }) {
40
41
  return fn();
41
42
  }
42
43
  async listByWorkspace(params) {
@@ -62,7 +63,7 @@ export function toContentTypeOutbox(deps) {
62
63
  id: deps.idGen.newId(),
63
64
  workspaceId: deps.workspaceId,
64
65
  name: event.name,
65
- occurredAt: deps.clock.nowIso(),
66
+ occurredAt: kernelNowIso({ clock: deps.clock }),
66
67
  payload: event.payload,
67
68
  });
68
69
  },
@@ -1,3 +1,5 @@
1
+ import type { IdGenerator } from "@jini-ai/core/primitives";
2
+ import type { Clock } from "@jini-ai/core/primitives";
1
3
  /**
2
4
  * @file Content-types' half of the agent-tool authorization wiring: maps `agent-tools.ts`'s catalog entries onto the
3
5
  * `write-service.ts`/`lifecycle.ts` functions the admin HTTP routes call, as `ToolRegistration`s.
@@ -32,7 +34,7 @@
32
34
  */
33
35
  import type { AuthorizeFn } from "../core/commands/command.js";
34
36
  import type { OutboxPort } from "../core/ports.js";
35
- import { type DerivedRiskByToolId, type ToolRegistration } from "../core/tools/registration-kit.js";
37
+ import { type DerivedRiskByToolId, type ToolRegistration } from "@jini-ai/core";
36
38
  import { type ContentTypeListPort } from "./list.js";
37
39
  import { type TeardownIndexProvisionerPort } from "./lifecycle.js";
38
40
  import { type ContentTypeRepoPort, type IndexProvisionerPort } from "./write-service.js";
@@ -40,17 +42,13 @@ import { type ContentTypeRepoPort, type IndexProvisionerPort } from "./write-ser
40
42
  * The exact slice of the route-deps bag Content-Types' tool handlers read. Declared structurally
41
43
  * (rather than importing `server/routes/types`'s `RouteDeps`) so this module carries no back-edge
42
44
  * into the composition root. `server/routes/*` satisfies this structurally by passing its existing
43
- * `RouteDeps` object; nothing there changes.
45
+ * `RouteDeps` object with the kernel clock/ID contracts.
44
46
  */
45
47
  export interface ContentTypesToolDeps {
46
48
  authorize: AuthorizeFn;
47
49
  workspaceId: string;
48
- clock: {
49
- nowIso(): string;
50
- };
51
- idGen: {
52
- newId(): string;
53
- };
50
+ clock: Clock;
51
+ idGen: IdGenerator;
54
52
  outbox: OutboxPort;
55
53
  contentTypeRepo: ContentTypeRepoPort & ContentTypeListPort;
56
54
  contentTypeIndexProvisioner: IndexProvisionerPort & TeardownIndexProvisionerPort;
@@ -1,10 +1,11 @@
1
- import { AGENT_TOOL_PRINCIPAL_KIND, buildDomainRegistrations, decorateWithSchema, fromResult, indexCatalogById, requireInputRecord, requireNoInput, requireNumber, requireString, requireToolPermission, } from "../core/tools/registration-kit.js";
1
+ import { AGENT_TOOL_PRINCIPAL_KIND, buildDomainRegistrations, decorateWithSchema, fromResult, indexCatalogById, requireInputRecord, requireNoInput, requireNumber, requireString } from "@jini-ai/core";
2
+ import { adaptLegacyAuthorize, requireToolPermission } from "../core/tools/index.js";
2
3
  import { contentTypesAgentToolCatalog } from "./agent-tools.js";
3
4
  import { parseContentTypeFieldDefs } from "./field-defs.js";
4
5
  import { listContentTypes } from "./list.js";
5
6
  import { deprecateContentType, reactivateContentType, tombstoneContentType } from "./lifecycle.js";
6
7
  import { registerContentType, updateContentTypeFields } from "./write-service.js";
7
- const CATALOG_BY_ID = indexCatalogById(contentTypesAgentToolCatalog);
8
+ const CATALOG_BY_ID = indexCatalogById({ catalog: contentTypesAgentToolCatalog });
8
9
  /** Descriptors for the 2 cleanup tools this pass does not wire — see file header. */
9
10
  const UNWIRED_CONTENT_TYPES_TOOL_IDS = new Set(["collections_plan_cleanup", "collections_execute_cleanup"]);
10
11
  /**
@@ -39,7 +40,7 @@ export const contentTypesDerivedRisk = new Map([
39
40
  * @overallScore 100
40
41
  */
41
42
  function requireFields(input, toolId) {
42
- const parsed = parseContentTypeFieldDefs(input.fields);
43
+ const parsed = parseContentTypeFieldDefs({ value: input.fields });
43
44
  if (parsed.ok)
44
45
  return parsed.value;
45
46
  throw decorateWithSchema({ toolId, catalog: CATALOG_BY_ID, message: parsed.error.message });
@@ -76,14 +77,14 @@ function toContentTypeView(record) {
76
77
  return view;
77
78
  }
78
79
  function fromContentTypeResult(fn) {
79
- return fromResult(fn).then(({ contentType }) => ({ contentType: toContentTypeView(contentType) }));
80
+ return fromResult({ fn: fn }).then(({ contentType }) => ({ contentType: toContentTypeView(contentType) }));
80
81
  }
81
82
  function contentTypesDeps(routeDeps) {
82
83
  return {
83
84
  repo: routeDeps.contentTypeRepo,
84
85
  clock: routeDeps.clock,
85
86
  ids: routeDeps.idGen,
86
- authorize: routeDeps.authorize,
87
+ authorize: adaptLegacyAuthorize({ authorize: routeDeps.authorize }),
87
88
  outbox: routeDeps.outbox,
88
89
  indexProvisioner: routeDeps.contentTypeIndexProvisioner,
89
90
  };
@@ -91,79 +92,75 @@ function contentTypesDeps(routeDeps) {
91
92
  export function buildContentTypesRegistrations(routeDeps) {
92
93
  const handlers = {
93
94
  collections_content_type_list: async (ctx) => {
94
- requireNoInput(ctx.input);
95
- await requireToolPermission(routeDeps, {
96
- principalId: ctx.principal.id,
97
- permission: "admin.collections.read",
98
- entityType: "content-type",
99
- });
95
+ requireNoInput({ input: ctx.input });
96
+ await requireToolPermission({ authorize: adaptLegacyAuthorize({ authorize: routeDeps.authorize }), workspaceId: routeDeps.workspaceId, principalId: ctx.principal.id, permission: "admin.collections.read" }, { entityType: "content-type" });
100
97
  const { items } = await listContentTypes({ repo: routeDeps.contentTypeRepo, workspaceId: routeDeps.workspaceId });
101
98
  return { contentTypes: items.map(toContentTypeView) };
102
99
  },
103
100
  collections_content_type_define: async (ctx) => {
104
- const input = requireInputRecord(ctx.input);
101
+ const input = requireInputRecord({ input: ctx.input });
105
102
  return fromContentTypeResult(() => registerContentType({
106
103
  deps: contentTypesDeps(routeDeps),
107
104
  input: {
108
105
  actorId: ctx.principal.id,
109
106
  principalKind: AGENT_TOOL_PRINCIPAL_KIND,
110
107
  workspaceId: routeDeps.workspaceId,
111
- key: requireString(input, "key"),
112
- label: requireString(input, "label"),
108
+ key: requireString({ input, key: "key" }),
109
+ label: requireString({ input, key: "label" }),
113
110
  fields: requireFields(input, "collections_content_type_define"),
114
111
  },
115
112
  }));
116
113
  },
117
114
  collections_content_type_update_fields: async (ctx) => {
118
- const input = requireInputRecord(ctx.input);
115
+ const input = requireInputRecord({ input: ctx.input });
119
116
  return fromContentTypeResult(() => updateContentTypeFields({
120
117
  deps: contentTypesDeps(routeDeps),
121
118
  input: {
122
119
  actorId: ctx.principal.id,
123
120
  principalKind: AGENT_TOOL_PRINCIPAL_KIND,
124
121
  workspaceId: routeDeps.workspaceId,
125
- key: requireString(input, "key"),
122
+ key: requireString({ input, key: "key" }),
126
123
  fields: requireFields(input, "collections_content_type_update_fields"),
127
- expectedVersion: requireNumber(input, "expectedVersion"),
124
+ expectedVersion: requireNumber({ input, key: "expectedVersion" }),
128
125
  },
129
126
  }));
130
127
  },
131
128
  collections_content_type_deprecate: async (ctx) => {
132
- const input = requireInputRecord(ctx.input);
129
+ const input = requireInputRecord({ input: ctx.input });
133
130
  return fromContentTypeResult(() => deprecateContentType({
134
131
  deps: contentTypesDeps(routeDeps),
135
132
  input: {
136
133
  actorId: ctx.principal.id,
137
134
  principalKind: AGENT_TOOL_PRINCIPAL_KIND,
138
135
  workspaceId: routeDeps.workspaceId,
139
- key: requireString(input, "key"),
140
- expectedVersion: requireNumber(input, "expectedVersion"),
136
+ key: requireString({ input, key: "key" }),
137
+ expectedVersion: requireNumber({ input, key: "expectedVersion" }),
141
138
  },
142
139
  }));
143
140
  },
144
141
  collections_content_type_reactivate: async (ctx) => {
145
- const input = requireInputRecord(ctx.input);
142
+ const input = requireInputRecord({ input: ctx.input });
146
143
  return fromContentTypeResult(() => reactivateContentType({
147
144
  deps: contentTypesDeps(routeDeps),
148
145
  input: {
149
146
  actorId: ctx.principal.id,
150
147
  principalKind: AGENT_TOOL_PRINCIPAL_KIND,
151
148
  workspaceId: routeDeps.workspaceId,
152
- key: requireString(input, "key"),
153
- expectedVersion: requireNumber(input, "expectedVersion"),
149
+ key: requireString({ input, key: "key" }),
150
+ expectedVersion: requireNumber({ input, key: "expectedVersion" }),
154
151
  },
155
152
  }));
156
153
  },
157
154
  collections_content_type_tombstone: async (ctx) => {
158
- const input = requireInputRecord(ctx.input);
155
+ const input = requireInputRecord({ input: ctx.input });
159
156
  return fromContentTypeResult(() => tombstoneContentType({
160
157
  deps: contentTypesDeps(routeDeps),
161
158
  input: {
162
159
  actorId: ctx.principal.id,
163
160
  principalKind: AGENT_TOOL_PRINCIPAL_KIND,
164
161
  workspaceId: routeDeps.workspaceId,
165
- key: requireString(input, "key"),
166
- expectedVersion: requireNumber(input, "expectedVersion"),
162
+ key: requireString({ input, key: "key" }),
163
+ expectedVersion: requireNumber({ input, key: "expectedVersion" }),
167
164
  },
168
165
  }));
169
166
  },
@@ -174,7 +171,6 @@ export function buildContentTypesRegistrations(routeDeps) {
174
171
  catalog: CATALOG_BY_ID,
175
172
  handlers,
176
173
  derivedRisk: contentTypesDerivedRisk,
177
- unwiredToolIds: UNWIRED_CONTENT_TYPES_TOOL_IDS,
178
- });
174
+ }, { unwiredToolIds: UNWIRED_CONTENT_TYPES_TOOL_IDS });
179
175
  }
180
176
  //# sourceMappingURL=tool-registrations.js.map
@@ -24,15 +24,16 @@
24
24
  * `features/content-types` domain vocabulary. No dependencies.
25
25
  */
26
26
  /**
27
- * CIC U-001-B1 — the closed, 5-entry INDEXABLE SCALAR set. Never extend ad hoc.
27
+ * — the closed, 5-entry INDEXABLE SCALAR set. Never extend ad hoc.
28
28
  *
29
29
  * Unchanged since the original enum: every value that has ever reached a `CAST` literal is still
30
30
  * here, in this order. Kept as its own constant so the "these five are the original, untouched
31
31
  * scalars" claim is expressible in code rather than only in a comment.
32
+ * See docs/decisions/DR-001-safe-schema-and-index-transitions.md.
32
33
  */
33
34
  export declare const CONTENT_TYPE_SCALAR_KINDS: readonly ["text", "integer", "real", "boolean", "datetime"];
34
35
  /**
35
- * CIC U-001-B1 — kinds that MAY carry `queryable: true` and therefore MAY reach
36
+ * — kinds that MAY carry `queryable: true` and therefore MAY reach
36
37
  * `mapFieldKindToCast`. Every member MUST have an entry in `index-provisioning.ts`'s
37
38
  * `KIND_TO_CAST_LITERAL`; the compiler enforces this via `Record<IndexableFieldKind, string>`, so
38
39
  * adding a member here fails the build until a CAST literal is supplied for it.
@@ -40,6 +41,7 @@ export declare const CONTENT_TYPE_SCALAR_KINDS: readonly ["text", "integer", "re
40
41
  * `relation` stores a foreign entity id and shares `text`'s storage class, so its CAST target is
41
42
  * the already-present literal `"TEXT"` — it adds a KEY to that table, never a new VALUE to the
42
43
  * DDL alphabet.
44
+ * See docs/decisions/DR-001-safe-schema-and-index-transitions.md.
43
45
  */
44
46
  export declare const INDEXABLE_FIELD_KINDS: readonly ["text", "integer", "real", "boolean", "datetime", "relation"];
45
47
  export type IndexableFieldKind = (typeof INDEXABLE_FIELD_KINDS)[number];
@@ -52,7 +54,7 @@ export type IndexableFieldKind = (typeof INDEXABLE_FIELD_KINDS)[number];
52
54
  export declare const STORAGE_ONLY_FIELD_KINDS: readonly ["json"];
53
55
  export type StorageOnlyFieldKind = (typeof STORAGE_ONLY_FIELD_KINDS)[number];
54
56
  /**
55
- * CIC U-001-B1 — the closed field-kind enum. UNCHANGED NAME AND MEANING for every existing
57
+ * — the closed field-kind enum. UNCHANGED NAME AND MEANING for every existing
56
58
  * consumer: it is still the complete, closed set of legal `kind` values, and
57
59
  * {@link isContentTypeFieldKind} is still the gate for it.
58
60
  *
@@ -61,6 +63,7 @@ export type StorageOnlyFieldKind = (typeof STORAGE_ONLY_FIELD_KINDS)[number];
61
63
  * message. The spread order below preserves that; the published agent-tool schema
62
64
  * (`agent-tools.ts`) also spreads this constant, so both widen in lockstep with no hand-copied
63
65
  * second list to drift.
66
+ * See docs/decisions/DR-001-safe-schema-and-index-transitions.md.
64
67
  */
65
68
  export declare const CONTENT_TYPE_FIELD_KINDS: readonly ["text", "integer", "real", "boolean", "datetime", "relation", "json"];
66
69
  export type ContentTypeFieldKind = (typeof CONTENT_TYPE_FIELD_KINDS)[number];
@@ -75,7 +78,11 @@ export type ContentTypeFieldKind = (typeof CONTENT_TYPE_FIELD_KINDS)[number];
75
78
  * @complexity O(1) — a fixed-size array membership test.
76
79
  * @overallScore 100
77
80
  */
78
- export declare function isContentTypeFieldKind(value: unknown): value is ContentTypeFieldKind;
81
+ export declare function isContentTypeFieldKind(required: {
82
+ value: unknown;
83
+ }, _optional?: Record<string, never>): required is {
84
+ value: ContentTypeFieldKind;
85
+ };
79
86
  /**
80
87
  * Type guard for {@link IndexableFieldKind} — the gate `mapFieldKindToCast` applies instead of
81
88
  * {@link isContentTypeFieldKind}, and the gate `write-service.ts` applies to reject
@@ -88,7 +95,11 @@ export declare function isContentTypeFieldKind(value: unknown): value is Content
88
95
  * @complexity O(1) — a fixed-size array membership test.
89
96
  * @overallScore 100
90
97
  */
91
- export declare function isIndexableFieldKind(value: unknown): value is IndexableFieldKind;
98
+ export declare function isIndexableFieldKind(required: {
99
+ value: unknown;
100
+ }, _optional?: Record<string, never>): required is {
101
+ value: IndexableFieldKind;
102
+ };
92
103
  export interface ContentTypeFieldDef {
93
104
  name: string;
94
105
  kind: ContentTypeFieldKind;
@@ -113,7 +124,7 @@ export interface ContentTypeRecord {
113
124
  * applies to `AuthorizeFn`). `identity.PrincipalRecord.kind` assigns to it directly.
114
125
  */
115
126
  export type ActorPrincipalKind = "user" | "agent" | "api_key" | "system";
116
- /** The actor-identity envelope every chokepoint write in this package accepts (REQ-01/02/16). */
127
+ /** The actor-identity envelope every chokepoint write in this package accepts. See docs/decisions/DR-001-safe-schema-and-index-transitions.md. */
117
128
  export interface ActorIdentityInput {
118
129
  actorId: string;
119
130
  /**
@@ -129,11 +140,4 @@ export interface ActorIdentityInput {
129
140
  delegatedById?: string | null;
130
141
  }
131
142
  /** Generic success/failure envelope used across this package instead of throwing for expected rejections. */
132
- export type Result<T, E> = {
133
- ok: true;
134
- value: T;
135
- } | {
136
- ok: false;
137
- error: E;
138
- };
139
143
  //# sourceMappingURL=types.d.ts.map
@@ -24,15 +24,16 @@
24
24
  * `features/content-types` domain vocabulary. No dependencies.
25
25
  */
26
26
  /**
27
- * CIC U-001-B1 — the closed, 5-entry INDEXABLE SCALAR set. Never extend ad hoc.
27
+ * — the closed, 5-entry INDEXABLE SCALAR set. Never extend ad hoc.
28
28
  *
29
29
  * Unchanged since the original enum: every value that has ever reached a `CAST` literal is still
30
30
  * here, in this order. Kept as its own constant so the "these five are the original, untouched
31
31
  * scalars" claim is expressible in code rather than only in a comment.
32
+ * See docs/decisions/DR-001-safe-schema-and-index-transitions.md.
32
33
  */
33
34
  export const CONTENT_TYPE_SCALAR_KINDS = ["text", "integer", "real", "boolean", "datetime"];
34
35
  /**
35
- * CIC U-001-B1 — kinds that MAY carry `queryable: true` and therefore MAY reach
36
+ * — kinds that MAY carry `queryable: true` and therefore MAY reach
36
37
  * `mapFieldKindToCast`. Every member MUST have an entry in `index-provisioning.ts`'s
37
38
  * `KIND_TO_CAST_LITERAL`; the compiler enforces this via `Record<IndexableFieldKind, string>`, so
38
39
  * adding a member here fails the build until a CAST literal is supplied for it.
@@ -40,6 +41,7 @@ export const CONTENT_TYPE_SCALAR_KINDS = ["text", "integer", "real", "boolean",
40
41
  * `relation` stores a foreign entity id and shares `text`'s storage class, so its CAST target is
41
42
  * the already-present literal `"TEXT"` — it adds a KEY to that table, never a new VALUE to the
42
43
  * DDL alphabet.
44
+ * See docs/decisions/DR-001-safe-schema-and-index-transitions.md.
43
45
  */
44
46
  export const INDEXABLE_FIELD_KINDS = [...CONTENT_TYPE_SCALAR_KINDS, "relation"];
45
47
  /**
@@ -50,7 +52,7 @@ export const INDEXABLE_FIELD_KINDS = [...CONTENT_TYPE_SCALAR_KINDS, "relation"];
50
52
  */
51
53
  export const STORAGE_ONLY_FIELD_KINDS = ["json"];
52
54
  /**
53
- * CIC U-001-B1 — the closed field-kind enum. UNCHANGED NAME AND MEANING for every existing
55
+ * — the closed field-kind enum. UNCHANGED NAME AND MEANING for every existing
54
56
  * consumer: it is still the complete, closed set of legal `kind` values, and
55
57
  * {@link isContentTypeFieldKind} is still the gate for it.
56
58
  *
@@ -59,6 +61,7 @@ export const STORAGE_ONLY_FIELD_KINDS = ["json"];
59
61
  * message. The spread order below preserves that; the published agent-tool schema
60
62
  * (`agent-tools.ts`) also spreads this constant, so both widen in lockstep with no hand-copied
61
63
  * second list to drift.
64
+ * See docs/decisions/DR-001-safe-schema-and-index-transitions.md.
62
65
  */
63
66
  export const CONTENT_TYPE_FIELD_KINDS = [
64
67
  ...INDEXABLE_FIELD_KINDS,
@@ -75,7 +78,8 @@ export const CONTENT_TYPE_FIELD_KINDS = [
75
78
  * @complexity O(1) — a fixed-size array membership test.
76
79
  * @overallScore 100
77
80
  */
78
- export function isContentTypeFieldKind(value) {
81
+ export function isContentTypeFieldKind(required, _optional = {}) {
82
+ const { value } = required;
79
83
  return typeof value === "string" && CONTENT_TYPE_FIELD_KINDS.includes(value);
80
84
  }
81
85
  /**
@@ -90,7 +94,9 @@ export function isContentTypeFieldKind(value) {
90
94
  * @complexity O(1) — a fixed-size array membership test.
91
95
  * @overallScore 100
92
96
  */
93
- export function isIndexableFieldKind(value) {
97
+ export function isIndexableFieldKind(required, _optional = {}) {
98
+ const { value } = required;
94
99
  return typeof value === "string" && INDEXABLE_FIELD_KINDS.includes(value);
95
100
  }
101
+ /** Generic success/failure envelope used across this package instead of throwing for expected rejections. */
96
102
  //# sourceMappingURL=types.js.map