@kindgi/api 0.0.0-bootstrap.0 → 0.1.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 (505) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +216 -1
  3. package/dist/adapter-binding.d.ts +177 -0
  4. package/dist/adapter-binding.d.ts.map +1 -0
  5. package/dist/adapter-binding.js +12 -0
  6. package/dist/adapter-binding.js.map +1 -0
  7. package/dist/agent-binding.d.ts +207 -0
  8. package/dist/agent-binding.d.ts.map +1 -0
  9. package/dist/agent-binding.js +4 -0
  10. package/dist/agent-binding.js.map +1 -0
  11. package/dist/app.d.ts +770 -0
  12. package/dist/app.d.ts.map +1 -0
  13. package/dist/app.js +397 -0
  14. package/dist/app.js.map +1 -0
  15. package/dist/capability-binding.d.ts +76 -0
  16. package/dist/capability-binding.d.ts.map +1 -0
  17. package/dist/capability-binding.js +4 -0
  18. package/dist/capability-binding.js.map +1 -0
  19. package/dist/cost-binding.d.ts +175 -0
  20. package/dist/cost-binding.d.ts.map +1 -0
  21. package/dist/cost-binding.js +13 -0
  22. package/dist/cost-binding.js.map +1 -0
  23. package/dist/deployment-binding.d.ts +201 -0
  24. package/dist/deployment-binding.d.ts.map +1 -0
  25. package/dist/deployment-binding.js +4 -0
  26. package/dist/deployment-binding.js.map +1 -0
  27. package/dist/env-binding.d.ts +132 -0
  28. package/dist/env-binding.d.ts.map +1 -0
  29. package/dist/env-binding.js +4 -0
  30. package/dist/env-binding.js.map +1 -0
  31. package/dist/errors.d.ts +37 -0
  32. package/dist/errors.d.ts.map +1 -0
  33. package/dist/errors.js +268 -0
  34. package/dist/errors.js.map +1 -0
  35. package/dist/eval-run-binding.d.ts +196 -0
  36. package/dist/eval-run-binding.d.ts.map +1 -0
  37. package/dist/eval-run-binding.js +16 -0
  38. package/dist/eval-run-binding.js.map +1 -0
  39. package/dist/eval-run-dispatcher.d.ts +131 -0
  40. package/dist/eval-run-dispatcher.d.ts.map +1 -0
  41. package/dist/eval-run-dispatcher.js +368 -0
  42. package/dist/eval-run-dispatcher.js.map +1 -0
  43. package/dist/eval-suite-binding.d.ts +227 -0
  44. package/dist/eval-suite-binding.d.ts.map +1 -0
  45. package/dist/eval-suite-binding.js +24 -0
  46. package/dist/eval-suite-binding.js.map +1 -0
  47. package/dist/event-bus-binding.d.ts +107 -0
  48. package/dist/event-bus-binding.d.ts.map +1 -0
  49. package/dist/event-bus-binding.js +5 -0
  50. package/dist/event-bus-binding.js.map +1 -0
  51. package/dist/flow-binding.d.ts +194 -0
  52. package/dist/flow-binding.d.ts.map +1 -0
  53. package/dist/flow-binding.js +4 -0
  54. package/dist/flow-binding.js.map +1 -0
  55. package/dist/guardrail-binding.d.ts +138 -0
  56. package/dist/guardrail-binding.d.ts.map +1 -0
  57. package/dist/guardrail-binding.js +4 -0
  58. package/dist/guardrail-binding.js.map +1 -0
  59. package/dist/handler-binding.d.ts +126 -0
  60. package/dist/handler-binding.d.ts.map +1 -0
  61. package/dist/handler-binding.js +4 -0
  62. package/dist/handler-binding.js.map +1 -0
  63. package/dist/hitl-binding.d.ts +115 -0
  64. package/dist/hitl-binding.d.ts.map +1 -0
  65. package/dist/hitl-binding.js +4 -0
  66. package/dist/hitl-binding.js.map +1 -0
  67. package/dist/identity-directory-binding.d.ts +116 -0
  68. package/dist/identity-directory-binding.d.ts.map +1 -0
  69. package/dist/identity-directory-binding.js +4 -0
  70. package/dist/identity-directory-binding.js.map +1 -0
  71. package/dist/identity-provider-binding.d.ts +184 -0
  72. package/dist/identity-provider-binding.d.ts.map +1 -0
  73. package/dist/identity-provider-binding.js +4 -0
  74. package/dist/identity-provider-binding.js.map +1 -0
  75. package/dist/image-registry-binding.d.ts +165 -0
  76. package/dist/image-registry-binding.d.ts.map +1 -0
  77. package/dist/image-registry-binding.js +4 -0
  78. package/dist/image-registry-binding.js.map +1 -0
  79. package/dist/index.d.ts +72 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +26 -0
  82. package/dist/index.js.map +1 -0
  83. package/dist/key-management-binding.d.ts +101 -0
  84. package/dist/key-management-binding.d.ts.map +1 -0
  85. package/dist/key-management-binding.js +4 -0
  86. package/dist/key-management-binding.js.map +1 -0
  87. package/dist/mcp-endpoint-binding.d.ts +312 -0
  88. package/dist/mcp-endpoint-binding.d.ts.map +1 -0
  89. package/dist/mcp-endpoint-binding.js +12 -0
  90. package/dist/mcp-endpoint-binding.js.map +1 -0
  91. package/dist/memory-binding.d.ts +209 -0
  92. package/dist/memory-binding.d.ts.map +1 -0
  93. package/dist/memory-binding.js +4 -0
  94. package/dist/memory-binding.js.map +1 -0
  95. package/dist/middleware/auth.d.ts +168 -0
  96. package/dist/middleware/auth.d.ts.map +1 -0
  97. package/dist/middleware/auth.js +247 -0
  98. package/dist/middleware/auth.js.map +1 -0
  99. package/dist/middleware/authorize.d.ts +26 -0
  100. package/dist/middleware/authorize.d.ts.map +1 -0
  101. package/dist/middleware/authorize.js +65 -0
  102. package/dist/middleware/authorize.js.map +1 -0
  103. package/dist/middleware/error-mapper.d.ts +20 -0
  104. package/dist/middleware/error-mapper.d.ts.map +1 -0
  105. package/dist/middleware/error-mapper.js +34 -0
  106. package/dist/middleware/error-mapper.js.map +1 -0
  107. package/dist/middleware/idempotency.d.ts +43 -0
  108. package/dist/middleware/idempotency.d.ts.map +1 -0
  109. package/dist/middleware/idempotency.js +118 -0
  110. package/dist/middleware/idempotency.js.map +1 -0
  111. package/dist/middleware/principal.d.ts +4 -0
  112. package/dist/middleware/principal.d.ts.map +1 -0
  113. package/dist/middleware/principal.js +42 -0
  114. package/dist/middleware/principal.js.map +1 -0
  115. package/dist/middleware/public-run-routes.d.ts +16 -0
  116. package/dist/middleware/public-run-routes.d.ts.map +1 -0
  117. package/dist/middleware/public-run-routes.js +43 -0
  118. package/dist/middleware/public-run-routes.js.map +1 -0
  119. package/dist/middleware/request-id.d.ts +14 -0
  120. package/dist/middleware/request-id.d.ts.map +1 -0
  121. package/dist/middleware/request-id.js +24 -0
  122. package/dist/middleware/request-id.js.map +1 -0
  123. package/dist/middleware/sigv4-verify.d.ts +64 -0
  124. package/dist/middleware/sigv4-verify.d.ts.map +1 -0
  125. package/dist/middleware/sigv4-verify.js +286 -0
  126. package/dist/middleware/sigv4-verify.js.map +1 -0
  127. package/dist/middleware/sigv4.d.ts +25 -0
  128. package/dist/middleware/sigv4.d.ts.map +1 -0
  129. package/dist/middleware/sigv4.js +120 -0
  130. package/dist/middleware/sigv4.js.map +1 -0
  131. package/dist/openapi/generate.d.ts +15 -0
  132. package/dist/openapi/generate.d.ts.map +1 -0
  133. package/dist/openapi/generate.js +241 -0
  134. package/dist/openapi/generate.js.map +1 -0
  135. package/dist/openapi/operations.d.ts +70 -0
  136. package/dist/openapi/operations.d.ts.map +1 -0
  137. package/dist/openapi/operations.js +5050 -0
  138. package/dist/openapi/operations.js.map +1 -0
  139. package/dist/openapi/schemas.d.ts +590 -0
  140. package/dist/openapi/schemas.d.ts.map +1 -0
  141. package/dist/openapi/schemas.js +5820 -0
  142. package/dist/openapi/schemas.js.map +1 -0
  143. package/dist/provenance-binding.d.ts +116 -0
  144. package/dist/provenance-binding.d.ts.map +1 -0
  145. package/dist/provenance-binding.js +31 -0
  146. package/dist/provenance-binding.js.map +1 -0
  147. package/dist/provider-binding.d.ts +174 -0
  148. package/dist/provider-binding.d.ts.map +1 -0
  149. package/dist/provider-binding.js +4 -0
  150. package/dist/provider-binding.js.map +1 -0
  151. package/dist/public-run-token.d.ts +97 -0
  152. package/dist/public-run-token.d.ts.map +1 -0
  153. package/dist/public-run-token.js +167 -0
  154. package/dist/public-run-token.js.map +1 -0
  155. package/dist/retention-binding.d.ts +69 -0
  156. package/dist/retention-binding.d.ts.map +1 -0
  157. package/dist/retention-binding.js +4 -0
  158. package/dist/retention-binding.js.map +1 -0
  159. package/dist/reviewer-binding.d.ts +84 -0
  160. package/dist/reviewer-binding.d.ts.map +1 -0
  161. package/dist/reviewer-binding.js +4 -0
  162. package/dist/reviewer-binding.js.map +1 -0
  163. package/dist/rotation-status-store.d.ts +96 -0
  164. package/dist/rotation-status-store.d.ts.map +1 -0
  165. package/dist/rotation-status-store.js +106 -0
  166. package/dist/rotation-status-store.js.map +1 -0
  167. package/dist/routes/adapters.d.ts +29 -0
  168. package/dist/routes/adapters.d.ts.map +1 -0
  169. package/dist/routes/adapters.js +230 -0
  170. package/dist/routes/adapters.js.map +1 -0
  171. package/dist/routes/agents.d.ts +17 -0
  172. package/dist/routes/agents.d.ts.map +1 -0
  173. package/dist/routes/agents.js +342 -0
  174. package/dist/routes/agents.js.map +1 -0
  175. package/dist/routes/approvals.d.ts +37 -0
  176. package/dist/routes/approvals.d.ts.map +1 -0
  177. package/dist/routes/approvals.js +551 -0
  178. package/dist/routes/approvals.js.map +1 -0
  179. package/dist/routes/artifacts.d.ts +25 -0
  180. package/dist/routes/artifacts.d.ts.map +1 -0
  181. package/dist/routes/artifacts.js +265 -0
  182. package/dist/routes/artifacts.js.map +1 -0
  183. package/dist/routes/audit.d.ts +6 -0
  184. package/dist/routes/audit.d.ts.map +1 -0
  185. package/dist/routes/audit.js +162 -0
  186. package/dist/routes/audit.js.map +1 -0
  187. package/dist/routes/auth.d.ts +47 -0
  188. package/dist/routes/auth.d.ts.map +1 -0
  189. package/dist/routes/auth.js +630 -0
  190. package/dist/routes/auth.js.map +1 -0
  191. package/dist/routes/capabilities.d.ts +14 -0
  192. package/dist/routes/capabilities.d.ts.map +1 -0
  193. package/dist/routes/capabilities.js +62 -0
  194. package/dist/routes/capabilities.js.map +1 -0
  195. package/dist/routes/compliance.d.ts +37 -0
  196. package/dist/routes/compliance.d.ts.map +1 -0
  197. package/dist/routes/compliance.js +321 -0
  198. package/dist/routes/compliance.js.map +1 -0
  199. package/dist/routes/conversations.d.ts +13 -0
  200. package/dist/routes/conversations.d.ts.map +1 -0
  201. package/dist/routes/conversations.js +295 -0
  202. package/dist/routes/conversations.js.map +1 -0
  203. package/dist/routes/cost.d.ts +24 -0
  204. package/dist/routes/cost.d.ts.map +1 -0
  205. package/dist/routes/cost.js +243 -0
  206. package/dist/routes/cost.js.map +1 -0
  207. package/dist/routes/deployments.d.ts +122 -0
  208. package/dist/routes/deployments.d.ts.map +1 -0
  209. package/dist/routes/deployments.js +1036 -0
  210. package/dist/routes/deployments.js.map +1 -0
  211. package/dist/routes/env.d.ts +62 -0
  212. package/dist/routes/env.d.ts.map +1 -0
  213. package/dist/routes/env.js +311 -0
  214. package/dist/routes/env.js.map +1 -0
  215. package/dist/routes/eval-runs.d.ts +28 -0
  216. package/dist/routes/eval-runs.d.ts.map +1 -0
  217. package/dist/routes/eval-runs.js +479 -0
  218. package/dist/routes/eval-runs.js.map +1 -0
  219. package/dist/routes/eval-suites.d.ts +24 -0
  220. package/dist/routes/eval-suites.d.ts.map +1 -0
  221. package/dist/routes/eval-suites.js +381 -0
  222. package/dist/routes/eval-suites.js.map +1 -0
  223. package/dist/routes/event-triggers.d.ts +12 -0
  224. package/dist/routes/event-triggers.d.ts.map +1 -0
  225. package/dist/routes/event-triggers.js +218 -0
  226. package/dist/routes/event-triggers.js.map +1 -0
  227. package/dist/routes/flows.d.ts +23 -0
  228. package/dist/routes/flows.d.ts.map +1 -0
  229. package/dist/routes/flows.js +344 -0
  230. package/dist/routes/flows.js.map +1 -0
  231. package/dist/routes/guardrails.d.ts +33 -0
  232. package/dist/routes/guardrails.d.ts.map +1 -0
  233. package/dist/routes/guardrails.js +236 -0
  234. package/dist/routes/guardrails.js.map +1 -0
  235. package/dist/routes/identity.d.ts +39 -0
  236. package/dist/routes/identity.d.ts.map +1 -0
  237. package/dist/routes/identity.js +138 -0
  238. package/dist/routes/identity.js.map +1 -0
  239. package/dist/routes/mcp.d.ts +23 -0
  240. package/dist/routes/mcp.d.ts.map +1 -0
  241. package/dist/routes/mcp.js +727 -0
  242. package/dist/routes/mcp.js.map +1 -0
  243. package/dist/routes/memory.d.ts +16 -0
  244. package/dist/routes/memory.d.ts.map +1 -0
  245. package/dist/routes/memory.js +353 -0
  246. package/dist/routes/memory.js.map +1 -0
  247. package/dist/routes/observations.d.ts +19 -0
  248. package/dist/routes/observations.d.ts.map +1 -0
  249. package/dist/routes/observations.js +135 -0
  250. package/dist/routes/observations.js.map +1 -0
  251. package/dist/routes/orgs.d.ts +24 -0
  252. package/dist/routes/orgs.d.ts.map +1 -0
  253. package/dist/routes/orgs.js +208 -0
  254. package/dist/routes/orgs.js.map +1 -0
  255. package/dist/routes/pagination.d.ts +18 -0
  256. package/dist/routes/pagination.d.ts.map +1 -0
  257. package/dist/routes/pagination.js +35 -0
  258. package/dist/routes/pagination.js.map +1 -0
  259. package/dist/routes/policies.d.ts +23 -0
  260. package/dist/routes/policies.d.ts.map +1 -0
  261. package/dist/routes/policies.js +314 -0
  262. package/dist/routes/policies.js.map +1 -0
  263. package/dist/routes/projects.d.ts +45 -0
  264. package/dist/routes/projects.d.ts.map +1 -0
  265. package/dist/routes/projects.js +485 -0
  266. package/dist/routes/projects.js.map +1 -0
  267. package/dist/routes/proposals.d.ts +24 -0
  268. package/dist/routes/proposals.d.ts.map +1 -0
  269. package/dist/routes/proposals.js +581 -0
  270. package/dist/routes/proposals.js.map +1 -0
  271. package/dist/routes/provenance.d.ts +34 -0
  272. package/dist/routes/provenance.d.ts.map +1 -0
  273. package/dist/routes/provenance.js +274 -0
  274. package/dist/routes/provenance.js.map +1 -0
  275. package/dist/routes/providers.d.ts +32 -0
  276. package/dist/routes/providers.d.ts.map +1 -0
  277. package/dist/routes/providers.js +490 -0
  278. package/dist/routes/providers.js.map +1 -0
  279. package/dist/routes/public-run-tokens.d.ts +17 -0
  280. package/dist/routes/public-run-tokens.d.ts.map +1 -0
  281. package/dist/routes/public-run-tokens.js +69 -0
  282. package/dist/routes/public-run-tokens.js.map +1 -0
  283. package/dist/routes/retention.d.ts +19 -0
  284. package/dist/routes/retention.d.ts.map +1 -0
  285. package/dist/routes/retention.js +152 -0
  286. package/dist/routes/retention.js.map +1 -0
  287. package/dist/routes/reviewers.d.ts +5 -0
  288. package/dist/routes/reviewers.d.ts.map +1 -0
  289. package/dist/routes/reviewers.js +161 -0
  290. package/dist/routes/reviewers.js.map +1 -0
  291. package/dist/routes/runs.d.ts +34 -0
  292. package/dist/routes/runs.d.ts.map +1 -0
  293. package/dist/routes/runs.js +705 -0
  294. package/dist/routes/runs.js.map +1 -0
  295. package/dist/routes/s3.d.ts +31 -0
  296. package/dist/routes/s3.d.ts.map +1 -0
  297. package/dist/routes/s3.js +433 -0
  298. package/dist/routes/s3.js.map +1 -0
  299. package/dist/routes/schedules.d.ts +20 -0
  300. package/dist/routes/schedules.d.ts.map +1 -0
  301. package/dist/routes/schedules.js +234 -0
  302. package/dist/routes/schedules.js.map +1 -0
  303. package/dist/routes/scope-params.d.ts +57 -0
  304. package/dist/routes/scope-params.d.ts.map +1 -0
  305. package/dist/routes/scope-params.js +105 -0
  306. package/dist/routes/scope-params.js.map +1 -0
  307. package/dist/routes/secret-ref.d.ts +20 -0
  308. package/dist/routes/secret-ref.d.ts.map +1 -0
  309. package/dist/routes/secret-ref.js +42 -0
  310. package/dist/routes/secret-ref.js.map +1 -0
  311. package/dist/routes/secrets.d.ts +53 -0
  312. package/dist/routes/secrets.d.ts.map +1 -0
  313. package/dist/routes/secrets.js +715 -0
  314. package/dist/routes/secrets.js.map +1 -0
  315. package/dist/routes/signing-keys.d.ts +23 -0
  316. package/dist/routes/signing-keys.d.ts.map +1 -0
  317. package/dist/routes/signing-keys.js +212 -0
  318. package/dist/routes/signing-keys.js.map +1 -0
  319. package/dist/routes/sse.d.ts +58 -0
  320. package/dist/routes/sse.d.ts.map +1 -0
  321. package/dist/routes/sse.js +92 -0
  322. package/dist/routes/sse.js.map +1 -0
  323. package/dist/routes/teams.d.ts +30 -0
  324. package/dist/routes/teams.d.ts.map +1 -0
  325. package/dist/routes/teams.js +443 -0
  326. package/dist/routes/teams.js.map +1 -0
  327. package/dist/routes/tenant.d.ts +57 -0
  328. package/dist/routes/tenant.d.ts.map +1 -0
  329. package/dist/routes/tenant.js +352 -0
  330. package/dist/routes/tenant.js.map +1 -0
  331. package/dist/routes/tokens.d.ts +14 -0
  332. package/dist/routes/tokens.d.ts.map +1 -0
  333. package/dist/routes/tokens.js +231 -0
  334. package/dist/routes/tokens.js.map +1 -0
  335. package/dist/routes/tools.d.ts +33 -0
  336. package/dist/routes/tools.d.ts.map +1 -0
  337. package/dist/routes/tools.js +380 -0
  338. package/dist/routes/tools.js.map +1 -0
  339. package/dist/routes/webhook-endpoints.d.ts +10 -0
  340. package/dist/routes/webhook-endpoints.d.ts.map +1 -0
  341. package/dist/routes/webhook-endpoints.js +407 -0
  342. package/dist/routes/webhook-endpoints.js.map +1 -0
  343. package/dist/routes/webhooks.d.ts +21 -0
  344. package/dist/routes/webhooks.d.ts.map +1 -0
  345. package/dist/routes/webhooks.js +228 -0
  346. package/dist/routes/webhooks.js.map +1 -0
  347. package/dist/s3-credential-binding.d.ts +54 -0
  348. package/dist/s3-credential-binding.d.ts.map +1 -0
  349. package/dist/s3-credential-binding.js +4 -0
  350. package/dist/s3-credential-binding.js.map +1 -0
  351. package/dist/secrets-binding.d.ts +281 -0
  352. package/dist/secrets-binding.d.ts.map +1 -0
  353. package/dist/secrets-binding.js +10 -0
  354. package/dist/secrets-binding.js.map +1 -0
  355. package/dist/secrets-provider-binding.d.ts +164 -0
  356. package/dist/secrets-provider-binding.d.ts.map +1 -0
  357. package/dist/secrets-provider-binding.js +4 -0
  358. package/dist/secrets-provider-binding.js.map +1 -0
  359. package/dist/session-store-binding.d.ts +148 -0
  360. package/dist/session-store-binding.d.ts.map +1 -0
  361. package/dist/session-store-binding.js +4 -0
  362. package/dist/session-store-binding.js.map +1 -0
  363. package/dist/signing-key-binding.d.ts +210 -0
  364. package/dist/signing-key-binding.d.ts.map +1 -0
  365. package/dist/signing-key-binding.js +4 -0
  366. package/dist/signing-key-binding.js.map +1 -0
  367. package/dist/state-store-binding.d.ts +53 -0
  368. package/dist/state-store-binding.d.ts.map +1 -0
  369. package/dist/state-store-binding.js +38 -0
  370. package/dist/state-store-binding.js.map +1 -0
  371. package/dist/supervisor-binding.d.ts +526 -0
  372. package/dist/supervisor-binding.d.ts.map +1 -0
  373. package/dist/supervisor-binding.js +4 -0
  374. package/dist/supervisor-binding.js.map +1 -0
  375. package/dist/tenant-host-access.d.ts +41 -0
  376. package/dist/tenant-host-access.d.ts.map +1 -0
  377. package/dist/tenant-host-access.js +42 -0
  378. package/dist/tenant-host-access.js.map +1 -0
  379. package/dist/token-admin.d.ts +99 -0
  380. package/dist/token-admin.d.ts.map +1 -0
  381. package/dist/token-admin.js +4 -0
  382. package/dist/token-admin.js.map +1 -0
  383. package/dist/tool-binding.d.ts +247 -0
  384. package/dist/tool-binding.d.ts.map +1 -0
  385. package/dist/tool-binding.js +4 -0
  386. package/dist/tool-binding.js.map +1 -0
  387. package/dist/trigger-binding.d.ts +13 -0
  388. package/dist/trigger-binding.d.ts.map +1 -0
  389. package/dist/trigger-binding.js +4 -0
  390. package/dist/trigger-binding.js.map +1 -0
  391. package/dist/types.d.ts +71 -0
  392. package/dist/types.d.ts.map +1 -0
  393. package/dist/types.js +4 -0
  394. package/dist/types.js.map +1 -0
  395. package/dist/webhook-endpoint-binding.d.ts +230 -0
  396. package/dist/webhook-endpoint-binding.d.ts.map +1 -0
  397. package/dist/webhook-endpoint-binding.js +12 -0
  398. package/dist/webhook-endpoint-binding.js.map +1 -0
  399. package/dist/xml.d.ts +79 -0
  400. package/dist/xml.d.ts.map +1 -0
  401. package/dist/xml.js +115 -0
  402. package/dist/xml.js.map +1 -0
  403. package/openapi.json +29649 -0
  404. package/package.json +76 -4
  405. package/scripts/emit-openapi.mjs +44 -0
  406. package/src/adapter-binding.ts +204 -0
  407. package/src/agent-binding.ts +231 -0
  408. package/src/app.ts +1286 -0
  409. package/src/capability-binding.ts +83 -0
  410. package/src/cost-binding.ts +213 -0
  411. package/src/deployment-binding.ts +225 -0
  412. package/src/env-binding.ts +140 -0
  413. package/src/errors.ts +295 -0
  414. package/src/eval-run-binding.ts +209 -0
  415. package/src/eval-run-dispatcher.ts +497 -0
  416. package/src/eval-suite-binding.ts +257 -0
  417. package/src/event-bus-binding.ts +127 -0
  418. package/src/flow-binding.ts +213 -0
  419. package/src/guardrail-binding.ts +151 -0
  420. package/src/handler-binding.ts +132 -0
  421. package/src/hitl-binding.ts +172 -0
  422. package/src/identity-directory-binding.ts +128 -0
  423. package/src/identity-provider-binding.ts +203 -0
  424. package/src/image-registry-binding.ts +193 -0
  425. package/src/index.ts +606 -0
  426. package/src/key-management-binding.ts +91 -0
  427. package/src/mcp-endpoint-binding.ts +311 -0
  428. package/src/memory-binding.ts +239 -0
  429. package/src/middleware/auth.ts +437 -0
  430. package/src/middleware/authorize.ts +125 -0
  431. package/src/middleware/error-mapper.ts +40 -0
  432. package/src/middleware/idempotency.ts +160 -0
  433. package/src/middleware/principal.ts +64 -0
  434. package/src/middleware/public-run-routes.ts +50 -0
  435. package/src/middleware/request-id.ts +28 -0
  436. package/src/middleware/sigv4-verify.ts +374 -0
  437. package/src/middleware/sigv4.ts +165 -0
  438. package/src/openapi/generate.ts +307 -0
  439. package/src/openapi/operations.ts +5444 -0
  440. package/src/openapi/schemas.ts +6363 -0
  441. package/src/provenance-binding.ts +169 -0
  442. package/src/provider-binding.ts +196 -0
  443. package/src/public-run-token.ts +263 -0
  444. package/src/retention-binding.ts +78 -0
  445. package/src/reviewer-binding.ts +99 -0
  446. package/src/rotation-status-store.ts +209 -0
  447. package/src/routes/adapters.ts +319 -0
  448. package/src/routes/agents.ts +424 -0
  449. package/src/routes/approvals.ts +759 -0
  450. package/src/routes/artifacts.ts +317 -0
  451. package/src/routes/audit.ts +219 -0
  452. package/src/routes/auth.ts +806 -0
  453. package/src/routes/capabilities.ts +79 -0
  454. package/src/routes/compliance.ts +482 -0
  455. package/src/routes/conversations.ts +369 -0
  456. package/src/routes/cost.ts +327 -0
  457. package/src/routes/deployments.ts +1493 -0
  458. package/src/routes/env.ts +429 -0
  459. package/src/routes/eval-runs.ts +631 -0
  460. package/src/routes/eval-suites.ts +490 -0
  461. package/src/routes/event-triggers.ts +283 -0
  462. package/src/routes/flows.ts +423 -0
  463. package/src/routes/guardrails.ts +320 -0
  464. package/src/routes/identity.ts +203 -0
  465. package/src/routes/mcp.ts +940 -0
  466. package/src/routes/memory.ts +430 -0
  467. package/src/routes/observations.ts +175 -0
  468. package/src/routes/orgs.ts +273 -0
  469. package/src/routes/pagination.ts +51 -0
  470. package/src/routes/policies.ts +413 -0
  471. package/src/routes/projects.ts +634 -0
  472. package/src/routes/proposals.ts +719 -0
  473. package/src/routes/provenance.ts +406 -0
  474. package/src/routes/providers.ts +624 -0
  475. package/src/routes/public-run-tokens.ts +104 -0
  476. package/src/routes/retention.ts +193 -0
  477. package/src/routes/reviewers.ts +209 -0
  478. package/src/routes/runs.ts +892 -0
  479. package/src/routes/s3.ts +519 -0
  480. package/src/routes/schedules.ts +300 -0
  481. package/src/routes/scope-params.ts +133 -0
  482. package/src/routes/secret-ref.ts +52 -0
  483. package/src/routes/secrets.ts +975 -0
  484. package/src/routes/signing-keys.ts +259 -0
  485. package/src/routes/sse.ts +148 -0
  486. package/src/routes/teams.ts +584 -0
  487. package/src/routes/tenant.ts +530 -0
  488. package/src/routes/tokens.ts +285 -0
  489. package/src/routes/tools.ts +491 -0
  490. package/src/routes/webhook-endpoints.ts +534 -0
  491. package/src/routes/webhooks.ts +296 -0
  492. package/src/s3-credential-binding.ts +58 -0
  493. package/src/secrets-binding.ts +308 -0
  494. package/src/secrets-provider-binding.ts +167 -0
  495. package/src/session-store-binding.ts +163 -0
  496. package/src/signing-key-binding.ts +235 -0
  497. package/src/state-store-binding.ts +84 -0
  498. package/src/supervisor-binding.ts +554 -0
  499. package/src/tenant-host-access.ts +62 -0
  500. package/src/token-admin.ts +104 -0
  501. package/src/tool-binding.ts +274 -0
  502. package/src/trigger-binding.ts +38 -0
  503. package/src/types.ts +74 -0
  504. package/src/webhook-endpoint-binding.ts +246 -0
  505. package/src/xml.ts +196 -0
@@ -0,0 +1,283 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+
4
+ import { Hono } from 'hono';
5
+ import type { Context } from 'hono';
6
+
7
+ import type { Cursor, TenantId, TriggerId } from '@kindgi/types';
8
+
9
+ import { statusFor, toWireError } from '../errors.js';
10
+ import type {
11
+ EventTriggerRecord,
12
+ RegisterEventTriggerInput,
13
+ TriggerRegistryBinding,
14
+ UpdateEventTriggerInput,
15
+ } from '../trigger-binding.js';
16
+ import type { AppEnv } from '../types.js';
17
+ import { clampLimit } from './pagination.js';
18
+
19
+ /**
20
+ * Event triggers — fire a flow run when a matching event arrives on
21
+ * the framework event bus.
22
+ *
23
+ * Seven routes, mirroring the schedules surface. This surface registers
24
+ * triggers; it does not publish events.
25
+ */
26
+ export function eventTriggersRouter(binding: TriggerRegistryBinding): Hono<AppEnv> {
27
+ const r = new Hono<AppEnv>();
28
+
29
+ // ---------- POST / (register) ----------
30
+ r.post('/', async (c) => {
31
+ const requestId = c.get('requestId');
32
+ const tenantId = c.get('tenantId') as TenantId;
33
+
34
+ const parsed = await parseJsonObject(c, requestId);
35
+ if (parsed.kind === 'err') return parsed.response;
36
+ const body = parsed.value;
37
+
38
+ const flowId = requireString(body, 'flowId');
39
+ const flowVersion = requireString(body, 'flowVersion');
40
+ const eventKind = requireString(body.config, 'config.eventKind');
41
+ if (flowId.kind === 'err') return bad(c, requestId, flowId.message);
42
+ if (flowVersion.kind === 'err') return bad(c, requestId, flowVersion.message);
43
+ if (eventKind.kind === 'err') return bad(c, requestId, eventKind.message);
44
+
45
+ const rawConfig = (body.config ?? {}) as Record<string, unknown>;
46
+ const registerInput: RegisterEventTriggerInput = {
47
+ kind: 'event',
48
+ tenantId,
49
+ flowId: flowId.value,
50
+ flowVersion: flowVersion.value,
51
+ config: {
52
+ eventKind: eventKind.value,
53
+ ...('input' in rawConfig && { input: rawConfig.input }),
54
+ },
55
+ ...(typeof body.label === 'string' && body.label.length > 0 && { label: body.label }),
56
+ };
57
+
58
+ const result = await binding.register(registerInput);
59
+ if (result.kind === 'err') {
60
+ c.status(statusFor(result.error.code) as never);
61
+ return c.json(
62
+ toWireError({ code: result.error.code, message: result.error.message }, requestId),
63
+ );
64
+ }
65
+ c.status(201);
66
+ return c.json(serializeEventTrigger(result.value as EventTriggerRecord));
67
+ });
68
+
69
+ // ---------- GET / (list) ----------
70
+ r.get('/', async (c) => {
71
+ const tenantId = c.get('tenantId') as TenantId;
72
+ const limit = clampLimit(c.req.query('limit'));
73
+ const cursorRaw = c.req.query('cursor');
74
+ const statusRaw = c.req.query('status');
75
+
76
+ let statusFilter: 'active' | 'paused' | undefined;
77
+ if (statusRaw === 'active' || statusRaw === 'paused') statusFilter = statusRaw;
78
+
79
+ const page = await binding.list({
80
+ tenantId,
81
+ kind: 'event',
82
+ limit,
83
+ ...(cursorRaw !== undefined && cursorRaw.length > 0 && { cursor: cursorRaw as Cursor }),
84
+ ...(statusFilter !== undefined && { status: statusFilter }),
85
+ });
86
+ return c.json({
87
+ data: page.data.map((row) => serializeEventTrigger(row as EventTriggerRecord)),
88
+ hasMore: page.nextCursor !== undefined,
89
+ ...(page.nextCursor !== undefined && { nextCursor: page.nextCursor as unknown as string }),
90
+ });
91
+ });
92
+
93
+ // ---------- GET /:triggerId (get) ----------
94
+ r.get('/:triggerId', async (c) => {
95
+ const requestId = c.get('requestId');
96
+ const tenantId = c.get('tenantId') as TenantId;
97
+ const triggerId = c.req.param('triggerId') as TriggerId;
98
+
99
+ const rec = await binding.get({ tenantId, triggerId });
100
+ if (rec === null || rec.kind !== 'event') return notFound(c, requestId, triggerId);
101
+ return c.json(serializeEventTrigger(rec));
102
+ });
103
+
104
+ // ---------- PATCH /:triggerId (update) ----------
105
+ r.patch('/:triggerId', async (c) => {
106
+ const requestId = c.get('requestId');
107
+ const tenantId = c.get('tenantId') as TenantId;
108
+ const triggerId = c.req.param('triggerId') as TriggerId;
109
+
110
+ const parsed = await parseJsonObject(c, requestId);
111
+ if (parsed.kind === 'err') return parsed.response;
112
+ const body = parsed.value;
113
+
114
+ const patchConfig = body.config as Record<string, unknown> | undefined;
115
+ const cfg: Partial<{ eventKind: string; input: unknown }> = {};
116
+ if (patchConfig !== undefined) {
117
+ if (typeof patchConfig.eventKind === 'string') cfg.eventKind = patchConfig.eventKind;
118
+ if ('input' in patchConfig) cfg.input = patchConfig.input;
119
+ }
120
+
121
+ const updateInput: UpdateEventTriggerInput = {
122
+ kind: 'event',
123
+ tenantId,
124
+ triggerId,
125
+ ...(Object.keys(cfg).length > 0 && { config: cfg }),
126
+ ...('label' in body && { label: body.label === null ? null : (body.label as string) }),
127
+ ...(typeof body.flowVersion === 'string' && { flowVersion: body.flowVersion }),
128
+ };
129
+
130
+ const result = await binding.update(updateInput);
131
+ if (result.kind === 'err') {
132
+ c.status(statusFor(result.error.code) as never);
133
+ return c.json(
134
+ toWireError(
135
+ {
136
+ code: result.error.code,
137
+ message: result.error.message,
138
+ triggerId: triggerId as unknown as string,
139
+ },
140
+ requestId,
141
+ ),
142
+ );
143
+ }
144
+ return c.json(serializeEventTrigger(result.value as EventTriggerRecord));
145
+ });
146
+
147
+ // ---------- POST /:triggerId/pause ----------
148
+ r.post('/:triggerId/pause', async (c) => {
149
+ const requestId = c.get('requestId');
150
+ const tenantId = c.get('tenantId') as TenantId;
151
+ const triggerId = c.req.param('triggerId') as TriggerId;
152
+ const result = await binding.pause({ tenantId, triggerId });
153
+ if (result.kind === 'err') return lifecycleError(c, requestId, result.error, triggerId);
154
+ return c.json(serializeEventTrigger(result.value as EventTriggerRecord));
155
+ });
156
+
157
+ // ---------- POST /:triggerId/resume ----------
158
+ r.post('/:triggerId/resume', async (c) => {
159
+ const requestId = c.get('requestId');
160
+ const tenantId = c.get('tenantId') as TenantId;
161
+ const triggerId = c.req.param('triggerId') as TriggerId;
162
+ const result = await binding.resume({ tenantId, triggerId });
163
+ if (result.kind === 'err') return lifecycleError(c, requestId, result.error, triggerId);
164
+ return c.json(serializeEventTrigger(result.value as EventTriggerRecord));
165
+ });
166
+
167
+ // ---------- POST /:triggerId/unregister (soft delete) ----------
168
+ r.post('/:triggerId/unregister', async (c) => {
169
+ const tenantId = c.get('tenantId') as TenantId;
170
+ const triggerId = c.req.param('triggerId') as TriggerId;
171
+ const outcome = await binding.unregister({ tenantId, triggerId });
172
+ return c.json({
173
+ eventTriggerId: triggerId as unknown as string,
174
+ unregistered: outcome.unregistered,
175
+ });
176
+ });
177
+
178
+ return r;
179
+ }
180
+
181
+ function serializeEventTrigger(r: EventTriggerRecord): Record<string, unknown> {
182
+ return {
183
+ eventTriggerId: r.triggerId as unknown as string,
184
+ triggerId: r.triggerId as unknown as string,
185
+ flowId: r.flowId,
186
+ flowVersion: r.flowVersion,
187
+ eventKind: r.config.eventKind,
188
+ ...(r.config.input !== undefined && { input: r.config.input }),
189
+ label: r.label,
190
+ status: r.status,
191
+ lastFiredAt: r.lastFiredAt,
192
+ createdAt: r.createdAt,
193
+ updatedAt: r.updatedAt,
194
+ };
195
+ }
196
+
197
+ type ParseOk<T> = { readonly kind: 'ok'; readonly value: T };
198
+ type ParseErr = { readonly kind: 'err'; readonly response: Response };
199
+
200
+ async function parseJsonObject(
201
+ c: Context<AppEnv>,
202
+ requestId: string,
203
+ ): Promise<ParseOk<Record<string, unknown>> | ParseErr> {
204
+ let body: unknown;
205
+ try {
206
+ body = await c.req.json();
207
+ } catch {
208
+ c.status(statusFor('bad-input') as never);
209
+ return {
210
+ kind: 'err',
211
+ response: c.json(
212
+ toWireError({ code: 'bad-input', message: 'Request body must be valid JSON' }, requestId),
213
+ ),
214
+ };
215
+ }
216
+ if (body === null || typeof body !== 'object' || Array.isArray(body)) {
217
+ c.status(statusFor('bad-input') as never);
218
+ return {
219
+ kind: 'err',
220
+ response: c.json(
221
+ toWireError(
222
+ { code: 'bad-input', message: 'Request body must be a JSON object' },
223
+ requestId,
224
+ ),
225
+ ),
226
+ };
227
+ }
228
+ return { kind: 'ok', value: body as Record<string, unknown> };
229
+ }
230
+
231
+ function requireString(
232
+ obj: unknown,
233
+ path: string,
234
+ ):
235
+ | { readonly kind: 'ok'; readonly value: string }
236
+ | { readonly kind: 'err'; readonly message: string } {
237
+ const parts = path.split('.');
238
+ let cur: unknown = obj;
239
+ for (const part of parts) {
240
+ if (cur === null || typeof cur !== 'object') {
241
+ return { kind: 'err', message: `\`${path}\` is required` };
242
+ }
243
+ cur = (cur as Record<string, unknown>)[part];
244
+ }
245
+ if (typeof cur !== 'string' || cur.length === 0) {
246
+ return { kind: 'err', message: `\`${path}\` is required` };
247
+ }
248
+ return { kind: 'ok', value: cur };
249
+ }
250
+
251
+ function bad(c: Context<AppEnv>, requestId: string, message: string): Response {
252
+ c.status(statusFor('bad-input') as never);
253
+ return c.json(toWireError({ code: 'bad-input', message }, requestId));
254
+ }
255
+
256
+ function notFound(c: Context<AppEnv>, requestId: string, triggerId: TriggerId): Response {
257
+ c.status(statusFor('trigger-not-found') as never);
258
+ return c.json(
259
+ toWireError(
260
+ {
261
+ code: 'trigger-not-found',
262
+ message: `No trigger with id "${triggerId as unknown as string}"`,
263
+ triggerId: triggerId as unknown as string,
264
+ },
265
+ requestId,
266
+ ),
267
+ );
268
+ }
269
+
270
+ function lifecycleError(
271
+ c: Context<AppEnv>,
272
+ requestId: string,
273
+ error: { readonly code: string; readonly message: string },
274
+ triggerId: TriggerId,
275
+ ): Response {
276
+ c.status(statusFor(error.code) as never);
277
+ return c.json(
278
+ toWireError(
279
+ { code: error.code, message: error.message, triggerId: triggerId as unknown as string },
280
+ requestId,
281
+ ),
282
+ );
283
+ }
@@ -0,0 +1,423 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+
4
+ import { Hono } from 'hono';
5
+
6
+ import { type Principal, ref, tuplesForCreate } from '@kindgi/authz';
7
+ import { type Flow, type FlowError, loadFlow } from '@kindgi/flow';
8
+ import type { Cursor, FlowId, ProjectId, TenantId, UserId } from '@kindgi/types';
9
+
10
+ import { statusFor, toWireError } from '../errors.js';
11
+ import type { FlowRegistryBinding } from '../flow-binding.js';
12
+ import type { Authorizer } from '../middleware/authorize.js';
13
+ import type { AppEnv } from '../types.js';
14
+ import { clampLimit } from './pagination.js';
15
+ import { parseScopeParams } from './scope-params.js';
16
+
17
+ /**
18
+ * Flows resource routes.
19
+ *
20
+ * Registry storage is caller-plugged via `FlowRegistryBinding`,
21
+ * mirroring `AgentRegistryBinding` 1:1. The API package does not own
22
+ * persistence — the binding implementation supplies the store (tests
23
+ * wrap an in-memory `Map`-backed adapter).
24
+ *
25
+ * Publish is data-as-code: the body is a full `Flow` definition
26
+ * (`@kindgi/specs/flow.schema.json`). Validation runs through
27
+ * `@kindgi/flow.loadFlow(...)` so a flow published through the
28
+ * API is byte-identical to one constructed in-process.
29
+ *
30
+ * Run initiation stays at `POST /v1/runs` (one primitive,
31
+ * discriminated subject). No
32
+ * `/v1/flows/:flowId/run` route is added here.
33
+ */
34
+ export function flowsRouter(binding: FlowRegistryBinding, authorizer?: Authorizer): Hono<AppEnv> {
35
+ const r = new Hono<AppEnv>();
36
+
37
+ // Authorization — mirrors agents 1:1. Check the resource directly;
38
+ // permissions cascade from the parent project because publish writes
39
+ // the parent tuple in the same transaction.
40
+ if (authorizer !== undefined) {
41
+ r.use('/', async (c, next) => {
42
+ if (c.req.method !== 'POST') return next();
43
+ const tenantId = c.get('tenantId') as TenantId;
44
+ const mw = authorizer.authorize('admin', async () => {
45
+ try {
46
+ const body = await c.req.json();
47
+ const pid =
48
+ body !== null && typeof body === 'object'
49
+ ? (body as Record<string, unknown>).projectId
50
+ : undefined;
51
+ if (typeof pid === 'string' && pid.length > 0) return ref('project', pid);
52
+ } catch {
53
+ // POST handler validates + returns 400
54
+ }
55
+ return ref('tenant', tenantId as unknown as string);
56
+ });
57
+ return mw(c, next);
58
+ });
59
+ r.use('/', async (c, next) => {
60
+ if (c.req.method !== 'GET') return next();
61
+ // A project filter needs read on that project. Parse it as the
62
+ // handler does (`?scopeKind=project&scopeId=`).
63
+ const s = parseScopeParams((n) => c.req.query(n), {
64
+ tenantId: c.get('tenantId') as TenantId,
65
+ });
66
+ if (s.kind !== 'ok' || s.scope?.kind !== 'project') return next();
67
+ const scopeProjectId = s.scope.projectId as unknown as string;
68
+ const mw = authorizer.authorize('read', () => ref('project', scopeProjectId));
69
+ return mw(c, next);
70
+ });
71
+ r.use('/:flowId/*', async (c, next) => {
72
+ const action = c.req.method === 'GET' ? 'read' : 'admin';
73
+ const flowId = c.req.param('flowId') ?? '';
74
+ const mw = authorizer.authorize(action, () => ref('flow', flowId));
75
+ return mw(c, next);
76
+ });
77
+ r.use('/:flowId', async (c, next) => {
78
+ if (c.req.method !== 'GET') return next();
79
+ const flowId = c.req.param('flowId') ?? '';
80
+ const mw = authorizer.authorize('read', () => ref('flow', flowId));
81
+ return mw(c, next);
82
+ });
83
+ }
84
+
85
+ // ---------- GET / (list, cursor-paginated) ----------
86
+ r.get('/', async (c) => {
87
+ const requestId = c.get('requestId');
88
+ const tenantId = c.get('tenantId') as TenantId;
89
+ const limit = clampLimit(c.req.query('limit'));
90
+
91
+ const cursorRaw = c.req.query('cursor');
92
+ const nameRaw = c.req.query('name');
93
+
94
+ const scopeParsed = parseScopeParams(c.req.query(), { tenantId });
95
+ if (scopeParsed.kind === 'err') {
96
+ c.status(statusFor('scope-invalid') as never);
97
+ return c.json(
98
+ toWireError({ code: 'scope-invalid', message: scopeParsed.message }, requestId),
99
+ );
100
+ }
101
+
102
+ const page = await binding.list({
103
+ tenantId,
104
+ limit,
105
+ ...(cursorRaw !== undefined && cursorRaw.length > 0 && { cursor: cursorRaw as Cursor }),
106
+ ...(nameRaw !== undefined && nameRaw.length > 0 && { nameFilter: nameRaw }),
107
+ ...(scopeParsed.scope !== undefined && { scope: scopeParsed.scope }),
108
+ ...(scopeParsed.inherit !== undefined && { inherit: scopeParsed.inherit }),
109
+ });
110
+ return c.json({
111
+ data: page.data.map(serializeGraph),
112
+ hasMore: page.nextCursor !== undefined,
113
+ ...(page.nextCursor !== undefined && { nextCursor: page.nextCursor as unknown as string }),
114
+ });
115
+ });
116
+
117
+ // ---------- GET /:flowId (latest version) ----------
118
+ r.get('/:flowId', async (c) => {
119
+ const requestId = c.get('requestId');
120
+ const tenantId = c.get('tenantId') as TenantId;
121
+ const flowId = c.req.param('flowId') as FlowId;
122
+
123
+ const flow = await binding.get({ tenantId, flowId });
124
+ if (flow === null) {
125
+ // 410 gone (head exists, no active version) vs 404 not-found
126
+ // (never registered).
127
+ const exists = await binding.headExists({ tenantId, flowId });
128
+ if (exists) {
129
+ c.status(statusFor('flow-gone') as never);
130
+ return c.json(
131
+ toWireError(
132
+ {
133
+ code: 'flow-gone',
134
+ message: `Flow "${flowId as unknown as string}" has no active versions; reinstate a tombstoned version or publish a new one`,
135
+ flowId: flowId as unknown as string,
136
+ },
137
+ requestId,
138
+ ),
139
+ );
140
+ }
141
+ c.status(statusFor('flow-not-found') as never);
142
+ return c.json(
143
+ toWireError(
144
+ {
145
+ code: 'flow-not-found',
146
+ message: `No flow registered with id "${flowId as unknown as string}"`,
147
+ flowId: flowId as unknown as string,
148
+ },
149
+ requestId,
150
+ ),
151
+ );
152
+ }
153
+ return c.json(serializeGraph(flow));
154
+ });
155
+
156
+ // ---------- GET /:flowId/versions (list versions) ----------
157
+ r.get('/:flowId/versions', async (c) => {
158
+ const requestId = c.get('requestId');
159
+ const tenantId = c.get('tenantId') as TenantId;
160
+ const flowId = c.req.param('flowId') as FlowId;
161
+ const limit = clampLimit(c.req.query('limit'));
162
+ const cursorRaw = c.req.query('cursor');
163
+
164
+ // Confirm the id exists at all — an empty versions list from the
165
+ // binding is ambiguous (no versions vs. unknown id), so we do a
166
+ // preliminary `get` to flip an unknown id to a `404`.
167
+ const latest = await binding.get({ tenantId, flowId });
168
+ if (latest === null) {
169
+ c.status(statusFor('flow-not-found') as never);
170
+ return c.json(
171
+ toWireError(
172
+ {
173
+ code: 'flow-not-found',
174
+ message: `No flow registered with id "${flowId as unknown as string}"`,
175
+ flowId: flowId as unknown as string,
176
+ },
177
+ requestId,
178
+ ),
179
+ );
180
+ }
181
+
182
+ const page = await binding.listVersions({
183
+ tenantId,
184
+ flowId,
185
+ limit,
186
+ ...(cursorRaw !== undefined && cursorRaw.length > 0 && { cursor: cursorRaw as Cursor }),
187
+ });
188
+ return c.json({
189
+ data: page.data.map(serializeGraph),
190
+ hasMore: page.nextCursor !== undefined,
191
+ ...(page.nextCursor !== undefined && { nextCursor: page.nextCursor as unknown as string }),
192
+ });
193
+ });
194
+
195
+ // ---------- GET /:flowId/versions/:version ----------
196
+ r.get('/:flowId/versions/:version', async (c) => {
197
+ const requestId = c.get('requestId');
198
+ const tenantId = c.get('tenantId') as TenantId;
199
+ const flowId = c.req.param('flowId') as FlowId;
200
+ const version = c.req.param('version');
201
+
202
+ const flow = await binding.getVersion({ tenantId, flowId, version });
203
+ if (flow === null) {
204
+ c.status(statusFor('flow-not-found') as never);
205
+ return c.json(
206
+ toWireError(
207
+ {
208
+ code: 'flow-not-found',
209
+ message: `No flow "${flowId as unknown as string}" at version "${version}"`,
210
+ flowId: flowId as unknown as string,
211
+ version: version,
212
+ },
213
+ requestId,
214
+ ),
215
+ );
216
+ }
217
+ return c.json(serializeGraph(flow));
218
+ });
219
+
220
+ // ---------- POST / (publish) ----------
221
+ r.post('/', async (c) => {
222
+ const requestId = c.get('requestId');
223
+ const tenantId = c.get('tenantId') as TenantId;
224
+
225
+ let body: unknown;
226
+ try {
227
+ body = await c.req.json();
228
+ } catch {
229
+ c.status(statusFor('bad-input') as never);
230
+ return c.json(
231
+ toWireError({ code: 'bad-input', message: 'Request body must be valid JSON' }, requestId),
232
+ );
233
+ }
234
+ if (body === null || typeof body !== 'object') {
235
+ c.status(statusFor('bad-input') as never);
236
+ return c.json(
237
+ toWireError({ code: 'bad-input', message: 'Request body must be an object' }, requestId),
238
+ );
239
+ }
240
+
241
+ // `projectId` is REQUIRED on the POST body.
242
+ // Missing / empty / non-string → 400 bad-input. Absent from the
243
+ // flow-shape validator on purpose — the caller controls what
244
+ // project the flow lands in; the flow definition itself is
245
+ // project-agnostic.
246
+ const bodyObj = body as Record<string, unknown>;
247
+ const projectIdRaw = bodyObj.projectId;
248
+ if (typeof projectIdRaw !== 'string' || projectIdRaw.length === 0) {
249
+ c.status(statusFor('bad-input') as never);
250
+ return c.json(
251
+ toWireError({ code: 'bad-input', message: '`projectId` is required' }, requestId),
252
+ );
253
+ }
254
+ const projectId = projectIdRaw as ProjectId;
255
+
256
+ // Validate via loadFlow — same rules as the runtime loader, so a
257
+ // flow published through the API is byte-identical to one
258
+ // constructed in-process. `loadFlow` returns a Result rather than
259
+ // throwing. `projectId` is stripped from the wire body before
260
+ // validation — the flow definition itself is project-agnostic
261
+ // (loadFlow rejects unknown top-level keys).
262
+ const { projectId: _pid, ...bodyWithoutProjectId } = bodyObj;
263
+ const loaded = loadFlow(bodyWithoutProjectId);
264
+ if (loaded.kind === 'err') {
265
+ c.status(statusFor('validation-failed') as never);
266
+ return c.json(
267
+ toWireError(
268
+ {
269
+ code: 'validation-failed',
270
+ message: loaded.error.message,
271
+ issues: toIssues(loaded.error) as unknown as Record<string, unknown>[],
272
+ },
273
+ requestId,
274
+ ),
275
+ );
276
+ }
277
+
278
+ const principal = c.get('principal') as Principal | undefined;
279
+ const creatorUserId =
280
+ principal?.actor.kind === 'user' ? (principal.actor.id as UserId) : undefined;
281
+ const outcome = await binding.publish({
282
+ tenantId,
283
+ projectId,
284
+ flow: loaded.value,
285
+ enqueueTuples: (flowId) =>
286
+ tuplesForCreate({ kind: 'flow', id: flowId as FlowId, tenantId, projectId }, creatorUserId),
287
+ });
288
+ if (outcome.kind === 'already-registered') {
289
+ c.status(statusFor('flow-already-registered') as never);
290
+ return c.json(
291
+ toWireError(
292
+ {
293
+ code: 'flow-already-registered',
294
+ message: `Flow "${outcome.flowId as unknown as string}" version "${outcome.version}" is already registered`,
295
+ flowId: outcome.flowId as unknown as string,
296
+ version: outcome.version,
297
+ },
298
+ requestId,
299
+ ),
300
+ );
301
+ }
302
+ if (outcome.kind === 'project-not-found') {
303
+ // Caller supplied a `projectId` that does not resolve within
304
+ // this tenant. Distinct signal from `already-registered` so the
305
+ // client can prompt for a valid project rather than assume the
306
+ // version was already used. Answered as `400 bad-input`; the
307
+ // caller learns from the message which field was invalid.
308
+ c.status(statusFor('bad-input') as never);
309
+ return c.json(
310
+ toWireError(
311
+ {
312
+ code: 'bad-input',
313
+ message: `\`projectId\` "${outcome.projectId as unknown as string}" does not resolve to a project in this tenant`,
314
+ },
315
+ requestId,
316
+ ),
317
+ );
318
+ }
319
+ c.status(201);
320
+ return c.json({
321
+ flowId: outcome.flowId as unknown as string,
322
+ version: outcome.version,
323
+ });
324
+ });
325
+
326
+ // ---------- POST /:flowId/versions/:version/unregister ----------
327
+ r.post('/:flowId/versions/:version/unregister', async (c) => {
328
+ const requestId = c.get('requestId');
329
+ const tenantId = c.get('tenantId') as TenantId;
330
+ const flowId = c.req.param('flowId') as FlowId;
331
+ const version = c.req.param('version');
332
+
333
+ const outcome = await binding.unregister({ tenantId, flowId, version });
334
+ if (!outcome.unregistered) {
335
+ c.status(statusFor('flow-not-found') as never);
336
+ return c.json(
337
+ toWireError(
338
+ {
339
+ code: 'flow-not-found',
340
+ message: `No flow "${flowId as unknown as string}" at version "${version}" to unregister`,
341
+ flowId: flowId as unknown as string,
342
+ version: version,
343
+ },
344
+ requestId,
345
+ ),
346
+ );
347
+ }
348
+ return c.json({
349
+ flowId: flowId as unknown as string,
350
+ version: version,
351
+ unregistered: true,
352
+ });
353
+ });
354
+
355
+ // ---------- POST /:flowId/versions/:version/reinstate ----------
356
+ r.post('/:flowId/versions/:version/reinstate', async (c) => {
357
+ const requestId = c.get('requestId');
358
+ const tenantId = c.get('tenantId') as TenantId;
359
+ const flowId = c.req.param('flowId') as FlowId;
360
+ const version = c.req.param('version');
361
+ const outcome = await binding.reinstateVersion({ tenantId, flowId, version });
362
+ if (outcome.kind === 'not-found') {
363
+ c.status(statusFor('flow-not-found') as never);
364
+ return c.json(
365
+ toWireError(
366
+ {
367
+ code: 'flow-not-found',
368
+ message: `No flow "${flowId as unknown as string}" at version "${version}" to reinstate`,
369
+ flowId: flowId as unknown as string,
370
+ version,
371
+ },
372
+ requestId,
373
+ ),
374
+ );
375
+ }
376
+ return c.json({
377
+ flowId: outcome.flowId as unknown as string,
378
+ version: outcome.version,
379
+ wasTombstoned: outcome.wasTombstoned,
380
+ });
381
+ });
382
+
383
+ return r;
384
+ }
385
+
386
+ function serializeGraph(g: Flow): Record<string, unknown> {
387
+ return {
388
+ id: g.id as unknown as string,
389
+ version: g.version,
390
+ ...(g.name !== undefined && { name: g.name }),
391
+ ...(g.description !== undefined && { description: g.description }),
392
+ nodes: g.nodes,
393
+ edges: g.edges,
394
+ ...(g.maxParallelism !== undefined && { maxParallelism: g.maxParallelism }),
395
+ ...(g.metadata !== undefined && { metadata: g.metadata }),
396
+ };
397
+ }
398
+
399
+ /**
400
+ * Normalize any `FlowError` to a flat `issues[]` list so the wire
401
+ * response shape is uniform. Errors that already carry an `issues`
402
+ * array (schema-validation-failed, loop-invalid-output-schema) pass
403
+ * through unchanged; the discrete errors project their structural
404
+ * fields into a single-element issues list keyed by the natural path.
405
+ */
406
+ function toIssues(err: FlowError): readonly { readonly path: string; readonly message: string }[] {
407
+ if ('issues' in err) return err.issues;
408
+ const path = derivePath(err);
409
+ return [{ path, message: err.message }];
410
+ }
411
+
412
+ function derivePath(err: FlowError): string {
413
+ if ('edgeId' in err && err.edgeId !== undefined) {
414
+ return `edges/${err.edgeId as unknown as string}`;
415
+ }
416
+ if ('nodeId' in err && err.nodeId !== undefined) {
417
+ return `nodes/${err.nodeId as unknown as string}`;
418
+ }
419
+ if ('loopNodeId' in err && err.loopNodeId !== undefined) {
420
+ return `nodes/${err.loopNodeId as unknown as string}`;
421
+ }
422
+ return '';
423
+ }