@vertesia/common 1.6.0-dev.20260923.085325Z → 1.6.0-dev.20261008.064737Z

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 (421) hide show
  1. package/lib/access-control-values.d.ts +2 -2
  2. package/lib/access-control-values.d.ts.map +1 -1
  3. package/lib/access-control-values.js +2 -2
  4. package/lib/access-control-values.js.map +1 -1
  5. package/lib/access-control.d.ts +7 -8
  6. package/lib/access-control.d.ts.map +1 -1
  7. package/lib/access-control.js +5 -0
  8. package/lib/access-control.js.map +1 -1
  9. package/lib/analytics.d.ts +6 -7
  10. package/lib/analytics.d.ts.map +1 -1
  11. package/lib/api-contract/components.generated.json +2553 -1046
  12. package/lib/api-contract/engine.d.ts +65 -0
  13. package/lib/api-contract/engine.d.ts.map +1 -0
  14. package/lib/api-contract/engine.js +569 -0
  15. package/lib/api-contract/engine.js.map +1 -0
  16. package/lib/api-contract/index.d.ts +21 -182
  17. package/lib/api-contract/index.d.ts.map +1 -1
  18. package/lib/api-contract/index.js +13 -551
  19. package/lib/api-contract/index.js.map +1 -1
  20. package/lib/api-schemas/access-control.d.ts +33 -10
  21. package/lib/api-schemas/access-control.d.ts.map +1 -1
  22. package/lib/api-schemas/access-control.js +7 -6
  23. package/lib/api-schemas/access-control.js.map +1 -1
  24. package/lib/api-schemas/account.d.ts +5 -9
  25. package/lib/api-schemas/account.d.ts.map +1 -1
  26. package/lib/api-schemas/account.js +0 -7
  27. package/lib/api-schemas/account.js.map +1 -1
  28. package/lib/api-schemas/agent-budget.d.ts +15 -0
  29. package/lib/api-schemas/agent-budget.d.ts.map +1 -0
  30. package/lib/api-schemas/agent-budget.js +55 -0
  31. package/lib/api-schemas/agent-budget.js.map +1 -0
  32. package/lib/api-schemas/agent-runs.d.ts +1525 -100
  33. package/lib/api-schemas/agent-runs.d.ts.map +1 -1
  34. package/lib/api-schemas/agent-runs.js +60 -28
  35. package/lib/api-schemas/agent-runs.js.map +1 -1
  36. package/lib/api-schemas/apikey.d.ts +11 -10
  37. package/lib/api-schemas/apikey.d.ts.map +1 -1
  38. package/lib/api-schemas/apikey.js.map +1 -1
  39. package/lib/api-schemas/app-lifecycle.d.ts +13 -0
  40. package/lib/api-schemas/app-lifecycle.d.ts.map +1 -1
  41. package/lib/api-schemas/app-lifecycle.js +4 -0
  42. package/lib/api-schemas/app-lifecycle.js.map +1 -1
  43. package/lib/api-schemas/app-runtime.d.ts +1821 -108
  44. package/lib/api-schemas/app-runtime.d.ts.map +1 -1
  45. package/lib/api-schemas/audit-trail.d.ts +275 -0
  46. package/lib/api-schemas/audit-trail.d.ts.map +1 -1
  47. package/lib/api-schemas/audit-trail.js +156 -1
  48. package/lib/api-schemas/audit-trail.js.map +1 -1
  49. package/lib/api-schemas/content.d.ts +665 -30
  50. package/lib/api-schemas/content.d.ts.map +1 -1
  51. package/lib/api-schemas/content.js +47 -0
  52. package/lib/api-schemas/content.js.map +1 -1
  53. package/lib/api-schemas/cost-analytics.d.ts +19 -0
  54. package/lib/api-schemas/cost-analytics.d.ts.map +1 -1
  55. package/lib/api-schemas/cost-analytics.js +38 -2
  56. package/lib/api-schemas/cost-analytics.js.map +1 -1
  57. package/lib/api-schemas/document-processing.d.ts +381 -18
  58. package/lib/api-schemas/document-processing.d.ts.map +1 -1
  59. package/lib/api-schemas/environment.d.ts +0 -5
  60. package/lib/api-schemas/environment.d.ts.map +1 -1
  61. package/lib/api-schemas/environment.js +0 -1
  62. package/lib/api-schemas/environment.js.map +1 -1
  63. package/lib/api-schemas/events.d.ts +1143 -54
  64. package/lib/api-schemas/events.d.ts.map +1 -1
  65. package/lib/api-schemas/group.d.ts +2 -1
  66. package/lib/api-schemas/group.d.ts.map +1 -1
  67. package/lib/api-schemas/group.js.map +1 -1
  68. package/lib/api-schemas/index.d.ts +2 -0
  69. package/lib/api-schemas/index.d.ts.map +1 -1
  70. package/lib/api-schemas/index.js +2 -0
  71. package/lib/api-schemas/index.js.map +1 -1
  72. package/lib/api-schemas/inference-profile.d.ts +5017 -0
  73. package/lib/api-schemas/inference-profile.d.ts.map +1 -0
  74. package/lib/api-schemas/inference-profile.js +135 -0
  75. package/lib/api-schemas/inference-profile.js.map +1 -0
  76. package/lib/api-schemas/integrations.d.ts +6 -6
  77. package/lib/api-schemas/interaction.d.ts +34391 -703
  78. package/lib/api-schemas/interaction.d.ts.map +1 -1
  79. package/lib/api-schemas/interaction.js +34 -1
  80. package/lib/api-schemas/interaction.js.map +1 -1
  81. package/lib/api-schemas/invites.d.ts +10 -9
  82. package/lib/api-schemas/invites.d.ts.map +1 -1
  83. package/lib/api-schemas/invites.js.map +1 -1
  84. package/lib/api-schemas/process.d.ts +653 -34
  85. package/lib/api-schemas/process.d.ts.map +1 -1
  86. package/lib/api-schemas/process.js +66 -0
  87. package/lib/api-schemas/process.js.map +1 -1
  88. package/lib/api-schemas/project-configuration.d.ts +1323 -62
  89. package/lib/api-schemas/project-configuration.d.ts.map +1 -1
  90. package/lib/api-schemas/project-configuration.js +15 -1
  91. package/lib/api-schemas/project-configuration.js.map +1 -1
  92. package/lib/api-schemas/project.d.ts +2031 -116
  93. package/lib/api-schemas/project.d.ts.map +1 -1
  94. package/lib/api-schemas/project.js +9 -1
  95. package/lib/api-schemas/project.js.map +1 -1
  96. package/lib/api-schemas/quota.d.ts +7 -6
  97. package/lib/api-schemas/quota.d.ts.map +1 -1
  98. package/lib/api-schemas/quota.js.map +1 -1
  99. package/lib/api-schemas/registry.d.ts +28171 -36096
  100. package/lib/api-schemas/registry.d.ts.map +1 -1
  101. package/lib/api-schemas/registry.js +77 -30
  102. package/lib/api-schemas/registry.js.map +1 -1
  103. package/lib/api-schemas/run-budget.d.ts +16 -0
  104. package/lib/api-schemas/run-budget.d.ts.map +1 -0
  105. package/lib/api-schemas/run-budget.js +22 -0
  106. package/lib/api-schemas/run-budget.js.map +1 -0
  107. package/lib/api-schemas/secrets.d.ts +0 -71
  108. package/lib/api-schemas/secrets.d.ts.map +1 -1
  109. package/lib/api-schemas/secrets.js +0 -73
  110. package/lib/api-schemas/secrets.js.map +1 -1
  111. package/lib/api-schemas/store.d.ts +6388 -338
  112. package/lib/api-schemas/store.d.ts.map +1 -1
  113. package/lib/api-schemas/store.js +11 -0
  114. package/lib/api-schemas/store.js.map +1 -1
  115. package/lib/api-schemas/user.d.ts +9 -8
  116. package/lib/api-schemas/user.d.ts.map +1 -1
  117. package/lib/api-schemas/user.js.map +1 -1
  118. package/lib/api-schemas/view-execution.d.ts +8 -0
  119. package/lib/api-schemas/view-execution.d.ts.map +1 -1
  120. package/lib/api-schemas/views.d.ts +14 -0
  121. package/lib/api-schemas/views.d.ts.map +1 -1
  122. package/lib/api-schemas/workflow-runs.d.ts +335 -12
  123. package/lib/api-schemas/workflow-runs.d.ts.map +1 -1
  124. package/lib/api-schemas/workflow-runs.js +2 -0
  125. package/lib/api-schemas/workflow-runs.js.map +1 -1
  126. package/lib/apikey.d.ts +30 -25
  127. package/lib/apikey.d.ts.map +1 -1
  128. package/lib/apikey.js.map +1 -1
  129. package/lib/apps.d.ts +116 -121
  130. package/lib/apps.d.ts.map +1 -1
  131. package/lib/apps.js.map +1 -1
  132. package/lib/audit-trail.d.ts +30 -19
  133. package/lib/audit-trail.d.ts.map +1 -1
  134. package/lib/audit-trail.js +6 -0
  135. package/lib/audit-trail.js.map +1 -1
  136. package/lib/browser-credentials.d.ts +11 -12
  137. package/lib/browser-credentials.d.ts.map +1 -1
  138. package/lib/common.d.ts +17 -24
  139. package/lib/common.d.ts.map +1 -1
  140. package/lib/content-query.d.ts +3 -4
  141. package/lib/content-query.d.ts.map +1 -1
  142. package/lib/cost-analytics.d.ts +13 -21
  143. package/lib/cost-analytics.d.ts.map +1 -1
  144. package/lib/cost-analytics.js +0 -7
  145. package/lib/cost-analytics.js.map +1 -1
  146. package/lib/data-platform.d.ts +79 -88
  147. package/lib/data-platform.d.ts.map +1 -1
  148. package/lib/data-platform.js.map +1 -1
  149. package/lib/delegation.d.ts +4 -5
  150. package/lib/delegation.d.ts.map +1 -1
  151. package/lib/email.d.ts +15 -17
  152. package/lib/email.d.ts.map +1 -1
  153. package/lib/email.js.map +1 -1
  154. package/lib/embeddings.d.ts +25 -26
  155. package/lib/embeddings.d.ts.map +1 -1
  156. package/lib/environment.d.ts +16 -17
  157. package/lib/environment.d.ts.map +1 -1
  158. package/lib/environment.js.map +1 -1
  159. package/lib/facets.d.ts +3 -4
  160. package/lib/facets.d.ts.map +1 -1
  161. package/lib/group.d.ts +6 -7
  162. package/lib/group.d.ts.map +1 -1
  163. package/lib/group.js.map +1 -1
  164. package/lib/index.d.ts +3 -1
  165. package/lib/index.d.ts.map +1 -1
  166. package/lib/index.js.map +1 -1
  167. package/lib/inference-profile.d.ts +17 -0
  168. package/lib/inference-profile.d.ts.map +1 -0
  169. package/lib/inference-profile.js +2 -0
  170. package/lib/inference-profile.js.map +1 -0
  171. package/lib/integrations.d.ts +19 -20
  172. package/lib/integrations.d.ts.map +1 -1
  173. package/lib/integrations.js.map +1 -1
  174. package/lib/interaction.d.ts +68 -73
  175. package/lib/interaction.d.ts.map +1 -1
  176. package/lib/interaction.js.map +1 -1
  177. package/lib/meters.d.ts +4 -5
  178. package/lib/meters.d.ts.map +1 -1
  179. package/lib/oauth-server.d.ts +40 -41
  180. package/lib/oauth-server.d.ts.map +1 -1
  181. package/lib/oauth.d.ts +9 -10
  182. package/lib/oauth.d.ts.map +1 -1
  183. package/lib/payload.d.ts +11 -14
  184. package/lib/payload.d.ts.map +1 -1
  185. package/lib/pending-asks.d.ts +8 -13
  186. package/lib/pending-asks.d.ts.map +1 -1
  187. package/lib/pending-asks.js +0 -4
  188. package/lib/pending-asks.js.map +1 -1
  189. package/lib/platform-event.d.ts +48 -71
  190. package/lib/platform-event.d.ts.map +1 -1
  191. package/lib/platform-event.js.map +1 -1
  192. package/lib/principal-context.d.ts +3 -3
  193. package/lib/principal-context.d.ts.map +1 -1
  194. package/lib/project.d.ts +42 -43
  195. package/lib/project.d.ts.map +1 -1
  196. package/lib/project.js.map +1 -1
  197. package/lib/prompt.d.ts +14 -16
  198. package/lib/prompt.d.ts.map +1 -1
  199. package/lib/prompt.js.map +1 -1
  200. package/lib/query.d.ts +10 -13
  201. package/lib/query.d.ts.map +1 -1
  202. package/lib/rate-limiter.d.ts +7 -11
  203. package/lib/rate-limiter.d.ts.map +1 -1
  204. package/lib/refs.d.ts +2 -3
  205. package/lib/refs.d.ts.map +1 -1
  206. package/lib/refs.js.map +1 -1
  207. package/lib/roles/types.d.ts +5 -6
  208. package/lib/roles/types.d.ts.map +1 -1
  209. package/lib/roles/types.js.map +1 -1
  210. package/lib/run-budget.d.ts +4 -0
  211. package/lib/run-budget.d.ts.map +1 -0
  212. package/lib/run-budget.js +2 -0
  213. package/lib/run-budget.js.map +1 -0
  214. package/lib/runs.d.ts +9 -10
  215. package/lib/runs.d.ts.map +1 -1
  216. package/lib/secrets.d.ts +10 -21
  217. package/lib/secrets.d.ts.map +1 -1
  218. package/lib/store/agent-approval.d.ts +4 -5
  219. package/lib/store/agent-approval.d.ts.map +1 -1
  220. package/lib/store/agent-approval.js.map +1 -1
  221. package/lib/store/agent-run.d.ts +50 -52
  222. package/lib/store/agent-run.d.ts.map +1 -1
  223. package/lib/store/agent-run.js.map +1 -1
  224. package/lib/store/collections.d.ts +11 -12
  225. package/lib/store/collections.d.ts.map +1 -1
  226. package/lib/store/collections.js.map +1 -1
  227. package/lib/store/conversation-state.d.ts +14 -8
  228. package/lib/store/conversation-state.d.ts.map +1 -1
  229. package/lib/store/doc-analyzer.d.ts +7 -8
  230. package/lib/store/doc-analyzer.d.ts.map +1 -1
  231. package/lib/store/dsl-workflow.d.ts +10 -12
  232. package/lib/store/dsl-workflow.d.ts.map +1 -1
  233. package/lib/store/dsl-workflow.js.map +1 -1
  234. package/lib/store/duration.d.ts +12 -0
  235. package/lib/store/duration.d.ts.map +1 -0
  236. package/lib/store/duration.js +2 -0
  237. package/lib/store/duration.js.map +1 -0
  238. package/lib/store/grounded-extraction.d.ts +6 -7
  239. package/lib/store/grounded-extraction.d.ts.map +1 -1
  240. package/lib/store/intake-policy-schema.generated.d.ts.map +1 -1
  241. package/lib/store/intake-policy-schema.generated.js +143 -2
  242. package/lib/store/intake-policy-schema.generated.js.map +1 -1
  243. package/lib/store/process.d.ts +70 -69
  244. package/lib/store/process.d.ts.map +1 -1
  245. package/lib/store/process.js.map +1 -1
  246. package/lib/store/rendering.d.ts +6 -12
  247. package/lib/store/rendering.d.ts.map +1 -1
  248. package/lib/store/rendering.js +0 -5
  249. package/lib/store/rendering.js.map +1 -1
  250. package/lib/store/signals.d.ts +43 -0
  251. package/lib/store/signals.d.ts.map +1 -1
  252. package/lib/store/signals.js +6 -1
  253. package/lib/store/signals.js.map +1 -1
  254. package/lib/store/store.d.ts +92 -91
  255. package/lib/store/store.d.ts.map +1 -1
  256. package/lib/store/store.js.map +1 -1
  257. package/lib/store/task.d.ts +10 -14
  258. package/lib/store/task.d.ts.map +1 -1
  259. package/lib/store/workflow.d.ts +35 -41
  260. package/lib/store/workflow.d.ts.map +1 -1
  261. package/lib/store/workflow.js.map +1 -1
  262. package/lib/sts-token-types.d.ts +14 -19
  263. package/lib/sts-token-types.d.ts.map +1 -1
  264. package/lib/tools.d.ts +12 -13
  265. package/lib/tools.d.ts.map +1 -1
  266. package/lib/transient-tokens.d.ts +3 -3
  267. package/lib/transient-tokens.d.ts.map +1 -1
  268. package/lib/user.d.ts +16 -20
  269. package/lib/user.d.ts.map +1 -1
  270. package/lib/user.js.map +1 -1
  271. package/lib/vertesia-common.js +2 -2
  272. package/lib/vertesia-common.js.map +1 -1
  273. package/lib/views.d.ts +61 -64
  274. package/lib/views.d.ts.map +1 -1
  275. package/lib/views.js.map +1 -1
  276. package/lib/wire-types.generated.d.ts +11227 -0
  277. package/lib/wire-types.generated.d.ts.map +1 -0
  278. package/lib/wire-types.generated.js +4 -0
  279. package/lib/wire-types.generated.js.map +1 -0
  280. package/lib/workflow-analytics.d.ts +21 -19
  281. package/lib/workflow-analytics.d.ts.map +1 -1
  282. package/lib/workflow-analytics.js +2 -2
  283. package/lib/workflow-analytics.js.map +1 -1
  284. package/package.json +16 -11
  285. package/src/access-control-values.ts +2 -2
  286. package/src/access-control.ts +7 -15
  287. package/src/analytics.ts +6 -13
  288. package/src/api-contract/components.generated.json +2553 -1046
  289. package/src/api-contract/engine.ts +641 -0
  290. package/src/api-contract/index.ts +30 -661
  291. package/src/api-schemas/access-control.ts +18 -16
  292. package/src/api-schemas/account.ts +5 -12
  293. package/src/api-schemas/agent-budget.ts +60 -0
  294. package/src/api-schemas/agent-runs.ts +63 -27
  295. package/src/api-schemas/apikey.ts +11 -10
  296. package/src/api-schemas/app-lifecycle.ts +5 -0
  297. package/src/api-schemas/audit-trail.ts +175 -1
  298. package/src/api-schemas/content.ts +55 -0
  299. package/src/api-schemas/cost-analytics.ts +42 -2
  300. package/src/api-schemas/environment.ts +0 -1
  301. package/src/api-schemas/group.ts +2 -1
  302. package/src/api-schemas/index.ts +2 -0
  303. package/src/api-schemas/inference-profile.ts +151 -0
  304. package/src/api-schemas/interaction.ts +40 -1
  305. package/src/api-schemas/invites.ts +10 -9
  306. package/src/api-schemas/process.ts +78 -2
  307. package/src/api-schemas/project-configuration.ts +19 -1
  308. package/src/api-schemas/project.ts +19 -10
  309. package/src/api-schemas/quota.ts +7 -6
  310. package/src/api-schemas/registry.ts +164 -62
  311. package/src/api-schemas/run-budget.ts +23 -0
  312. package/src/api-schemas/secrets.ts +0 -84
  313. package/src/api-schemas/store.ts +12 -0
  314. package/src/api-schemas/user.ts +9 -8
  315. package/src/api-schemas/workflow-runs.ts +2 -0
  316. package/src/apikey.ts +30 -39
  317. package/src/apps.ts +116 -239
  318. package/src/audit-trail.ts +37 -35
  319. package/src/browser-credentials.ts +11 -23
  320. package/src/common.ts +17 -37
  321. package/src/content-query.ts +3 -4
  322. package/src/cost-analytics.ts +13 -35
  323. package/src/data-platform.ts +79 -168
  324. package/src/delegation.ts +4 -9
  325. package/src/email.ts +15 -29
  326. package/src/embeddings.ts +25 -51
  327. package/src/environment.ts +16 -33
  328. package/src/facets.ts +3 -4
  329. package/src/group.ts +6 -13
  330. package/src/index.ts +23 -0
  331. package/src/inference-profile.ts +20 -0
  332. package/src/integrations.ts +21 -41
  333. package/src/interaction.ts +68 -137
  334. package/src/meters.ts +4 -9
  335. package/src/oauth-server.ts +40 -81
  336. package/src/oauth.ts +9 -19
  337. package/src/payload.ts +11 -25
  338. package/src/pending-asks.ts +8 -22
  339. package/src/platform-event.ts +48 -122
  340. package/src/principal-context.ts +3 -3
  341. package/src/project.ts +43 -86
  342. package/src/prompt.ts +14 -31
  343. package/src/query.ts +10 -20
  344. package/src/rate-limiter.ts +7 -19
  345. package/src/refs.ts +2 -3
  346. package/src/roles/types.ts +5 -11
  347. package/src/run-budget.ts +4 -0
  348. package/src/runs.ts +9 -19
  349. package/src/secrets.ts +10 -42
  350. package/src/store/agent-approval.ts +4 -9
  351. package/src/store/agent-run.ts +53 -99
  352. package/src/store/collections.ts +11 -23
  353. package/src/store/conversation-state.ts +15 -15
  354. package/src/store/doc-analyzer.ts +7 -15
  355. package/src/store/dsl-workflow.ts +10 -23
  356. package/src/store/duration.ts +45 -0
  357. package/src/store/grounded-extraction.ts +6 -13
  358. package/src/store/intake-policy-schema.generated.ts +148 -2
  359. package/src/store/process.ts +70 -140
  360. package/src/store/rendering.ts +6 -19
  361. package/src/store/signals.ts +48 -0
  362. package/src/store/store.ts +92 -181
  363. package/src/store/task.ts +10 -24
  364. package/src/store/workflow.ts +35 -71
  365. package/src/sts-token-types.ts +14 -33
  366. package/src/tools.ts +12 -25
  367. package/src/transient-tokens.ts +3 -3
  368. package/src/user.ts +16 -40
  369. package/src/views.ts +61 -125
  370. package/src/wire-types.generated.ts +11888 -0
  371. package/src/workflow-analytics.ts +21 -19
  372. package/src/agent-resources.test.ts +0 -89
  373. package/src/api-contract/components.contract.test.ts +0 -99
  374. package/src/api-schemas/access-control.contract.test.ts +0 -209
  375. package/src/api-schemas/account-apikey.test.ts +0 -60
  376. package/src/api-schemas/account.contract.test.ts +0 -319
  377. package/src/api-schemas/adapter-edge-cases.test.ts +0 -499
  378. package/src/api-schemas/agent-communication.contract.test.ts +0 -90
  379. package/src/api-schemas/agent-history.contract.test.ts +0 -42
  380. package/src/api-schemas/agent-runs.contract.test.ts +0 -240
  381. package/src/api-schemas/api-discriminators.test.ts +0 -185
  382. package/src/api-schemas/apikey.contract.test.ts +0 -270
  383. package/src/api-schemas/app-delete-summary.contract.test.ts +0 -67
  384. package/src/api-schemas/bulk-operation.contract.test.ts +0 -39
  385. package/src/api-schemas/bundle-isolation.test.ts +0 -44
  386. package/src/api-schemas/commands.contract.test.ts +0 -51
  387. package/src/api-schemas/cost-analytics.contract.test.ts +0 -64
  388. package/src/api-schemas/dashboard.contract.test.ts +0 -138
  389. package/src/api-schemas/data-store.contract.test.ts +0 -97
  390. package/src/api-schemas/document-processing.contract.test.ts +0 -76
  391. package/src/api-schemas/emit-json-schema.test.ts +0 -36
  392. package/src/api-schemas/environment.contract.test.ts +0 -202
  393. package/src/api-schemas/group.contract.test.ts +0 -205
  394. package/src/api-schemas/indexing.contract.test.ts +0 -122
  395. package/src/api-schemas/interaction.contract.test.ts +0 -307
  396. package/src/api-schemas/invites.contract.test.ts +0 -268
  397. package/src/api-schemas/llumiverse.contract.test.ts +0 -179
  398. package/src/api-schemas/mcp-api-key.contract.test.ts +0 -125
  399. package/src/api-schemas/oauth.contract.test.ts +0 -181
  400. package/src/api-schemas/parameters.test.ts +0 -402
  401. package/src/api-schemas/process.contract.test.ts +0 -115
  402. package/src/api-schemas/project.contract.test.ts +0 -472
  403. package/src/api-schemas/pruning-limits.test.ts +0 -189
  404. package/src/api-schemas/quota.contract.test.ts +0 -147
  405. package/src/api-schemas/registry-groups.test.ts +0 -99
  406. package/src/api-schemas/response-pruning.test.ts +0 -260
  407. package/src/api-schemas/store.contract.test.ts +0 -378
  408. package/src/api-schemas/sts.contract.test.ts +0 -112
  409. package/src/api-schemas/user.contract.test.ts +0 -197
  410. package/src/api-schemas/views.contract.test.ts +0 -112
  411. package/src/api-schemas/zeno-response-contracts.test.ts +0 -380
  412. package/src/apps.test.ts +0 -89
  413. package/src/oauth-scopes.test.ts +0 -15
  414. package/src/roles.test.ts +0 -33
  415. package/src/schema-for-extraction.test.ts +0 -191
  416. package/src/store/agent-approval.test.ts +0 -18
  417. package/src/store/content-type-editing.test.ts +0 -17
  418. package/src/store/ms.d.ts +0 -42
  419. package/src/store/schedule.test.ts +0 -59
  420. package/src/store/workflow.test.ts +0 -640
  421. package/src/versions.test.ts +0 -13
@@ -0,0 +1,641 @@
1
+ import type { ErrorObject, ValidateFunction } from 'ajv/dist/2020.js';
2
+ import { Ajv2020 } from 'ajv/dist/2020.js';
3
+ import ajvFormats from 'ajv-formats';
4
+ import { findUnprunablePaths, isPlainObject, type JsonObject, pruneToSchema } from '../api-schemas/adapter.js';
5
+ import {
6
+ type ApiParameterLocation,
7
+ type NormalizedApiParameters,
8
+ normalizeParameters,
9
+ type RawApiParameters,
10
+ } from '../api-schemas/parameters.js';
11
+
12
+ const addFormats = ajvFormats.default;
13
+
14
+ export interface ApiValidationIssue {
15
+ /**
16
+ * AJV's `instancePath` for the failing value, with `'/'` substituted for the root.
17
+ *
18
+ * Not quite a JSON Pointer: the pointer for a document root is the empty string, which reads as
19
+ * a missing path in a message. `'/'` is a display sentinel, so treat this as human-facing rather
20
+ * than as something to resolve against the payload.
21
+ */
22
+ path: string;
23
+ /** AJV's own message, e.g. `must NOT have additional properties`. */
24
+ message: string;
25
+ /** Undeclared property names at {@link path}, in the order AJV reported them. */
26
+ undeclared?: string[];
27
+ /**
28
+ * The union candidate this issue is a claim ABOUT, when it is not a fact about the value.
29
+ *
30
+ * Set on every issue produced by expanding a failed untagged `oneOf`/`anyOf` — see
31
+ * {@link collectIssues}. Under such a union each candidate rejects the value for its own
32
+ * reasons, most of which are irrelevant to the shape the value actually meant, so an issue
33
+ * carrying a component must be read as "as a `<component>`, this is wrong" and never as
34
+ * "this is wrong".
35
+ *
36
+ * Absent means the opposite and stronger thing: the issue holds against the component the
37
+ * payload is being validated as, whatever candidate it turns out to be.
38
+ */
39
+ component?: string;
40
+ }
41
+
42
+ export type ValidateApiPayloadResult<T> =
43
+ | { valid: true; data: T }
44
+ /**
45
+ * `errors` is the rendered form, complete and ready to log; `issues` is the same failures with
46
+ * the property names still separable. Shorten from `issues`, never from `errors`.
47
+ */
48
+ | { valid: false; errors: string[]; issues: ApiValidationIssue[] };
49
+
50
+ export type PruneAndValidateResult<T> =
51
+ | { valid: true; data: T }
52
+ | { valid: false; data: unknown; errors: string[]; issues: ApiValidationIssue[] };
53
+
54
+ /** Bind shared validation policies to an independently owned component registry. */
55
+ export function createApiContract<T extends object>(ApiSchemaComponents: Readonly<Record<string, JsonObject>>) {
56
+ type ApiComponentName = Extract<keyof T, string>;
57
+ type ApiComponentType<N extends ApiComponentName> = T[N];
58
+ /**
59
+ * A canonical component as a SELF-CONTAINED JSON Schema, for consumers that compile it directly.
60
+ *
61
+ * `components` defaults to the generated artifact, which is what a server wants. A GENERATOR must
62
+ * pass `buildApiSchemaComponents()` instead: the artifact on disk is the previous run's output, so
63
+ * bundling from it would emit an artifact derived from the last contract rather than the current Zod
64
+ * schemas — and, run in the wrong order, would leave the two generated files describing different
65
+ * shapes. Passing the fresh emission makes each generator independent of the others' ordering.
66
+ *
67
+ * The published component `$ref`s its neighbours through `#/components/schemas/...`, which resolves
68
+ * only inside the OpenAPI document. AJV and the Monaco editor need a document they can compile on
69
+ * its own, so the transitive closure is inlined under `$defs` and the pointers rewritten. Nothing
70
+ * about the shapes changes — this is a re-rooting of the same objects, plus the removal of the
71
+ * OpenAPI-only discriminator keywords described below, which is what lets a generated artifact be
72
+ * compared with the component it came from.
73
+ */
74
+ function bundleCanonicalComponent(
75
+ name: ApiComponentName,
76
+ components: Readonly<Record<string, JsonObject>> = ApiSchemaComponents,
77
+ ): JsonObject {
78
+ const seen = new Set<string>();
79
+ const queue: string[] = [name];
80
+ while (queue.length > 0) {
81
+ const current = queue.shift() as string;
82
+ if (seen.has(current)) continue;
83
+ seen.add(current);
84
+ for (const referenced of collectComponentRefs(components[current])) {
85
+ if (!seen.has(referenced)) queue.push(referenced);
86
+ }
87
+ }
88
+ seen.delete(name);
89
+ const defs: JsonObject = {};
90
+ for (const dependency of [...seen].sort()) {
91
+ defs[dependency] = toPlainJsonSchema(components[dependency]) as JsonObject;
92
+ }
93
+ const root = toPlainJsonSchema(components[name]) as JsonObject;
94
+ return seen.size > 0 ? { ...root, $defs: defs } : root;
95
+ }
96
+
97
+ const COMPONENT_REF_PREFIX = '#/components/schemas/';
98
+
99
+ /**
100
+ * Re-roots the component pointers AND drops the discriminator keywords, which are OpenAPI's, not
101
+ * JSON Schema's.
102
+ *
103
+ * `synthesizeDiscriminator` in the adapter gives a discriminated union a `discriminator` plus a
104
+ * restated `type: 'object'` and `required: [propertyName]` ON THE UNION NODE, so a generated
105
+ * Java/Go client can pick a subtype from the union rather than the branches. That restatement is a
106
+ * codegen hint: the node carries no `properties`, so it says "an object that must have
107
+ * `_option_id`" while declaring nothing that could be one.
108
+ *
109
+ * A JSON Schema validator does not mind — `required` needs no matching `properties`, and each
110
+ * branch requires the same key anyway, so removing all three is validation-neutral. Gemini's
111
+ * function-declaration validator does mind, and rejects the whole tool:
112
+ *
113
+ * schema at properties.intake.properties.extraction.properties.config.properties.model_options
114
+ * requires unspecified property '_option_id'
115
+ *
116
+ * That was a 400 on every agent turn offering `create_or_update_type`, because the intake-policy
117
+ * artifact reaches Vertex inside that tool's input schema. Stripping here rather than at the tool
118
+ * keeps the next component someone bundles from reintroducing it. The OpenAPI document is untouched
119
+ * — `ApiSchemaComponents` still carries the hint, and the generated clients still read it.
120
+ */
121
+ function toPlainJsonSchema(value: unknown): unknown {
122
+ const rerooted = rerootComponentRefs(value);
123
+ return stripDiscriminators(rerooted);
124
+ }
125
+
126
+ function stripDiscriminators(value: unknown): unknown {
127
+ if (Array.isArray(value)) return value.map(stripDiscriminators);
128
+ if (!value || typeof value !== 'object') return value;
129
+ const node = value as JsonObject;
130
+ // `properties` present means the node describes an object in its own right, so its `type` and
131
+ // `required` are the schema's own rather than the restatement — only the OpenAPI keyword goes.
132
+ const restated = node.discriminator !== undefined && node.properties === undefined;
133
+ const out: JsonObject = {};
134
+ for (const [key, item] of Object.entries(node)) {
135
+ if (key === 'discriminator') continue;
136
+ if (restated && (key === 'type' || key === 'required')) continue;
137
+ out[key] = stripDiscriminators(item) as never;
138
+ }
139
+ return out;
140
+ }
141
+
142
+ function collectComponentRefs(value: unknown, out = new Set<string>()): Set<string> {
143
+ if (Array.isArray(value)) {
144
+ for (const item of value) collectComponentRefs(item, out);
145
+ return out;
146
+ }
147
+ if (!value || typeof value !== 'object') return out;
148
+ for (const [key, item] of Object.entries(value)) {
149
+ if (key === '$ref' && typeof item === 'string' && item.startsWith(COMPONENT_REF_PREFIX)) {
150
+ out.add(item.slice(COMPONENT_REF_PREFIX.length));
151
+ } else {
152
+ collectComponentRefs(item, out);
153
+ }
154
+ }
155
+ return out;
156
+ }
157
+
158
+ function rerootComponentRefs(value: unknown): unknown {
159
+ if (Array.isArray(value)) return value.map(rerootComponentRefs);
160
+ if (!value || typeof value !== 'object') return value;
161
+ const out: JsonObject = {};
162
+ for (const [key, item] of Object.entries(value)) {
163
+ out[key] =
164
+ key === '$ref' && typeof item === 'string' && item.startsWith(COMPONENT_REF_PREFIX)
165
+ ? `#/$defs/${item.slice(COMPONENT_REF_PREFIX.length)}`
166
+ : (rerootComponentRefs(item) as never);
167
+ }
168
+ return out;
169
+ }
170
+
171
+ /** The `$ref` pointer for a component, in the same spelling the spec publishes. */
172
+ function apiComponentRef(name: ApiComponentName): string {
173
+ return `#/components/schemas/${name}`;
174
+ }
175
+
176
+ /**
177
+ * Validators compiled against the published components, through an envelope so the pointer AJV
178
+ * resolves is the exact pointer the spec publishes. `strictSchema: false` tolerates the
179
+ * `components` wrapper while leaving type and tuple checks active.
180
+ *
181
+ * Compiled lazily and cached: AJV compilation is the expensive step, and most components are
182
+ * never validated in a given process.
183
+ */
184
+ const validators = new Map<string, ValidateFunction>();
185
+
186
+ /**
187
+ * One instance for the process, built on first validation.
188
+ *
189
+ * Per-component instances meant re-registering the whole thousand-component envelope for every
190
+ * component ever validated, and AJV walks a schema when it is added. Sharing one instance also lets
191
+ * it reuse the compiled form of a component that two others reference.
192
+ */
193
+ let ajvInstance: Ajv2020 | undefined;
194
+
195
+ /**
196
+ * The published components as AJV can consume them: the same schemas, with the two adjustments
197
+ * AJV's discriminator support requires and the OpenAPI document must not have.
198
+ *
199
+ * `discriminator: true` below is what makes AJV validate a discriminated union through the branch
200
+ * its tag names, instead of trying every branch and reporting all of their failures at once. The
201
+ * difference is not cosmetic — a legacy MCP tool collection missing `id` used to report the real
202
+ * error alongside two impossible ones from the branch it was never meant to match:
203
+ *
204
+ * / must have required property 'id' <- the real one
205
+ * / must NOT have additional properties: oauth_app <- vertesia_sdk branch
206
+ * /type must be equal to constant <- vertesia_sdk branch
207
+ * / must match exactly one schema in oneOf
208
+ *
209
+ * AJV rejects `mapping` outright ("discriminator: mapping is not supported"), because it derives
210
+ * the tag-to-branch map from each branch's own `const`/`enum` instead. The OpenAPI document still
211
+ * needs the mapping — a generated Java or Go client reads it to pick a concrete subtype — so both
212
+ * fixups here apply to AJV's copy only, and `ApiSchemaComponents` is published exactly as built.
213
+ *
214
+ * AJV's remaining requirements — the tag required in every branch, carrying `const` or a
215
+ * single-valued `enum`, with the union node typed as an object — are what `synthesizeDiscriminator`
216
+ * in the adapter already checks before it emits a discriminator at all, and what the hand-written
217
+ * `.meta({ discriminator })` declarations restate. `api-discriminators.test.ts` compiles every
218
+ * registered component so a union satisfying neither fails the build rather than the request.
219
+ */
220
+ function toAjvComponents(): Record<string, JsonObject> {
221
+ const schemas = structuredClone(ApiSchemaComponents) as Record<string, JsonObject>;
222
+ const resolve = (value: unknown): JsonObject | undefined => {
223
+ if (!isPlainObject(value)) return undefined;
224
+ const ref = value.$ref;
225
+ if (typeof ref !== 'string' || !ref.startsWith(COMPONENT_REF_PREFIX)) return value;
226
+ return schemas[ref.slice(COMPONENT_REF_PREFIX.length)];
227
+ };
228
+
229
+ visitSchemaNodes(schemas, (node) => {
230
+ const discriminator = node.discriminator;
231
+ if (!isPlainObject(discriminator) || !Array.isArray(node.oneOf)) return;
232
+ // AJV derives the tag-to-branch map from each branch's own literal, so `mapping` is both
233
+ // redundant and rejected.
234
+ delete discriminator.mapping;
235
+
236
+ const tag = discriminator.propertyName;
237
+ if (typeof tag !== 'string') return;
238
+ for (const member of node.oneOf) {
239
+ const branch = resolve(member);
240
+ const properties = branch && isPlainObject(branch.properties) ? branch.properties : undefined;
241
+ const tagSchema = properties?.[tag];
242
+ if (!isPlainObject(tagSchema) || tagSchema.const !== undefined || tagSchema.enum !== undefined)
243
+ continue;
244
+ // The tag is a `$ref` to a named literal component — `TaskType_ACTIVITY`,
245
+ // `SupportedIntegrations_gladia` — because the literal carries its own `.meta({ id })`.
246
+ // AJV reads `properties/<tag>` looking for `const` or `enum` and does not follow a
247
+ // `$ref` to find one, so it refuses to compile the union at all. Restating the resolved
248
+ // literal ALONGSIDE the `$ref` is validation-neutral: `$ref` has no special precedence
249
+ // in 2020-12, both keywords apply, and they carry the same value by construction.
250
+ const target = resolve(tagSchema);
251
+ if (!target) continue;
252
+ if (target.const !== undefined) tagSchema.const = target.const;
253
+ else if (Array.isArray(target.enum)) tagSchema.enum = target.enum;
254
+ }
255
+ });
256
+ return schemas;
257
+ }
258
+
259
+ /** Every object node in the component graph, parents before children. */
260
+ function visitSchemaNodes(value: unknown, visit: (node: JsonObject) => void): void {
261
+ if (Array.isArray(value)) {
262
+ for (const item of value) visitSchemaNodes(item, visit);
263
+ return;
264
+ }
265
+ if (!isPlainObject(value)) return;
266
+ visit(value);
267
+ for (const item of Object.values(value)) visitSchemaNodes(item, visit);
268
+ }
269
+
270
+ /** The `$id` the whole component envelope is registered under, and the base of every `$ref` to it. */
271
+ const AJV_SCHEMA_ID = 'vertesia://openapi';
272
+
273
+ function getAjv(): Ajv2020 {
274
+ if (ajvInstance) return ajvInstance;
275
+ // `verbose` carries two things {@link collectIssues} needs and nothing else supplies: the schema
276
+ // object that raised each error, which is the only unambiguous way to tell one union candidate
277
+ // from another, and the value under evaluation, which is what a failed union is re-checked
278
+ // against. Both are populated only when validation fails, and both are references rather than
279
+ // copies.
280
+ // `allowUnionTypes` because a few published components declare `type: [...]` on purpose:
281
+ // `DurationValue` is `['string', 'number']` specifically so the generated Java client gets one
282
+ // writable property instead of the unusable `AnyOfnumber` an `anyOf` produces. AJV's
283
+ // `strictTypes` default of "log" reported that deliberate choice to its logger on every startup.
284
+ // The default logger is `console`, so the notice left on stderr, where log collectors routinely
285
+ // classify it as an error — turning a healthy design decision into recurring server error noise.
286
+ const ajv = new Ajv2020({
287
+ strictSchema: false,
288
+ allErrors: true,
289
+ discriminator: true,
290
+ verbose: true,
291
+ allowUnionTypes: true,
292
+ });
293
+ // Without this, AJV treats `format` as an annotation and ignores it, so a `date-time` property
294
+ // would document a constraint nothing checks — the exact spec/enforcement gap this design is
295
+ // meant to close.
296
+ addFormats(ajv);
297
+ ajv.addSchema({ $id: AJV_SCHEMA_ID, components: { schemas: toAjvComponents() } });
298
+ ajvInstance = ajv;
299
+ return ajv;
300
+ }
301
+
302
+ function getValidator(name: ApiComponentName): ValidateFunction {
303
+ const cached = validators.get(name);
304
+ if (cached) return cached;
305
+ const validate = getAjv().compile({ $ref: `${AJV_SCHEMA_ID}${apiComponentRef(name)}` });
306
+ validators.set(name, validate);
307
+ return validate;
308
+ }
309
+
310
+ function additionalProperty(error: { params?: unknown }): string | undefined {
311
+ // AJV writes "must NOT have additional properties" and puts the offending key in `params`,
312
+ // so the message alone says a body is wrong without saying which property made it wrong.
313
+ // Every other keyword names its subject already — `required` quotes the missing property,
314
+ // `enum` and `type` describe the value in place — and this is the one a caller most often
315
+ // trips, so it is the one worth spelling out rather than reformatting all of them.
316
+ return (error.params as { additionalProperty?: string } | undefined)?.additionalProperty;
317
+ }
318
+
319
+ /**
320
+ * One validation failure, with the undeclared property names kept AS NAMES.
321
+ *
322
+ * The structure exists because the rendered line cannot be taken apart again. Property names are
323
+ * arbitrary JSON strings: `{"customer secret token": 1}` and `{"a, b": 1}` are both valid, so
324
+ * neither a space nor a comma is a reliable separator once the names have been joined. Any consumer
325
+ * that needs to shorten the list — the HTTP boundary does, the log does not — has to do it here,
326
+ * on the array, where a name can be dropped whole.
327
+ */
328
+
329
+ /**
330
+ * The failures, with the undeclared properties a SINGLE schema reported at a given path gathered
331
+ * into one issue, and each failed untagged union expanded per candidate.
332
+ *
333
+ * AJV reports `additionalProperties` per property, so a value carrying a whole foreign object — a
334
+ * Mongoose document that reached the response mapper unmapped, say — produces one error per own key
335
+ * and buries every other failure in the payload. Gathering is lossless: every name is kept, in the
336
+ * order AJV found it. It is keyed by the schema that raised the error as well as the path, so two
337
+ * candidates complaining at one path never merge into a single line. `schemaPath` will not do: a
338
+ * `$ref`'d candidate resets it to `#/additionalProperties`, identical for every candidate. The
339
+ * schema object itself is unambiguous, and `verbose: true` supplies it.
340
+ *
341
+ * `discriminator: true` narrows a TAGGED union to the one branch its tag names, so nothing below
342
+ * applies to those. What is left is the unions with no tag: AJV runs the value against every
343
+ * candidate and reports all of their failures, flat and unattributed. Read as facts they are
344
+ * nonsense — for a condition branch `{ to, when }` with a malformed `when`, raw AJV says
345
+ *
346
+ * /nodes/a/branches/0/when must be object <- BranchDefinition
347
+ * /nodes/a/branches/0 must have required property 'id' <- BranchNodeBranchDefinition
348
+ * /nodes/a/branches/0 must NOT have additional properties: to, when <- BranchNodeBranchDefinition
349
+ * /nodes/a/branches/0 must match exactly one schema in oneOf
350
+ *
351
+ * where `to` and `when` are declared on `BranchDefinition` and only wrong for a candidate the value
352
+ * never meant. Nothing in the error list says which claim belongs to which candidate, and the
353
+ * candidates fail at DIFFERENT paths, so no rule based on the path can recover it.
354
+ *
355
+ * So the union is re-validated candidate by candidate, and each candidate's own failures are
356
+ * attributed to it by name. That is exact rather than inferred, at the cost of one extra validation
357
+ * per candidate — paid only on a response that is already failing:
358
+ *
359
+ * /nodes/a/branches/0 must match exactly one schema in oneOf
360
+ * /nodes/a/branches/0/when as BranchDefinition: must be object
361
+ * /nodes/a/branches/0 as BranchNodeBranchDefinition: must have required property 'id'
362
+ * /nodes/a/branches/0 as BranchNodeBranchDefinition: must NOT have additional properties: to, when
363
+ *
364
+ * Expansion goes ONE level deep: a candidate's own errors are collected without expanding any union
365
+ * nested inside it, which bounds the work and keeps the output readable.
366
+ */
367
+ function collectIssues(validate: ValidateFunction): ApiValidationIssue[] {
368
+ return toIssues(validate.errors ?? [], true);
369
+ }
370
+
371
+ function toIssues(errors: readonly ErrorObject[], expandUnions: boolean): ApiValidationIssue[] {
372
+ const expansions = new Map<string, ApiValidationIssue[]>();
373
+ if (expandUnions) {
374
+ for (const error of errors) {
375
+ if (error.keyword !== 'oneOf' && error.keyword !== 'anyOf') continue;
376
+ const expanded = expandUnion(error);
377
+ if (expanded) expansions.set(error.instancePath, expanded);
378
+ }
379
+ }
380
+ /** Whether an expanded union already accounts for this error, making the raw form redundant. */
381
+ const superseded = (error: ErrorObject): boolean => {
382
+ for (const base of expansions.keys()) {
383
+ if (error.instancePath === base || error.instancePath.startsWith(`${base}/`)) return true;
384
+ }
385
+ return false;
386
+ };
387
+
388
+ const issues: ApiValidationIssue[] = [];
389
+ // Keyed by the raising schema, then by path: two candidates at one path stay separate, and one
390
+ // schema's repeats at one path merge.
391
+ const gathered = new Map<unknown, Map<string, { issue: ApiValidationIssue; names: Set<string> }>>();
392
+
393
+ for (const error of errors) {
394
+ const path = error.instancePath || '/';
395
+ const message = error.message ?? 'is invalid';
396
+ const expanded = expansions.get(error.instancePath);
397
+ if (expanded && (error.keyword === 'oneOf' || error.keyword === 'anyOf')) {
398
+ // The union's own line frames the candidates that follow it.
399
+ issues.push({ path, message });
400
+ issues.push(...expanded);
401
+ continue;
402
+ }
403
+ if (superseded(error)) continue;
404
+
405
+ const additional = additionalProperty(error);
406
+ if (additional === undefined) {
407
+ issues.push({ path, message });
408
+ continue;
409
+ }
410
+
411
+ let byPath = gathered.get(error.parentSchema);
412
+ if (!byPath) {
413
+ byPath = new Map();
414
+ gathered.set(error.parentSchema, byPath);
415
+ }
416
+ const existing = byPath.get(path);
417
+ if (existing) {
418
+ // One schema reporting the same name twice is not a second fact.
419
+ if (!existing.names.has(additional)) {
420
+ existing.names.add(additional);
421
+ existing.issue.undeclared?.push(additional);
422
+ }
423
+ continue;
424
+ }
425
+ const issue: ApiValidationIssue = { path, message, undeclared: [additional] };
426
+ byPath.set(path, { issue, names: new Set([additional]) });
427
+ issues.push(issue);
428
+ }
429
+ return issues;
430
+ }
431
+
432
+ /**
433
+ * One failed union, re-stated as what each candidate objected to.
434
+ *
435
+ * `undefined` when the union cannot be attributed exactly — a candidate that is not a `$ref` to a
436
+ * registered component has no name to report it under, and a partly-named expansion would read as
437
+ * though the unnamed candidate had no objection. The raw errors are kept in that case, which is what
438
+ * AJV would have produced anyway.
439
+ */
440
+ function expandUnion(error: ErrorObject): ApiValidationIssue[] | undefined {
441
+ const parent = error.parentSchema;
442
+ if (!isPlainObject(parent)) return undefined;
443
+ const members = Array.isArray(parent.oneOf)
444
+ ? parent.oneOf
445
+ : Array.isArray(parent.anyOf)
446
+ ? parent.anyOf
447
+ : undefined;
448
+ if (!members?.length) return undefined;
449
+
450
+ const issues: ApiValidationIssue[] = [];
451
+ for (const member of members) {
452
+ const ref = isPlainObject(member) && typeof member.$ref === 'string' ? member.$ref : undefined;
453
+ if (!ref?.startsWith(COMPONENT_REF_PREFIX)) return undefined;
454
+ const validateMember = getAjv().getSchema(`${AJV_SCHEMA_ID}${ref}`);
455
+ if (!validateMember) return undefined;
456
+ // `verbose: true` puts the value under evaluation on the error, so the candidates are run
457
+ // against exactly what the union saw.
458
+ if (validateMember(error.data)) continue;
459
+ const component = ref.slice(COMPONENT_REF_PREFIX.length);
460
+ for (const issue of toIssues(validateMember.errors ?? [], false)) {
461
+ issues.push({ ...issue, path: joinInstancePath(error.instancePath, issue.path), component });
462
+ }
463
+ }
464
+ return issues.length > 0 ? issues : undefined;
465
+ }
466
+
467
+ /** Re-roots a candidate-relative path under the union's own path. */
468
+ function joinInstancePath(base: string, relative: string): string {
469
+ if (relative === '/') return base || '/';
470
+ return `${base}${relative}`;
471
+ }
472
+
473
+ /**
474
+ * The complete rendering of one issue — every name, no budget.
475
+ *
476
+ * This is what gets logged. A caller-facing message renders from {@link ApiValidationIssue} itself
477
+ * with a length limit rather than shortening this string; see `reportableErrors` in the enforcer.
478
+ */
479
+ function renderApiValidationIssue(issue: ApiValidationIssue): string {
480
+ const head = renderApiValidationIssueHead(issue);
481
+ return issue.undeclared?.length ? `${head}: ${issue.undeclared.join(', ')}` : head;
482
+ }
483
+
484
+ /**
485
+ * Everything in a rendered issue except the property names: `<path> [as <component>]: <message>`.
486
+ *
487
+ * Exported because it is not the only renderer. A caller that has to bound the length of a message
488
+ * cannot use {@link renderApiValidationIssue} — it emits every name — and has to rebuild the line
489
+ * from {@link ApiValidationIssue} with its own budget for the names. Rebuilding the HEAD too is what
490
+ * lets the two drift: when `component` was added, the bounded renderer at the HTTP boundary went on
491
+ * concatenating path and message and silently dropped it, so callers were told
492
+ * `must NOT have additional properties: to, when` with no sign it was one candidate's claim. There is
493
+ * one definition of the head so that cannot happen again.
494
+ */
495
+ function renderApiValidationIssueHead(issue: ApiValidationIssue): string {
496
+ return issue.component
497
+ ? `${issue.path} as ${issue.component}: ${issue.message}`
498
+ : `${issue.path} ${issue.message}`;
499
+ }
500
+
501
+ /** The failed branch of every validator here, so the two views cannot be built inconsistently. */
502
+ function invalidResult(validate: ValidateFunction): {
503
+ valid: false;
504
+ errors: string[];
505
+ issues: ApiValidationIssue[];
506
+ } {
507
+ const issues = collectIssues(validate);
508
+ return { valid: false, errors: issues.map(renderApiValidationIssue), issues };
509
+ }
510
+
511
+ /**
512
+ * Validates an untyped request body against the component the endpoint publishes.
513
+ *
514
+ * Non-mutating by design. AJV's removal modes are never used here: the server would then accept a
515
+ * body the published schema declares invalid, silently disagreeing with its own spec — and
516
+ * `removeAdditional: 'all'` additionally empties freeform maps. An undeclared property is reported,
517
+ * not deleted.
518
+ *
519
+ * The component type is handed back only on the `valid` branch, so a body missing required fields
520
+ * cannot be typed as complete. What the caller does with a failure — reject, or log and continue —
521
+ * is the endpoint's policy, not this function's.
522
+ */
523
+ function validateApiRequest<N extends ApiComponentName>(
524
+ name: N,
525
+ value: unknown,
526
+ ): ValidateApiPayloadResult<ApiComponentType<N>> {
527
+ const validate = getValidator(name);
528
+ if (validate(value)) {
529
+ return { valid: true, data: value as ApiComponentType<N> };
530
+ }
531
+ return invalidResult(validate);
532
+ }
533
+
534
+ /**
535
+ * Validates an already-mapped response against the component it is published as.
536
+ *
537
+ * Separate from {@link pruneAndValidateApiResponse} because a resource mapper has already produced
538
+ * the wire shape: there is nothing to prune, and pruning would only mask a mapper bug. Use this at
539
+ * the response boundary to detect drift between what the mapper builds and what the spec promises.
540
+ */
541
+ function validateApiResponse<N extends ApiComponentName>(
542
+ name: N,
543
+ value: unknown,
544
+ ): ValidateApiPayloadResult<ApiComponentType<N>> {
545
+ const validate = getValidator(name);
546
+ if (validate(value)) {
547
+ return { valid: true, data: value as ApiComponentType<N> };
548
+ }
549
+ return invalidResult(validate);
550
+ }
551
+
552
+ /**
553
+ * Best-effort normalization of a response payload towards the fields its published component
554
+ * declares. Use this on the response path INSTEAD of an AJV removal mode, which would empty
555
+ * freeform maps such as `Account.feature_flags`.
556
+ *
557
+ * NOT a secret-removal boundary. Ambiguous schema shapes pass values through untouched — see
558
+ * {@link pruneToSchema} and check a component with {@link findUnprunablePaths} before treating its
559
+ * output as closed. Fields that must never ship still need an explicit response mapper.
560
+ *
561
+ * Never throws and never rejects: an undocumented field is server-side drift, and failing the
562
+ * response would punish the caller for it.
563
+ *
564
+ * Takes a value the caller has already typed as the component. Pruning only REMOVES undeclared
565
+ * extras, so a conforming input yields a conforming output and the return type is honest. It does
566
+ * NOT validate, which is why it cannot accept `unknown` — narrowing a payload that is missing
567
+ * required fields would hand TypeScript a complete `Account` that does not exist at runtime. Use
568
+ * {@link pruneAndValidateApiResponse} when the payload's shape is not already established.
569
+ *
570
+ * Request validation stays separate and non-mutating — pruning a request would make the server
571
+ * silently disagree with the permissive schema it publishes.
572
+ */
573
+ function pruneApiResponse<N extends ApiComponentName>(name: N, value: ApiComponentType<N>): ApiComponentType<N> {
574
+ return pruneToSchema(value, { $ref: apiComponentRef(name) }, ApiSchemaComponents) as ApiComponentType<N>;
575
+ }
576
+
577
+ /**
578
+ * Prunes an untyped payload and validates the result against the published component.
579
+ *
580
+ * The only sound entry point for a payload of unknown shape: the component type is handed back
581
+ * exclusively on the `valid` branch, so a document missing required fields cannot be typed as
582
+ * complete. On failure the pruned value is still returned — the caller decides whether to ship it
583
+ * and log, or fail — which keeps the "never turn drift into a 500" property a policy choice rather
584
+ * than something baked in here.
585
+ *
586
+ */
587
+ function pruneAndValidateApiResponse<N extends ApiComponentName>(
588
+ name: N,
589
+ value: unknown,
590
+ ): PruneAndValidateResult<ApiComponentType<N>> {
591
+ const pruned = pruneToSchema(value, { $ref: apiComponentRef(name) }, ApiSchemaComponents);
592
+ const validate = getValidator(name);
593
+ if (validate(pruned)) {
594
+ return { valid: true, data: pruned as ApiComponentType<N> };
595
+ }
596
+ return { ...invalidResult(validate), data: pruned };
597
+ }
598
+
599
+ /**
600
+ * Paths inside a component where pruning cannot narrow. Empty means no STRUCTURAL gaps for
601
+ * schema-conforming input — see {@link findUnprunablePaths} for why that is weaker than "nothing
602
+ * can escape". Anything listed needs an explicit response mapper.
603
+ */
604
+ function findUnprunableApiPaths(name: ApiComponentName): string[] {
605
+ return findUnprunablePaths({ $ref: apiComponentRef(name) }, ApiSchemaComponents);
606
+ }
607
+
608
+ /**
609
+ * Normalizes raw query or header text into the value a component describes.
610
+ *
611
+ * Binds {@link normalizeParameters} to {@link ApiSchemaComponents} — the same objects the OpenAPI
612
+ * document publishes and {@link validateApiRequest} compiles. That is what keeps the published
613
+ * parameter and the enforced one the same declaration: the scanner expands this component's
614
+ * properties into `in: query` parameters, and the coercion below is decided by those same property
615
+ * schemas, so neither can be changed without changing the other.
616
+ *
617
+ * Validate the result with {@link validateApiRequest}, which is non-coercing: everything type-related
618
+ * has already happened here, so a value this could not coerce is reported against the published
619
+ * schema rather than by a second rule.
620
+ */
621
+ function normalizeApiParameters(
622
+ name: ApiComponentName,
623
+ raw: RawApiParameters,
624
+ location: ApiParameterLocation,
625
+ ): NormalizedApiParameters {
626
+ return normalizeParameters(name, raw, location, ApiSchemaComponents[name], ApiSchemaComponents);
627
+ }
628
+
629
+ return {
630
+ bundleCanonicalComponent,
631
+ apiComponentRef,
632
+ renderApiValidationIssue,
633
+ renderApiValidationIssueHead,
634
+ validateApiRequest,
635
+ validateApiResponse,
636
+ pruneApiResponse,
637
+ pruneAndValidateApiResponse,
638
+ findUnprunableApiPaths,
639
+ normalizeApiParameters,
640
+ };
641
+ }