@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,172 @@
1
+ /**
2
+ * `LiteLLM.ToolPolicy` through Alchemy's real Plan and Apply over the fake proxy
3
+ * (`fake-tool-litellm.ts`): the upsert create, no-op, adopt, partial update, replace and reset.
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 { FAKE_BASE } from './fake-litellm.ts';
14
+ import { FAKE_KEY } from './fake-registry-base.ts';
15
+ import { type FakeToolLitellm, startFakeToolLitellm, toolRow } from './fake-tool-litellm.ts';
16
+ import { fakeStack, writesOf } from './fake-stack.ts';
17
+ import { LiteLLMToolPolicy } from './tool-policy.ts';
18
+ import { resetToolPolicy } from './tool-policy-operations.ts';
19
+ import type { ToolPolicyProps } from './tool-policy-types.ts';
20
+
21
+ const stack = (fake: FakeToolLitellm) =>
22
+ fakeStack({ apiKey: FAKE_KEY, baseUrl: FAKE_BASE }, fake.fetch);
23
+ const declare = (props: ToolPolicyProps, name = 'Search') =>
24
+ Effect.gen(function* () {
25
+ yield* LiteLLMToolPolicy(name, props);
26
+ });
27
+
28
+ const search: ToolPolicyProps = {
29
+ inputPolicy: 'blocked',
30
+ outputPolicy: 'untrusted',
31
+ toolName: 'FAKE_search-query',
32
+ };
33
+
34
+ test('a tool never seen is created by the upsert, then a second deploy writes nothing', async () => {
35
+ const fake = startFakeToolLitellm();
36
+ const same = stack(fake);
37
+ expect(await same.deploy(declare(search))).toEqual({ Search: 'create' });
38
+ expect(fake.tools()[0]).toMatchObject({
39
+ input_policy: 'blocked',
40
+ output_policy: 'untrusted',
41
+ tool_name: 'FAKE_search-query',
42
+ });
43
+ expect(fake.bodies()[0]).toEqual({
44
+ input_policy: 'blocked',
45
+ output_policy: 'untrusted',
46
+ tool_name: 'FAKE_search-query',
47
+ });
48
+ const before = fake.requests().length;
49
+ expect(await same.deploy(declare(search))).toEqual({ Search: 'noop' });
50
+ expect(writesOf(fake.requests().slice(before))).toEqual([]);
51
+ });
52
+
53
+ test('a tool LiteLLM already discovered is Unowned: refused without --adopt, and a matching row writes nothing', async () => {
54
+ const seen = toolRow({
55
+ input_policy: 'blocked',
56
+ tool_id: 'FAKE-tool-live',
57
+ tool_name: 'FAKE_search-query',
58
+ });
59
+ const fake = startFakeToolLitellm({ seed: [seen] });
60
+ const engine = stack(fake);
61
+ await expect(engine.deploy(declare(search))).rejects.toThrow();
62
+ expect(writesOf(fake.requests())).toEqual([]);
63
+ expect(Object.values(await engine.deploy(declare(search), { adopt: true }))).toEqual(['adopted']);
64
+ expect(writesOf(fake.requests())).toEqual([]);
65
+ });
66
+
67
+ test('adopting a tool with another policy sends ONLY the field that differs, and leaves the other alone', async () => {
68
+ const seen = toolRow({
69
+ output_policy: 'trusted',
70
+ tool_id: 'FAKE-tool-live',
71
+ tool_name: 'FAKE_search-query',
72
+ });
73
+ const fake = startFakeToolLitellm({ seed: [seen] });
74
+ await stack(fake).deploy(declare({ inputPolicy: 'blocked', toolName: 'FAKE_search-query' }), {
75
+ adopt: true,
76
+ });
77
+ expect(fake.bodies()).toEqual([{ input_policy: 'blocked', tool_name: 'FAKE_search-query' }]);
78
+ // ★ the output policy was never declared, so it is not compared and not sent
79
+ expect(fake.tools()[0]?.['output_policy']).toBe('trusted');
80
+ });
81
+
82
+ test('a changed policy is an update that sends only the changed field', async () => {
83
+ const fake = startFakeToolLitellm();
84
+ const same = stack(fake);
85
+ await same.deploy(declare(search));
86
+ expect(await same.deploy(declare({ ...search, inputPolicy: 'trusted' }))).toEqual({
87
+ Search: 'update',
88
+ });
89
+ expect(fake.bodies().at(-1)).toEqual({ input_policy: 'trusted', tool_name: 'FAKE_search-query' });
90
+ });
91
+
92
+ test('a different tool name is a replace, create-first, and the old tool is retained', async () => {
93
+ const fake = startFakeToolLitellm();
94
+ const same = stack(fake);
95
+ await same.deploy(declare(search));
96
+ expect(await same.deploy(declare({ ...search, toolName: 'FAKE_other-tool' }))).toEqual({
97
+ Search: 'replace',
98
+ });
99
+ expect(fake.tools().map((row) => row['tool_name'])).toEqual([
100
+ 'FAKE_search-query',
101
+ 'FAKE_other-tool',
102
+ ]);
103
+ });
104
+
105
+ test('a proxy that drops a field fails the deploy instead of claiming success', async () => {
106
+ // ⚠️ the fake's own model of a route that loses one field — unmeasured at 1.103.0
107
+ const fake = startFakeToolLitellm({ dropsOutputPolicy: true });
108
+ await expect(
109
+ stack(fake).deploy(declare({ ...search, outputPolicy: 'trusted' })),
110
+ ).rejects.toThrow();
111
+ });
112
+
113
+ test('a read that 404s for a tool that exists ends in a write that succeeds, not in a wrong "absent"', async () => {
114
+ // ⛔ measured in the source: db_get_tool swallows every exception into None, which the route makes a 404
115
+ const seen = toolRow({ tool_id: 'FAKE-tool-live', tool_name: 'FAKE_search-query' });
116
+ const fake = startFakeToolLitellm({ getSwallowsErrors: true, seed: [seen] });
117
+ await expect(stack(fake).deploy(declare(search))).rejects.toThrow();
118
+ // the write reached the proxy (an upsert), and the read back is what refused to call it converged
119
+ expect(writesOf(fake.requests())).toEqual(['POST /v1/tool/policy']);
120
+ });
121
+
122
+ test('a refused declaration fails the plan before a single request', async () => {
123
+ for (const props of [
124
+ { toolName: 'FAKE_search-query' },
125
+ { ...search, toolName: ' ' },
126
+ { ...search, toolName: 'list' },
127
+ { ...search, toolName: 'spend' },
128
+ { ...search, toolName: 'policy/options' },
129
+ { ...search, toolName: 'x/detail' },
130
+ { ...search, toolName: 'x/logs' },
131
+ { ...search, inputPolicy: 'dual_llm' as never },
132
+ { ...search, outputPolicy: 'blocked' as never },
133
+ ]) {
134
+ const fake = startFakeToolLitellm();
135
+ await expect(stack(fake).deploy(declare(props))).rejects.toThrow();
136
+ expect(fake.requests()).toEqual([]);
137
+ }
138
+ });
139
+
140
+ test('removing the declaration RETAINS the tool row', async () => {
141
+ const fake = startFakeToolLitellm();
142
+ const same = stack(fake);
143
+ await same.deploy(declare(search));
144
+ await same.deploy(Effect.void);
145
+ expect(fake.tools()[0]).toMatchObject({ input_policy: 'blocked' });
146
+ });
147
+
148
+ const run = <A, E>(fetchFn: typeof globalThis.fetch, effect: Effect.Effect<A, E, unknown>) =>
149
+ Effect.runPromise(
150
+ effect.pipe(
151
+ Effect.provide(FetchHttpClient.layer),
152
+ Effect.provide(Layer.succeed(FetchHttpClient.Fetch, fetchFn)),
153
+ Effect.provide(credentials({ apiKey: FAKE_KEY, baseUrl: FAKE_BASE })),
154
+ ) as Effect.Effect<A, E, never>,
155
+ );
156
+
157
+ test('delete RESETS only the managed fields that are not already the default, and sends nothing for an unknown tool', async () => {
158
+ const seen = toolRow({
159
+ input_policy: 'blocked',
160
+ output_policy: 'trusted',
161
+ tool_id: 'FAKE-tool-live',
162
+ tool_name: 'FAKE_search-query',
163
+ });
164
+ const fake = startFakeToolLitellm({ seed: [seen] });
165
+ await run(fake.fetch, resetToolPolicy({ inputPolicy: 'blocked', toolName: 'FAKE_search-query' }));
166
+ // ★ only the declared field was reset; the undeclared output policy keeps what it had
167
+ expect(fake.tools()[0]).toMatchObject({ input_policy: 'untrusted', output_policy: 'trusted' });
168
+ const before = fake.requests().length;
169
+ await run(fake.fetch, resetToolPolicy({ inputPolicy: 'blocked', toolName: 'FAKE_search-query' }));
170
+ await run(fake.fetch, resetToolPolicy({ inputPolicy: 'blocked', toolName: 'FAKE_unknown' }));
171
+ expect(writesOf(fake.requests().slice(before))).toEqual([]);
172
+ });
@@ -0,0 +1,125 @@
1
+ /**
2
+ * `LiteLLM.ToolPolicy` — the input and output trust policy of one tool in LiteLLM's tool registry
3
+ * (`LiteLLM_ToolTable`, `POST /v1/tool/policy`). Props, the enforcement precondition and what is left
4
+ * out: tool-policy-types.ts.
5
+ *
6
+ * ⛔ INERT WITHOUT THE `tool_policy` GUARDRAIL in the proxy's own config (tool-policy-types.ts).
7
+ * ★ ADOPT BY NAME. LiteLLM discovers tools itself, so a tool it has already seen has a live row with no
8
+ * state: `Unowned`, which needs `--adopt` (a row at the defaults is adopted the same way). A tool
9
+ * never seen has no row, and the write creates it.
10
+ * ★ `defaultRemovalPolicy: 'retain'` — there is no delete route. `delete` RESETS the managed fields to
11
+ * `untrusted` (tool-policy-operations.ts), which for an `input_policy` of `blocked` re-opens a tool.
12
+ * Opt in with `.pipe(RemovalPolicy.destroy())`.
13
+ * ⚠️ NO LICENCE GATE ON THESE ROUTES: `tool_management_endpoints.py` has no `premium_user` check
14
+ * (1.103.0). Whether the `tool_policy` guardrail itself is licence-gated is UNVERIFIED (its module
15
+ * has no `premium` reference either).
16
+ * ⛔ NO LITELLM CREDENTIAL IS A PROP; `litellmProviders`' layer supplies `Credentials`.
17
+ */
18
+ import { Resource } from 'alchemy';
19
+ import { Unowned } from 'alchemy/AdoptPolicy';
20
+ import { isResolved } from 'alchemy/Diff';
21
+ import type { Input } from 'alchemy/Input';
22
+ import * as Provider from 'alchemy/Provider';
23
+ import * as Effect from 'effect/Effect';
24
+ import * as Predicate from 'effect/Predicate';
25
+ import {
26
+ LitellmRegistryAbsentAfterWriteError,
27
+ LitellmRegistryNotConvergedError,
28
+ } from './registry-errors.ts';
29
+ import { dieIfInvalid, failIfInvalid } from './registry-support.ts';
30
+ import { differing, firstProblem, updateBody } from './tool-policy-form.ts';
31
+ import { readTool, resetToolPolicy, writeToolPolicy } from './tool-policy-operations.ts';
32
+ import type { ToolPolicyAttributes, ToolPolicyProps } from './tool-policy-types.ts';
33
+
34
+ export type { ToolPolicyAttributes, ToolPolicyProps };
35
+ export type { ToolInputPolicy, ToolOutputPolicy } from './tool-policy-types.ts';
36
+ export type { RegistryError as ToolPolicyError } from './registry-errors.ts';
37
+
38
+ const RESOURCE = 'LiteLLM.ToolPolicy';
39
+
40
+ export interface LiteLLMToolPolicy extends Resource<
41
+ 'LiteLLM.ToolPolicy',
42
+ ToolPolicyProps,
43
+ ToolPolicyAttributes
44
+ > {}
45
+
46
+ export const LiteLLMToolPolicy = Resource<LiteLLMToolPolicy>('LiteLLM.ToolPolicy', {
47
+ defaultRemovalPolicy: 'retain',
48
+ });
49
+
50
+ export const isLiteLLMToolPolicy = (value: unknown): value is LiteLLMToolPolicy =>
51
+ Predicate.hasProperty(value, 'Type') && value.Type === 'LiteLLM.ToolPolicy';
52
+
53
+ /** ⛔ TEST-ONLY EXPORT. Not on index.ts's barrel. */
54
+ export const toolPolicyHandlers = {
55
+ /** ⛔ With no `output` this is the adoption probe, so the refusals run here too (registry-support.ts). */
56
+ read: ({ olds, output }: { olds: ToolPolicyProps; output: ToolPolicyAttributes | undefined }) =>
57
+ Effect.gen(function* () {
58
+ if (output === undefined) {
59
+ yield* dieIfInvalid(RESOURCE, String(olds.toolName), firstProblem(olds));
60
+ }
61
+ const live = yield* readTool(output?.toolName ?? olds.toolName);
62
+ if (live === undefined) return undefined;
63
+ return output === undefined ? Unowned(live) : live;
64
+ }),
65
+
66
+ diff: ({
67
+ news,
68
+ output,
69
+ }: {
70
+ news: Input<ToolPolicyProps>;
71
+ output: ToolPolicyAttributes | undefined;
72
+ }) =>
73
+ Effect.gen(function* () {
74
+ if (!isResolved(news)) return undefined;
75
+ yield* failIfInvalid(RESOURCE, String(news.toolName), firstProblem(news));
76
+ if (output === undefined) return undefined;
77
+ // The name is identity: a different tool is a different row.
78
+ if (news.toolName !== output.toolName) {
79
+ return { action: 'replace', deleteFirst: false } as const;
80
+ }
81
+ return differing(output, news).length === 0
82
+ ? ({ action: 'noop' } as const)
83
+ : ({ action: 'update' } as const);
84
+ }),
85
+
86
+ reconcile: ({ news }: { news: ToolPolicyProps }) =>
87
+ Effect.gen(function* () {
88
+ yield* failIfInvalid(RESOURCE, String(news.toolName), firstProblem(news));
89
+ // ★ THE TOOL THIS DECLARATION NAMES IS READ BY ITS NAME, never by a recorded one: a create-first
90
+ // replace hands reconcile no output, and the name is the whole identity.
91
+ const before = yield* readTool(news.toolName);
92
+ if (before === undefined || differing(before, news).length > 0) {
93
+ yield* writeToolPolicy(updateBody(news, before));
94
+ }
95
+ const after = yield* readTool(news.toolName);
96
+ if (after === undefined) {
97
+ return yield* Effect.fail(
98
+ new LitellmRegistryAbsentAfterWriteError({ name: news.toolName, resource: RESOURCE }),
99
+ );
100
+ }
101
+ const left = differing(after, news);
102
+ if (left.length > 0) {
103
+ return yield* Effect.fail(
104
+ new LitellmRegistryNotConvergedError({
105
+ fields: left,
106
+ name: news.toolName,
107
+ resource: RESOURCE,
108
+ }),
109
+ );
110
+ }
111
+ return after;
112
+ }),
113
+
114
+ /** ⛔ A RESET, not a removal: see tool-policy-operations.ts. */
115
+ delete: ({ olds }: { olds: ToolPolicyProps }) => resetToolPolicy(olds),
116
+
117
+ /** ⛔ EMPTY: adoption is an explicit act (`--adopt`), and a discovered tool row has no owner mark. */
118
+ list: () => Effect.succeed([]),
119
+ };
120
+
121
+ export const LiteLLMToolPolicyProvider = () =>
122
+ Provider.effect(
123
+ LiteLLMToolPolicy,
124
+ Effect.succeed(LiteLLMToolPolicy.Provider.of(toolPolicyHandlers)),
125
+ );
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Wire bodies, comparison and refusals for `LiteLLM.Toolset`, testable without a server.
3
+ *
4
+ * ★ THE EDIT IS A PARTIAL ONE (`update_mcp_toolset`, 1.103.0, read from the live container): an absent
5
+ * field keeps its stored value, a `null` clears it, EXCEPT `toolset_name` and `tools`, where `null`
6
+ * is a no-op ("a toolset always has a name and a tool list"). So `tools` is sent only as a list, and
7
+ * emptying a selection is an explicit `[]`. This resource never sends a `null` name or list.
8
+ */
9
+ import type * as mcp from '@distilled.cloud/litellm/mcp_management';
10
+ import { asRow, firstBadEntry, isBlank, stringOrNull } from './registry-support.ts';
11
+ import type { ToolsetAttributes, ToolsetProps, ToolsetTool } from './toolset-types.ts';
12
+
13
+ const pairKey = (tool: ToolsetTool): string => JSON.stringify([tool.serverId, tool.toolName]);
14
+
15
+ /** Sorted by server, then tool. A set has no order, so this is the form two reads compare in. */
16
+ const canonicalTools = (tools: readonly ToolsetTool[]): readonly ToolsetTool[] =>
17
+ [...new Map(tools.map((tool) => [pairKey(tool), tool])).values()].sort((a, b) =>
18
+ pairKey(a).localeCompare(pairKey(b)),
19
+ );
20
+
21
+ const sameTools = (left: readonly ToolsetTool[], right: readonly ToolsetTool[]): boolean => {
22
+ const a = canonicalTools(left).map(pairKey);
23
+ const b = canonicalTools(right).map(pairKey);
24
+ return a.length === b.length && a.every((each, index) => each === b[index]);
25
+ };
26
+
27
+ /** The first reason a declaration is refused, or `undefined`. Runs before any request. */
28
+ export const firstProblem = (props: ToolsetProps): string | undefined => {
29
+ if (isBlank(props.toolsetName) || props.toolsetName !== props.toolsetName.trim()) {
30
+ return '`toolsetName` must be a non-blank name with no leading or trailing space';
31
+ }
32
+ if (props.toolsetName.includes('/')) {
33
+ return '`toolsetName` contains `/`: a toolset is served at /toolset/{toolset_name}/mcp, so that name can never be addressed';
34
+ }
35
+ if (props.description !== undefined && isBlank(props.description)) {
36
+ return '`description` is blank; leave it out to keep the live text';
37
+ }
38
+ if (!Array.isArray(props.tools)) return '`tools` must be a list (an empty one is `[]`)';
39
+ const bad =
40
+ firstBadEntry(props.tools.map((tool) => tool.serverId)) ??
41
+ firstBadEntry(props.tools.map((tool) => tool.toolName));
42
+ if (bad !== undefined)
43
+ return `a tool has a blank or padded serverId or toolName (${JSON.stringify(bad)})`;
44
+ const keys = props.tools.map(pairKey);
45
+ const twice = keys.find((key, index) => keys.indexOf(key) !== index);
46
+ if (twice !== undefined) return `\`tools\` lists ${twice} twice`;
47
+ return undefined;
48
+ };
49
+
50
+ /** One toolset row. `undefined` is "not a toolset": the caller refuses the whole answer. */
51
+ export const toAttributes = (value: unknown): ToolsetAttributes | undefined => {
52
+ const row = asRow(value);
53
+ if (row === undefined) return undefined;
54
+ const toolsetId = row['toolset_id'];
55
+ const toolsetName = row['toolset_name'];
56
+ if (typeof toolsetId !== 'string' || typeof toolsetName !== 'string') return undefined;
57
+ const tools: ToolsetTool[] = [];
58
+ for (const entry of Array.isArray(row['tools']) ? row['tools'] : []) {
59
+ const pair = asRow(entry);
60
+ if (typeof pair?.['server_id'] === 'string' && typeof pair['tool_name'] === 'string') {
61
+ tools.push({ serverId: pair['server_id'], toolName: pair['tool_name'] });
62
+ }
63
+ }
64
+ return {
65
+ description: stringOrNull(row['description']),
66
+ toolsetId,
67
+ toolsetName,
68
+ tools: canonicalTools(tools),
69
+ };
70
+ };
71
+
72
+ /** Wire names of the fields where live and declared disagree. */
73
+ export const differing = (live: ToolsetAttributes, props: ToolsetProps): readonly string[] => {
74
+ const fields: string[] = [];
75
+ if (live.toolsetName !== props.toolsetName) fields.push('toolset_name');
76
+ if (props.description !== undefined && live.description !== props.description) {
77
+ fields.push('description');
78
+ }
79
+ if (!sameTools(live.tools, props.tools)) fields.push('tools');
80
+ return fields;
81
+ };
82
+
83
+ const wireTools = (tools: readonly ToolsetTool[]): mcp.MCPToolsetTool[] =>
84
+ tools.map((tool) => ({ server_id: tool.serverId, tool_name: tool.toolName }));
85
+
86
+ export const createBody = (props: ToolsetProps): mcp.AddMcpToolsetV1McpToolsetPostRequest => ({
87
+ toolset_name: props.toolsetName,
88
+ tools: wireTools(props.tools),
89
+ ...(props.description === undefined ? {} : { description: props.description }),
90
+ });
91
+
92
+ /** Only what differs, and never a `null` name or list (LiteLLM ignores those). */
93
+ export const updateBody = (
94
+ props: ToolsetProps,
95
+ live: ToolsetAttributes,
96
+ ): mcp.EditMcpToolsetV1McpToolsetPutRequest => {
97
+ const changed = new Set(differing(live, props));
98
+ return {
99
+ toolset_id: live.toolsetId,
100
+ ...(changed.has('toolset_name') ? { toolset_name: props.toolsetName } : {}),
101
+ ...(changed.has('description') ? { description: props.description ?? null } : {}),
102
+ ...(changed.has('tools') ? { tools: wireTools(props.tools) } : {}),
103
+ };
104
+ };
@@ -0,0 +1,90 @@
1
+ /**
2
+ * The five LiteLLM `/v1/mcp/toolset*` calls `LiteLLM.Toolset` uses, through the SDK's typed operations
3
+ * in `@distilled.cloud/litellm/mcp_management` (LiteLLM 1.103.0):
4
+ *
5
+ * list `fetchMcpToolsetsV1McpToolsetGet` GET /v1/mcp/toolset
6
+ * read `fetchMcpToolsetV1McpToolsetToolsetIdGet` GET /v1/mcp/toolset/{toolset_id}
7
+ * create `addMcpToolsetV1McpToolsetPost` POST /v1/mcp/toolset (201)
8
+ * update `editMcpToolsetV1McpToolsetPut` PUT /v1/mcp/toolset
9
+ * delete `removeMcpToolsetV1McpToolsetToolsetIdDelete` DELETE /v1/mcp/toolset/{toolset_id} (202, no body)
10
+ *
11
+ * ⛔ THE LIST CANNOT PROVE ABSENCE, THE BY-ID READ CAN (`mcp_management_endpoints.py` and
12
+ * `toolset_db.py`, read from the live 1.103.0 container). `list_mcp_toolsets` wraps its query in
13
+ * `except Exception: … return []`, so a database error answers an EMPTY LIST with a 200; and the
14
+ * route narrows the answer to the caller's granted toolsets unless the caller is an admin. The by-id
15
+ * route reads the table (`get_mcp_toolset`, a `find_unique`) and answers 404 only for a missing row.
16
+ * So the list is used ONLY to adopt by name, and everything else reads by id. A wrong "absent" from
17
+ * the list can only end in a create, which a unique name turns into a 409 that fails the deploy.
18
+ * ⛔ NO MESSAGE SNIFFING. `readToolset` tests the SDK's `NotFound` CLASS (registry-support.ts) and
19
+ * nothing else; a 401, a 403 or a dead network propagates, and is never read as absence.
20
+ * ★ DELETE IS IDEMPOTENT BY A REAL READ: a failed DELETE is swallowed only when a by-id read says the
21
+ * row is gone. A 403 (only PROXY_ADMIN may delete) leaves it live, so it re-raises the original.
22
+ */
23
+ import * as mcp from '@distilled.cloud/litellm/mcp_management';
24
+ import * as Effect from 'effect/Effect';
25
+ import { type LitellmOpContext, throughFetch } from './operations.ts';
26
+ import { LitellmRegistryUnreadableError } from './registry-errors.ts';
27
+ import { bodyOf, isNotFound } from './registry-support.ts';
28
+ import { toAttributes } from './toolset-form.ts';
29
+ import type { ToolsetAttributes } from './toolset-types.ts';
30
+
31
+ const RESOURCE = 'LiteLLM.Toolset';
32
+
33
+ /** ⚠️ NOT PROOF OF ABSENCE: see the file header. Adopt-by-name only. */
34
+ export const listToolsets = (): Effect.Effect<
35
+ readonly ToolsetAttributes[],
36
+ mcp.FetchMcpToolsetsV1McpToolsetGetError | LitellmRegistryUnreadableError,
37
+ LitellmOpContext
38
+ > =>
39
+ throughFetch(mcp.fetchMcpToolsetsV1McpToolsetGet({})).pipe(
40
+ Effect.flatMap((response) => {
41
+ const rows: unknown = bodyOf(response);
42
+ if (!Array.isArray(rows)) {
43
+ return Effect.fail(
44
+ new LitellmRegistryUnreadableError({ reason: 'not an array', resource: RESOURCE }),
45
+ );
46
+ }
47
+ const parsed = rows.map(toAttributes);
48
+ return parsed.every((row) => row !== undefined)
49
+ ? Effect.succeed(parsed as readonly ToolsetAttributes[])
50
+ : Effect.fail(
51
+ new LitellmRegistryUnreadableError({
52
+ reason: 'a row has no id or name',
53
+ resource: RESOURCE,
54
+ }),
55
+ );
56
+ }),
57
+ );
58
+
59
+ /**
60
+ * One toolset BY ID, from the table, or `undefined` when the proxy has no such row. The row must carry
61
+ * the id asked for; anything else the proxy answers is "no such row".
62
+ */
63
+ export const readToolset = (toolsetId: string) =>
64
+ throughFetch(mcp.fetchMcpToolsetV1McpToolsetToolsetIdGet({ toolset_id: toolsetId })).pipe(
65
+ Effect.map((response) => {
66
+ const row = toAttributes(bodyOf(response));
67
+ return row?.toolsetId === toolsetId ? row : undefined;
68
+ }),
69
+ Effect.catch((error) => (isNotFound(error) ? Effect.succeed(undefined) : Effect.fail(error))),
70
+ );
71
+
72
+ /** The created row, which carries the id LiteLLM issued. `undefined` when the answer is not a toolset. */
73
+ export const createToolset = (body: mcp.AddMcpToolsetV1McpToolsetPostRequest) =>
74
+ throughFetch(mcp.addMcpToolsetV1McpToolsetPost(body)).pipe(
75
+ Effect.map((response) => toAttributes(bodyOf(response))),
76
+ );
77
+
78
+ export const updateToolset = (body: mcp.EditMcpToolsetV1McpToolsetPutRequest) =>
79
+ throughFetch(mcp.editMcpToolsetV1McpToolsetPut(body)).pipe(Effect.asVoid);
80
+
81
+ export const deleteToolset = (toolsetId: string) =>
82
+ throughFetch(mcp.removeMcpToolsetV1McpToolsetToolsetIdDelete({ toolset_id: toolsetId })).pipe(
83
+ Effect.asVoid,
84
+ Effect.catch((original) =>
85
+ readToolset(toolsetId).pipe(
86
+ Effect.catch(() => Effect.fail(original)),
87
+ Effect.flatMap((row) => (row === undefined ? Effect.void : Effect.fail(original))),
88
+ ),
89
+ ),
90
+ );
@@ -0,0 +1,47 @@
1
+ /**
2
+ * What a `LiteLLM.Toolset` declares (props) and what is remembered about it (attributes).
3
+ *
4
+ * ★ A TOOLSET IS A NAMED SELECTION OF `{ server_id, tool_name }` PAIRS drawn from one or more MCP
5
+ * servers (`LiteLLM_MCPToolsetTable`, `/v1/mcp/toolset`; docs.litellm.ai/docs/mcp_toolsets). A key or
6
+ * team is granted one through `object_permission.mcp_toolsets`, which holds the toolset's ID
7
+ * (`fetch_mcp_toolsets` filters `list_mcp_toolsets(toolset_ids=…)`), so `LiteLLM.Team` takes
8
+ * `toolset.toolsetId`, not the name.
9
+ * ⚠️ THE ID IS THE PROXY'S. `create_mcp_toolset` sets `toolset_id = str(uuid.uuid4())` and the create
10
+ * request has no id field, so nothing here can pick one. The id LiteLLM answers is what is recorded.
11
+ * ★ THE NAME IS A URL SEGMENT. A toolset is served at `/toolset/{toolset_name}/mcp`
12
+ * (`proxy_server.py` line 19346) and `litellm_proxy/mcp/<toolset_name>` (docs), so a name with a `/`
13
+ * can never be addressed. LiteLLM itself accepts one; the refusal is this package's.
14
+ * ⚠️ NOT MODELLED: nothing beyond name, description and tools — the table has no other column that a
15
+ * write reaches.
16
+ */
17
+ export interface ToolsetTool {
18
+ /** The MCP server's `server_id`. Declare it as `server.serverId` (a `LiteLLM.MCPServer`). */
19
+ readonly serverId: string;
20
+ /** The tool's name on that server, as the server lists it. */
21
+ readonly toolName: string;
22
+ }
23
+
24
+ export interface ToolsetProps {
25
+ /**
26
+ * The toolset's name, and the way an existing row is ADOPTED. `toolset_name` is unique in the table
27
+ * (a create or rename onto a taken name is a 409), so the match is exact. Changing it is an update of
28
+ * the same row, never a replace.
29
+ */
30
+ readonly toolsetName: string;
31
+ /** Compared only when declared: adopting a row never clears text a person wrote. Blank is refused. */
32
+ readonly description?: string;
33
+ /**
34
+ * The selection, compared as a SET of pairs and ALWAYS compared: it is what a caller may reach, so an
35
+ * adopted toolset with more than declared is corrected. `[]` is an explicit empty selection (LiteLLM
36
+ * keeps an empty list only when it is sent as one). Required, so the declaration always says.
37
+ */
38
+ readonly tools: readonly ToolsetTool[];
39
+ }
40
+
41
+ export interface ToolsetAttributes {
42
+ readonly toolsetId: string;
43
+ readonly toolsetName: string;
44
+ readonly description: string | null;
45
+ /** Sorted by server, then tool, so two reads of one row are equal. */
46
+ readonly tools: readonly ToolsetTool[];
47
+ }