@kindgi/api 0.0.0-bootstrap.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +396 -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 +264 -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 +13 -0
  104. package/dist/middleware/error-mapper.d.ts.map +1 -0
  105. package/dist/middleware/error-mapper.js +32 -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 +5051 -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 +773 -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 +29659 -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 +1285 -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 +291 -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 +37 -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 +5445 -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 +981 -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,160 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+
4
+ import { createHash } from 'node:crypto';
5
+
6
+ import type { MiddlewareHandler } from 'hono';
7
+
8
+ import type { TenantId } from '@kindgi/types';
9
+
10
+ import { statusFor, toWireError } from '../errors.js';
11
+
12
+ /**
13
+ * Idempotency-key store: `(tenantId, route, key) → cached response`,
14
+ * cached for `ttlMs` (default 24h per API-ROUTE-CONVENTIONS.md §3.1).
15
+ *
16
+ * Injected into the middleware so deployments can plug in a durable
17
+ * store (e.g. Postgres, Redis). The bundled `createInMemoryIdempotencyStore()`
18
+ * is fine for dev + tests; production installs are expected to plug
19
+ * in a persistent one so retries survive restarts.
20
+ */
21
+ export interface IdempotencyStore {
22
+ get(key: string): Promise<StoredIdempotencyEntry | null>;
23
+ set(key: string, entry: StoredIdempotencyEntry): Promise<void>;
24
+ }
25
+
26
+ export interface StoredIdempotencyEntry {
27
+ readonly bodyHash: string;
28
+ readonly status: number;
29
+ readonly contentType: string;
30
+ readonly bodyText: string;
31
+ readonly expiresAt: number;
32
+ }
33
+
34
+ /** Simple in-memory store with lazy expiry — swap for a DB store in prod. */
35
+ export function createInMemoryIdempotencyStore(): IdempotencyStore {
36
+ const table = new Map<string, StoredIdempotencyEntry>();
37
+ return {
38
+ async get(key) {
39
+ const hit = table.get(key);
40
+ if (hit === undefined) return null;
41
+ if (hit.expiresAt <= Date.now()) {
42
+ table.delete(key);
43
+ return null;
44
+ }
45
+ return hit;
46
+ },
47
+ async set(key, entry) {
48
+ table.set(key, entry);
49
+ },
50
+ };
51
+ }
52
+
53
+ const MUTATING_METHODS: ReadonlySet<string> = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
54
+ const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
55
+
56
+ /**
57
+ * Idempotency-Key middleware per API-ROUTE-CONVENTIONS.md §3.1.
58
+ *
59
+ * Behaviour:
60
+ * - Only applies to mutating methods (POST/PUT/PATCH/DELETE).
61
+ * - No `Idempotency-Key` header → pass through.
62
+ * - Cached hit with matching body hash → replay stored response
63
+ * byte-identical (status, content-type, body).
64
+ * - Cached hit with different body hash → 409
65
+ * `idempotency-key-body-mismatch`.
66
+ * - Cache miss → run the handler, then store the response.
67
+ *
68
+ * The middleware sits AFTER auth so `tenantId` is available; the
69
+ * cache key is namespaced by tenant so callers can't collide across
70
+ * tenants.
71
+ */
72
+ export function idempotencyMiddleware(
73
+ store: IdempotencyStore,
74
+ opts: { ttlMs?: number } = {},
75
+ ): MiddlewareHandler {
76
+ const ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
77
+ return async (c, next) => {
78
+ if (!MUTATING_METHODS.has(c.req.method.toUpperCase())) {
79
+ return next();
80
+ }
81
+ const rawKey = c.req.header('idempotency-key');
82
+ if (rawKey === undefined || rawKey.length === 0) {
83
+ return next();
84
+ }
85
+ const requestId = c.get('requestId') as string;
86
+ const tenantId = c.get('tenantId') as TenantId | undefined;
87
+ if (tenantId === undefined) {
88
+ // Auth middleware didn't set it — bail out and let the auth
89
+ // failure surface. This shouldn't happen because auth runs
90
+ // first, but the guard keeps the cache key well-formed.
91
+ return next();
92
+ }
93
+
94
+ const bodyText = await readRawBody(c.req.raw);
95
+ const bodyHash = hashBody(bodyText);
96
+ const cacheKey = `${tenantId}|${c.req.method.toUpperCase()}:${c.req.path}|${rawKey}`;
97
+ const hit = await store.get(cacheKey);
98
+
99
+ if (hit !== null) {
100
+ if (hit.bodyHash !== bodyHash) {
101
+ c.status(statusFor('idempotency-key-body-mismatch') as never);
102
+ return c.json(
103
+ toWireError(
104
+ {
105
+ code: 'idempotency-key-body-mismatch',
106
+ message:
107
+ 'Idempotency-Key was reused with a different request body. Use a fresh key or the original body.',
108
+ },
109
+ requestId,
110
+ ),
111
+ );
112
+ }
113
+ return c.body(hit.bodyText, hit.status as never, {
114
+ 'Content-Type': hit.contentType,
115
+ 'X-Idempotent-Replay': 'true',
116
+ });
117
+ }
118
+
119
+ // Re-attach the buffered body so downstream handlers reading
120
+ // `c.req.json()` see the same bytes.
121
+ if (bodyText.length > 0) rebindBody(c, bodyText);
122
+ await next();
123
+
124
+ const res = c.res;
125
+ const savedBody = await res.clone().text();
126
+ const contentType = res.headers.get('Content-Type') ?? 'application/octet-stream';
127
+ await store.set(cacheKey, {
128
+ bodyHash,
129
+ status: res.status,
130
+ contentType,
131
+ bodyText: savedBody,
132
+ expiresAt: Date.now() + ttlMs,
133
+ });
134
+ return;
135
+ };
136
+ }
137
+
138
+ async function readRawBody(req: Request): Promise<string> {
139
+ const method = req.method.toUpperCase();
140
+ if (method === 'GET' || method === 'HEAD') return '';
141
+ try {
142
+ return await req.clone().text();
143
+ } catch {
144
+ return '';
145
+ }
146
+ }
147
+
148
+ function hashBody(body: string): string {
149
+ return createHash('sha256').update(body).digest('hex');
150
+ }
151
+
152
+ function rebindBody(c: { req: { raw: Request } }, body: string): void {
153
+ const original = c.req.raw;
154
+ const rebuilt = new Request(original.url, {
155
+ method: original.method,
156
+ headers: original.headers,
157
+ body,
158
+ });
159
+ Object.defineProperty(c.req, 'raw', { value: rebuilt, configurable: true });
160
+ }
@@ -0,0 +1,64 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+
4
+ //
5
+ // principalMiddleware — Hono middleware that constructs a composite
6
+ // authz Principal from the values `bearerAuthMiddleware` set on the
7
+ // context (tenantId + optional userId + optional sessionId).
8
+ //
9
+ // Runs AFTER bearerAuthMiddleware. Every route below `/v1` gets a
10
+ // principal populated via `c.get('principal')`. Downstream:
11
+ // - `authorize(action, resource)` reads it for enforcement.
12
+ // - Route handlers can read it directly for conditional logic.
13
+ //
14
+ // Delegation chains (agent-on-behalf-of-user) are constructed at
15
+ // deeper layers (kernel start-of-run) — the request-scoped principal
16
+ // is always a single actor.
17
+ //
18
+
19
+ import type { MiddlewareHandler } from 'hono';
20
+
21
+ import { principalFromToken } from '@kindgi/authz';
22
+
23
+ import type { AppEnv } from '../types.js';
24
+
25
+ export function principalMiddleware(): MiddlewareHandler<AppEnv> {
26
+ return async (c, next) => {
27
+ const tenantId = c.get('tenantId');
28
+ const userId = c.get('userId');
29
+ const tokenId = c.get('tokenId');
30
+ const sessionId = c.get('sessionId');
31
+
32
+ if (tenantId === undefined) {
33
+ // Bearer middleware didn't populate — either the route is
34
+ // pre-auth (unlikely at this mount point) or the resolver
35
+ // failed silently. Skip; downstream authorize() will 403 in a
36
+ // coherent way if it needs the principal.
37
+ return next();
38
+ }
39
+
40
+ // A user when the token names one; otherwise a service account: a
41
+ // durable API key's id, or else the session id (which uniquely
42
+ // identifies the token record). With none of them, leave `principal`
43
+ // unset; `authorize()` treats that as "no principal" and 403s cleanly.
44
+ const serviceAccountId =
45
+ (tokenId as unknown as string | undefined) ?? (sessionId as unknown as string | undefined);
46
+ if (userId === undefined && serviceAccountId === undefined) {
47
+ return next();
48
+ }
49
+ try {
50
+ const principal = principalFromToken({
51
+ tenantId,
52
+ ...(userId !== undefined ? { userId } : {}),
53
+ ...(userId === undefined && serviceAccountId !== undefined
54
+ ? { tokenId: serviceAccountId }
55
+ : {}),
56
+ });
57
+ c.set('principal', principal);
58
+ } catch {
59
+ // Defensive: principalFromToken throws when its guardrail is
60
+ // violated; downstream authorize() handles the missing principal.
61
+ }
62
+ return next();
63
+ };
64
+ }
@@ -0,0 +1,50 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+
4
+ import type { MiddlewareHandler } from 'hono';
5
+ import { cors } from 'hono/cors';
6
+
7
+ import { OPERATIONS } from '../openapi/operations.js';
8
+
9
+ /**
10
+ * The routes a public run token may call: the operations registered with
11
+ * `security: 'bearer-or-public-run'`. Deriving the list from the
12
+ * operation registry keeps the middleware, the OpenAPI document and the
13
+ * routes in step.
14
+ */
15
+ export function publicRunRouteMatcher(): (method: string, path: string) => boolean {
16
+ const routes = OPERATIONS.filter((op) => op.security === 'bearer-or-public-run').map((op) => ({
17
+ method: op.method.toUpperCase(),
18
+ pattern: new RegExp(
19
+ `^${op.honoPath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/:[A-Za-z][A-Za-z0-9_]*/g, '[^/]+')}$`,
20
+ ),
21
+ }));
22
+ return (method, path) =>
23
+ routes.some((route) => route.method === method && route.pattern.test(path));
24
+ }
25
+
26
+ /**
27
+ * CORS for the public-run-token routes only, so a browser on one of
28
+ * `allowedOrigins` can call them with a public token. Every other route
29
+ * gets no CORS headers: secret API tokens stay server-side. Registered
30
+ * ahead of authentication, so preflights don't need a token.
31
+ */
32
+ export function publicRunCorsMiddleware(allowedOrigins: readonly string[]): MiddlewareHandler {
33
+ const matchesPath = publicRunRouteMatcher();
34
+ const handler = cors({
35
+ origin: [...allowedOrigins],
36
+ allowMethods: ['GET'],
37
+ allowHeaders: ['Authorization', 'Last-Event-ID'],
38
+ exposeHeaders: ['X-Request-Id'],
39
+ maxAge: 600,
40
+ });
41
+ return async (c, next) => {
42
+ // A preflight asks about the method it will use; match on that.
43
+ const method =
44
+ c.req.method === 'OPTIONS'
45
+ ? (c.req.header('access-control-request-method') ?? '').toUpperCase()
46
+ : c.req.method;
47
+ if (!matchesPath(method, c.req.path)) return next();
48
+ return handler(c, next);
49
+ };
50
+ }
@@ -0,0 +1,28 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+
4
+ import { randomUUID } from 'node:crypto';
5
+
6
+ import type { MiddlewareHandler } from 'hono';
7
+
8
+ /**
9
+ * Assigns a request id to every incoming request. Stored on the Hono
10
+ * context as `c.get('requestId')`. Every error envelope embeds this so
11
+ * a caller reporting a bug can hand us one string to grep the logs.
12
+ *
13
+ * If the client provided `X-Request-Id`, we honor it (matching a
14
+ * caller-supplied id makes SDK retries observable in server logs).
15
+ * Otherwise we mint a new UUID.
16
+ *
17
+ * The response header `X-Request-Id` mirrors the id back.
18
+ */
19
+ export function requestIdMiddleware(): MiddlewareHandler {
20
+ return async (c, next) => {
21
+ const provided = c.req.header('x-request-id');
22
+ const requestId =
23
+ provided !== undefined && provided.length > 0 ? provided : `req-${randomUUID()}`;
24
+ c.set('requestId', requestId);
25
+ await next();
26
+ c.header('X-Request-Id', requestId);
27
+ };
28
+ }
@@ -0,0 +1,374 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+
4
+ /**
5
+ * AWS Signature Version 4 verification for the `/s3/*` surface — pure
6
+ * functions, no HTTP framework.
7
+ *
8
+ * Verification re-derives the signature from exactly what the client
9
+ * signed:
10
+ *
11
+ * - the timestamp the client signed with (`x-amz-date` header, or the
12
+ * `X-Amz-Date` query parameter of a presigned URL) — never the
13
+ * server's clock. The server's clock only bounds it: requests more
14
+ * than {@link MAX_CLOCK_SKEW_SECONDS} away are rejected
15
+ * (`RequestTimeTooSkewed`), presigned URLs past `X-Amz-Expires` are
16
+ * rejected (`AccessDenied`);
17
+ * - only the headers the client listed in `SignedHeaders`. Anything a
18
+ * proxy or HTTP stack adds after signing is ignored;
19
+ * - the canonical URI / query exactly as S3 defines them (path
20
+ * segments not normalized; query keys sorted, first value only).
21
+ *
22
+ * The signature comparison is constant-time.
23
+ */
24
+
25
+ import { createHash, createHmac, timingSafeEqual } from 'node:crypto';
26
+
27
+ /** S3's allowed clock skew for signed requests (15 minutes). */
28
+ export const MAX_CLOCK_SKEW_SECONDS = 15 * 60;
29
+ /** S3's maximum presigned-URL lifetime (7 days). */
30
+ export const MAX_PRESIGN_EXPIRES_SECONDS = 7 * 24 * 60 * 60;
31
+
32
+ const ALGORITHM = 'AWS4-HMAC-SHA256';
33
+ const AMZ_DATE = /^(\d{8})T\d{6}Z$/;
34
+ const UNSIGNED_PAYLOAD = 'UNSIGNED-PAYLOAD';
35
+
36
+ export interface SigV4Error {
37
+ /** S3 error code. */
38
+ readonly code: string;
39
+ readonly message: string;
40
+ readonly status: 400 | 403;
41
+ }
42
+
43
+ export type SigV4Result<T> =
44
+ | { readonly kind: 'ok'; readonly value: T }
45
+ | { readonly kind: 'err'; readonly error: SigV4Error };
46
+
47
+ /** What a request claims about its signature, before verification. */
48
+ export interface SigV4Claim {
49
+ readonly kind: 'header' | 'presigned';
50
+ readonly accessKeyId: string;
51
+ /** Credential-scope date, `YYYYMMDD`. */
52
+ readonly scopeDate: string;
53
+ readonly region: string;
54
+ readonly service: string;
55
+ /** Lowercase header names, as the client listed them. */
56
+ readonly signedHeaders: readonly string[];
57
+ readonly signature: string;
58
+ /** `YYYYMMDDTHHMMSSZ`. */
59
+ readonly amzDate: string;
60
+ /** Presigned only: `X-Amz-Expires`, seconds. */
61
+ readonly expiresSeconds?: number;
62
+ }
63
+
64
+ export interface SigV4Request {
65
+ readonly method: string;
66
+ /** The request URL as received (pathname still percent-encoded). */
67
+ readonly url: URL;
68
+ readonly headers: Headers;
69
+ }
70
+
71
+ function err(code: string, message: string, status: 400 | 403): { kind: 'err'; error: SigV4Error } {
72
+ return { kind: 'err', error: { code, message, status } };
73
+ }
74
+
75
+ /**
76
+ * Parse the signature claim from the `Authorization` header or the
77
+ * presigned-URL query parameters. Does not verify anything.
78
+ */
79
+ export function parseSigV4(request: SigV4Request): SigV4Result<SigV4Claim> {
80
+ const query = request.url.searchParams;
81
+ const presignedAlgorithm = query.get('X-Amz-Algorithm');
82
+ if (presignedAlgorithm !== null) {
83
+ if (presignedAlgorithm !== ALGORITHM) {
84
+ return err('InvalidRequest', `Unsupported presign algorithm "${presignedAlgorithm}"`, 403);
85
+ }
86
+ const credential = query.get('X-Amz-Credential');
87
+ const signature = query.get('X-Amz-Signature');
88
+ const amzDate = query.get('X-Amz-Date');
89
+ const signedHeaders = query.get('X-Amz-SignedHeaders');
90
+ const expires = query.get('X-Amz-Expires');
91
+ if (credential === null || signature === null || amzDate === null || signedHeaders === null) {
92
+ return err(
93
+ 'AuthorizationQueryParametersError',
94
+ 'Presigned URL must carry X-Amz-Credential, X-Amz-Date, X-Amz-SignedHeaders and X-Amz-Signature',
95
+ 400,
96
+ );
97
+ }
98
+ const scope = parseCredentialScope(credential);
99
+ if (scope === null) return err('InvalidRequest', 'Malformed X-Amz-Credential', 403);
100
+ const expiresSeconds = expires === null ? MAX_PRESIGN_EXPIRES_SECONDS : Number(expires);
101
+ if (
102
+ !Number.isInteger(expiresSeconds) ||
103
+ expiresSeconds < 1 ||
104
+ expiresSeconds > MAX_PRESIGN_EXPIRES_SECONDS
105
+ ) {
106
+ return err(
107
+ 'AuthorizationQueryParametersError',
108
+ `X-Amz-Expires must be an integer between 1 and ${MAX_PRESIGN_EXPIRES_SECONDS}`,
109
+ 400,
110
+ );
111
+ }
112
+ return {
113
+ kind: 'ok',
114
+ value: {
115
+ kind: 'presigned',
116
+ ...scope,
117
+ signedHeaders: signedHeaders.split(';'),
118
+ signature,
119
+ amzDate,
120
+ expiresSeconds,
121
+ },
122
+ };
123
+ }
124
+
125
+ const authorization = request.headers.get('authorization') ?? '';
126
+ if (authorization.length === 0) return err('AccessDenied', 'Missing Authorization header', 403);
127
+ const match = /^AWS4-HMAC-SHA256\s+(.+)$/i.exec(authorization);
128
+ if (match === null) {
129
+ return err('InvalidRequest', 'Only AWS4-HMAC-SHA256 signatures are supported', 403);
130
+ }
131
+ const fields = new Map<string, string>();
132
+ for (const part of (match[1] as string).split(',')) {
133
+ const eq = part.indexOf('=');
134
+ if (eq > 0) fields.set(part.slice(0, eq).trim(), part.slice(eq + 1).trim());
135
+ }
136
+ const credential = fields.get('Credential');
137
+ const signedHeaders = fields.get('SignedHeaders');
138
+ const signature = fields.get('Signature');
139
+ if (credential === undefined || signedHeaders === undefined || signature === undefined) {
140
+ return err(
141
+ 'InvalidRequest',
142
+ 'Malformed Authorization header (needs Credential, SignedHeaders, Signature)',
143
+ 403,
144
+ );
145
+ }
146
+ const scope = parseCredentialScope(credential);
147
+ if (scope === null) return err('InvalidRequest', 'Malformed credential scope', 403);
148
+ const amzDate = request.headers.get('x-amz-date');
149
+ if (amzDate === null) {
150
+ return err('AccessDenied', 'Signed requests must carry an x-amz-date header', 403);
151
+ }
152
+ return {
153
+ kind: 'ok',
154
+ value: {
155
+ kind: 'header',
156
+ ...scope,
157
+ signedHeaders: signedHeaders.split(';'),
158
+ signature,
159
+ amzDate,
160
+ },
161
+ };
162
+ }
163
+
164
+ /**
165
+ * Check the claim's timestamp and shape against the server clock:
166
+ * `X-Amz-Date` well-formed and consistent with the credential scope,
167
+ * within {@link MAX_CLOCK_SKEW_SECONDS} (header auth / presigned not
168
+ * dated in the future), and — presigned — not expired. Also checks the
169
+ * signed-header list is sorted, lowercase, and covers what must be
170
+ * signed.
171
+ */
172
+ export function checkSigV4Claim(claim: SigV4Claim, now: Date): SigV4Result<void> {
173
+ const dateMatch = AMZ_DATE.exec(claim.amzDate);
174
+ if (dateMatch === null) {
175
+ return err('AccessDenied', 'X-Amz-Date must be formatted as YYYYMMDDTHHMMSSZ', 403);
176
+ }
177
+ if (dateMatch[1] !== claim.scopeDate) {
178
+ return err('SignatureDoesNotMatch', 'The credential scope date does not match X-Amz-Date', 403);
179
+ }
180
+ const signedAt = parseAmzDate(claim.amzDate);
181
+ const skewSeconds = (now.getTime() - signedAt.getTime()) / 1000;
182
+ if (skewSeconds < -MAX_CLOCK_SKEW_SECONDS) {
183
+ return err(
184
+ 'RequestTimeTooSkewed',
185
+ "The difference between the request time and the server's time is too large.",
186
+ 403,
187
+ );
188
+ }
189
+ if (claim.kind === 'header' && skewSeconds > MAX_CLOCK_SKEW_SECONDS) {
190
+ return err(
191
+ 'RequestTimeTooSkewed',
192
+ "The difference between the request time and the server's time is too large.",
193
+ 403,
194
+ );
195
+ }
196
+ if (claim.kind === 'presigned' && skewSeconds > (claim.expiresSeconds ?? 0)) {
197
+ return err('AccessDenied', 'Request has expired', 403);
198
+ }
199
+
200
+ const sorted = [...claim.signedHeaders].sort();
201
+ if (
202
+ claim.signedHeaders.some((h, i) => h !== h.toLowerCase() || h !== sorted[i] || h === '') ||
203
+ new Set(claim.signedHeaders).size !== claim.signedHeaders.length
204
+ ) {
205
+ return err('InvalidRequest', 'SignedHeaders must be lowercase, sorted and unique', 403);
206
+ }
207
+ const required =
208
+ claim.kind === 'header' ? ['host', 'x-amz-content-sha256', 'x-amz-date'] : ['host'];
209
+ const missing = required.filter((h) => !claim.signedHeaders.includes(h));
210
+ if (missing.length > 0) {
211
+ return err('AccessDenied', `SignedHeaders must include: ${missing.join(', ')}`, 403);
212
+ }
213
+ return { kind: 'ok', value: undefined };
214
+ }
215
+
216
+ /**
217
+ * Re-derive the signature from exactly what the client signed and compare
218
+ * it (constant-time) with the claimed one. `payloadHash` is the header
219
+ * `x-amz-content-sha256` for header auth (the caller verifies it against
220
+ * the body); presigned requests always sign `UNSIGNED-PAYLOAD`.
221
+ */
222
+ export function verifySigV4Signature(
223
+ request: SigV4Request,
224
+ claim: SigV4Claim,
225
+ secretKey: string,
226
+ ): SigV4Result<void> {
227
+ const canonical = canonicalRequest(request, claim);
228
+ if (canonical.kind === 'err') return canonical;
229
+ const scope = `${claim.scopeDate}/${claim.region}/${claim.service}/aws4_request`;
230
+ const stringToSign = [ALGORITHM, claim.amzDate, scope, sha256Hex(canonical.value)].join('\n');
231
+ const kDate = hmac(`AWS4${secretKey}`, claim.scopeDate);
232
+ const kRegion = hmac(kDate, claim.region);
233
+ const kService = hmac(kRegion, claim.service);
234
+ const kSigning = hmac(kService, 'aws4_request');
235
+ const expected = createHmac('sha256', kSigning).update(stringToSign, 'utf8').digest('hex');
236
+ if (!constantTimeEqual(expected, claim.signature.toLowerCase())) {
237
+ return err(
238
+ 'SignatureDoesNotMatch',
239
+ 'The request signature we calculated does not match the signature you provided.',
240
+ 403,
241
+ );
242
+ }
243
+ return { kind: 'ok', value: undefined };
244
+ }
245
+
246
+ /** The SigV4 canonical request (exported for tests). */
247
+ export function canonicalRequest(request: SigV4Request, claim: SigV4Claim): SigV4Result<string> {
248
+ const headerLines: string[] = [];
249
+ for (const name of claim.signedHeaders) {
250
+ const value =
251
+ name === 'host'
252
+ ? (request.headers.get('host') ?? request.url.host)
253
+ : request.headers.get(name);
254
+ if (value === null) {
255
+ return err(
256
+ 'SignatureDoesNotMatch',
257
+ `Signed header "${name}" is missing from the request`,
258
+ 403,
259
+ );
260
+ }
261
+ headerLines.push(`${name}:${value.trim().replace(/\s+/g, ' ')}`);
262
+ }
263
+ const payloadHash =
264
+ claim.kind === 'presigned'
265
+ ? UNSIGNED_PAYLOAD
266
+ : (request.headers.get('x-amz-content-sha256') ?? UNSIGNED_PAYLOAD);
267
+ return {
268
+ kind: 'ok',
269
+ value: [
270
+ request.method.toUpperCase(),
271
+ canonicalUri(request.url.pathname),
272
+ canonicalQuery(request.url.search, claim.kind === 'presigned'),
273
+ `${headerLines.join('\n')}\n`,
274
+ claim.signedHeaders.join(';'),
275
+ payloadHash,
276
+ ].join('\n'),
277
+ };
278
+ }
279
+
280
+ // -------------------- canonicalization (S3 rules) --------------------
281
+
282
+ /** RFC 3986 encoding: everything but unreserved characters. */
283
+ function encodeRfc3986(value: string): string {
284
+ return encodeURIComponent(value).replace(
285
+ /[!'()*]/g,
286
+ (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`,
287
+ );
288
+ }
289
+
290
+ /** Decode, tolerating stray `%` that is not a valid escape. */
291
+ function safeDecode(value: string): string {
292
+ try {
293
+ return decodeURIComponent(value);
294
+ } catch {
295
+ return value;
296
+ }
297
+ }
298
+
299
+ /**
300
+ * S3 canonical URI: each path segment decoded, then RFC 3986-encoded;
301
+ * segments are not normalized (`.` / `..` / `//` are significant for S3
302
+ * keys) and an encoded slash stays a slash. `+` in the path is read as a
303
+ * space, matching the common S3 signers.
304
+ */
305
+ function canonicalUri(rawPath: string): string {
306
+ if (rawPath === '' || rawPath === '/') return '/';
307
+ const encoded = rawPath
308
+ .split('/')
309
+ .map((segment) => encodeRfc3986(safeDecode(segment.replace(/\+/g, ' '))))
310
+ .join('/')
311
+ .replace(/%2F/g, '/');
312
+ return encoded.startsWith('/') ? encoded : `/${encoded}`;
313
+ }
314
+
315
+ /**
316
+ * S3 canonical query: parameters decoded, re-encoded (RFC 3986), sorted
317
+ * by key; for a repeated key only its first value counts. A presigned
318
+ * URL's `X-Amz-Signature` is not part of what was signed.
319
+ */
320
+ function canonicalQuery(rawSearch: string, presigned: boolean): string {
321
+ const search = rawSearch.startsWith('?') ? rawSearch.slice(1) : rawSearch;
322
+ if (search === '') return '';
323
+ const first = new Map<string, string>();
324
+ for (const pair of search.split('&')) {
325
+ if (pair === '') continue;
326
+ const eq = pair.indexOf('=');
327
+ const rawKey = eq < 0 ? pair : pair.slice(0, eq);
328
+ const rawValue = eq < 0 ? '' : pair.slice(eq + 1);
329
+ const key = safeDecode(rawKey.replace(/\+/g, ' '));
330
+ if (key === '' || (presigned && key === 'X-Amz-Signature')) continue;
331
+ const encodedKey = encodeRfc3986(key);
332
+ if (!first.has(encodedKey)) {
333
+ first.set(encodedKey, encodeRfc3986(safeDecode(rawValue.replace(/\+/g, ' '))));
334
+ }
335
+ }
336
+ return [...first.keys()]
337
+ .sort()
338
+ .map((key) => `${key}=${first.get(key)}`)
339
+ .join('&');
340
+ }
341
+
342
+ // -------------------- helpers --------------------
343
+
344
+ function parseCredentialScope(
345
+ raw: string,
346
+ ): { accessKeyId: string; scopeDate: string; region: string; service: string } | null {
347
+ // <accessKeyId>/<YYYYMMDD>/<region>/<service>/aws4_request
348
+ const parts = raw.split('/');
349
+ if (parts.length !== 5 || parts[4] !== 'aws4_request') return null;
350
+ const [accessKeyId, scopeDate, region, service] = parts as [string, string, string, string];
351
+ if (accessKeyId === '' || !/^\d{8}$/.test(scopeDate) || region === '' || service === '')
352
+ return null;
353
+ return { accessKeyId, scopeDate, region, service };
354
+ }
355
+
356
+ function parseAmzDate(amzDate: string): Date {
357
+ const iso = `${amzDate.slice(0, 4)}-${amzDate.slice(4, 6)}-${amzDate.slice(6, 8)}T${amzDate.slice(9, 11)}:${amzDate.slice(11, 13)}:${amzDate.slice(13, 15)}Z`;
358
+ return new Date(iso);
359
+ }
360
+
361
+ function hmac(key: string | Buffer, data: string): Buffer {
362
+ return createHmac('sha256', key).update(data, 'utf8').digest();
363
+ }
364
+
365
+ function sha256Hex(data: string): string {
366
+ return createHash('sha256').update(data, 'utf8').digest('hex');
367
+ }
368
+
369
+ export function constantTimeEqual(a: string, b: string): boolean {
370
+ const aBuf = Buffer.from(a, 'utf8');
371
+ const bBuf = Buffer.from(b, 'utf8');
372
+ if (aBuf.length !== bBuf.length) return false;
373
+ return timingSafeEqual(aBuf, bBuf);
374
+ }