@homeflare/alchemy 0.43.0 → 0.44.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 (604) 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 +40 -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 +1975 -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 +109 -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 +126 -0
  233. package/dist/postgres/role-errors.d.ts.map +1 -0
  234. package/dist/postgres/role-membership-sql.d.ts +75 -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 +6 -0
  239. package/dist/postgres/role-scram.d.ts.map +1 -0
  240. package/dist/postgres/role-secrets.d.ts +30 -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 +114 -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/litellm/access-group-form.ts +105 -0
  344. package/src/litellm/access-group-operations.ts +92 -0
  345. package/src/litellm/access-group-types.ts +49 -0
  346. package/src/litellm/access-group.test.ts +197 -0
  347. package/src/litellm/access-group.ts +151 -0
  348. package/src/litellm/credential-errors.ts +183 -0
  349. package/src/litellm/credential-form.test.ts +151 -0
  350. package/src/litellm/credential-form.ts +211 -0
  351. package/src/litellm/credential-guards.test.ts +241 -0
  352. package/src/litellm/credential-operations.ts +208 -0
  353. package/src/litellm/credential-recovery.test.ts +93 -0
  354. package/src/litellm/credential-rewrite.test.ts +164 -0
  355. package/src/litellm/credential-rewrite.ts +50 -0
  356. package/src/litellm/credential-types.ts +117 -0
  357. package/src/litellm/credential-values.ts +94 -0
  358. package/src/litellm/credential.test.ts +218 -0
  359. package/src/litellm/credential.ts +227 -0
  360. package/src/litellm/fake-access-group-litellm.ts +127 -0
  361. package/src/litellm/fake-credential-litellm.ts +216 -0
  362. package/src/litellm/fake-keys.ts +190 -0
  363. package/src/litellm/fake-litellm.ts +19 -9
  364. package/src/litellm/fake-mcp-litellm.ts +214 -0
  365. package/src/litellm/fake-model-litellm-post-update.ts +103 -0
  366. package/src/litellm/fake-model-litellm.ts +233 -0
  367. package/src/litellm/fake-policy-attachment-litellm.ts +97 -0
  368. package/src/litellm/fake-policy-litellm.ts +186 -0
  369. package/src/litellm/fake-registry-base.ts +69 -0
  370. package/src/litellm/fake-stack.ts +17 -1
  371. package/src/litellm/fake-team-litellm.ts +229 -0
  372. package/src/litellm/fake-tool-litellm.ts +88 -0
  373. package/src/litellm/fake-toolset-litellm.ts +110 -0
  374. package/src/litellm/index.ts +140 -0
  375. package/src/litellm/key-delete.test.ts +212 -0
  376. package/src/litellm/key-errors.ts +241 -0
  377. package/src/litellm/key-form.ts +200 -0
  378. package/src/litellm/key-harness.ts +121 -0
  379. package/src/litellm/key-metadata-errors.ts +49 -0
  380. package/src/litellm/key-metadata.test.ts +156 -0
  381. package/src/litellm/key-metadata.ts +74 -0
  382. package/src/litellm/key-operations.ts +184 -0
  383. package/src/litellm/key-rotation.test.ts +110 -0
  384. package/src/litellm/key-scope.test.ts +135 -0
  385. package/src/litellm/key-secret.test.ts +248 -0
  386. package/src/litellm/key-secret.ts +137 -0
  387. package/src/litellm/key-transport.test.ts +166 -0
  388. package/src/litellm/key.test.ts +231 -0
  389. package/src/litellm/key.ts +213 -0
  390. package/src/litellm/mcp-server-adopt.test.ts +86 -0
  391. package/src/litellm/mcp-server-alias.test.ts +184 -0
  392. package/src/litellm/mcp-server-credential.ts +85 -0
  393. package/src/litellm/mcp-server-errors.ts +141 -0
  394. package/src/litellm/mcp-server-exports.test.ts +15 -0
  395. package/src/litellm/mcp-server-form.test.ts +241 -0
  396. package/src/litellm/mcp-server-form.ts +233 -0
  397. package/src/litellm/mcp-server-handlers.test.ts +150 -0
  398. package/src/litellm/mcp-server-locate.ts +66 -0
  399. package/src/litellm/mcp-server-operations.ts +111 -0
  400. package/src/litellm/mcp-server-registry.test.ts +146 -0
  401. package/src/litellm/mcp-server-retype.test.ts +114 -0
  402. package/src/litellm/mcp-server-shadow.test.ts +91 -0
  403. package/src/litellm/mcp-server-shadow.ts +45 -0
  404. package/src/litellm/mcp-server-tools.test.ts +85 -0
  405. package/src/litellm/mcp-server-types.ts +143 -0
  406. package/src/litellm/mcp-server-url.ts +66 -0
  407. package/src/litellm/mcp-server.test.ts +213 -0
  408. package/src/litellm/mcp-server.ts +225 -0
  409. package/src/litellm/model-claim.ts +69 -0
  410. package/src/litellm/model-credential.ts +45 -0
  411. package/src/litellm/model-errors.ts +168 -0
  412. package/src/litellm/model-foreign-row.test.ts +173 -0
  413. package/src/litellm/model-form.test.ts +228 -0
  414. package/src/litellm/model-form.ts +223 -0
  415. package/src/litellm/model-locate.test.ts +128 -0
  416. package/src/litellm/model-locate.ts +67 -0
  417. package/src/litellm/model-operations.test.ts +93 -0
  418. package/src/litellm/model-operations.ts +146 -0
  419. package/src/litellm/model-params-preserve.test.ts +119 -0
  420. package/src/litellm/model-recovery.test.ts +57 -0
  421. package/src/litellm/model-types.ts +112 -0
  422. package/src/litellm/model.test.ts +222 -0
  423. package/src/litellm/model.ts +237 -0
  424. package/src/litellm/policy-attachment-form.ts +103 -0
  425. package/src/litellm/policy-attachment-operations.ts +74 -0
  426. package/src/litellm/policy-attachment-types.ts +48 -0
  427. package/src/litellm/policy-attachment.test.ts +198 -0
  428. package/src/litellm/policy-attachment.ts +178 -0
  429. package/src/litellm/policy-form.ts +122 -0
  430. package/src/litellm/policy-operations.ts +112 -0
  431. package/src/litellm/policy-types.ts +58 -0
  432. package/src/litellm/policy.test.ts +214 -0
  433. package/src/litellm/policy.ts +146 -0
  434. package/src/litellm/providers.ts +24 -3
  435. package/src/litellm/registry-errors.ts +88 -0
  436. package/src/litellm/registry-exports.test.ts +66 -0
  437. package/src/litellm/registry-support.ts +109 -0
  438. package/src/litellm/team-form.ts +140 -0
  439. package/src/litellm/team-members.test.ts +150 -0
  440. package/src/litellm/team-members.ts +58 -0
  441. package/src/litellm/team-operations.ts +90 -0
  442. package/src/litellm/team-permission.ts +159 -0
  443. package/src/litellm/team-read.test.ts +89 -0
  444. package/src/litellm/team-types.ts +106 -0
  445. package/src/litellm/team.test.ts +206 -0
  446. package/src/litellm/team.ts +159 -0
  447. package/src/litellm/tool-policy-form.ts +94 -0
  448. package/src/litellm/tool-policy-operations.ts +58 -0
  449. package/src/litellm/tool-policy-types.ts +48 -0
  450. package/src/litellm/tool-policy.test.ts +172 -0
  451. package/src/litellm/tool-policy.ts +125 -0
  452. package/src/litellm/toolset-form.ts +104 -0
  453. package/src/litellm/toolset-operations.ts +90 -0
  454. package/src/litellm/toolset-types.ts +47 -0
  455. package/src/litellm/toolset.test.ts +198 -0
  456. package/src/litellm/toolset.ts +151 -0
  457. package/src/ownership/ownership.test.ts +33 -1
  458. package/src/ownership/rows.ts +53 -0
  459. package/src/postgres/connection.ts +42 -7
  460. package/src/postgres/database-bigint-serialization.test.ts +1 -0
  461. package/src/postgres/database-refusals.test.ts +2 -2
  462. package/src/postgres/database-sql.ts +36 -9
  463. package/src/postgres/fake-grants-parse.ts +189 -0
  464. package/src/postgres/fake-grants-read.ts +250 -0
  465. package/src/postgres/fake-grants-sql.ts +207 -0
  466. package/src/postgres/fake-grants-write.ts +90 -0
  467. package/src/postgres/fake-role-sql.ts +220 -0
  468. package/src/postgres/fake-schema-semantics.test.ts +36 -0
  469. package/src/postgres/fake-schema-sql.ts +146 -0
  470. package/src/postgres/fake-sql-parse.ts +86 -0
  471. package/src/postgres/fake-sql-quote.ts +36 -0
  472. package/src/postgres/fake-sql.ts +161 -46
  473. package/src/postgres/fixtures/pg-REL_18_6-acl.h.txt +147 -0
  474. package/src/postgres/fixtures/pg-REL_18_6-aclexplode-func.txt +31 -0
  475. package/src/postgres/fixtures/pg-REL_18_6-alter-default-privileges-synopsis.txt +82 -0
  476. package/src/postgres/fixtures/pg-REL_18_6-alter_role.sgml.txt +44 -0
  477. package/src/postgres/fixtures/pg-REL_18_6-create_role.sgml.txt +26 -0
  478. package/src/postgres/fixtures/pg-REL_18_6-grant-synopsis.txt +95 -0
  479. package/src/postgres/fixtures/pg-REL_18_6-pg_attribute.h.txt +24 -0
  480. package/src/postgres/fixtures/pg-REL_18_6-pg_auth_members.h.txt +62 -0
  481. package/src/postgres/fixtures/pg-REL_18_6-pg_authid.h.txt +70 -0
  482. package/src/postgres/fixtures/pg-REL_18_6-pg_class.h.txt +33 -0
  483. package/src/postgres/fixtures/pg-REL_18_6-pg_default_acl.h.txt +81 -0
  484. package/src/postgres/fixtures/pg-REL_18_6-pg_namespace.h.txt +28 -0
  485. package/src/postgres/fixtures/pg-REL_18_6-revoke-synopsis.txt +124 -0
  486. package/src/postgres/grants-acl.test.ts +61 -0
  487. package/src/postgres/grants-attrs.ts +185 -0
  488. package/src/postgres/grants-database.test.ts +158 -0
  489. package/src/postgres/grants-declare.ts +172 -0
  490. package/src/postgres/grants-delete-proof.test.ts +154 -0
  491. package/src/postgres/grants-diff.ts +101 -0
  492. package/src/postgres/grants-errors.ts +215 -0
  493. package/src/postgres/grants-existence-guards.test.ts +113 -0
  494. package/src/postgres/grants-existence.ts +101 -0
  495. package/src/postgres/grants-lifecycle-guards.test.ts +208 -0
  496. package/src/postgres/grants-lifecycle-repair.test.ts +208 -0
  497. package/src/postgres/grants-lifecycle.test.ts +181 -0
  498. package/src/postgres/grants-ops.ts +229 -0
  499. package/src/postgres/grants-owner-revoke.test.ts +121 -0
  500. package/src/postgres/grants-ownership.ts +49 -0
  501. package/src/postgres/grants-plan-collateral.test.ts +202 -0
  502. package/src/postgres/grants-plan-diff.test.ts +204 -0
  503. package/src/postgres/grants-plan-restore.ts +43 -0
  504. package/src/postgres/grants-plan-revocations.test.ts +69 -0
  505. package/src/postgres/grants-plan.test.ts +148 -0
  506. package/src/postgres/grants-plan.ts +245 -0
  507. package/src/postgres/grants-provenance.test.ts +134 -0
  508. package/src/postgres/grants-psql-lifecycle.test.ts +105 -0
  509. package/src/postgres/grants-read-absent.test.ts +91 -0
  510. package/src/postgres/grants-read-defaults.ts +51 -0
  511. package/src/postgres/grants-read.ts +250 -0
  512. package/src/postgres/grants-refusals.test.ts +136 -0
  513. package/src/postgres/grants-refuse.ts +119 -0
  514. package/src/postgres/grants-relkind-wire.test.ts +111 -0
  515. package/src/postgres/grants-repair-plan.test.ts +201 -0
  516. package/src/postgres/grants-sql.test.ts +128 -0
  517. package/src/postgres/grants-sql.ts +144 -0
  518. package/src/postgres/grants-words.ts +34 -0
  519. package/src/postgres/grants.ts +110 -0
  520. package/src/postgres/index.ts +128 -5
  521. package/src/postgres/installed-classifier.ts +36 -0
  522. package/src/postgres/providers.ts +33 -9
  523. package/src/postgres/psql-executor-escaping.test.ts +67 -0
  524. package/src/postgres/psql-executor.test.ts +63 -2
  525. package/src/postgres/psql-executor.ts +74 -34
  526. package/src/postgres/role-adopt.test.ts +98 -0
  527. package/src/postgres/role-attrs.ts +134 -0
  528. package/src/postgres/role-diff.ts +89 -0
  529. package/src/postgres/role-errors.ts +198 -0
  530. package/src/postgres/role-guard.test.ts +60 -0
  531. package/src/postgres/role-identity.test.ts +185 -0
  532. package/src/postgres/role-lifecycle.test.ts +228 -0
  533. package/src/postgres/role-membership-sql.ts +198 -0
  534. package/src/postgres/role-password.test.ts +158 -0
  535. package/src/postgres/role-privilege.test.ts +80 -0
  536. package/src/postgres/role-provenance.test.ts +200 -0
  537. package/src/postgres/role-provider.ts +104 -0
  538. package/src/postgres/role-refusals.test.ts +250 -0
  539. package/src/postgres/role-scram.test.ts +38 -0
  540. package/src/postgres/role-scram.ts +38 -0
  541. package/src/postgres/role-secrets.ts +46 -0
  542. package/src/postgres/role-sql.ts +211 -0
  543. package/src/postgres/role-valid-until.test.ts +68 -0
  544. package/src/postgres/role.ts +218 -0
  545. package/src/postgres/schema-assert.ts +139 -0
  546. package/src/postgres/schema-attrs.ts +71 -0
  547. package/src/postgres/schema-delete-proofs.test.ts +192 -0
  548. package/src/postgres/schema-delete.ts +96 -0
  549. package/src/postgres/schema-diff.ts +44 -0
  550. package/src/postgres/schema-drop-2bp01.test.ts +146 -0
  551. package/src/postgres/schema-errors.ts +209 -0
  552. package/src/postgres/schema-handlers.test.ts +193 -0
  553. package/src/postgres/schema-identity.ts +39 -0
  554. package/src/postgres/schema-lifecycle.test.ts +246 -0
  555. package/src/postgres/schema-race.test.ts +70 -0
  556. package/src/postgres/schema-reconcile.ts +100 -0
  557. package/src/postgres/schema-refusals.test.ts +144 -0
  558. package/src/postgres/schema-socket.test.ts +161 -0
  559. package/src/postgres/schema-sql.ts +130 -0
  560. package/src/postgres/schema-takeover.test.ts +149 -0
  561. package/src/postgres/schema-test-kit.ts +85 -0
  562. package/src/postgres/schema.ts +130 -0
  563. package/src/release/binary-alias.test.ts +3 -3
  564. package/src/release/binary-claims.test.ts +3 -3
  565. package/src/release/binary-directory-umask.test.ts +65 -0
  566. package/src/release/fake-engine.ts +15 -0
  567. package/src/valkey/acl-attrs.ts +98 -0
  568. package/src/valkey/acl-compare.ts +57 -0
  569. package/src/valkey/acl-connection.ts +13 -0
  570. package/src/valkey/acl-delete.test.ts +127 -0
  571. package/src/valkey/acl-form.ts +239 -0
  572. package/src/valkey/acl-managed.ts +13 -0
  573. package/src/valkey/acl-ops.ts +122 -0
  574. package/src/valkey/acl-ownership.test.ts +118 -0
  575. package/src/valkey/acl-prefix.test.ts +38 -0
  576. package/src/valkey/acl-profiles.ts +81 -0
  577. package/src/valkey/acl-reconcile.ts +180 -0
  578. package/src/valkey/acl-reserved.test.ts +69 -0
  579. package/src/valkey/acl-revocation.test.ts +94 -0
  580. package/src/valkey/acl-seat-prefix.test.ts +111 -0
  581. package/src/valkey/acl-validation.test.ts +54 -0
  582. package/src/valkey/acl.test.ts +215 -0
  583. package/src/valkey/acl.ts +169 -0
  584. package/src/valkey/connection-service.ts +46 -0
  585. package/src/valkey/connection.ts +180 -0
  586. package/src/valkey/errors.ts +239 -0
  587. package/src/valkey/fake-acl.ts +128 -0
  588. package/src/valkey/fake-valkey.ts +224 -0
  589. package/src/valkey/handler-test-fixture.ts +43 -0
  590. package/src/valkey/handlers.test.ts +205 -0
  591. package/src/valkey/index.ts +54 -0
  592. package/src/valkey/instance-attrs.ts +48 -0
  593. package/src/valkey/instance-form.ts +104 -0
  594. package/src/valkey/instance.test.ts +108 -0
  595. package/src/valkey/instance.ts +160 -0
  596. package/src/valkey/provider-socket-fixture.ts +71 -0
  597. package/src/valkey/providers.test.ts +129 -0
  598. package/src/valkey/providers.ts +21 -0
  599. package/src/valkey/resp.ts +212 -0
  600. package/src/valkey/transport-bounds.test.ts +150 -0
  601. package/src/valkey/transport-error.ts +37 -0
  602. package/src/valkey/transport.test.ts +158 -0
  603. package/src/valkey/transport.ts +109 -0
  604. package/src/valkey/upstream-bounds.test.ts +14 -0
@@ -0,0 +1,49 @@
1
+ /**
2
+ * What a `LiteLLM.AccessGroup` declares (props) and what is remembered about it (attributes).
3
+ *
4
+ * ★ THIS IS THE UNIFIED ACCESS GROUP, `LiteLLM_AccessGroupTable` (`/v1/unified_access_group`), not
5
+ * the two other things LiteLLM calls an "access group": a MODEL access group (`access_groups` in a
6
+ * model's `model_info`) and an MCP access group (a bare name on an MCP server row, referenced by
7
+ * `object_permission.mcp_access_groups`). A unified group bundles models, MCP servers and agents
8
+ * under one name and attaches to teams and keys (docs.litellm.ai/docs/proxy/access_groups).
9
+ * ⚠️ TOOLSETS ARE NOT IN IT. `AccessGroupCreateRequest` (`litellm/types/access_group.py`, 1.103.0)
10
+ * has `access_model_names`, `access_mcp_server_ids`, `access_agent_ids`, `assigned_team_ids` and
11
+ * `assigned_key_ids` and no toolset field. A toolset is granted through `object_permission.mcp_toolsets`
12
+ * on a team or key (`LiteLLM.Team`), not through a group.
13
+ * ★ MODELS ARE MODEL NAMES, MCP SERVERS ARE SERVER IDS. `access_model_names` holds the `model_name`
14
+ * a caller sends (`cf-code`), and `access_mcp_server_ids` holds `server_id`s. Declare a server's id
15
+ * with `server.serverId` (a `LiteLLM.MCPServer`) so the dependency edge exists.
16
+ * ⚠️ NOT MODELLED, on purpose: `assigned_team_ids`, `assigned_key_ids` and `access_agent_ids`. A
17
+ * team's group membership is declared on the TEAM (`accessGroupIds`), and LiteLLM mirrors it into
18
+ * `assigned_team_ids` in the same transaction; two resources writing one edge would fight. Agents
19
+ * are not managed here. None of the three is ever sent, and the update is a partial one, so an
20
+ * adopted group keeps whatever it has there.
21
+ */
22
+ export interface AccessGroupProps {
23
+ /**
24
+ * The group's name, and the way an existing row is ADOPTED: `access_group_name` is UNIQUE in the
25
+ * table (`access_group_endpoints.py` finds it with `find_unique`), so the match is exact. Changing
26
+ * it is an update of the same row, never a replace: the id does not change.
27
+ */
28
+ readonly accessGroupName: string;
29
+ /** Compared only when declared: adopting a row never clears text a person wrote. Blank is refused. */
30
+ readonly description?: string;
31
+ /**
32
+ * `model_name`s the group grants, compared as a SET and ALWAYS compared (default `[]`): it is an
33
+ * access grant, so an adopted group that grants more than declared is corrected, never left open.
34
+ * ⚠️ LiteLLM prunes a name itself when its last deployment is deleted
35
+ * (`management_helpers/access_group_model_sync.py`), so a plan can show an update for a model that
36
+ * was removed elsewhere.
37
+ */
38
+ readonly modelNames?: readonly string[];
39
+ /** MCP `server_id`s the group grants, compared as a set and always compared (default `[]`). */
40
+ readonly mcpServerIds?: readonly string[];
41
+ }
42
+
43
+ export interface AccessGroupAttributes {
44
+ readonly accessGroupId: string;
45
+ readonly accessGroupName: string;
46
+ readonly description: string | null;
47
+ readonly modelNames: readonly string[];
48
+ readonly mcpServerIds: readonly string[];
49
+ }
@@ -0,0 +1,197 @@
1
+ /**
2
+ * `LiteLLM.AccessGroup` through Alchemy's real Plan and Apply over the fake proxy
3
+ * (`fake-access-group-litellm.ts`): create, no-op, adopt, update, rename, drift and delete.
4
+ *
5
+ * ★ EVERY VALUE IS `FAKE-*`.
6
+ * ⚠️ WHAT THE FAKE MODELS IS READ FROM THE 1.103.0 SOURCE, NOT MEASURED ON A LIVE PROXY (its header).
7
+ */
8
+ import { expect, test } from 'bun:test';
9
+ import { credentials } from '@distilled.cloud/litellm/Credentials';
10
+ import * as Effect from 'effect/Effect';
11
+ import * as Layer from 'effect/Layer';
12
+ import * as FetchHttpClient from 'effect/unstable/http/FetchHttpClient';
13
+ import { LiteLLMAccessGroup } from './access-group.ts';
14
+ import { deleteAccessGroup } from './access-group-operations.ts';
15
+ import type { AccessGroupProps } from './access-group-types.ts';
16
+ import { FAKE_BASE } from './fake-litellm.ts';
17
+ import {
18
+ type FakeAccessGroupLitellm,
19
+ groupRow,
20
+ startFakeAccessGroupLitellm,
21
+ } from './fake-access-group-litellm.ts';
22
+ import { FAKE_KEY } from './fake-registry-base.ts';
23
+ import { fakeStack, writesOf } from './fake-stack.ts';
24
+
25
+ const stack = (fake: FakeAccessGroupLitellm) =>
26
+ fakeStack({ apiKey: FAKE_KEY, baseUrl: FAKE_BASE }, fake.fetch);
27
+ const declare = (props: AccessGroupProps, name = 'Estate') =>
28
+ Effect.gen(function* () {
29
+ yield* LiteLLMAccessGroup(name, props);
30
+ });
31
+
32
+ const estate: AccessGroupProps = {
33
+ accessGroupName: 'FAKE-estate',
34
+ description: 'FAKE estate group',
35
+ mcpServerIds: ['FAKE-server-a'],
36
+ modelNames: ['fake-code', 'fake-flash'],
37
+ };
38
+
39
+ test('creates a group with both grant lists, then a second deploy writes nothing', async () => {
40
+ const fake = startFakeAccessGroupLitellm();
41
+ const same = stack(fake);
42
+ expect(await same.deploy(declare(estate))).toEqual({ Estate: 'create' });
43
+ expect(fake.groups()[0]).toMatchObject({
44
+ access_group_name: 'FAKE-estate',
45
+ access_mcp_server_ids: ['FAKE-server-a'],
46
+ access_model_names: ['fake-code', 'fake-flash'],
47
+ description: 'FAKE estate group',
48
+ });
49
+ // ★ the id is the proxy's, and it is what the state remembers
50
+ expect(String(fake.groups()[0]?.['access_group_id'])).toStartWith('FAKE-group-');
51
+ const before = fake.requests().length;
52
+ expect(await same.deploy(declare(estate))).toEqual({ Estate: 'noop' });
53
+ expect(writesOf(fake.requests().slice(before))).toEqual([]);
54
+ });
55
+
56
+ test('an undeclared grant list means "grants nothing": it is sent as an empty list on create', async () => {
57
+ const fake = startFakeAccessGroupLitellm();
58
+ await stack(fake).deploy(declare({ accessGroupName: 'FAKE-empty' }));
59
+ expect(fake.bodies()[0]).toMatchObject({ access_mcp_server_ids: [], access_model_names: [] });
60
+ expect(fake.bodies()[0]).not.toHaveProperty('description');
61
+ });
62
+
63
+ test('a changed model set is an update that sends ONLY the field that changed', async () => {
64
+ const fake = startFakeAccessGroupLitellm();
65
+ const same = stack(fake);
66
+ await same.deploy(declare(estate));
67
+ const planned = await same.deploy(declare({ ...estate, modelNames: ['fake-code'] }));
68
+ expect(planned).toEqual({ Estate: 'update' });
69
+ expect(fake.bodies().at(-1)).toEqual({ access_model_names: ['fake-code'] });
70
+ expect(fake.groups()[0]?.['access_mcp_server_ids']).toEqual(['FAKE-server-a']);
71
+ });
72
+
73
+ test('a rename is an update of the SAME row: the id does not change', async () => {
74
+ const fake = startFakeAccessGroupLitellm();
75
+ const same = stack(fake);
76
+ await same.deploy(declare(estate));
77
+ const id = fake.groups()[0]?.['access_group_id'];
78
+ expect(await same.deploy(declare({ ...estate, accessGroupName: 'FAKE-renamed' }))).toEqual({
79
+ Estate: 'update',
80
+ });
81
+ expect(fake.groups()).toHaveLength(1);
82
+ expect(fake.groups()[0]).toMatchObject({
83
+ access_group_id: id,
84
+ access_group_name: 'FAKE-renamed',
85
+ });
86
+ });
87
+
88
+ test('a live row is Unowned: refused without --adopt, taken by name with it, and a matching row writes nothing', async () => {
89
+ const live = groupRow({
90
+ access_group_id: 'FAKE-live-1',
91
+ access_group_name: 'FAKE-estate',
92
+ access_mcp_server_ids: ['FAKE-server-a'],
93
+ access_model_names: ['fake-code', 'fake-flash'],
94
+ description: 'FAKE estate group',
95
+ });
96
+ const fake = startFakeAccessGroupLitellm({ seed: [live] });
97
+ const engine = stack(fake);
98
+ await expect(engine.deploy(declare(estate))).rejects.toThrow();
99
+ expect(writesOf(fake.requests())).toEqual([]);
100
+ expect(Object.values(await engine.deploy(declare(estate), { adopt: true }))).toEqual(['adopted']);
101
+ expect(writesOf(fake.requests())).toEqual([]);
102
+ });
103
+
104
+ test('adopting a group that grants MORE than declared corrects it, and leaves undeclared text and teams alone', async () => {
105
+ const wide = groupRow({
106
+ access_group_id: 'FAKE-live-2',
107
+ access_group_name: 'FAKE-estate',
108
+ access_mcp_server_ids: ['FAKE-server-a', 'FAKE-server-extra'],
109
+ access_model_names: ['fake-code', 'fake-flash', 'fake-extra'],
110
+ assigned_team_ids: ['FAKE-team-1'],
111
+ description: 'written by a person',
112
+ });
113
+ const fake = startFakeAccessGroupLitellm({ seed: [wide] });
114
+ const { description: _kept, ...withoutDescription } = estate;
115
+ await stack(fake).deploy(declare(withoutDescription), { adopt: true });
116
+ expect(fake.groups()[0]).toMatchObject({
117
+ access_mcp_server_ids: ['FAKE-server-a'],
118
+ access_model_names: ['fake-code', 'fake-flash'],
119
+ assigned_team_ids: ['FAKE-team-1'],
120
+ description: 'written by a person',
121
+ });
122
+ // ★ a partial update: the team edge is not in the body at all
123
+ expect(fake.bodies()[0]).not.toHaveProperty('assigned_team_ids');
124
+ expect(fake.bodies()[0]).not.toHaveProperty('description');
125
+ });
126
+
127
+ test('reconcile compares the LIVE row: after LiteLLM prunes a model name itself, the next update puts it back', async () => {
128
+ const fake = startFakeAccessGroupLitellm();
129
+ const same = stack(fake);
130
+ await same.deploy(declare(estate));
131
+ fake.dropModel('fake-flash'); // ⚠️ access_group_model_sync.py: a deleted last deployment
132
+ // ★ Alchemy plans from state, so an unchanged declaration is a no-op even now (beta.79 reads live
133
+ // state only to adopt); a declaration that changes anything reaches reconcile, which reads live
134
+ expect(await same.deploy(declare(estate))).toEqual({ Estate: 'noop' });
135
+ expect(await same.deploy(declare({ ...estate, description: 'FAKE changed' }))).toEqual({
136
+ Estate: 'update',
137
+ });
138
+ expect(fake.bodies().at(-1)).toEqual({
139
+ access_model_names: ['fake-code', 'fake-flash'],
140
+ description: 'FAKE changed',
141
+ });
142
+ });
143
+
144
+ test('a proxy that drops an empty-list edit fails the deploy instead of claiming success', async () => {
145
+ // ⚠️ the fake's own model of a truthiness check on the edit route — unmeasured at 1.103.0
146
+ const fake = startFakeAccessGroupLitellm({ editIgnoresEmpty: true });
147
+ const same = stack(fake);
148
+ await same.deploy(declare(estate));
149
+ await expect(same.deploy(declare({ ...estate, mcpServerIds: [] }))).rejects.toThrow();
150
+ });
151
+
152
+ test('a refused declaration fails the plan before a single request', async () => {
153
+ for (const props of [
154
+ { ...estate, accessGroupName: ' ' },
155
+ { ...estate, accessGroupName: ' padded' },
156
+ { ...estate, description: ' ' },
157
+ { ...estate, modelNames: ['fake-code', 'fake-code'] },
158
+ { ...estate, mcpServerIds: ['FAKE-server-a', ''] },
159
+ ]) {
160
+ const fake = startFakeAccessGroupLitellm();
161
+ await expect(stack(fake).deploy(declare(props))).rejects.toThrow();
162
+ expect(fake.requests()).toEqual([]);
163
+ }
164
+ });
165
+
166
+ test('removing the declaration RETAINS the row: nothing deletes a group unless the stack opts in', async () => {
167
+ const fake = startFakeAccessGroupLitellm();
168
+ const same = stack(fake);
169
+ await same.deploy(declare(estate));
170
+ await same.deploy(Effect.void);
171
+ expect(fake.groups()).toHaveLength(1);
172
+ });
173
+
174
+ const run = <A, E>(fetchFn: typeof globalThis.fetch, effect: Effect.Effect<A, E, unknown>) =>
175
+ Effect.runPromise(
176
+ effect.pipe(
177
+ Effect.provide(FetchHttpClient.layer),
178
+ Effect.provide(Layer.succeed(FetchHttpClient.Fetch, fetchFn)),
179
+ Effect.provide(credentials({ apiKey: FAKE_KEY, baseUrl: FAKE_BASE })),
180
+ ) as Effect.Effect<A, E, never>,
181
+ );
182
+
183
+ test('delete answers 204 with no body, and a missing id is swallowed only because a real read says so', async () => {
184
+ const live = groupRow({ access_group_id: 'FAKE-live-3', access_group_name: 'FAKE-estate' });
185
+ const fake = startFakeAccessGroupLitellm({ seed: [live] });
186
+ await run(fake.fetch, deleteAccessGroup('FAKE-live-3'));
187
+ expect(fake.groups()).toEqual([]);
188
+ // already gone: the DELETE 404s, the re-list confirms absence, so it is success
189
+ await run(fake.fetch, deleteAccessGroup('FAKE-live-3'));
190
+ });
191
+
192
+ test('a delete refused for lack of rights re-raises the ORIGINAL error and the row stays', async () => {
193
+ const live = groupRow({ access_group_id: 'FAKE-live-4', access_group_name: 'FAKE-estate' });
194
+ const fake = startFakeAccessGroupLitellm({ forbidWrites: true, seed: [live] });
195
+ await expect(run(fake.fetch, deleteAccessGroup('FAKE-live-4'))).rejects.toThrow();
196
+ expect(fake.groups()).toHaveLength(1);
197
+ });
@@ -0,0 +1,151 @@
1
+ /**
2
+ * `LiteLLM.AccessGroup` — one row of LiteLLM's unified access group table
3
+ * (`LiteLLM_AccessGroupTable`, `/v1/unified_access_group`): a named bundle of models and MCP servers
4
+ * that teams and keys are attached to. Types and what is left out: access-group-types.ts.
5
+ *
6
+ * ★ ADOPT BY NAME. `access_group_name` is unique in the table, so `accessGroupName` finds the one
7
+ * live row that carries it. A live row with no state is `Unowned`, so it needs `--adopt`.
8
+ * ★ `defaultRemovalPolicy: 'retain'` — deleting a group detaches it from every team and key that
9
+ * holds it (`delete_access_group` rewrites their `access_group_ids`), and those callers lose the
10
+ * models and servers it granted. Opt in with `.pipe(RemovalPolicy.destroy())`.
11
+ * ★ THE GRANTS ARE THE DECLARATION. `modelNames` and `mcpServerIds` are always compared (an
12
+ * undeclared list means "grants nothing"), so an adopted group that grants more is corrected.
13
+ * ⚠️ NO LICENCE GATE ON THESE ROUTES: `access_group_endpoints.py` has no `premium_user` check
14
+ * (grep, 1.103.0), and docs.litellm.ai/docs/proxy/access_groups makes no Enterprise statement.
15
+ * ⛔ NO LITELLM CREDENTIAL IS A PROP; `litellmProviders`' layer supplies `Credentials`.
16
+ */
17
+ import { Resource } from 'alchemy';
18
+ import { Unowned } from 'alchemy/AdoptPolicy';
19
+ import { isResolved } from 'alchemy/Diff';
20
+ import type { Input } from 'alchemy/Input';
21
+ import * as Provider from 'alchemy/Provider';
22
+ import * as Effect from 'effect/Effect';
23
+ import * as Predicate from 'effect/Predicate';
24
+ import { createBody, differing, firstProblem, updateBody } from './access-group-form.ts';
25
+ import {
26
+ createAccessGroup,
27
+ deleteAccessGroup,
28
+ listAccessGroups,
29
+ updateAccessGroup,
30
+ } from './access-group-operations.ts';
31
+ import type { AccessGroupAttributes, AccessGroupProps } from './access-group-types.ts';
32
+ import {
33
+ LitellmRegistryAbsentAfterWriteError,
34
+ LitellmRegistryNotConvergedError,
35
+ } from './registry-errors.ts';
36
+ import { dieIfInvalid, failIfInvalid } from './registry-support.ts';
37
+
38
+ export type { AccessGroupAttributes, AccessGroupProps };
39
+ export type { RegistryError as AccessGroupError } from './registry-errors.ts';
40
+
41
+ const RESOURCE = 'LiteLLM.AccessGroup';
42
+
43
+ export interface LiteLLMAccessGroup extends Resource<
44
+ 'LiteLLM.AccessGroup',
45
+ AccessGroupProps,
46
+ AccessGroupAttributes
47
+ > {}
48
+
49
+ export const LiteLLMAccessGroup = Resource<LiteLLMAccessGroup>('LiteLLM.AccessGroup', {
50
+ defaultRemovalPolicy: 'retain',
51
+ });
52
+
53
+ export const isLiteLLMAccessGroup = (value: unknown): value is LiteLLMAccessGroup =>
54
+ Predicate.hasProperty(value, 'Type') && value.Type === 'LiteLLM.AccessGroup';
55
+
56
+ /**
57
+ * The live row this declaration means. A RECORDED id wins and is matched by id alone: a row that
58
+ * vanished and was recreated by hand under the same name is not silently taken over (the create
59
+ * would then fail on the unique name, loudly). With no state, the name decides.
60
+ */
61
+ const locate = (
62
+ rows: readonly AccessGroupAttributes[],
63
+ props: AccessGroupProps,
64
+ output: AccessGroupAttributes | undefined,
65
+ ) =>
66
+ output !== undefined
67
+ ? rows.find((row) => row.accessGroupId === output.accessGroupId)
68
+ : rows.find((row) => row.accessGroupName === props.accessGroupName);
69
+
70
+ /** ⛔ TEST-ONLY EXPORT. Not on index.ts's barrel. */
71
+ export const accessGroupHandlers = {
72
+ /** ⛔ With no `output` this is the adoption probe, so the refusals run here too (registry-support.ts). */
73
+ read: ({ olds, output }: { olds: AccessGroupProps; output: AccessGroupAttributes | undefined }) =>
74
+ Effect.gen(function* () {
75
+ if (output === undefined) {
76
+ yield* dieIfInvalid(RESOURCE, String(olds.accessGroupName), firstProblem(olds));
77
+ }
78
+ const live = locate(yield* listAccessGroups(), olds, output);
79
+ if (live === undefined) return undefined;
80
+ return output === undefined ? Unowned(live) : live;
81
+ }),
82
+
83
+ diff: ({
84
+ news,
85
+ output,
86
+ }: {
87
+ news: Input<AccessGroupProps>;
88
+ output: AccessGroupAttributes | undefined;
89
+ }) =>
90
+ Effect.gen(function* () {
91
+ if (!isResolved(news)) return undefined;
92
+ yield* failIfInvalid(RESOURCE, String(news.accessGroupName), firstProblem(news));
93
+ if (output === undefined) return undefined;
94
+ return differing(output, news).length === 0
95
+ ? ({ action: 'noop' } as const)
96
+ : ({ action: 'update' } as const);
97
+ }),
98
+
99
+ reconcile: ({
100
+ news,
101
+ output,
102
+ }: {
103
+ news: AccessGroupProps;
104
+ output: AccessGroupAttributes | undefined;
105
+ }) =>
106
+ Effect.gen(function* () {
107
+ yield* failIfInvalid(RESOURCE, String(news.accessGroupName), firstProblem(news));
108
+ const before = locate(yield* listAccessGroups(), news, output);
109
+ if (before === undefined) yield* createAccessGroup(createBody(news));
110
+ else if (differing(before, news).length > 0) {
111
+ yield* updateAccessGroup(before.accessGroupId, updateBody(news, before));
112
+ }
113
+
114
+ const rows = yield* listAccessGroups();
115
+ const after =
116
+ before === undefined
117
+ ? rows.find((row) => row.accessGroupName === news.accessGroupName)
118
+ : rows.find((row) => row.accessGroupId === before.accessGroupId);
119
+ if (after === undefined) {
120
+ return yield* Effect.fail(
121
+ new LitellmRegistryAbsentAfterWriteError({
122
+ name: news.accessGroupName,
123
+ resource: RESOURCE,
124
+ }),
125
+ );
126
+ }
127
+ const left = differing(after, news);
128
+ if (left.length > 0) {
129
+ return yield* Effect.fail(
130
+ new LitellmRegistryNotConvergedError({
131
+ fields: left,
132
+ name: news.accessGroupName,
133
+ resource: RESOURCE,
134
+ }),
135
+ );
136
+ }
137
+ return after;
138
+ }),
139
+
140
+ delete: ({ output }: { output: AccessGroupAttributes }) =>
141
+ deleteAccessGroup(output.accessGroupId),
142
+
143
+ /** ⛔ EMPTY: adoption is an explicit act (`--adopt`), and no ownership mark exists to filter by. */
144
+ list: () => Effect.succeed([]),
145
+ };
146
+
147
+ export const LiteLLMAccessGroupProvider = () =>
148
+ Provider.effect(
149
+ LiteLLMAccessGroup,
150
+ Effect.succeed(LiteLLMAccessGroup.Provider.of(accessGroupHandlers)),
151
+ );
@@ -0,0 +1,183 @@
1
+ /**
2
+ * The typed refusals `LiteLLM.Credential` raises on top of `@distilled.cloud/litellm`'s own SDK
3
+ * errors.
4
+ *
5
+ * ⛔ NO MESSAGE HERE MAY CARRY A CREDENTIAL VALUE: only the credential's NAME, field names, the
6
+ * NAMES of environment variables, and SDK error text — exactly like mcp-server-errors.ts.
7
+ * ⚠️ THE SDK'S TYPED UNION IS NARROW ON PURPOSE, and the runtime is wider: the credential routes
8
+ * declare only `UnprocessableEntity` (422) in `credential_management.ts`, so a create on an
9
+ * existing name — which the live 1.103.0 container answers `409` (`endpoints.py`'s
10
+ * `_credential_exists_detail`) — decodes at run time as the core `Conflict` class (`Errors.ts`
11
+ * re-exports it, but it is not in the operation's TS union) and PROPAGATES as such, never
12
+ * silently swallowed (S21). The read's and delete's `404` is TYPED as the SDK's
13
+ * `CredentialNotFound` (a distilled patch matched on the vendor's "Credential not found"
14
+ * message, `endpoints.py`), so credential-operations.ts `catchTag`s it instead of `instanceof`
15
+ * `NotFound`: a 404 from a front proxy, Access, or a wrong base path stays a `NotFound` and is
16
+ * never read as absence. `CredentialError` carries the typed members of the four operations the
17
+ * resource calls (create, by-name read, PATCH, delete), plus the refusals below.
18
+ */
19
+ import type * as credentials from '@distilled.cloud/litellm/credential_management';
20
+ import * as Data from 'effect/Data';
21
+ import type { HttpClientErrorReason } from 'effect/unstable/http/HttpClientError';
22
+
23
+ /** A declaration the resource refuses before any request: a combination nobody meant. */
24
+ export class LitellmCredentialInvalidError extends Data.TaggedError(
25
+ 'LitellmCredentialInvalidError',
26
+ )<{
27
+ readonly credentialName: string;
28
+ readonly problem: string;
29
+ }> {
30
+ override get message(): string {
31
+ return `LiteLLM.Credential "${this.credentialName}": ${this.problem}.`;
32
+ }
33
+ }
34
+
35
+ /**
36
+ * A create's `POST /credentials` or an update's `PATCH /credentials/{name}` failed on the wire (or
37
+ * its answer could not be read), so nobody knows whether the credential is what was asked for.
38
+ *
39
+ * ⛔ THIS IS WHAT STANDS IN FOR AN `HttpClientError`, WHICH CARRIES ITS REQUEST, AND THE REQUEST
40
+ * BODY OF A CREATE OR UPDATE IS `{"credential_name": …, "credential_values": {"api_key": "…"}}`.
41
+ * Measured 2026-09-30: on a dropped connection `JSON.stringify(error)`, `Bun.inspect(error)` and
42
+ * Effect's JSON logger all printed the value, as did a failed deploy over it — the same leak
43
+ * key-operations.ts's `LitellmKeyTransportError` closes. A defect reading a broken answer
44
+ * (`protocol-rest.ts` reads it `Effect.orDie`) carries the same request. So `reason` keeps the
45
+ * `HttpClientError` reason's TAG (a string) and nothing else: no request, no cause, no
46
+ * description. The credential NAME stays — it is not secret.
47
+ */
48
+ export class LitellmCredentialTransportError extends Data.TaggedError(
49
+ 'LitellmCredentialTransportError',
50
+ )<{
51
+ readonly credentialName: string;
52
+ readonly reason: HttpClientErrorReason['_tag'] | 'Defect';
53
+ }> {
54
+ override get message(): string {
55
+ return (
56
+ `LiteLLM.Credential "${this.credentialName}": a /credentials write failed ` +
57
+ `(${this.reason}) before an answer could be read, so the credential MAY have been written. ` +
58
+ 'This error keeps neither the request nor its cause: the request body holds the credential ' +
59
+ 'values. Look the name up in LiteLLM. A row that landed is taken over by the next deploy ' +
60
+ 'with --adopt; one that did not is created by it.'
61
+ );
62
+ }
63
+ }
64
+
65
+ /**
66
+ * The SDK prints request and response bodies to stderr while `DISTILLED_DEBUG_HTTP` is set, and a
67
+ * `POST /credentials` carries the values in its body — refused before any request, exactly like
68
+ * `key-secret.ts`'s `refuseDebugLogging` for `/key/generate`.
69
+ */
70
+ export class LitellmCredentialDebugLoggingError extends Data.TaggedError(
71
+ 'LitellmCredentialDebugLoggingError',
72
+ )<{
73
+ readonly credentialName: string;
74
+ }> {
75
+ override get message(): string {
76
+ return (
77
+ `LiteLLM.Credential "${this.credentialName}": DISTILLED_DEBUG_HTTP is set, so the SDK ` +
78
+ "would print the credential values to stderr in /credentials' request and response. Unset " +
79
+ 'it and run again. Nothing was written.'
80
+ );
81
+ }
82
+ }
83
+
84
+ /**
85
+ * A write had to send the credential values and the deploying process does not hold one or more
86
+ * of the declared variables. The names are listed, never a value.
87
+ */
88
+ export class LitellmCredentialEnvUnsetError extends Data.TaggedError(
89
+ 'LitellmCredentialEnvUnsetError',
90
+ )<{
91
+ readonly credentialName: string;
92
+ readonly variables: readonly string[];
93
+ }> {
94
+ override get message(): string {
95
+ return (
96
+ `LiteLLM.Credential "${this.credentialName}": ` +
97
+ `the deploying process does not set ${this.variables.join(', ')}.`
98
+ );
99
+ }
100
+ }
101
+
102
+ /**
103
+ * A credentials read answered something that is not a row of the credential table (or named a
104
+ * different row), so adopt-by-name cannot trust it. The by-name read is this resource's only
105
+ * read, so a row it cannot recognise is refused rather than guessed at.
106
+ */
107
+ export class LitellmCredentialUnreadableError extends Data.TaggedError(
108
+ 'LitellmCredentialUnreadableError',
109
+ )<{
110
+ readonly reason: string;
111
+ }> {
112
+ override get message(): string {
113
+ return `LiteLLM.Credential: a credentials read is unreadable (${this.reason}).`;
114
+ }
115
+ }
116
+
117
+ /**
118
+ * A create or update returned no error, yet the by-name read does not answer the credential — the
119
+ * proxy failed to record it in memory or in the DB. Refused instead of reported as done.
120
+ */
121
+ export class LitellmCredentialAbsentAfterWriteError extends Data.TaggedError(
122
+ 'LitellmCredentialAbsentAfterWriteError',
123
+ )<{
124
+ readonly credentialName: string;
125
+ }> {
126
+ override get message(): string {
127
+ return (
128
+ `LiteLLM.Credential "${this.credentialName}": the write returned no error but the ` +
129
+ 'credential is absent from the by-name read.'
130
+ );
131
+ }
132
+ }
133
+
134
+ /**
135
+ * The write returned no error but the credential still differs from the declaration. The update
136
+ * path this resource uses is a PATCH merge (credential.ts, credential-operations.ts) — or a
137
+ * whole-row rewrite to drop a key — so a residual difference is refused here instead of being
138
+ * reported as converged.
139
+ */
140
+ export class LitellmCredentialNotConvergedError extends Data.TaggedError(
141
+ 'LitellmCredentialNotConvergedError',
142
+ )<{
143
+ readonly credentialName: string;
144
+ readonly fields: readonly string[];
145
+ }> {
146
+ override get message(): string {
147
+ return (
148
+ `LiteLLM.Credential "${this.credentialName}": after the write it still differs from the ` +
149
+ `declaration in ${this.fields.join(', ')}.`
150
+ );
151
+ }
152
+ }
153
+
154
+ /** A rewrite deleted the old row before its POST failed. Keep only the failure tag. */
155
+ export class LitellmCredentialRewriteError extends Data.TaggedError(
156
+ 'LitellmCredentialRewriteError',
157
+ )<{
158
+ readonly credentialName: string;
159
+ readonly reason: string;
160
+ }> {
161
+ override get message(): string {
162
+ return (
163
+ `LiteLLM.Credential "${this.credentialName}": DELETE already ran, but the replacement ` +
164
+ `POST failed (${this.reason}). The next deploy recreates the row if absent; keep all ` +
165
+ 'declared credential variables set. If the POST landed despite the failure, the next ' +
166
+ 'deploy reads and reconciles that row.'
167
+ );
168
+ }
169
+ }
170
+
171
+ export type CredentialError =
172
+ | credentials.CreateCredentialCredentialsPostError
173
+ | credentials.GetCredentialByNameCredentialsByNameCredentialNameGetError
174
+ | credentials.UpdateCredentialCredentialsCredentialNamePatchError
175
+ | credentials.DeleteCredentialCredentialsCredentialNameDeleteError
176
+ | LitellmCredentialInvalidError
177
+ | LitellmCredentialTransportError
178
+ | LitellmCredentialRewriteError
179
+ | LitellmCredentialDebugLoggingError
180
+ | LitellmCredentialEnvUnsetError
181
+ | LitellmCredentialUnreadableError
182
+ | LitellmCredentialAbsentAfterWriteError
183
+ | LitellmCredentialNotConvergedError;