@homeflare/alchemy 0.43.0 → 0.45.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 (612) hide show
  1. package/README.md +10 -1
  2. package/dist/caddy/index.js +35 -1
  3. package/dist/caddy/index.js.map +3 -3
  4. package/dist/launchd/index.js +35 -1
  5. package/dist/launchd/index.js.map +3 -3
  6. package/dist/linux/index.js +35 -1
  7. package/dist/linux/index.js.map +3 -3
  8. package/dist/litellm/access-group-form.d.ts +26 -0
  9. package/dist/litellm/access-group-form.d.ts.map +1 -0
  10. package/dist/litellm/access-group-operations.d.ts +37 -0
  11. package/dist/litellm/access-group-operations.d.ts.map +1 -0
  12. package/dist/litellm/access-group-types.d.ts +49 -0
  13. package/dist/litellm/access-group-types.d.ts.map +1 -0
  14. package/dist/litellm/access-group.d.ts +55 -0
  15. package/dist/litellm/access-group.d.ts.map +1 -0
  16. package/dist/litellm/credential-errors.d.ts +131 -0
  17. package/dist/litellm/credential-errors.d.ts.map +1 -0
  18. package/dist/litellm/credential-form.d.ts +79 -0
  19. package/dist/litellm/credential-form.d.ts.map +1 -0
  20. package/dist/litellm/credential-operations.d.ts +84 -0
  21. package/dist/litellm/credential-operations.d.ts.map +1 -0
  22. package/dist/litellm/credential-rewrite.d.ts +6 -0
  23. package/dist/litellm/credential-rewrite.d.ts.map +1 -0
  24. package/dist/litellm/credential-types.d.ts +87 -0
  25. package/dist/litellm/credential-types.d.ts.map +1 -0
  26. package/dist/litellm/credential-values.d.ts +53 -0
  27. package/dist/litellm/credential-values.d.ts.map +1 -0
  28. package/dist/litellm/credential.d.ts +83 -0
  29. package/dist/litellm/credential.d.ts.map +1 -0
  30. package/dist/litellm/fake-access-group-litellm.d.ts +34 -0
  31. package/dist/litellm/fake-access-group-litellm.d.ts.map +1 -0
  32. package/dist/litellm/fake-credential-litellm.d.ts +54 -0
  33. package/dist/litellm/fake-credential-litellm.d.ts.map +1 -0
  34. package/dist/litellm/fake-keys.d.ts +53 -0
  35. package/dist/litellm/fake-keys.d.ts.map +1 -0
  36. package/dist/litellm/fake-litellm.d.ts +4 -1
  37. package/dist/litellm/fake-litellm.d.ts.map +1 -1
  38. package/dist/litellm/fake-mcp-litellm.d.ts +67 -0
  39. package/dist/litellm/fake-mcp-litellm.d.ts.map +1 -0
  40. package/dist/litellm/fake-model-litellm-post-update.d.ts +49 -0
  41. package/dist/litellm/fake-model-litellm-post-update.d.ts.map +1 -0
  42. package/dist/litellm/fake-model-litellm.d.ts +48 -0
  43. package/dist/litellm/fake-model-litellm.d.ts.map +1 -0
  44. package/dist/litellm/fake-policy-attachment-litellm.d.ts +33 -0
  45. package/dist/litellm/fake-policy-attachment-litellm.d.ts.map +1 -0
  46. package/dist/litellm/fake-policy-litellm.d.ts +32 -0
  47. package/dist/litellm/fake-policy-litellm.d.ts.map +1 -0
  48. package/dist/litellm/fake-registry-base.d.ts +42 -0
  49. package/dist/litellm/fake-registry-base.d.ts.map +1 -0
  50. package/dist/litellm/fake-stack.d.ts +8 -1
  51. package/dist/litellm/fake-stack.d.ts.map +1 -1
  52. package/dist/litellm/fake-team-litellm.d.ts +47 -0
  53. package/dist/litellm/fake-team-litellm.d.ts.map +1 -0
  54. package/dist/litellm/fake-tool-litellm.d.ts +28 -0
  55. package/dist/litellm/fake-tool-litellm.d.ts.map +1 -0
  56. package/dist/litellm/fake-toolset-litellm.d.ts +29 -0
  57. package/dist/litellm/fake-toolset-litellm.d.ts.map +1 -0
  58. package/dist/litellm/index.d.ts +18 -0
  59. package/dist/litellm/index.d.ts.map +1 -1
  60. package/dist/litellm/index.js +3078 -2
  61. package/dist/litellm/index.js.map +65 -4
  62. package/dist/litellm/key-errors.d.ts +169 -0
  63. package/dist/litellm/key-errors.d.ts.map +1 -0
  64. package/dist/litellm/key-form.d.ts +119 -0
  65. package/dist/litellm/key-form.d.ts.map +1 -0
  66. package/dist/litellm/key-harness.d.ts +41 -0
  67. package/dist/litellm/key-harness.d.ts.map +1 -0
  68. package/dist/litellm/key-metadata-errors.d.ts +30 -0
  69. package/dist/litellm/key-metadata-errors.d.ts.map +1 -0
  70. package/dist/litellm/key-metadata.d.ts +22 -0
  71. package/dist/litellm/key-metadata.d.ts.map +1 -0
  72. package/dist/litellm/key-operations.d.ts +63 -0
  73. package/dist/litellm/key-operations.d.ts.map +1 -0
  74. package/dist/litellm/key-secret.d.ts +33 -0
  75. package/dist/litellm/key-secret.d.ts.map +1 -0
  76. package/dist/litellm/key.d.ts +78 -0
  77. package/dist/litellm/key.d.ts.map +1 -0
  78. package/dist/litellm/mcp-server-credential.d.ts +50 -0
  79. package/dist/litellm/mcp-server-credential.d.ts.map +1 -0
  80. package/dist/litellm/mcp-server-errors.d.ts +101 -0
  81. package/dist/litellm/mcp-server-errors.d.ts.map +1 -0
  82. package/dist/litellm/mcp-server-form.d.ts +56 -0
  83. package/dist/litellm/mcp-server-form.d.ts.map +1 -0
  84. package/dist/litellm/mcp-server-locate.d.ts +26 -0
  85. package/dist/litellm/mcp-server-locate.d.ts.map +1 -0
  86. package/dist/litellm/mcp-server-operations.d.ts +63 -0
  87. package/dist/litellm/mcp-server-operations.d.ts.map +1 -0
  88. package/dist/litellm/mcp-server-shadow.d.ts +24 -0
  89. package/dist/litellm/mcp-server-shadow.d.ts.map +1 -0
  90. package/dist/litellm/mcp-server-types.d.ts +118 -0
  91. package/dist/litellm/mcp-server-types.d.ts.map +1 -0
  92. package/dist/litellm/mcp-server-url.d.ts +11 -0
  93. package/dist/litellm/mcp-server-url.d.ts.map +1 -0
  94. package/dist/litellm/mcp-server.d.ts +95 -0
  95. package/dist/litellm/mcp-server.d.ts.map +1 -0
  96. package/dist/litellm/model-claim.d.ts +24 -0
  97. package/dist/litellm/model-claim.d.ts.map +1 -0
  98. package/dist/litellm/model-credential.d.ts +12 -0
  99. package/dist/litellm/model-credential.d.ts.map +1 -0
  100. package/dist/litellm/model-errors.d.ts +119 -0
  101. package/dist/litellm/model-errors.d.ts.map +1 -0
  102. package/dist/litellm/model-form.d.ts +78 -0
  103. package/dist/litellm/model-form.d.ts.map +1 -0
  104. package/dist/litellm/model-locate.d.ts +13 -0
  105. package/dist/litellm/model-locate.d.ts.map +1 -0
  106. package/dist/litellm/model-operations.d.ts +59 -0
  107. package/dist/litellm/model-operations.d.ts.map +1 -0
  108. package/dist/litellm/model-types.d.ts +91 -0
  109. package/dist/litellm/model-types.d.ts.map +1 -0
  110. package/dist/litellm/model.d.ts +88 -0
  111. package/dist/litellm/model.d.ts.map +1 -0
  112. package/dist/litellm/policy-attachment-form.d.ts +19 -0
  113. package/dist/litellm/policy-attachment-form.d.ts.map +1 -0
  114. package/dist/litellm/policy-attachment-operations.d.ts +31 -0
  115. package/dist/litellm/policy-attachment-operations.d.ts.map +1 -0
  116. package/dist/litellm/policy-attachment-types.d.ts +48 -0
  117. package/dist/litellm/policy-attachment-types.d.ts.map +1 -0
  118. package/dist/litellm/policy-attachment.d.ts +61 -0
  119. package/dist/litellm/policy-attachment.d.ts.map +1 -0
  120. package/dist/litellm/policy-form.d.ts +22 -0
  121. package/dist/litellm/policy-form.d.ts.map +1 -0
  122. package/dist/litellm/policy-operations.d.ts +42 -0
  123. package/dist/litellm/policy-operations.d.ts.map +1 -0
  124. package/dist/litellm/policy-types.d.ts +57 -0
  125. package/dist/litellm/policy-types.d.ts.map +1 -0
  126. package/dist/litellm/policy.d.ts +65 -0
  127. package/dist/litellm/policy.d.ts.map +1 -0
  128. package/dist/litellm/providers.d.ts +1 -1
  129. package/dist/litellm/providers.d.ts.map +1 -1
  130. package/dist/litellm/registry-errors.d.ts +62 -0
  131. package/dist/litellm/registry-errors.d.ts.map +1 -0
  132. package/dist/litellm/registry-support.d.ts +42 -0
  133. package/dist/litellm/registry-support.d.ts.map +1 -0
  134. package/dist/litellm/team-form.d.ts +26 -0
  135. package/dist/litellm/team-form.d.ts.map +1 -0
  136. package/dist/litellm/team-members.d.ts +10 -0
  137. package/dist/litellm/team-members.d.ts.map +1 -0
  138. package/dist/litellm/team-operations.d.ts +38 -0
  139. package/dist/litellm/team-operations.d.ts.map +1 -0
  140. package/dist/litellm/team-permission.d.ts +35 -0
  141. package/dist/litellm/team-permission.d.ts.map +1 -0
  142. package/dist/litellm/team-types.d.ts +101 -0
  143. package/dist/litellm/team-types.d.ts.map +1 -0
  144. package/dist/litellm/team.d.ts +67 -0
  145. package/dist/litellm/team.d.ts.map +1 -0
  146. package/dist/litellm/tool-policy-form.d.ts +21 -0
  147. package/dist/litellm/tool-policy-form.d.ts.map +1 -0
  148. package/dist/litellm/tool-policy-operations.d.ts +30 -0
  149. package/dist/litellm/tool-policy-operations.d.ts.map +1 -0
  150. package/dist/litellm/tool-policy-types.d.ts +46 -0
  151. package/dist/litellm/tool-policy-types.d.ts.map +1 -0
  152. package/dist/litellm/tool-policy.d.ts +62 -0
  153. package/dist/litellm/tool-policy.d.ts.map +1 -0
  154. package/dist/litellm/toolset-form.d.ts +20 -0
  155. package/dist/litellm/toolset-form.d.ts.map +1 -0
  156. package/dist/litellm/toolset-operations.d.ts +39 -0
  157. package/dist/litellm/toolset-operations.d.ts.map +1 -0
  158. package/dist/litellm/toolset-types.d.ts +46 -0
  159. package/dist/litellm/toolset-types.d.ts.map +1 -0
  160. package/dist/litellm/toolset.d.ts +55 -0
  161. package/dist/litellm/toolset.d.ts.map +1 -0
  162. package/dist/openbao/index.js +35 -1
  163. package/dist/openbao/index.js.map +3 -3
  164. package/dist/ownership/rows.d.ts +11 -0
  165. package/dist/ownership/rows.d.ts.map +1 -1
  166. package/dist/postgres/connection.d.ts +14 -2
  167. package/dist/postgres/connection.d.ts.map +1 -1
  168. package/dist/postgres/database-sql.d.ts +27 -8
  169. package/dist/postgres/database-sql.d.ts.map +1 -1
  170. package/dist/postgres/fake-grants-parse.d.ts +37 -0
  171. package/dist/postgres/fake-grants-parse.d.ts.map +1 -0
  172. package/dist/postgres/fake-grants-read.d.ts +61 -0
  173. package/dist/postgres/fake-grants-read.d.ts.map +1 -0
  174. package/dist/postgres/fake-grants-sql.d.ts +46 -0
  175. package/dist/postgres/fake-grants-sql.d.ts.map +1 -0
  176. package/dist/postgres/fake-grants-write.d.ts +29 -0
  177. package/dist/postgres/fake-grants-write.d.ts.map +1 -0
  178. package/dist/postgres/fake-role-sql.d.ts +41 -0
  179. package/dist/postgres/fake-role-sql.d.ts.map +1 -0
  180. package/dist/postgres/fake-schema-sql.d.ts +42 -0
  181. package/dist/postgres/fake-schema-sql.d.ts.map +1 -0
  182. package/dist/postgres/fake-sql-parse.d.ts +23 -0
  183. package/dist/postgres/fake-sql-parse.d.ts.map +1 -0
  184. package/dist/postgres/fake-sql-quote.d.ts +12 -0
  185. package/dist/postgres/fake-sql-quote.d.ts.map +1 -0
  186. package/dist/postgres/fake-sql.d.ts +42 -0
  187. package/dist/postgres/fake-sql.d.ts.map +1 -1
  188. package/dist/postgres/grants-attrs.d.ts +115 -0
  189. package/dist/postgres/grants-attrs.d.ts.map +1 -0
  190. package/dist/postgres/grants-declare.d.ts +88 -0
  191. package/dist/postgres/grants-declare.d.ts.map +1 -0
  192. package/dist/postgres/grants-diff.d.ts +25 -0
  193. package/dist/postgres/grants-diff.d.ts.map +1 -0
  194. package/dist/postgres/grants-errors.d.ts +137 -0
  195. package/dist/postgres/grants-errors.d.ts.map +1 -0
  196. package/dist/postgres/grants-existence.d.ts +14 -0
  197. package/dist/postgres/grants-existence.d.ts.map +1 -0
  198. package/dist/postgres/grants-ops.d.ts +65 -0
  199. package/dist/postgres/grants-ops.d.ts.map +1 -0
  200. package/dist/postgres/grants-ownership.d.ts +18 -0
  201. package/dist/postgres/grants-ownership.d.ts.map +1 -0
  202. package/dist/postgres/grants-plan-restore.d.ts +22 -0
  203. package/dist/postgres/grants-plan-restore.d.ts.map +1 -0
  204. package/dist/postgres/grants-plan.d.ts +65 -0
  205. package/dist/postgres/grants-plan.d.ts.map +1 -0
  206. package/dist/postgres/grants-read-defaults.d.ts +17 -0
  207. package/dist/postgres/grants-read-defaults.d.ts.map +1 -0
  208. package/dist/postgres/grants-read.d.ts +77 -0
  209. package/dist/postgres/grants-read.d.ts.map +1 -0
  210. package/dist/postgres/grants-refuse.d.ts +25 -0
  211. package/dist/postgres/grants-refuse.d.ts.map +1 -0
  212. package/dist/postgres/grants-sql.d.ts +42 -0
  213. package/dist/postgres/grants-sql.d.ts.map +1 -0
  214. package/dist/postgres/grants-words.d.ts +29 -0
  215. package/dist/postgres/grants-words.d.ts.map +1 -0
  216. package/dist/postgres/grants.d.ts +37 -0
  217. package/dist/postgres/grants.d.ts.map +1 -0
  218. package/dist/postgres/index.d.ts +31 -6
  219. package/dist/postgres/index.d.ts.map +1 -1
  220. package/dist/postgres/index.js +1998 -37
  221. package/dist/postgres/index.js.map +46 -7
  222. package/dist/postgres/installed-classifier.d.ts +13 -0
  223. package/dist/postgres/installed-classifier.d.ts.map +1 -0
  224. package/dist/postgres/providers.d.ts +16 -8
  225. package/dist/postgres/providers.d.ts.map +1 -1
  226. package/dist/postgres/psql-executor.d.ts +4 -0
  227. package/dist/postgres/psql-executor.d.ts.map +1 -1
  228. package/dist/postgres/role-attrs.d.ts +112 -0
  229. package/dist/postgres/role-attrs.d.ts.map +1 -0
  230. package/dist/postgres/role-diff.d.ts +22 -0
  231. package/dist/postgres/role-diff.d.ts.map +1 -0
  232. package/dist/postgres/role-errors.d.ts +132 -0
  233. package/dist/postgres/role-errors.d.ts.map +1 -0
  234. package/dist/postgres/role-membership-sql.d.ts +78 -0
  235. package/dist/postgres/role-membership-sql.d.ts.map +1 -0
  236. package/dist/postgres/role-provider.d.ts +11 -0
  237. package/dist/postgres/role-provider.d.ts.map +1 -0
  238. package/dist/postgres/role-scram.d.ts +8 -0
  239. package/dist/postgres/role-scram.d.ts.map +1 -0
  240. package/dist/postgres/role-secrets.d.ts +38 -0
  241. package/dist/postgres/role-secrets.d.ts.map +1 -0
  242. package/dist/postgres/role-sql.d.ts +68 -0
  243. package/dist/postgres/role-sql.d.ts.map +1 -0
  244. package/dist/postgres/role.d.ts +57 -0
  245. package/dist/postgres/role.d.ts.map +1 -0
  246. package/dist/postgres/schema-assert.d.ts +50 -0
  247. package/dist/postgres/schema-assert.d.ts.map +1 -0
  248. package/dist/postgres/schema-attrs.d.ts +51 -0
  249. package/dist/postgres/schema-attrs.d.ts.map +1 -0
  250. package/dist/postgres/schema-delete.d.ts +28 -0
  251. package/dist/postgres/schema-delete.d.ts.map +1 -0
  252. package/dist/postgres/schema-diff.d.ts +14 -0
  253. package/dist/postgres/schema-diff.d.ts.map +1 -0
  254. package/dist/postgres/schema-errors.d.ts +139 -0
  255. package/dist/postgres/schema-errors.d.ts.map +1 -0
  256. package/dist/postgres/schema-identity.d.ts +8 -0
  257. package/dist/postgres/schema-identity.d.ts.map +1 -0
  258. package/dist/postgres/schema-reconcile.d.ts +12 -0
  259. package/dist/postgres/schema-reconcile.d.ts.map +1 -0
  260. package/dist/postgres/schema-sql.d.ts +45 -0
  261. package/dist/postgres/schema-sql.d.ts.map +1 -0
  262. package/dist/postgres/schema-test-kit.d.ts +67 -0
  263. package/dist/postgres/schema-test-kit.d.ts.map +1 -0
  264. package/dist/postgres/schema.d.ts +54 -0
  265. package/dist/postgres/schema.d.ts.map +1 -0
  266. package/dist/proxmox/index.js +35 -1
  267. package/dist/proxmox/index.js.map +3 -3
  268. package/dist/release/fake-engine.d.ts +10 -0
  269. package/dist/release/fake-engine.d.ts.map +1 -1
  270. package/dist/release/index.js +35 -1
  271. package/dist/release/index.js.map +3 -3
  272. package/dist/valkey/acl-attrs.d.ts +94 -0
  273. package/dist/valkey/acl-attrs.d.ts.map +1 -0
  274. package/dist/valkey/acl-compare.d.ts +28 -0
  275. package/dist/valkey/acl-compare.d.ts.map +1 -0
  276. package/dist/valkey/acl-connection.d.ts +6 -0
  277. package/dist/valkey/acl-connection.d.ts.map +1 -0
  278. package/dist/valkey/acl-form.d.ts +62 -0
  279. package/dist/valkey/acl-form.d.ts.map +1 -0
  280. package/dist/valkey/acl-managed.d.ts +4 -0
  281. package/dist/valkey/acl-managed.d.ts.map +1 -0
  282. package/dist/valkey/acl-ops.d.ts +37 -0
  283. package/dist/valkey/acl-ops.d.ts.map +1 -0
  284. package/dist/valkey/acl-profiles.d.ts +53 -0
  285. package/dist/valkey/acl-profiles.d.ts.map +1 -0
  286. package/dist/valkey/acl-reconcile.d.ts +26 -0
  287. package/dist/valkey/acl-reconcile.d.ts.map +1 -0
  288. package/dist/valkey/acl.d.ts +24 -0
  289. package/dist/valkey/acl.d.ts.map +1 -0
  290. package/dist/valkey/connection-service.d.ts +22 -0
  291. package/dist/valkey/connection-service.d.ts.map +1 -0
  292. package/dist/valkey/connection.d.ts +59 -0
  293. package/dist/valkey/connection.d.ts.map +1 -0
  294. package/dist/valkey/errors.d.ts +165 -0
  295. package/dist/valkey/errors.d.ts.map +1 -0
  296. package/dist/valkey/fake-acl.d.ts +29 -0
  297. package/dist/valkey/fake-acl.d.ts.map +1 -0
  298. package/dist/valkey/fake-valkey.d.ts +35 -0
  299. package/dist/valkey/fake-valkey.d.ts.map +1 -0
  300. package/dist/valkey/handler-test-fixture.d.ts +20 -0
  301. package/dist/valkey/handler-test-fixture.d.ts.map +1 -0
  302. package/dist/valkey/index.d.ts +18 -0
  303. package/dist/valkey/index.d.ts.map +1 -0
  304. package/dist/valkey/index.js +964 -0
  305. package/dist/valkey/index.js.map +27 -0
  306. package/dist/valkey/instance-attrs.d.ts +46 -0
  307. package/dist/valkey/instance-attrs.d.ts.map +1 -0
  308. package/dist/valkey/instance-form.d.ts +22 -0
  309. package/dist/valkey/instance-form.d.ts.map +1 -0
  310. package/dist/valkey/instance.d.ts +48 -0
  311. package/dist/valkey/instance.d.ts.map +1 -0
  312. package/dist/valkey/provider-socket-fixture.d.ts +8 -0
  313. package/dist/valkey/provider-socket-fixture.d.ts.map +1 -0
  314. package/dist/valkey/providers.d.ts +16 -0
  315. package/dist/valkey/providers.d.ts.map +1 -0
  316. package/dist/valkey/resp.d.ts +38 -0
  317. package/dist/valkey/resp.d.ts.map +1 -0
  318. package/dist/valkey/transport-error.d.ts +36 -0
  319. package/dist/valkey/transport-error.d.ts.map +1 -0
  320. package/dist/valkey/transport.d.ts +50 -0
  321. package/dist/valkey/transport.d.ts.map +1 -0
  322. package/docs/litellm-access-group.md +105 -0
  323. package/docs/litellm-credential.md +60 -0
  324. package/docs/litellm-key-metadata.md +56 -0
  325. package/docs/litellm-key.md +194 -0
  326. package/docs/litellm-mcp.md +187 -0
  327. package/docs/litellm-model.md +111 -0
  328. package/docs/litellm-policy-attachment.md +86 -0
  329. package/docs/litellm-policy.md +103 -0
  330. package/docs/litellm-team.md +117 -0
  331. package/docs/litellm-tool-policy.md +90 -0
  332. package/docs/litellm-toolset.md +92 -0
  333. package/docs/litellm.md +16 -9
  334. package/docs/peers.md +15 -6
  335. package/docs/postgres-grants-example.md +55 -0
  336. package/docs/postgres-grants.md +157 -0
  337. package/docs/postgres-role.md +126 -0
  338. package/docs/postgres-schema.md +139 -0
  339. package/docs/postgres.md +20 -3
  340. package/docs/valkey-transport.md +29 -0
  341. package/docs/valkey.md +187 -0
  342. package/package.json +6 -2
  343. package/src/ceph/ceph-argv.test.ts +1 -1
  344. package/src/launchd/sudo-allowlist.test.ts +2 -2
  345. package/src/linux/sudo-allowlist.test.ts +3 -3
  346. package/src/linux/sudo-runner.test.ts +2 -2
  347. package/src/litellm/access-group-form.ts +105 -0
  348. package/src/litellm/access-group-operations.ts +92 -0
  349. package/src/litellm/access-group-types.ts +49 -0
  350. package/src/litellm/access-group.test.ts +197 -0
  351. package/src/litellm/access-group.ts +151 -0
  352. package/src/litellm/credential-errors.ts +183 -0
  353. package/src/litellm/credential-form.test.ts +151 -0
  354. package/src/litellm/credential-form.ts +211 -0
  355. package/src/litellm/credential-guards.test.ts +241 -0
  356. package/src/litellm/credential-operations.ts +208 -0
  357. package/src/litellm/credential-recovery.test.ts +93 -0
  358. package/src/litellm/credential-rewrite.test.ts +164 -0
  359. package/src/litellm/credential-rewrite.ts +50 -0
  360. package/src/litellm/credential-types.ts +117 -0
  361. package/src/litellm/credential-values.ts +94 -0
  362. package/src/litellm/credential.test.ts +218 -0
  363. package/src/litellm/credential.ts +227 -0
  364. package/src/litellm/fake-access-group-litellm.ts +127 -0
  365. package/src/litellm/fake-credential-litellm.ts +216 -0
  366. package/src/litellm/fake-keys.ts +190 -0
  367. package/src/litellm/fake-litellm.ts +19 -9
  368. package/src/litellm/fake-mcp-litellm.ts +214 -0
  369. package/src/litellm/fake-model-litellm-post-update.ts +103 -0
  370. package/src/litellm/fake-model-litellm.ts +233 -0
  371. package/src/litellm/fake-policy-attachment-litellm.ts +97 -0
  372. package/src/litellm/fake-policy-litellm.ts +186 -0
  373. package/src/litellm/fake-registry-base.ts +69 -0
  374. package/src/litellm/fake-stack.ts +17 -1
  375. package/src/litellm/fake-team-litellm.ts +229 -0
  376. package/src/litellm/fake-tool-litellm.ts +88 -0
  377. package/src/litellm/fake-toolset-litellm.ts +110 -0
  378. package/src/litellm/index.ts +140 -0
  379. package/src/litellm/key-delete.test.ts +212 -0
  380. package/src/litellm/key-errors.ts +241 -0
  381. package/src/litellm/key-form.ts +200 -0
  382. package/src/litellm/key-harness.ts +121 -0
  383. package/src/litellm/key-metadata-errors.ts +49 -0
  384. package/src/litellm/key-metadata.test.ts +156 -0
  385. package/src/litellm/key-metadata.ts +74 -0
  386. package/src/litellm/key-operations.ts +184 -0
  387. package/src/litellm/key-rotation.test.ts +110 -0
  388. package/src/litellm/key-scope.test.ts +135 -0
  389. package/src/litellm/key-secret.test.ts +248 -0
  390. package/src/litellm/key-secret.ts +137 -0
  391. package/src/litellm/key-transport.test.ts +166 -0
  392. package/src/litellm/key.test.ts +231 -0
  393. package/src/litellm/key.ts +213 -0
  394. package/src/litellm/mcp-server-adopt.test.ts +86 -0
  395. package/src/litellm/mcp-server-alias.test.ts +184 -0
  396. package/src/litellm/mcp-server-credential.ts +85 -0
  397. package/src/litellm/mcp-server-errors.ts +141 -0
  398. package/src/litellm/mcp-server-exports.test.ts +15 -0
  399. package/src/litellm/mcp-server-form.test.ts +241 -0
  400. package/src/litellm/mcp-server-form.ts +233 -0
  401. package/src/litellm/mcp-server-handlers.test.ts +150 -0
  402. package/src/litellm/mcp-server-locate.ts +66 -0
  403. package/src/litellm/mcp-server-operations.ts +111 -0
  404. package/src/litellm/mcp-server-registry.test.ts +146 -0
  405. package/src/litellm/mcp-server-retype.test.ts +114 -0
  406. package/src/litellm/mcp-server-shadow.test.ts +91 -0
  407. package/src/litellm/mcp-server-shadow.ts +45 -0
  408. package/src/litellm/mcp-server-tools.test.ts +85 -0
  409. package/src/litellm/mcp-server-types.ts +143 -0
  410. package/src/litellm/mcp-server-url.ts +66 -0
  411. package/src/litellm/mcp-server.test.ts +213 -0
  412. package/src/litellm/mcp-server.ts +225 -0
  413. package/src/litellm/model-claim.ts +69 -0
  414. package/src/litellm/model-credential.ts +45 -0
  415. package/src/litellm/model-errors.ts +168 -0
  416. package/src/litellm/model-foreign-row.test.ts +173 -0
  417. package/src/litellm/model-form.test.ts +228 -0
  418. package/src/litellm/model-form.ts +223 -0
  419. package/src/litellm/model-locate.test.ts +128 -0
  420. package/src/litellm/model-locate.ts +67 -0
  421. package/src/litellm/model-operations.test.ts +93 -0
  422. package/src/litellm/model-operations.ts +146 -0
  423. package/src/litellm/model-params-preserve.test.ts +119 -0
  424. package/src/litellm/model-recovery.test.ts +57 -0
  425. package/src/litellm/model-types.ts +112 -0
  426. package/src/litellm/model.test.ts +222 -0
  427. package/src/litellm/model.ts +237 -0
  428. package/src/litellm/policy-attachment-form.ts +103 -0
  429. package/src/litellm/policy-attachment-operations.ts +74 -0
  430. package/src/litellm/policy-attachment-types.ts +48 -0
  431. package/src/litellm/policy-attachment.test.ts +198 -0
  432. package/src/litellm/policy-attachment.ts +178 -0
  433. package/src/litellm/policy-form.ts +122 -0
  434. package/src/litellm/policy-operations.ts +112 -0
  435. package/src/litellm/policy-types.ts +58 -0
  436. package/src/litellm/policy.test.ts +214 -0
  437. package/src/litellm/policy.ts +146 -0
  438. package/src/litellm/providers.ts +24 -3
  439. package/src/litellm/registry-errors.ts +88 -0
  440. package/src/litellm/registry-exports.test.ts +66 -0
  441. package/src/litellm/registry-support.ts +109 -0
  442. package/src/litellm/team-form.ts +140 -0
  443. package/src/litellm/team-members.test.ts +150 -0
  444. package/src/litellm/team-members.ts +58 -0
  445. package/src/litellm/team-operations.ts +90 -0
  446. package/src/litellm/team-permission.ts +159 -0
  447. package/src/litellm/team-read.test.ts +89 -0
  448. package/src/litellm/team-types.ts +106 -0
  449. package/src/litellm/team.test.ts +206 -0
  450. package/src/litellm/team.ts +159 -0
  451. package/src/litellm/tool-policy-form.ts +94 -0
  452. package/src/litellm/tool-policy-operations.ts +58 -0
  453. package/src/litellm/tool-policy-types.ts +48 -0
  454. package/src/litellm/tool-policy.test.ts +172 -0
  455. package/src/litellm/tool-policy.ts +125 -0
  456. package/src/litellm/toolset-form.ts +104 -0
  457. package/src/litellm/toolset-operations.ts +90 -0
  458. package/src/litellm/toolset-types.ts +47 -0
  459. package/src/litellm/toolset.test.ts +198 -0
  460. package/src/litellm/toolset.ts +151 -0
  461. package/src/ownership/ownership.test.ts +33 -1
  462. package/src/ownership/rows.ts +53 -0
  463. package/src/postgres/connection.ts +42 -7
  464. package/src/postgres/database-bigint-serialization.test.ts +1 -0
  465. package/src/postgres/database-refusals.test.ts +2 -2
  466. package/src/postgres/database-sql.ts +36 -9
  467. package/src/postgres/fake-grants-parse.ts +189 -0
  468. package/src/postgres/fake-grants-read.ts +250 -0
  469. package/src/postgres/fake-grants-sql.ts +207 -0
  470. package/src/postgres/fake-grants-write.ts +90 -0
  471. package/src/postgres/fake-role-sql.ts +240 -0
  472. package/src/postgres/fake-schema-semantics.test.ts +36 -0
  473. package/src/postgres/fake-schema-sql.ts +146 -0
  474. package/src/postgres/fake-sql-parse.ts +86 -0
  475. package/src/postgres/fake-sql-quote.ts +36 -0
  476. package/src/postgres/fake-sql.ts +166 -46
  477. package/src/postgres/fixtures/pg-REL_18_6-acl.h.txt +147 -0
  478. package/src/postgres/fixtures/pg-REL_18_6-aclexplode-func.txt +31 -0
  479. package/src/postgres/fixtures/pg-REL_18_6-alter-default-privileges-synopsis.txt +82 -0
  480. package/src/postgres/fixtures/pg-REL_18_6-alter_role.sgml.txt +44 -0
  481. package/src/postgres/fixtures/pg-REL_18_6-create_role.sgml.txt +26 -0
  482. package/src/postgres/fixtures/pg-REL_18_6-grant-synopsis.txt +95 -0
  483. package/src/postgres/fixtures/pg-REL_18_6-pg_attribute.h.txt +24 -0
  484. package/src/postgres/fixtures/pg-REL_18_6-pg_auth_members.h.txt +62 -0
  485. package/src/postgres/fixtures/pg-REL_18_6-pg_authid.h.txt +70 -0
  486. package/src/postgres/fixtures/pg-REL_18_6-pg_class.h.txt +33 -0
  487. package/src/postgres/fixtures/pg-REL_18_6-pg_default_acl.h.txt +81 -0
  488. package/src/postgres/fixtures/pg-REL_18_6-pg_namespace.h.txt +28 -0
  489. package/src/postgres/fixtures/pg-REL_18_6-revoke-synopsis.txt +124 -0
  490. package/src/postgres/grants-acl.test.ts +61 -0
  491. package/src/postgres/grants-attrs.ts +185 -0
  492. package/src/postgres/grants-database.test.ts +158 -0
  493. package/src/postgres/grants-declare.ts +172 -0
  494. package/src/postgres/grants-delete-proof.test.ts +154 -0
  495. package/src/postgres/grants-diff.ts +101 -0
  496. package/src/postgres/grants-errors.ts +215 -0
  497. package/src/postgres/grants-existence-guards.test.ts +113 -0
  498. package/src/postgres/grants-existence.ts +101 -0
  499. package/src/postgres/grants-lifecycle-guards.test.ts +208 -0
  500. package/src/postgres/grants-lifecycle-repair.test.ts +208 -0
  501. package/src/postgres/grants-lifecycle.test.ts +181 -0
  502. package/src/postgres/grants-ops.ts +229 -0
  503. package/src/postgres/grants-owner-revoke.test.ts +121 -0
  504. package/src/postgres/grants-ownership.ts +49 -0
  505. package/src/postgres/grants-plan-collateral.test.ts +202 -0
  506. package/src/postgres/grants-plan-diff.test.ts +204 -0
  507. package/src/postgres/grants-plan-restore.ts +43 -0
  508. package/src/postgres/grants-plan-revocations.test.ts +69 -0
  509. package/src/postgres/grants-plan.test.ts +148 -0
  510. package/src/postgres/grants-plan.ts +245 -0
  511. package/src/postgres/grants-provenance.test.ts +134 -0
  512. package/src/postgres/grants-psql-lifecycle.test.ts +105 -0
  513. package/src/postgres/grants-read-absent.test.ts +91 -0
  514. package/src/postgres/grants-read-defaults.ts +51 -0
  515. package/src/postgres/grants-read.ts +250 -0
  516. package/src/postgres/grants-refusals.test.ts +136 -0
  517. package/src/postgres/grants-refuse.ts +119 -0
  518. package/src/postgres/grants-relkind-wire.test.ts +111 -0
  519. package/src/postgres/grants-repair-plan.test.ts +201 -0
  520. package/src/postgres/grants-sql.test.ts +128 -0
  521. package/src/postgres/grants-sql.ts +144 -0
  522. package/src/postgres/grants-words.ts +34 -0
  523. package/src/postgres/grants.ts +110 -0
  524. package/src/postgres/index.ts +129 -5
  525. package/src/postgres/installed-classifier.ts +36 -0
  526. package/src/postgres/providers.ts +33 -9
  527. package/src/postgres/psql-executor-escaping.test.ts +67 -0
  528. package/src/postgres/psql-executor.test.ts +63 -2
  529. package/src/postgres/psql-executor.ts +74 -34
  530. package/src/postgres/role-adopt.test.ts +98 -0
  531. package/src/postgres/role-attrs.ts +137 -0
  532. package/src/postgres/role-diff.ts +93 -0
  533. package/src/postgres/role-errors.ts +206 -0
  534. package/src/postgres/role-guard.test.ts +60 -0
  535. package/src/postgres/role-identity.test.ts +197 -0
  536. package/src/postgres/role-lifecycle.test.ts +228 -0
  537. package/src/postgres/role-membership-options.test.ts +73 -0
  538. package/src/postgres/role-membership-repair.test.ts +153 -0
  539. package/src/postgres/role-membership-sql.ts +223 -0
  540. package/src/postgres/role-password-ascii.test.ts +53 -0
  541. package/src/postgres/role-password-transports.test.ts +123 -0
  542. package/src/postgres/role-password.test.ts +158 -0
  543. package/src/postgres/role-privilege.test.ts +107 -0
  544. package/src/postgres/role-provenance.test.ts +200 -0
  545. package/src/postgres/role-provider.ts +105 -0
  546. package/src/postgres/role-refusals.test.ts +225 -0
  547. package/src/postgres/role-scram.test.ts +38 -0
  548. package/src/postgres/role-scram.ts +40 -0
  549. package/src/postgres/role-secrets.ts +61 -0
  550. package/src/postgres/role-sql.ts +213 -0
  551. package/src/postgres/role-valid-until.test.ts +68 -0
  552. package/src/postgres/role.ts +226 -0
  553. package/src/postgres/schema-assert.ts +139 -0
  554. package/src/postgres/schema-attrs.ts +71 -0
  555. package/src/postgres/schema-delete-proofs.test.ts +192 -0
  556. package/src/postgres/schema-delete.ts +96 -0
  557. package/src/postgres/schema-diff.ts +44 -0
  558. package/src/postgres/schema-drop-2bp01.test.ts +146 -0
  559. package/src/postgres/schema-errors.ts +209 -0
  560. package/src/postgres/schema-handlers.test.ts +193 -0
  561. package/src/postgres/schema-identity.ts +39 -0
  562. package/src/postgres/schema-lifecycle.test.ts +246 -0
  563. package/src/postgres/schema-race.test.ts +70 -0
  564. package/src/postgres/schema-reconcile.ts +100 -0
  565. package/src/postgres/schema-refusals.test.ts +144 -0
  566. package/src/postgres/schema-socket.test.ts +162 -0
  567. package/src/postgres/schema-sql.ts +130 -0
  568. package/src/postgres/schema-takeover.test.ts +149 -0
  569. package/src/postgres/schema-test-kit.ts +85 -0
  570. package/src/postgres/schema.ts +130 -0
  571. package/src/release/binary-alias.test.ts +3 -3
  572. package/src/release/binary-claims.test.ts +3 -3
  573. package/src/release/binary-directory-umask.test.ts +65 -0
  574. package/src/release/fake-engine.ts +15 -0
  575. package/src/valkey/acl-attrs.ts +98 -0
  576. package/src/valkey/acl-compare.ts +57 -0
  577. package/src/valkey/acl-connection.ts +13 -0
  578. package/src/valkey/acl-delete.test.ts +127 -0
  579. package/src/valkey/acl-form.ts +239 -0
  580. package/src/valkey/acl-managed.ts +13 -0
  581. package/src/valkey/acl-ops.ts +122 -0
  582. package/src/valkey/acl-ownership.test.ts +118 -0
  583. package/src/valkey/acl-prefix.test.ts +38 -0
  584. package/src/valkey/acl-profiles.ts +81 -0
  585. package/src/valkey/acl-reconcile.ts +180 -0
  586. package/src/valkey/acl-reserved.test.ts +69 -0
  587. package/src/valkey/acl-revocation.test.ts +94 -0
  588. package/src/valkey/acl-seat-prefix.test.ts +111 -0
  589. package/src/valkey/acl-validation.test.ts +54 -0
  590. package/src/valkey/acl.test.ts +215 -0
  591. package/src/valkey/acl.ts +169 -0
  592. package/src/valkey/connection-service.ts +46 -0
  593. package/src/valkey/connection.ts +180 -0
  594. package/src/valkey/errors.ts +239 -0
  595. package/src/valkey/fake-acl.ts +128 -0
  596. package/src/valkey/fake-valkey.ts +224 -0
  597. package/src/valkey/handler-test-fixture.ts +43 -0
  598. package/src/valkey/handlers.test.ts +205 -0
  599. package/src/valkey/index.ts +54 -0
  600. package/src/valkey/instance-attrs.ts +48 -0
  601. package/src/valkey/instance-form.ts +104 -0
  602. package/src/valkey/instance.test.ts +108 -0
  603. package/src/valkey/instance.ts +160 -0
  604. package/src/valkey/provider-socket-fixture.ts +71 -0
  605. package/src/valkey/providers.test.ts +129 -0
  606. package/src/valkey/providers.ts +21 -0
  607. package/src/valkey/resp.ts +212 -0
  608. package/src/valkey/transport-bounds.test.ts +150 -0
  609. package/src/valkey/transport-error.ts +37 -0
  610. package/src/valkey/transport.test.ts +158 -0
  611. package/src/valkey/transport.ts +109 -0
  612. package/src/valkey/upstream-bounds.test.ts +14 -0
@@ -0,0 +1,50 @@
1
+ /**
2
+ * The RESP wire the `Valkey` family speaks, hand-rolled the same way `postgres/database-sql.ts`
3
+ * hand-rolls its four statements: there is no `@distilled.cloud/valkey` SDK (registry 404, checked
4
+ * 2026-09-29), and `effect@4.0.0-rc.115` ships no Valkey/Redis client, so the family declares a
5
+ * `ValkeyExecutor` seam — the real socket client below, or `fake-valkey.ts` in tests — and every
6
+ * lifecycle function depends only on that small interface, never on `node:net`.
7
+ * ★ Alchemy beta.79 DOES ship Redis.connect. Its internal parser/queue cannot enforce our
8
+ * reply caps before allocating, and it exposes no deadline settings. The audited exception
9
+ * and executable measurements are in `docs/valkey-transport.md`.
10
+ *
11
+ * ⛔ RESP, NOT A TAG TO VALKEY'S C VERSION. The protocol is line-and-prefix oriented and stable
12
+ * across Valkey's releases; the commands this family issues (`INFO`, `CONFIG GET`, `ACL LIST`,
13
+ * `ACL SETUSER`, `PING`) are all long-settled. Nothing here parses a version-specific field.
14
+ * ★ RUNTIME-NEUTRAL. The executor is a function of `node:net` sockets, no Bun API; a Bun-only
15
+ * consumer would be a regression the postgres family's own `PgClient` avoided.
16
+ * ⛔ AN `error` EVENT WITH NO LISTENER EXITS THE PROCESS. `openSocket` listens only until
17
+ * `connect`. This executor installs the listener that stays for the life of the socket, and
18
+ * fails the in-flight read with `ValkeySocketError` (measured 2026-09-30: a peer RST after
19
+ * the connect listener was dropped was `uncaughtException` `read ECONNRESET`, exit 1).
20
+ */
21
+ import * as Effect from 'effect/Effect';
22
+ import type { Socket } from 'node:net';
23
+ import { type ValkeyReply, type ValkeyTransportError } from './transport-error.ts';
24
+ export type { ValkeyReply, ValkeyTransportError } from './transport-error.ts';
25
+ export { ValkeyServerError, ValkeySocketError } from './transport-error.ts';
26
+ /** One command with its arguments, as the byte strings that go on the wire. */
27
+ export interface ValkeyCommand {
28
+ readonly args: ReadonlyArray<string>;
29
+ }
30
+ /** The smallest thing a lifecycle function needs from a client: send one command, read the reply
31
+ * as one of the three RESP top-level shapes the family interprets — a bulk string, a flat array of
32
+ * bulk strings, or an error. `null` is the RESP "nil" reply (a missing key). Failures are the two
33
+ * transport tags: a server error reply, or a socket failure. */
34
+ export interface ValkeyExecutor {
35
+ readonly send: (args: ReadonlyArray<string>) => Effect.Effect<ValkeyReply, ValkeyTransportError>;
36
+ }
37
+ /** The per-read abort, and the idle/`connect` deadline `withValkey` sets on the socket. */
38
+ export declare const DEFAULT_SOCKET_TIMEOUT_MS = 10000;
39
+ /**
40
+ * The real executor over a `node:net` socket. `socket` is supplied by the caller (which owns
41
+ * connect/close), so `withValkey` can open one socket per operation and close it after.
42
+ * `timeoutMs` bounds each read; the default matches the socket deadline in `connection.ts`.
43
+ */
44
+ export declare const makeSocketExecutor: (socket: Socket, timeoutMs?: number) => ValkeyExecutor;
45
+ /**
46
+ * Decode a flat array reply into `Map<string, string | null>` for the `key value key value`
47
+ * shape `CONFIG GET` answers. Null values are preserved; a missing key is `null`, never `''`.
48
+ */
49
+ export declare const arrayPairs: (values: ReadonlyArray<string | null>) => ReadonlyMap<string, string | null>;
50
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/valkey/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,OAAO,EACL,KAAK,WAAW,EAEhB,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;AAE9B,YAAY,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE5E,+EAA+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACtC;AAED;;;gEAGgE;AAChE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC;CAClG;AAED,2FAA2F;AAC3F,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAOhD;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,WACrB,MAAM,cACH,MAAM,KAChB,cAiCF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,UAAU,WACb,aAAa,CAAC,MAAM,GAAG,IAAI,CAAC,KACnC,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAMnC,CAAC"}
@@ -0,0 +1,105 @@
1
+ # LiteLLM — `LiteLLM.AccessGroup`
2
+
3
+ One row of LiteLLM's **unified access group** table (`LiteLLM_AccessGroupTable`,
4
+ `/v1/unified_access_group`): a named bundle of models and MCP servers that teams and keys are attached to.
5
+ Typed calls come from `@distilled.cloud/litellm/access_groups`, generated from LiteLLM **v1.103.0**;
6
+ credentials and the family's other refusals are in [litellm.md](./litellm.md).
7
+
8
+ Everything below marked "read" was read from the **live 1.103.0 container's source** on 2026-09-30 (no
9
+ request was sent to a proxy). What the docs page says is cited by URL.
10
+
11
+ ## Which "access group" this is
12
+
13
+ LiteLLM uses the words for three different things. This resource is the first.
14
+
15
+ | Thing | Where it lives | Holds |
16
+ | ------------------------ | ------------------------------------------------------ | --------------------------- |
17
+ | **Unified access group** | `LiteLLM_AccessGroupTable`, `/v1/unified_access_group` | models, MCP servers, agents |
18
+ | Model access group | `access_groups` in a model's `model_info` | models only |
19
+ | MCP access group | a bare name on an MCP server row (`mcp_access_groups`) | MCP servers by name |
20
+
21
+ ⚠️ **Toolsets are not in a unified group.** `AccessGroupCreateRequest` (`litellm/types/access_group.py`)
22
+ has `access_model_names`, `access_mcp_server_ids`, `access_agent_ids`, `assigned_team_ids` and
23
+ `assigned_key_ids`, and nothing else. A toolset is granted through `object_permission.mcp_toolsets` on a
24
+ team or key ([litellm-team.md](./litellm-team.md)).
25
+ The docs agree: docs.litellm.ai/docs/proxy/access_groups lists models, MCP servers and agents.
26
+
27
+ ## The distilled operations it uses
28
+
29
+ Nothing is hand-rolled: every call is one of these, through `access-group-operations.ts`.
30
+
31
+ | step | operation (`@distilled.cloud/litellm/access_groups`) | route |
32
+ | ------ | ---------------------------------------------------------- | ------------------------------------- |
33
+ | list | `listAccessGroupsV1UnifiedAccessGroupGet` | `GET /v1/unified_access_group` |
34
+ | create | `createAccessGroupV1UnifiedAccessGroupPost` | `POST /v1/unified_access_group` (201) |
35
+ | update | `updateAccessGroupV1UnifiedAccessGroupAccessGroupIdPut` | `PUT /v1/unified_access_group/{id}` |
36
+ | delete | `deleteAccessGroupV1UnifiedAccessGroupAccessGroupIdDelete` | `DELETE …/{id}` (204, no body) |
37
+
38
+ Not used: the by-id `GET` (a missing id is a 404 this tag does not declare; the list decides absence
39
+ without it), and the `/v1/access_group` routes (registered as aliases of these on the same handlers,
40
+ `access_group_endpoints.py`, "Alias routes").
41
+
42
+ ## Example
43
+
44
+ ```ts
45
+ import { LiteLLMAccessGroup, litellmProviders } from '@homeflare/alchemy/litellm';
46
+
47
+ // An existing group, adopted by its name (needs --adopt), made to grant exactly this.
48
+ export class Estate extends LiteLLMAccessGroup('Estate', {
49
+ accessGroupName: 'estate',
50
+ description: 'Models and tools every estate seat may use',
51
+ modelNames: ['cf-code', 'cf-flash'],
52
+ mcpServerIds: [docs.serverId], // a LiteLLM.MCPServer: the dependency edge is the Output
53
+ }) {}
54
+ ```
55
+
56
+ Then provide `litellmProviders()` alongside the stack's other providers.
57
+
58
+ ## Behaviour
59
+
60
+ | Concern | Rule |
61
+ | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
62
+ | Identity | `access_group_name` is **unique** (`find_unique`, a duplicate is a 409), so the name finds the one row. The id is the proxy's (a uuid) and is what state remembers. |
63
+ | Adopt | A live row with no state is `Unowned`; it needs `--adopt`. A matching row writes nothing. |
64
+ | Rename | An update of the same row (the id does not change), never a replace. |
65
+ | Grants | `modelNames` and `mcpServerIds` are **always compared**, as sets; an undeclared list means "grants nothing". An adopted group that grants more than declared is corrected. |
66
+ | Description | Compared only when declared: adopting never clears text a person wrote. Blank is refused. |
67
+ | Update | Partial (`exclude_unset`, a `null` list becomes `[]`), so only the fields that differ are sent. Team and key edges, agents and `access_agent_ids` are never in the body. |
68
+ | Removal | `defaultRemovalPolicy: 'retain'`. Opt in with `RemovalPolicy.destroy()`. Deleting a group **detaches it from every team and key** that holds it (`delete_access_group`). |
69
+ | Delete | Idempotent by a real read: a failed DELETE is swallowed only when the list no longer has the id. A 403 (PROXY_ADMIN only) re-raises the original error. |
70
+ | Write check | Reconcile lists again and fails (`LitellmRegistryNotConvergedError`) if a declared field did not land, or (`LitellmRegistryAbsentAfterWriteError`) if the row is not there. |
71
+
72
+ ## Team and key membership is declared on the other side
73
+
74
+ `assigned_team_ids` and `assigned_key_ids` are **not modelled**. A team's group membership is
75
+ `LiteLLM.Team`'s `accessGroupIds`, and LiteLLM mirrors it into the group's `assigned_team_ids` in the same
76
+ transaction (`_sync_add_access_group_to_teams`). Two resources writing one edge would fight, so the group
77
+ never sends either field, and an adopted group keeps whatever it has there.
78
+
79
+ ⚠️ **LiteLLM edits `access_model_names` itself.** Unified groups store model **names**, and
80
+ `management_helpers/access_group_model_sync.py` removes a name from every group when its last deployment is
81
+ deleted (and renames it when a deployment is renamed). A model removed elsewhere therefore shows up as a
82
+ plan difference on the next change. Alchemy plans from state and reads live rows only to adopt (beta.79), so
83
+ the correction lands on the next deploy that changes the group at all, not on its own.
84
+
85
+ ## Refused before any request
86
+
87
+ A blank or padded `accessGroupName`; a blank `description`; a blank, padded or repeated entry in
88
+ `modelNames` or `mcpServerIds`.
89
+
90
+ ## Licence gating (measured)
91
+
92
+ None. `access_group_endpoints.py` has no `premium_user` check (`grep -ci premium`: 0), and the docs page makes
93
+ no Enterprise statement. Writes need PROXY_ADMIN (`_require_proxy_admin`, 403), reads admin or admin-view.
94
+
95
+ ## Not modelled
96
+
97
+ `assigned_team_ids`, `assigned_key_ids`, `access_agent_ids`; nothing validates that a model name or a server
98
+ id exists (LiteLLM stores them raw), so a dangling id is accepted and silently grants nothing.
99
+
100
+ ## Unmeasured at 1.103.0
101
+
102
+ No live proxy was contacted. The fake (`fake-access-group-litellm.ts`) is built from the source and the
103
+ generated schema; each choice it makes is in its header. Whether the list is paged, and what the by-id
104
+ `GET` answers for a missing id, were not exercised. The typed fix for the undeclared 404 and 409 of this tag
105
+ is a distilled patch, which belongs in the distilled clone and is not part of this change.
@@ -0,0 +1,60 @@
1
+ # LiteLLM — `LiteLLM.Credential`
2
+
3
+ One row of LiteLLM's reusable credential table (`/credentials/*`): a named bag of values the
4
+ proxy stores **encrypted** and can bind to a deployment by `model_id`. Typed calls come from
5
+ `@distilled.cloud/litellm/credential_management` (generated from v1.103.0, the same schema this
6
+ resource's rules were read from); credentials and refusals are the family's, see
7
+ [litellm.md](./litellm.md).
8
+
9
+ ## The values never live in a declaration
10
+
11
+ `credentialValues` is `Record<string, { fromEnv: 'NAME' }>`. Alchemy's state is unencrypted and
12
+ LiteLLM stores these literals encrypted in its own database (`credential_endpoints/endpoints.py`,
13
+ read from a 1.103.0 container), so the declaration holds only the variable's NAME; the
14
+ deploying process resolves the value at call time and the wire body carries the literal once.
15
+ A literal value in the props is refused at plan time, and so is a sensitive-keyed
16
+ `credentialInfo` entry — `credential_info` is stored and returned in the clear.
17
+
18
+ The reads hand the values back masked (`litellm_logging.py::_get_masked_values`: a
19
+ sensitive-keyed string answers `v[:2] + "****" + v[-2:]`, `*****` for a short one), so no value
20
+ is ever compared against or copied from the masked row (only value key names are retained): what was last written is remembered as
21
+ a salted scrypt seal (`valuesSeal`), and a rotated value is noticed by re-resolving and
22
+ re-sealing. A variable that is unset makes the state "cannot tell" — it never drifts a
23
+ plan-only environment. An info-only PATCH needs no value; a create, values PATCH or rewrite
24
+ demands every declared variable. A required rewrite refuses before DELETE if any is missing.
25
+
26
+ ## Behaviour
27
+
28
+ | Concern | Rule |
29
+ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
30
+ | Identity | `credentialName` (the table's unique column). A different declared name is a `replace`, `deleteFirst: false` — the old row survives. |
31
+ | Adopt | A live row with the name and no state is `Unowned`; needs `--adopt`. The full intended info and value-key maps are authoritative, including undeclared live keys. Resolvable values are stamped and sealed; removal requires all declared values. |
32
+ | Removal | `defaultRemovalPolicy: 'retain'` — a deployment's `model_id` may reference the row. Opt in with `RemovalPolicy.destroy()`. Delete is idempotent (`NotFound` is already-absent). |
33
+ | Read | `GET /credentials/by_name/{name}` — the proxy's in-memory list, not the table. A row committed to the database but not loaded in memory reads as absent; a create for it answers `409`, which fails the deploy loudly. |
34
+ | Update | PATCH changes values/info; DELETE + POST removes value or info keys. The regenerated SDK sends the required `credential_name` in both path and body. |
35
+ | Write check | Reconcile reads back; unapplied info or remaining removed key names fail with `LitellmCredentialNotConvergedError`. Values and masked fragments never enter state. |
36
+
37
+ ## PATCH and removal
38
+
39
+ Measured in LiteLLM 1.103.0 `proxy/credential_endpoints/endpoints.py:312,384`: PATCH merges
40
+ `credential_values` by key in both database and memory. It cannot remove a value key. The
41
+ by-name read exposes key names even when values are masked, so removed names trigger a rewrite.
42
+
43
+ `credential_info` differs: nonempty PATCH info normally **replaces** the database map
44
+ (`:314–319`, except when the old map contains a literal `credential_info` key); empty info
45
+ leaves it unchanged. In-memory info only merges (`:385–387`), retaining old keys until restart.
46
+ Every PATCH sends the full intended info map. **The declaration owns the complete map**, with
47
+ omission meaning `{}`: undeclared live info keys, including on adoption, are removed by rewrite
48
+ so both stores agree. Sensitive info values are withheld; only their names are retained.
49
+
50
+ Reconcile refuses invalid declarations and `DISTILLED_DEBUG_HTTP` at entry, rechecks ownership,
51
+ and demands all values needed for a write before any DELETE. Debug logging could print request
52
+ or response values; plan-time reads refuse debug logging too. Transport failures from value-bearing POST/PATCH become a typed
53
+ `LitellmCredentialTransportError` containing the name and reason tag, no request or cause.
54
+ A failed PATCH leaves the row in place. A rewrite is still non-atomic: a failed POST after a
55
+ successful DELETE can leave no row. No live proxy was contacted for these regression tests.
56
+
57
+ ## Not modelled
58
+
59
+ `model_id` (copying a deployment's values into a credential) — nothing in the estate declares
60
+ one yet; add it with a measured read of the copy semantics.
@@ -0,0 +1,56 @@
1
+ # LiteLLM — `LiteLLM.Key` metadata
2
+
3
+ How [`LiteLLM.Key`](./litellm-key.md) compares and writes a key's `metadata`, and what it never holds.
4
+ Read 2026-09-29 in the LiteLLM **1.103.0** PyPI wheel's source (`litellm/proxy/…`), not against a live
5
+ proxy. The code is `src/litellm/key-metadata.ts`; its header carries the same reasoning.
6
+
7
+ ## Why `metadata` is not the declarer's alone
8
+
9
+ LiteLLM stores many per-key settings **inside** the `metadata` JSON column:
10
+
11
+ - `LiteLLM_ManagementEndpoint_MetadataFields` and `..._Premium` (`_types.py:4821-4853`): `model_rpm_limit`,
12
+ `model_tpm_limit`, `enforced_params`, `end_user_budget_id`, `guardrails`, `policies`, `tags`, `prompts`,
13
+ `logging`, `secret_manager_settings`, `allowed_passthrough_routes`, and others.
14
+ - `/key/generate` folds them in through `metadata_json_with_limits` (`key_management_endpoints.py:4429-4457`).
15
+ - `/key/update` **replaces** the column with the `metadata` it is sent (`prepare_metadata_fields`, :2312-2359).
16
+ When `metadata` is not sent it keeps the existing one (:2318-2319). Only `service_account_id` is
17
+ preserved across a replacement (`LiteLLM_Reserved_Metadata_Fields`, `_types.py:4857`; :2323-2336).
18
+
19
+ A body that carried only the declared keys therefore strips the key's guardrails, per-model caps and
20
+ passthrough allowlist, and the deploy reports success. Measured over the test fake, which replaces the
21
+ column the same way: an adopted key with `{ seat: 'a', guardrails: [...], model_rpm_limit: {...} }` and a
22
+ declaration of `metadata: { seat: 'b' }` lost both before this merge (`key-metadata.test.ts`).
23
+
24
+ ## The merge
25
+
26
+ | Declaration | Compared | Sent (only when a declared key differs) |
27
+ | -------------------------- | ----------------------------------------------- | ---------------------------------------------- |
28
+ | `metadata` omitted | nothing | nothing |
29
+ | `metadata: { seat: 'a' }` | the live `seat` against `'a'` | every live key, with `seat` set as declared |
30
+ | `metadata: { seat: null }` | the live `seat` against `null` (absent differs) | every live key, with `seat: null`; quiet after |
31
+
32
+ A key you stop declaring is **carried, never removed**: leaving it out does not clear it, declare it
33
+ `null`. The alternative, a list of the keys LiteLLM owns to carry while clearing the rest, was not
34
+ taken: the list is per-version, a key LiteLLM adds next release would be stripped until it is updated,
35
+ and this way fails safe on a live credential. The scope is top-level keys, as LiteLLM reads them.
36
+
37
+ ## Callback credentials are never held
38
+
39
+ `logging`, `callback_settings` and `secret_manager_settings` (`common_utils/callback_utils.py:51`,
40
+ `_CALLBACK_CONFIG_SLOTS`) carry `callback_vars`: an observability platform's secret keys. LiteLLM
41
+ encrypts them at rest (`encrypt_callback_vars`, :716), but a legacy row's are plaintext ("Legacy
42
+ plaintext rows pass through unchanged", `decrypt_callback_vars`, :725-731), and Alchemy persists
43
+ attributes unencrypted. So:
44
+
45
+ | What | What this resource does |
46
+ | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
47
+ | A row with one of the slots (read, adopt) | Drops the slot from `attributes.metadata`; keeps only its **name** in `attributes.withheld`. |
48
+ | A declaration whose `metadata` names a slot | Refused (`LitellmKeyCallbackMetadataDeclaredError`): stored encrypted, it would never read back equal and every deploy would fail with `LitellmKeyFieldNotAppliedError`. |
49
+ | A metadata write onto a key that has a slot | Refused (`LitellmKeyCallbackMetadataLiveError`): the resource never read the slot, so the update could not carry it, and LiteLLM would drop it. |
50
+ | A write that touches no `metadata` | Goes ahead: the update body has no `metadata`, and the column is left as it is. |
51
+
52
+ Configure key logging in LiteLLM itself. ⚠️ The raw slot still crosses the wire in `/key/list`'s answer
53
+ (as every read of that row does), so `DISTILLED_DEBUG_HTTP`, which prints response bodies, would show a
54
+ legacy plaintext one on a read; it is refused only for a create, where the request carries the key.
55
+ UNVERIFIED: whether `/key/list` returns the stored (encrypted) or the decrypted form of `callback_vars`;
56
+ either is dropped before it reaches an attribute.
@@ -0,0 +1,194 @@
1
+ # LiteLLM — `LiteLLM.Key`
2
+
3
+ One virtual key of LiteLLM's `LiteLLM_VerificationToken` (`/key/*`), bound to a
4
+ [`LiteLLM.Budget`](./litellm-budget.md) tier, with its value **kept out of Alchemy state**. Typed
5
+ calls come from `@distilled.cloud/litellm/key_management`; credentials and the family's refusals are
6
+ in [litellm.md](./litellm.md). Read 2026-09-29 against `@homeflare/distilled-litellm@0.3.0`
7
+ (generated at LiteLLM **1.103.0**) and the 1.103.0 PyPI wheel's own source.
8
+
9
+ ## The key value is write-only
10
+
11
+ Alchemy persists props **and** attributes unencrypted: a `Redacted` is tagged, not encrypted
12
+ (`State/StateEncoding.ts` writes the inner value beside the tag). So the key's value can be neither a
13
+ prop nor an attribute, and `LiteLLM.Key` uses the mechanism every other kit secret uses
14
+ (`src/secrets/write-only.ts`, the same one as the PBS webhook secret): the prop holds the **name** of
15
+ an environment variable.
16
+
17
+ ```ts
18
+ import * as Effect from 'effect/Effect';
19
+ import { LiteLLMBudget, LiteLLMKey } from '@homeflare/alchemy/litellm';
20
+
21
+ export default Effect.gen(function* () {
22
+ const tier = yield* LiteLLMBudget('Tier', { budgetId: 'hf-tier-seat', softBudget: 25 });
23
+ yield* LiteLLMKey('Seat', {
24
+ keyAlias: 'hf-seat-a',
25
+ key: { fromEnv: 'HF_SEAT_A_KEY' }, // a random `sk-…` minted outside, e.g. in the vault
26
+ budgetId: tier.budgetId, // an Output: Alchemy creates the tier first
27
+ models: ['glm-5.3', 'gpt-oss-120b'],
28
+ metadata: { seat: 'a' },
29
+ });
30
+ });
31
+ ```
32
+
33
+ Then provide `litellmProviders()` alongside the stack's other providers, as
34
+ [litellm.md](./litellm.md#example) shows.
35
+
36
+ | where the value is | it is |
37
+ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
38
+ | the declaration / state | never: the state row holds `{ fromEnv: 'HF_SEAT_A_KEY' }`, the NAME |
39
+ | `diff`, a plan | a set variable is checked against the live token in memory; unset/empty skips verification |
40
+ | `/key/generate`'s body | once, on create, unwrapped in `createBody` and nowhere else |
41
+ | `/key/generate`'s response | `Redacted` (the SDK's `T.SensitiveValue`); compared with what was sent |
42
+ | an attribute, error or log | never: errors name the alias, the variable and the rule, not the value; a failed create is `LitellmKeyTransportError`, never the SDK's `HttpClientError` (below) |
43
+
44
+ ★ **Why the value is minted outside and not by LiteLLM.** `/key/generate` does return the new key,
45
+ and the SDK hands it back `Redacted`. A resource has two places to put it: an attribute, which is
46
+ state in the clear, or nowhere, and LiteLLM never shows the plaintext again (only its hash). A key
47
+ minted and dropped is a row nobody can use. `/key/generate`'s own docstring supports a caller-chosen
48
+ value: "Must start with 'sk-' and be at least 16 characters long."
49
+
50
+ - **The value is sent only on create.** For an existing key, plan and reconcile compare a set
51
+ variable's sha256 with the live row's `token`, only in memory. A mismatch is a typed
52
+ `LitellmKeyValueMismatchError`, even when every prop is unchanged. `/key/update` drops `key`
53
+ and cannot rotate it; `/key/regenerate` is an Enterprise feature. **Rotate with a new alias.**
54
+ - **Unset or empty variables skip verification on existing keys**, including ordinary settings
55
+ updates. A deployer need not hold the seat key. Creation still requires the declared value.
56
+ - **Adopting needs no value.** Omit `key` to manage an existing key's settings. A create with no `key`
57
+ is refused (`LitellmKeyValueRequiredError`): it would mint a value nobody holds.
58
+ - **A malformed value is refused before any write**: not `sk-…`, under 16 characters (both LiteLLM's
59
+ rules) or containing whitespace (the house's: a renderer's trailing newline would be sent as part of
60
+ the value). The error names the variable and the rule, never the value.
61
+ - ⛔ **`DISTILLED_DEBUG_HTTP` refuses a create.** While it is set the SDK prints the first 400
62
+ characters of every request and response body to stderr (`@distilled.cloud/core`, read 2026-09-29),
63
+ and `/key/generate` carries the key in both. An update carries no value, so it is not refused.
64
+ - ⛔ **A create that fails on the wire does not carry the request.** `/key/generate`'s request body is
65
+ `{"key":"sk-…"}`, and the SDK's `HttpClientError` holds its request, so `JSON.stringify`,
66
+ `Bun.inspect` at depth or Effect's JSON logger printed the value from a dropped connection, from the
67
+ deploy that failed over it, and from a defect (`protocol-rest.ts` reads a body with `Effect.orDie`).
68
+ Measured 2026-09-29 with a synthetic key (`key-transport.test.ts`, each reading searched for the
69
+ value). `generateKey` turns both into `LitellmKeyTransportError`: the alias and the reason's tag, no
70
+ request, no cause. The key **may** exist afterwards (the answer can be lost after the write); the next
71
+ deploy sees a live key with no state and takes it with `--adopt`, and one that did not land is created.
72
+ The SDK's status errors (`BadRequest`, `Forbidden`, …) hold only the proxy's message and stay typed.
73
+ - ⚠️ **A proxy with the dashboard's `disable_custom_api_keys` setting on** answers 403 to any
74
+ user-defined key (`_check_custom_key_allowed`). It surfaces as the SDK's `Forbidden`.
75
+ UNVERIFIED whether the estate's proxy has it on.
76
+ - **A proxy that ignores the value** and mints its own would leave a key nobody can use, reported as
77
+ a success. `/key/generate` echoes the key; a different one is deleted again and refused
78
+ (`LitellmKeyValueNotHonouredError`). UNVERIFIED that any proxy does this.
79
+
80
+ Measured against the installed `alchemy@2.0.0-beta.79`: `src/Provider.ts:274–289` declares
81
+ `diff` as `Effect<Diff | void, any, DiffReq>`. `src/Plan.ts:1503–1527` invokes it before falling
82
+ back to props equality, so unchanged props do not bypass verification; `:750–765` also calls it
83
+ for stable-reference evaluation. The check reads the live token each time and persists neither
84
+ value nor hash. Unresolved props defer to reconcile. `key-rotation.test.ts` exercises real
85
+ Plan/Apply with only the environment changed, no adoption and no other drift.
86
+
87
+ ## Props
88
+
89
+ | prop | type | notes |
90
+ | --------------- | ------------------------- | --------------------------------------------------------------------------------------- |
91
+ | `keyAlias` | `string` | **Identity.** Non-empty, unique per proxy. Declare an existing key's alias to adopt it. |
92
+ | `key` | `{ fromEnv: string }` | Write-only, create-only. Optional when the key already exists. |
93
+ | `budgetId` | `string \| null` | The tier. Pass `budget.budgetId` and Alchemy creates the tier first. `null` unbinds. |
94
+ | `models` | `string[]` | `[]` = **all models** (LiteLLM's reading). Compared order-insensitively. |
95
+ | `allowedRoutes` | `string[]` | Exact or wildcard routes. `[]` = no route restriction. |
96
+ | `teamId` | `string \| null` | `null` detaches the team. |
97
+ | `metadata` | `Record<string, unknown>` | The keys you manage: a **merge**, see [below](#metadata). Stored in state: no secrets. |
98
+ | `duration` | `string \| null` | `'30d'`, `'12h'`, … from creation. `null` = never expires. See below. |
99
+
100
+ ⛔ **A declaration manages only what it names.** An omitted prop is neither compared nor sent, so a
101
+ live scope, budget, team or expiry stays as it is; a **new** key with no `models` starts with
102
+ LiteLLM's default, all models. Clearing is explicit: `models: []`, `allowedRoutes: []`,
103
+ `budgetId: null`, `teamId: null`, `duration: null`. Omission never clears, because clearing fails open
104
+ on a credential: `[]` is "all models" and "no route restriction", and an adopted key's plan says
105
+ `adopted`, never the `update` the apply would send (the plan cannot probe it; `--adopt` given for
106
+ another resource takes over every declared key whose alias is live).
107
+
108
+ Attributes: `keyAlias`, `budgetId`, `models`, `allowedRoutes`, `teamId`, `metadata`, `expires` (what
109
+ the row says, observed), `duration` (see below) and `withheld` (the names of the `metadata` callback
110
+ slots the row has, [below](#metadata)). ⛔ There is no `key`, `token` or hash attribute.
111
+
112
+ ## Behaviour
113
+
114
+ | Concern | Rule |
115
+ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
116
+ | Identity | `keyAlias`. A different alias is **refused** (`LitellmKeyAliasChangedError`), not replaced: the new key would need the same value, and a retained old row still holds it. |
117
+ | Adopt | A live key with the alias and no state is `Unowned`; needs `--adopt`. The apply re-checks it (`refuseTakeover`) for a create the planner could not probe. |
118
+ | Removal | `defaultRemovalPolicy: 'retain'`: deleting a key breaks whatever holds it. Opt in with `RemovalPolicy.destroy()`. |
119
+ | Read | `/key/list?key_alias=…&return_full_object=true`. Two rows under one alias are refused (`LitellmKeyAmbiguousAliasError`); the column is not unique in LiteLLM's schema. |
120
+ | Update | `/key/update` by alias with **only the declared fields that differ**. A declared `null` on `budget_id`/`team_id`/`duration` is sent as `null`, a declared `[]` as `[]`; `metadata` is merged. |
121
+ | Write check | Reconcile reads back; a field the row still differs on fails with `LitellmKeyFieldNotAppliedError`. |
122
+ | Delete | Idempotent by the list: an absent alias writes nothing. The SDK's `KeyNotFound` (a lost race, a retried delete) re-lists and is swallowed only if the key is gone. Any other failure propagates. |
123
+ | Read errors | A 5xx on `/key/list` propagates typed. It is never read as "no such key" (which would go on to create one). |
124
+
125
+ ### `duration`
126
+
127
+ The row carries `expires`, an absolute time, so a declared `'30d'` cannot be read back. State
128
+ remembers the duration this provider last wrote. Changing it, or declaring `null`, plans an `update`
129
+ that sends `duration` (`null` = never expires; the 1.103.0 source sets `expires` from it). Omitting it
130
+ leaves a live expiry alone. A key whose expiry was set or cleared by hand while the declaration names
131
+ a `duration` plans an update too.
132
+ ⚠️ **An adopted key remembers nothing**, so declaring a `duration` on one re-arms its expiry once,
133
+ from that deploy; afterwards a plan is quiet.
134
+
135
+ ## Operations used, none guessed
136
+
137
+ Every call is `@distilled.cloud/litellm/key_management`'s own operation with its own request type,
138
+ through `throughFetch` (`operations.ts`); nothing is hand-rolled.
139
+
140
+ | operation | route | used for |
141
+ | ------------------------------ | -------------------- | -------------------------------------------------------- |
142
+ | `listKeysKeyListGet` | `GET /key/list` | read by `key_alias`, `return_full_object: true` |
143
+ | `generateKeyFnKeyGeneratePost` | `POST /key/generate` | create, with the user-defined `key` |
144
+ | `updateKeyFnKeyUpdatePost` | `POST /key/update` | merge patch, found by `key_alias` (no `key` in the body) |
145
+ | `deleteKeyFnKeyDeletePost` | `POST /key/delete` | delete by `key_aliases` |
146
+
147
+ Not used: `/key/info` and `/v2/key/info` take the key or its hash, which an adopted key never has.
148
+
149
+ ## Measured, and not
150
+
151
+ Measured 2026-09-29 in the 1.103.0 wheel's source (`litellm/proxy/management_endpoints/
152
+ key_management_endpoints.py`), not against a live proxy: `hash_token` is `sha256` hex; a duplicate
153
+ alias is 400 (`_enforce_unique_key_alias`, :7639); a user-defined key must start `sk-` and be 16+
154
+ characters (:1477-1490); `/key/update` applies `model_dump(exclude_unset=True)`, so an explicit `null`
155
+ clears a column and `key` is dropped (:2468-2469); `/key/delete` of an absent alias is **404** "No
156
+ keys found" (:4914) and of a forbidden one 403 (:4933); `/key/list` filters `key_alias` exactly, page
157
+ size at most 100 (:6376); `models` and `allowed_routes` are non-null `String[]` columns, hence `[]`
158
+ not `null` to clear.
159
+
160
+ ★ **`/key/delete`'s 404 and 403 are typed by the SDK, as resource-specific tags.** The operation
161
+ declared 400 and 422 only, so both surfaced at runtime as core's status-mapped `NotFound`/`Forbidden`,
162
+ outside its error type. A distilled patch (`patches/key_management/delete_key_fn_key_delete_post.json`
163
+ in the distilled clone, byte-copied here) now types them as `KeyNotFound` (404, the message
164
+ `No keys found`) and `KeyDeleteForbidden` (403, `You are not authorized to delete this key`), each
165
+ matched on the status AND that phrase. `delete_key_fn` re-raises through `handle_exception_on_proxy`, so
166
+ the wire message is Python's `str(detail)`, `{'error': 'No keys found'}`, which the `includes` matcher
167
+ fits, as it fits a bare `detail`. `deleteKey` does `catchTag('KeyNotFound')`, then re-lists: the absence
168
+ proof is still the list, never the tag. A 404 without the phrase (a proxy in front) stays core's
169
+ `NotFound` and fails. UNVERIFIED against a live proxy: the wire shape is read from the wheel's source.
170
+ The tags ship with the next `@homeflare/distilled-litellm` release (its own changeset); the workspace copy has them now.
171
+
172
+ UNVERIFIED: that `/key/list?return_full_object=true` returns `budget_id` on a live 1.103.0 proxy (the
173
+ generated row type and the Prisma model both carry it; a miss fails the apply loudly as
174
+ `LitellmKeyFieldNotAppliedError`, never silently); the status of a `budget_id` naming no budget; a
175
+ retried `/key/generate` after a lost response (the SDK's default retry applies; the next deploy reads
176
+ the row). No live LiteLLM was contacted.
177
+
178
+ ## `metadata`
179
+
180
+ LiteLLM keeps a key's guardrails, tags, per-model RPM/TPM limits, `allowed_passthrough_routes` and
181
+ more **inside** `metadata`, and `/key/update` replaces the column with what it is sent. So `metadata`
182
+ is a **merge** at the top-level key: the keys you declare are compared and written, every other live
183
+ key is carried into the update body unchanged, and one is cleared by declaring it `null`. Declaring
184
+ `{ seat: 'a' }` on a key that also has `guardrails` leaves them. Details and the measured source:
185
+ [litellm-key-metadata.md](./litellm-key-metadata.md). ⛔ `logging`, `callback_settings` and
186
+ `secret_manager_settings` carry callback secret keys: they are never held in state, a declaration
187
+ naming one is refused, and a metadata write onto a key that has one is refused (`withheld`).
188
+
189
+ ## Not modelled
190
+
191
+ `max_budget`/`soft_budget`, `object_permission`, `blocked`, `spend` and the top-level rate limits.
192
+ The row read back has some of them, some it does not, and a field a declaration cannot diff is a field
193
+ it cannot own. Bind a `LiteLLM.Budget` for limits. `/key/update` is a merge patch for the columns, so
194
+ a field this resource never sends is left as it is; the ones inside `metadata` are left by the merge.