@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,206 @@
1
+ /**
2
+ * `LiteLLM.Team` through Alchemy's real Plan and Apply over the fake proxy (`fake-team-litellm.ts`):
3
+ * create, no-op, adopt, the partial update, the object-permission merge and the refusals. The roster
4
+ * and delete are `team-members.test.ts`.
5
+ *
6
+ * ★ EVERY VALUE IS `FAKE-*`.
7
+ * ⚠️ WHAT THE FAKE MODELS IS READ FROM THE 1.103.0 SOURCE, NOT MEASURED ON A LIVE PROXY (its header).
8
+ */
9
+ import { expect, test } from 'bun:test';
10
+ import * as Effect from 'effect/Effect';
11
+ import { FAKE_BASE } from './fake-litellm.ts';
12
+ import { FAKE_KEY } from './fake-registry-base.ts';
13
+ import { type FakeTeamLitellm, startFakeTeamLitellm, teamRow } from './fake-team-litellm.ts';
14
+ import { fakeStack, writesOf } from './fake-stack.ts';
15
+ import { LiteLLMTeam } from './team.ts';
16
+ import type { TeamProps } from './team-types.ts';
17
+
18
+ const stack = (fake: FakeTeamLitellm) =>
19
+ fakeStack({ apiKey: FAKE_KEY, baseUrl: FAKE_BASE }, fake.fetch);
20
+ const declare = (props: TeamProps, name = 'Estate') =>
21
+ Effect.gen(function* () {
22
+ yield* LiteLLMTeam(name, props);
23
+ });
24
+
25
+ const estate: TeamProps = {
26
+ blocked: false,
27
+ models: ['fake-code', 'fake-flash'],
28
+ objectPermission: {
29
+ mcpServers: [],
30
+ mcpToolsets: ['FAKE-toolset-1'],
31
+ mcpToolPermissions: { FAKE_docs: ['search'] },
32
+ },
33
+ teamAlias: 'FAKE-estate',
34
+ teamId: 'FAKE-team-estate',
35
+ };
36
+
37
+ test('creates a team with its ceiling, then a second deploy writes nothing', async () => {
38
+ const fake = startFakeTeamLitellm();
39
+ const same = stack(fake);
40
+ expect(await same.deploy(declare(estate))).toEqual({ Estate: 'create' });
41
+ expect(fake.teams()[0]).toMatchObject({
42
+ blocked: false,
43
+ models: ['fake-code', 'fake-flash'],
44
+ object_permission: {
45
+ mcp_servers: [],
46
+ mcp_tool_permissions: { FAKE_docs: ['search'] },
47
+ mcp_toolsets: ['FAKE-toolset-1'],
48
+ },
49
+ team_alias: 'FAKE-estate',
50
+ team_id: 'FAKE-team-estate',
51
+ });
52
+ const before = fake.requests().length;
53
+ expect(await same.deploy(declare(estate))).toEqual({ Estate: 'noop' });
54
+ expect(writesOf(fake.requests().slice(before))).toEqual([]);
55
+ });
56
+
57
+ test('an undeclared team id is a deterministic physical name, never a proxy uuid', async () => {
58
+ const fake = startFakeTeamLitellm();
59
+ await stack(fake).deploy(declare({ teamAlias: 'FAKE-named' }));
60
+ expect(String(fake.teams()[0]?.['team_id'])).toMatch(/^[a-z0-9-]+$/);
61
+ });
62
+
63
+ test('an undeclared field is never sent: a create with only an alias sends no models, no block, no permission', async () => {
64
+ const fake = startFakeTeamLitellm();
65
+ await stack(fake).deploy(declare({ teamAlias: 'FAKE-bare', teamId: 'FAKE-team-bare' }));
66
+ expect(fake.bodies()[0]).toEqual({ team_alias: 'FAKE-bare', team_id: 'FAKE-team-bare' });
67
+ });
68
+
69
+ test('`models: []` is sent as an empty list (it means EVERY model), not dropped', async () => {
70
+ const fake = startFakeTeamLitellm();
71
+ await stack(fake).deploy(
72
+ declare({ models: [], teamAlias: 'FAKE-open', teamId: 'FAKE-team-open' }),
73
+ );
74
+ expect(fake.bodies()[0]).toMatchObject({ models: [] });
75
+ });
76
+
77
+ test('a live team is Unowned: refused without --adopt, adopted by id with it, and a match writes nothing', async () => {
78
+ const live = teamRow({
79
+ blocked: false,
80
+ models: ['fake-flash', 'fake-code'],
81
+ object_permission: {
82
+ mcp_servers: [],
83
+ mcp_tool_permissions: { FAKE_docs: ['search'] },
84
+ mcp_toolsets: ['FAKE-toolset-1'],
85
+ },
86
+ team_alias: 'FAKE-estate',
87
+ team_id: 'FAKE-team-estate',
88
+ });
89
+ const fake = startFakeTeamLitellm({ seed: [live] });
90
+ const engine = stack(fake);
91
+ await expect(engine.deploy(declare(estate))).rejects.toThrow();
92
+ expect(writesOf(fake.requests())).toEqual([]);
93
+ expect(Object.values(await engine.deploy(declare(estate), { adopt: true }))).toEqual(['adopted']);
94
+ expect(writesOf(fake.requests())).toEqual([]);
95
+ });
96
+
97
+ test('the object permission is a MERGE: adopting a team corrects the declared field and leaves the others', async () => {
98
+ const live = teamRow({
99
+ models: ['fake-code'],
100
+ object_permission: {
101
+ mcp_servers: ['FAKE-server-a'],
102
+ mcp_toolsets: ['FAKE-toolset-1'],
103
+ vector_stores: ['FAKE-vector'],
104
+ },
105
+ team_alias: 'FAKE-estate',
106
+ team_id: 'FAKE-team-estate',
107
+ });
108
+ const fake = startFakeTeamLitellm({ seed: [live] });
109
+ await stack(fake).deploy(
110
+ declare({
111
+ objectPermission: { mcpServers: [] },
112
+ teamAlias: 'FAKE-estate',
113
+ teamId: 'FAKE-team-estate',
114
+ }),
115
+ { adopt: true },
116
+ );
117
+ // ★ the red-team fact: a non-empty team `mcp_servers` intersects every key's grants, so it is cleared
118
+ expect(fake.bodies()[0]).toEqual({
119
+ object_permission: { mcp_servers: [] },
120
+ team_id: 'FAKE-team-estate',
121
+ });
122
+ expect(fake.teams()[0]?.['object_permission']).toEqual({
123
+ mcp_servers: [],
124
+ mcp_toolsets: ['FAKE-toolset-1'],
125
+ vector_stores: ['FAKE-vector'],
126
+ });
127
+ expect(fake.teams()[0]?.['models']).toEqual(['fake-code']);
128
+ });
129
+
130
+ test('a changed field is an update that sends the id and ONLY what changed', async () => {
131
+ const fake = startFakeTeamLitellm();
132
+ const same = stack(fake);
133
+ await same.deploy(declare(estate));
134
+ const planned = await same.deploy(
135
+ declare({
136
+ ...estate,
137
+ blocked: true,
138
+ objectPermission: { ...estate.objectPermission, blockedTools: ['FAKE_docs-danger'] },
139
+ }),
140
+ );
141
+ expect(planned).toEqual({ Estate: 'update' });
142
+ expect(fake.bodies().at(-1)).toEqual({
143
+ blocked: true,
144
+ object_permission: { blocked_tools: ['FAKE_docs-danger'] },
145
+ team_id: 'FAKE-team-estate',
146
+ });
147
+ });
148
+
149
+ test('a proxy that hands mcp_tool_permissions back as a JSON string is still a no-op', async () => {
150
+ const fake = startFakeTeamLitellm({ toolPermissionsAsString: true });
151
+ const same = stack(fake);
152
+ await same.deploy(declare(estate));
153
+ const before = fake.requests().length;
154
+ expect(await same.deploy(declare(estate))).toEqual({ Estate: 'noop' });
155
+ expect(writesOf(fake.requests().slice(before))).toEqual([]);
156
+ });
157
+
158
+ test('access group ids are compared as a set, and only when declared', async () => {
159
+ const fake = startFakeTeamLitellm();
160
+ const same = stack(fake);
161
+ await same.deploy(declare({ ...estate, accessGroupIds: ['FAKE-group-b', 'FAKE-group-a'] }));
162
+ expect(
163
+ await same.deploy(declare({ ...estate, accessGroupIds: ['FAKE-group-a', 'FAKE-group-b'] })),
164
+ ).toEqual({
165
+ Estate: 'noop',
166
+ });
167
+ expect(await same.deploy(declare({ ...estate, accessGroupIds: ['FAKE-group-a'] }))).toEqual({
168
+ Estate: 'update',
169
+ });
170
+ expect(fake.bodies().at(-1)).toEqual({
171
+ access_group_ids: ['FAKE-group-a'],
172
+ team_id: 'FAKE-team-estate',
173
+ });
174
+ });
175
+
176
+ test('a changed declared team id is a replace, create-first, and the old team is retained', async () => {
177
+ const fake = startFakeTeamLitellm();
178
+ const same = stack(fake);
179
+ await same.deploy(declare(estate));
180
+ expect(await same.deploy(declare({ ...estate, teamId: 'FAKE-team-other' }))).toEqual({
181
+ Estate: 'replace',
182
+ });
183
+ expect(fake.teams().map((row) => row['team_id'])).toEqual([
184
+ 'FAKE-team-estate',
185
+ 'FAKE-team-other',
186
+ ]);
187
+ expect(fake.deletedKeys()).toEqual([]);
188
+ });
189
+
190
+ test('a refused declaration fails the plan before a single request', async () => {
191
+ for (const props of [
192
+ { ...estate, teamAlias: ' ' },
193
+ { ...estate, teamId: ' padded' },
194
+ { ...estate, models: ['a', 'a'] },
195
+ { ...estate, accessGroupIds: [''] },
196
+ { ...estate, objectPermission: { mcpServers: ['all-proxy-mcpservers'] } },
197
+ { ...estate, objectPermission: { mcpToolsets: ['x', 'x'] } },
198
+ { ...estate, objectPermission: { mcpToolPermissions: { ' ': ['a'] } } },
199
+ { ...estate, members: [{ userId: 'a' }, { userId: 'a' }] },
200
+ { ...estate, members: [{ role: 'owner' as never, userId: 'a' }] },
201
+ ]) {
202
+ const fake = startFakeTeamLitellm();
203
+ await expect(stack(fake).deploy(declare(props))).rejects.toThrow();
204
+ expect(fake.requests()).toEqual([]);
205
+ }
206
+ });
@@ -0,0 +1,159 @@
1
+ /**
2
+ * `LiteLLM.Team` — one row of LiteLLM's team table (`/team/*`): the models, MCP grants and roster that
3
+ * bound every key of a team. Props, the MCP ceiling and everything left out: team-types.ts.
4
+ *
5
+ * ★ ADOPT BY ID. `teamId` names the live team; without it a deterministic physical name is used. A
6
+ * team with that id and no state is `Unowned`, so it needs `--adopt`. (`team_alias` is not unique, so
7
+ * it cannot identify a team.)
8
+ * ★ `defaultRemovalPolicy: 'retain'` — deleting a team DELETES EVERY KEY OF THE TEAM (team-operations.ts).
9
+ * Opt in with `.pipe(RemovalPolicy.destroy())`, knowing that.
10
+ * ★ A DECLARED FIELD IS THE TRUTH, AN UNDECLARED ONE IS LEFT ALONE. `models`, `blocked`,
11
+ * `accessGroupIds`, each object-permission field and the roster are compared and sent only when
12
+ * declared; the update is a partial one, and the object permission a merge by field (team-permission.ts),
13
+ * so an adopted team keeps everything this resource does not manage.
14
+ * ⛔ THE ROSTER IS ADDITIVE ONLY (team-members.ts): removing a member would delete that user's keys.
15
+ * ⚠️ NO LICENCE GATE ON THE FIELDS IT MANAGES except a member's `admin` role (Enterprise, 400 without a
16
+ * licence: `team_endpoints.py` lines 2713-2723, 3806-3810). Every other Enterprise team field is one
17
+ * this resource never sends (team-types.ts lists them).
18
+ * ⛔ NO LITELLM CREDENTIAL IS A PROP; `litellmProviders`' layer supplies `Credentials`.
19
+ */
20
+ import { Resource } from 'alchemy';
21
+ import { Unowned } from 'alchemy/AdoptPolicy';
22
+ import { isResolved } from 'alchemy/Diff';
23
+ import type { Input } from 'alchemy/Input';
24
+ import { createPhysicalName } from 'alchemy/PhysicalName';
25
+ import * as Provider from 'alchemy/Provider';
26
+ import * as Effect from 'effect/Effect';
27
+ import * as Predicate from 'effect/Predicate';
28
+ import {
29
+ LitellmRegistryAbsentAfterWriteError,
30
+ LitellmRegistryNotConvergedError,
31
+ } from './registry-errors.ts';
32
+ import { dieIfInvalid, failIfInvalid } from './registry-support.ts';
33
+ import { createBody, differing, firstProblem, updateBody } from './team-form.ts';
34
+ import { membersToAdd, roleChanges } from './team-members.ts';
35
+ import {
36
+ addMembers,
37
+ createTeam,
38
+ deleteTeam,
39
+ readTeam,
40
+ setMemberRole,
41
+ updateTeam,
42
+ } from './team-operations.ts';
43
+ import type { TeamAttributes, TeamProps } from './team-types.ts';
44
+
45
+ export type { TeamAttributes, TeamProps };
46
+ export type {
47
+ TeamMember,
48
+ TeamMemberAttributes,
49
+ TeamObjectPermission,
50
+ TeamObjectPermissionAttributes,
51
+ } from './team-types.ts';
52
+ export type { RegistryError as TeamError } from './registry-errors.ts';
53
+
54
+ const RESOURCE = 'LiteLLM.Team';
55
+
56
+ export interface LiteLLMTeam extends Resource<'LiteLLM.Team', TeamProps, TeamAttributes> {}
57
+
58
+ export const LiteLLMTeam = Resource<LiteLLMTeam>('LiteLLM.Team', {
59
+ defaultRemovalPolicy: 'retain',
60
+ });
61
+
62
+ export const isLiteLLMTeam = (value: unknown): value is LiteLLMTeam =>
63
+ Predicate.hasProperty(value, 'Type') && value.Type === 'LiteLLM.Team';
64
+
65
+ /** The team id: the recorded one, else the declared one, else a deterministic physical name. */
66
+ const idOf = (
67
+ id: string,
68
+ instanceId: string,
69
+ props: TeamProps,
70
+ output: TeamAttributes | undefined,
71
+ ) =>
72
+ output?.teamId !== undefined
73
+ ? Effect.succeed(output.teamId)
74
+ : props.teamId !== undefined
75
+ ? Effect.succeed(props.teamId)
76
+ : createPhysicalName({ id, instanceId, lowercase: true, maxLength: 64 });
77
+
78
+ type Args<P> = { id: string; instanceId: string; output: TeamAttributes | undefined } & P;
79
+
80
+ /** ⛔ TEST-ONLY EXPORT. Not on index.ts's barrel. */
81
+ export const teamHandlers = {
82
+ /** ⛔ With no `output` this is the adoption probe, so the refusals run here too (registry-support.ts). */
83
+ read: ({ id, instanceId, olds, output }: Args<{ olds: TeamProps }>) =>
84
+ Effect.gen(function* () {
85
+ if (output === undefined) {
86
+ yield* dieIfInvalid(RESOURCE, String(olds.teamAlias), firstProblem(olds));
87
+ }
88
+ const live = yield* readTeam(yield* idOf(id, instanceId, olds, output));
89
+ if (live === undefined) return undefined;
90
+ return output === undefined ? Unowned(live) : live;
91
+ }),
92
+
93
+ diff: ({ news, output }: { news: Input<TeamProps>; output: TeamAttributes | undefined }) =>
94
+ Effect.gen(function* () {
95
+ if (!isResolved(news)) return undefined;
96
+ yield* failIfInvalid(RESOURCE, String(news.teamAlias), firstProblem(news));
97
+ if (output === undefined) return undefined;
98
+ // The id is identity: a different declared id is a different team.
99
+ if (news.teamId !== undefined && news.teamId !== output.teamId) {
100
+ return { action: 'replace', deleteFirst: false } as const;
101
+ }
102
+ return differing(output, news).length === 0
103
+ ? ({ action: 'noop' } as const)
104
+ : ({ action: 'update' } as const);
105
+ }),
106
+
107
+ reconcile: ({ id, instanceId, news, output }: Args<{ news: TeamProps }>) =>
108
+ Effect.gen(function* () {
109
+ yield* failIfInvalid(RESOURCE, String(news.teamAlias), firstProblem(news));
110
+ const teamId = yield* idOf(id, instanceId, news, output);
111
+ const before = yield* readTeam(teamId);
112
+ if (before === undefined) yield* createTeam(createBody(news, teamId));
113
+ else {
114
+ const body = updateBody(news, before);
115
+ if (body !== undefined) yield* updateTeam(body);
116
+ }
117
+
118
+ // The roster, additively (team-members.ts). Read after the team write so a fresh team is seen.
119
+ if (news.members !== undefined) {
120
+ const live = yield* readTeam(teamId);
121
+ if (live === undefined) {
122
+ return yield* Effect.fail(
123
+ new LitellmRegistryAbsentAfterWriteError({ name: news.teamAlias, resource: RESOURCE }),
124
+ );
125
+ }
126
+ const missing = membersToAdd(live.members, news.members);
127
+ if (missing.length > 0) yield* addMembers(teamId, missing);
128
+ for (const member of roleChanges(live.members, news.members)) {
129
+ yield* setMemberRole(teamId, member);
130
+ }
131
+ }
132
+
133
+ const after = yield* readTeam(teamId);
134
+ if (after === undefined) {
135
+ return yield* Effect.fail(
136
+ new LitellmRegistryAbsentAfterWriteError({ name: news.teamAlias, resource: RESOURCE }),
137
+ );
138
+ }
139
+ const left = differing(after, news);
140
+ if (left.length > 0) {
141
+ return yield* Effect.fail(
142
+ new LitellmRegistryNotConvergedError({
143
+ fields: left,
144
+ name: news.teamAlias,
145
+ resource: RESOURCE,
146
+ }),
147
+ );
148
+ }
149
+ return after;
150
+ }),
151
+
152
+ delete: ({ output }: { output: TeamAttributes }) => deleteTeam(output.teamId),
153
+
154
+ /** ⛔ EMPTY: adoption is an explicit act (`--adopt`), and no ownership mark exists to filter by. */
155
+ list: () => Effect.succeed([]),
156
+ };
157
+
158
+ export const LiteLLMTeamProvider = () =>
159
+ Provider.effect(LiteLLMTeam, Effect.succeed(LiteLLMTeam.Provider.of(teamHandlers)));
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Wire bodies, comparison and refusals for `LiteLLM.ToolPolicy`, testable without a server.
3
+ *
4
+ * ★ THE WRITE IS AN UPSERT. `update_tool_policy` (`db/tool_registry_writer.py`, 1.103.0) upserts on
5
+ * `tool_name`: it CREATES the row when the tool has not been seen (a sent field, else `untrusted`),
6
+ * and on an existing row updates only the fields that are sent. So there is no separate create.
7
+ */
8
+ import type * as tools from '@distilled.cloud/litellm/tools';
9
+ import { asRow, isBlank } from './registry-support.ts';
10
+ import {
11
+ INPUT_POLICIES,
12
+ OUTPUT_POLICIES,
13
+ type ToolPolicyAttributes,
14
+ type ToolPolicyProps,
15
+ } from './tool-policy-types.ts';
16
+
17
+ /** Names the route table hands to another route before `GET /v1/tool/{tool_name:path}` sees them. */
18
+ const shadowed = (name: string): boolean =>
19
+ name === 'list' ||
20
+ name === 'spend' ||
21
+ name === 'policy/options' ||
22
+ ['/detail', '/logs'].some((suffix) => name.endsWith(suffix));
23
+
24
+ /** The first reason a declaration is refused, or `undefined`. Runs before any request. */
25
+ export const firstProblem = (props: ToolPolicyProps): string | undefined => {
26
+ if (isBlank(props.toolName) || props.toolName !== props.toolName.trim()) {
27
+ return '`toolName` must be a non-blank name with no leading or trailing space';
28
+ }
29
+ if (shadowed(props.toolName)) {
30
+ return '`toolName` is one the /v1/tool route table answers itself (list, spend, policy/options, …/detail, …/logs), so it could never be read back';
31
+ }
32
+ if (props.inputPolicy === undefined && props.outputPolicy === undefined) {
33
+ return 'declare `inputPolicy`, `outputPolicy` or both (LiteLLM answers 400 to neither)';
34
+ }
35
+ if (props.inputPolicy !== undefined && !INPUT_POLICIES.includes(props.inputPolicy)) {
36
+ return `\`inputPolicy\` must be one of ${INPUT_POLICIES.join(', ')}`;
37
+ }
38
+ if (props.outputPolicy !== undefined && !OUTPUT_POLICIES.includes(props.outputPolicy)) {
39
+ return `\`outputPolicy\` must be one of ${OUTPUT_POLICIES.join(', ')}`;
40
+ }
41
+ return undefined;
42
+ };
43
+
44
+ /** One tool row. `undefined` is "not a tool row". A missing policy reads as LiteLLM's default. */
45
+ export const toAttributes = (value: unknown): ToolPolicyAttributes | undefined => {
46
+ const row = asRow(value);
47
+ if (row === undefined) return undefined;
48
+ const toolId = row['tool_id'];
49
+ const toolName = row['tool_name'];
50
+ if (typeof toolId !== 'string' || typeof toolName !== 'string') return undefined;
51
+ const policy = (field: string): string =>
52
+ typeof row[field] === 'string' && row[field] !== '' ? row[field] : 'untrusted';
53
+ return {
54
+ inputPolicy: policy('input_policy'),
55
+ outputPolicy: policy('output_policy'),
56
+ toolId,
57
+ toolName,
58
+ };
59
+ };
60
+
61
+ /** Wire names of the DECLARED fields where live and declared disagree. */
62
+ export const differing = (
63
+ live: ToolPolicyAttributes,
64
+ props: ToolPolicyProps,
65
+ ): readonly string[] => {
66
+ const fields: string[] = [];
67
+ if (props.inputPolicy !== undefined && live.inputPolicy !== props.inputPolicy) {
68
+ fields.push('input_policy');
69
+ }
70
+ if (props.outputPolicy !== undefined && live.outputPolicy !== props.outputPolicy) {
71
+ fields.push('output_policy');
72
+ }
73
+ return fields;
74
+ };
75
+
76
+ /**
77
+ * The write: the declared fields that differ (all declared ones when the tool row is new). ⚠️ NEVER a
78
+ * `team_id` or `key_hash` — those turn the call into an override of another object's `blocked_tools`.
79
+ */
80
+ export const updateBody = (
81
+ props: ToolPolicyProps,
82
+ live: ToolPolicyAttributes | undefined,
83
+ ): tools.UpdateToolPolicyV1ToolPolicyPostRequest => {
84
+ const changed = live === undefined ? undefined : new Set(differing(live, props));
85
+ return {
86
+ tool_name: props.toolName,
87
+ ...(props.inputPolicy !== undefined && (changed === undefined || changed.has('input_policy'))
88
+ ? { input_policy: props.inputPolicy }
89
+ : {}),
90
+ ...(props.outputPolicy !== undefined && (changed === undefined || changed.has('output_policy'))
91
+ ? { output_policy: props.outputPolicy }
92
+ : {}),
93
+ };
94
+ };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The two LiteLLM `/v1/tool*` calls `LiteLLM.ToolPolicy` uses, through the SDK's typed operations in
3
+ * `@distilled.cloud/litellm/tools` (LiteLLM 1.103.0):
4
+ *
5
+ * read `getToolV1ToolToolNameGet` GET /v1/tool/{tool_name:path}
6
+ * write `updateToolPolicyV1ToolPolicyPost` POST /v1/tool/policy (an UPSERT on tool_name)
7
+ *
8
+ * ⛔ A READ THAT SAYS "NOT FOUND" IS NOT PROOF OF ABSENCE. `db_get_tool` (`db/tool_registry_writer.py`)
9
+ * wraps its query in `except Exception: log; return None`, and the route turns `None` into a 404, so a
10
+ * database error reads exactly like a tool that was never seen. Nothing here depends on it: the write
11
+ * is an upsert, so a wrong "absent" ends in a write that succeeds or fails loudly, and the read back
12
+ * after it is what the deploy reports.
13
+ * ⛔ THERE IS NO DELETE ROUTE for a tool row or for its global policy: `DELETE /v1/tool/{name}/overrides`
14
+ * removes only a team or key override. So this resource's delete RESETS the fields it managed to
15
+ * LiteLLM's default (`untrusted`), it does not remove a row. It is a write, so it runs only when the
16
+ * stack opts in (`retain` is the default), and only for a field that is not already the default.
17
+ * ⛔ NO MESSAGE SNIFFING: absence is the SDK's `NotFound` CLASS (registry-support.ts) and nothing else.
18
+ */
19
+ import * as tools from '@distilled.cloud/litellm/tools';
20
+ import * as Effect from 'effect/Effect';
21
+ import { throughFetch } from './operations.ts';
22
+ import { bodyOf, isNotFound } from './registry-support.ts';
23
+ import { toAttributes } from './tool-policy-form.ts';
24
+ import { DEFAULT_TOOL_POLICY, type ToolPolicyProps } from './tool-policy-types.ts';
25
+
26
+ /** One tool by name, or `undefined` when the proxy has no such row (see the file header). */
27
+ export const readTool = (toolName: string) =>
28
+ throughFetch(tools.getToolV1ToolToolNameGet({ tool_name: toolName })).pipe(
29
+ Effect.map((response) => {
30
+ const row = toAttributes(bodyOf(response));
31
+ return row?.toolName === toolName ? row : undefined;
32
+ }),
33
+ Effect.catch((error) => (isNotFound(error) ? Effect.succeed(undefined) : Effect.fail(error))),
34
+ );
35
+
36
+ export const writeToolPolicy = (body: tools.UpdateToolPolicyV1ToolPolicyPostRequest) =>
37
+ throughFetch(tools.updateToolPolicyV1ToolPolicyPost(body)).pipe(Effect.asVoid);
38
+
39
+ /**
40
+ * The delete: reset each managed field that is not already the default, and nothing else. A tool the
41
+ * proxy does not know, or one already at the defaults, sends no request (an empty body would be a 400).
42
+ */
43
+ export const resetToolPolicy = (props: ToolPolicyProps) =>
44
+ readTool(props.toolName).pipe(
45
+ Effect.flatMap((live) => {
46
+ if (live === undefined) return Effect.void;
47
+ const inputStale =
48
+ props.inputPolicy !== undefined && live.inputPolicy !== DEFAULT_TOOL_POLICY;
49
+ const outputStale =
50
+ props.outputPolicy !== undefined && live.outputPolicy !== DEFAULT_TOOL_POLICY;
51
+ if (!inputStale && !outputStale) return Effect.void;
52
+ return writeToolPolicy({
53
+ tool_name: props.toolName,
54
+ ...(inputStale ? { input_policy: DEFAULT_TOOL_POLICY } : {}),
55
+ ...(outputStale ? { output_policy: DEFAULT_TOOL_POLICY } : {}),
56
+ });
57
+ }),
58
+ );
@@ -0,0 +1,48 @@
1
+ /**
2
+ * What a `LiteLLM.ToolPolicy` declares (props) and what is remembered about it (attributes).
3
+ *
4
+ * ★ A TOOL POLICY IS THE TRUST SETTING OF ONE TOOL in `LiteLLM_ToolTable` (`/v1/tool/policy`): an
5
+ * input policy (`untrusted`, `trusted`, `blocked`) and an output policy (`untrusted`, `trusted`).
6
+ * LiteLLM DISCOVERS tools as requests use them and gives each `untrusted`/`untrusted`
7
+ * (`TOOL_POLICY_OPTIONS`, `tool_management_endpoints.py`, 1.103.0); this resource sets them.
8
+ * ⛔ IT DOES NOTHING UNTIL THE `tool_policy` GUARDRAIL IS CONFIGURED. The rows are data; only
9
+ * `guardrails/guardrail_hooks/tool_policy/tool_policy_guardrail.py` reads them, and it is a guardrail
10
+ * the proxy's own config must enable (`guardrails: - guardrail_name: tool_policy, litellm_params:
11
+ * { guardrail: tool_policy, mode: post_call }`, its module docstring). Declaring a policy without it
12
+ * is an inert row, not a control. Measured 2026-09-30: the rendered CT100 config has no
13
+ * `tool_policy` guardrail (count 0), so on that proxy today these rows are not enforced.
14
+ * ⚠️ NOT MODELLED: the team and key OVERRIDES of `POST /v1/tool/policy` (`team_id`, `key_hash`). An
15
+ * override is stored as an entry of that team's or key's `object_permission.blocked_tools`
16
+ * (`add_tool_to_object_permission_blocked`), the same list `LiteLLM.Team` manages through
17
+ * `objectPermission.blockedTools`; two resources writing one list would fight. Block a tool for a
18
+ * team there, and for a key on the key.
19
+ */
20
+ export type ToolInputPolicy = 'untrusted' | 'trusted' | 'blocked';
21
+ export type ToolOutputPolicy = 'untrusted' | 'trusted';
22
+
23
+ export interface ToolPolicyProps {
24
+ /**
25
+ * The tool's name as LiteLLM records it (for an MCP tool, `<server prefix>-<tool>`). Changing it is
26
+ * a DIFFERENT tool, so it is a replace. Refused if it is one of the names the route table shadows
27
+ * (`list`, `spend`, `policy/options`) or ends in `/detail` or `/logs`: the read is
28
+ * `GET /v1/tool/{tool_name:path}`, which those routes are registered before.
29
+ */
30
+ readonly toolName: string;
31
+ /** Compared and sent only when declared. Declare at least one of the two. */
32
+ readonly inputPolicy?: ToolInputPolicy;
33
+ /** Compared and sent only when declared. Declare at least one of the two. */
34
+ readonly outputPolicy?: ToolOutputPolicy;
35
+ }
36
+
37
+ export interface ToolPolicyAttributes {
38
+ readonly toolName: string;
39
+ readonly toolId: string;
40
+ /** What the row carries, as a string: a later LiteLLM may add a value this package does not know. */
41
+ readonly inputPolicy: string;
42
+ readonly outputPolicy: string;
43
+ }
44
+
45
+ /** What LiteLLM gives a newly discovered tool, and what `delete` resets a managed field to. */
46
+ export const DEFAULT_TOOL_POLICY = 'untrusted';
47
+ export const INPUT_POLICIES: readonly ToolInputPolicy[] = ['untrusted', 'trusted', 'blocked'];
48
+ export const OUTPUT_POLICIES: readonly ToolOutputPolicy[] = ['untrusted', 'trusted'];