@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,150 @@
1
+ /**
2
+ * `LiteLLM.Team`'s roster (additive only) and its delete (which deletes the team's keys), over the fake
3
+ * proxy (`fake-team-litellm.ts`).
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 FakeTeamLitellm, startFakeTeamLitellm, teamRow } from './fake-team-litellm.ts';
16
+ import { fakeStack, writesOf } from './fake-stack.ts';
17
+ import { LiteLLMTeam } from './team.ts';
18
+ import { deleteTeam } from './team-operations.ts';
19
+ import type { TeamProps } from './team-types.ts';
20
+
21
+ const stack = (fake: FakeTeamLitellm) =>
22
+ fakeStack({ apiKey: FAKE_KEY, baseUrl: FAKE_BASE }, fake.fetch);
23
+ const declare = (props: TeamProps, name = 'Estate') =>
24
+ Effect.gen(function* () {
25
+ yield* LiteLLMTeam(name, props);
26
+ });
27
+
28
+ const seats: TeamProps = {
29
+ members: [{ userId: 'FAKE-user-a' }, { userId: 'FAKE-user-b' }],
30
+ teamAlias: 'FAKE-seats',
31
+ teamId: 'FAKE-team-seats',
32
+ };
33
+
34
+ const roster = (fake: FakeTeamLitellm) => {
35
+ const members = (fake.teams()[0]?.['members_with_roles'] ?? []) as {
36
+ user_id: string;
37
+ role: string;
38
+ }[];
39
+ return members.map((member) => `${member.user_id}:${member.role}`);
40
+ };
41
+
42
+ test('adds the declared members in ONE call, and the caller LiteLLM auto-adds as admin is not drift', async () => {
43
+ const fake = startFakeTeamLitellm();
44
+ const same = stack(fake);
45
+ expect(await same.deploy(declare(seats))).toEqual({ Estate: 'create' });
46
+ expect(roster(fake)).toEqual(['default_user_id:admin', 'FAKE-user-a:user', 'FAKE-user-b:user']);
47
+ expect(fake.requests().filter((each) => each.path === '/team/member_add')).toHaveLength(1);
48
+ const before = fake.requests().length;
49
+ expect(await same.deploy(declare(seats))).toEqual({ Estate: 'noop' });
50
+ expect(writesOf(fake.requests().slice(before))).toEqual([]);
51
+ });
52
+
53
+ test('a new member on an existing roster is added alone, and nobody is ever removed', async () => {
54
+ const fake = startFakeTeamLitellm();
55
+ const same = stack(fake);
56
+ await same.deploy(declare(seats));
57
+ await same.deploy(declare({ ...seats, members: [{ userId: 'FAKE-user-c' }] }));
58
+ // ★ user-a and user-b are not declared any more and are still there
59
+ expect(roster(fake)).toEqual([
60
+ 'default_user_id:admin',
61
+ 'FAKE-user-a:user',
62
+ 'FAKE-user-b:user',
63
+ 'FAKE-user-c:user',
64
+ ]);
65
+ expect(fake.requests().some((each) => each.path === '/team/member_delete')).toBe(false);
66
+ });
67
+
68
+ test('a member with another role is updated through member_update, not re-added', async () => {
69
+ const live = teamRow({
70
+ members_with_roles: [{ role: 'admin', user_email: null, user_id: 'FAKE-user-a' }],
71
+ team_alias: 'FAKE-seats',
72
+ team_id: 'FAKE-team-seats',
73
+ });
74
+ const fake = startFakeTeamLitellm({ seed: [live] });
75
+ await stack(fake).deploy(
76
+ declare({ ...seats, members: [{ role: 'user', userId: 'FAKE-user-a' }] }),
77
+ {
78
+ adopt: true,
79
+ },
80
+ );
81
+ expect(fake.requests().some((each) => each.path === '/team/member_add')).toBe(false);
82
+ expect(fake.requests().filter((each) => each.path === '/team/member_update')).toHaveLength(1);
83
+ expect(roster(fake)).toEqual(['FAKE-user-a:user']);
84
+ });
85
+
86
+ test('an admin member on a proxy without a licence fails the deploy and leaves the roster as it was', async () => {
87
+ // ⛔ measured in the source: team_endpoints.py lines 2713-2723 and 3806-3810 (Enterprise)
88
+ const fake = startFakeTeamLitellm({ community: true });
89
+ await expect(
90
+ stack(fake).deploy(declare({ ...seats, members: [{ role: 'admin', userId: 'FAKE-user-a' }] })),
91
+ ).rejects.toThrow();
92
+ expect(roster(fake)).toEqual(['default_user_id:admin']);
93
+ });
94
+
95
+ test('the same declaration on a licensed proxy adds the admin', async () => {
96
+ const fake = startFakeTeamLitellm({ community: false });
97
+ await stack(fake).deploy(
98
+ declare({ ...seats, members: [{ role: 'admin', userId: 'FAKE-user-a' }] }),
99
+ );
100
+ expect(roster(fake)).toContain('FAKE-user-a:admin');
101
+ });
102
+
103
+ test('undeclared members leave the roster alone: no member_add and no read-back drift', async () => {
104
+ const fake = startFakeTeamLitellm();
105
+ await stack(fake).deploy(declare({ teamAlias: 'FAKE-seats', teamId: 'FAKE-team-seats' }));
106
+ expect(fake.requests().some((each) => each.path === '/team/member_add')).toBe(false);
107
+ });
108
+
109
+ test('removing the declaration RETAINS the team and its keys', async () => {
110
+ const fake = startFakeTeamLitellm();
111
+ const same = stack(fake);
112
+ await same.deploy(declare(seats));
113
+ await same.deploy(Effect.void);
114
+ expect(fake.teams()).toHaveLength(1);
115
+ expect(fake.deletedKeys()).toEqual([]);
116
+ });
117
+
118
+ const run = <A, E>(fetchFn: typeof globalThis.fetch, effect: Effect.Effect<A, E, unknown>) =>
119
+ Effect.runPromise(
120
+ effect.pipe(
121
+ Effect.provide(FetchHttpClient.layer),
122
+ Effect.provide(Layer.succeed(FetchHttpClient.Fetch, fetchFn)),
123
+ Effect.provide(credentials({ apiKey: FAKE_KEY, baseUrl: FAKE_BASE })),
124
+ ) as Effect.Effect<A, E, never>,
125
+ );
126
+
127
+ test('delete removes the team AND records that LiteLLM deleted its keys', async () => {
128
+ const fake = startFakeTeamLitellm({
129
+ seed: [teamRow({ team_alias: 'FAKE-seats', team_id: 'FAKE-team-seats' })],
130
+ });
131
+ await run(fake.fetch, deleteTeam('FAKE-team-seats'));
132
+ expect(fake.teams()).toEqual([]);
133
+ expect(fake.deletedKeys()).toEqual(['FAKE-team-seats']);
134
+ });
135
+
136
+ test('delete of a team that is gone is swallowed only because /team/list confirms it', async () => {
137
+ const fake = startFakeTeamLitellm();
138
+ await run(fake.fetch, deleteTeam('FAKE-team-gone'));
139
+ expect(fake.requests().map((each) => each.path)).toEqual(['/team/delete', '/team/list']);
140
+ });
141
+
142
+ test('a 404 for a team that is still listed (a swallowed database error) re-raises the ORIGINAL error', async () => {
143
+ // ⛔ measured in the source: /team/delete answers 404 for any exception on its lookup
144
+ const fake = startFakeTeamLitellm({
145
+ deleteLies: true,
146
+ seed: [teamRow({ team_alias: 'FAKE-seats', team_id: 'FAKE-team-seats' })],
147
+ });
148
+ await expect(run(fake.fetch, deleteTeam('FAKE-team-seats'))).rejects.toThrow();
149
+ expect(fake.teams()).toHaveLength(1);
150
+ });
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The member roster half of `LiteLLM.Team`: reading it, and what a declared roster still needs.
3
+ *
4
+ * ⛔ ADDITIVE ONLY, AND THAT IS A SAFETY RULE, NOT A SHORTCUT. `/team/member_delete` does not only take a
5
+ * user off the roster: it also DELETES every virtual key that user created for the team
6
+ * (`litellm_verificationtoken.delete_many` where `user_id` and `team_id`, `team_endpoints.py`
7
+ * lines 3701-3748, 1.103.0). A seat's key would vanish with a roster edit. So a live member the declaration does not
8
+ * list is never removed and never an error; `delete` on the team is the only removal, and it too
9
+ * deletes the team's keys (team.ts).
10
+ * ★ A ROLE IS CHANGED THROUGH `/team/member_update`, which rewrites the roster entry under the team's
11
+ * advisory lock. `admin` is Enterprise on both routes (`team_endpoints.py` lines 2713-2723 and
12
+ * 3806-3810): a proxy without a licence answers 400, the deploy fails with it, and the roster stays
13
+ * as it was.
14
+ * ⚠️ A NEW USER ID CREATES A USER ROW (`add_new_member`), and only PROXY_ADMIN may name an id that has no
15
+ * user yet (`_validate_member_user_id_provisioning`, 403 otherwise).
16
+ */
17
+ import { asRow } from './registry-support.ts';
18
+ import type { TeamMember, TeamMemberAttributes } from './team-types.ts';
19
+
20
+ /** The roster of a `team_info` row. An entry with no `user_id` (an email-only invite) is skipped. */
21
+ export const toMemberAttributes = (value: unknown): readonly TeamMemberAttributes[] => {
22
+ if (!Array.isArray(value)) return [];
23
+ const members: TeamMemberAttributes[] = [];
24
+ for (const entry of value) {
25
+ const row = asRow(entry);
26
+ if (typeof row?.['user_id'] === 'string' && row['user_id'] !== '') {
27
+ members.push({
28
+ role: typeof row['role'] === 'string' ? row['role'] : 'user',
29
+ userId: row['user_id'],
30
+ });
31
+ }
32
+ }
33
+ return members.sort((a, b) => a.userId.localeCompare(b.userId));
34
+ };
35
+
36
+ const roleOf = (member: TeamMember): string => member.role ?? 'user';
37
+
38
+ /** Declared members that are not on the live roster at all. */
39
+ export const membersToAdd = (
40
+ live: readonly TeamMemberAttributes[],
41
+ declared: readonly TeamMember[] | undefined,
42
+ ): readonly TeamMember[] =>
43
+ (declared ?? []).filter((member) => !live.some((each) => each.userId === member.userId));
44
+
45
+ /** Declared members that are on the roster with another role. */
46
+ export const roleChanges = (
47
+ live: readonly TeamMemberAttributes[],
48
+ declared: readonly TeamMember[] | undefined,
49
+ ): readonly TeamMember[] =>
50
+ (declared ?? []).filter((member) =>
51
+ live.some((each) => each.userId === member.userId && each.role !== roleOf(member)),
52
+ );
53
+
54
+ /** Whether the declared roster is fully present. Extra live members do not count. */
55
+ export const rosterPending = (
56
+ live: readonly TeamMemberAttributes[],
57
+ declared: readonly TeamMember[] | undefined,
58
+ ): boolean => membersToAdd(live, declared).length + roleChanges(live, declared).length > 0;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * The seven LiteLLM `/team/*` calls `LiteLLM.Team` uses, through the SDK's typed operations in
3
+ * `@distilled.cloud/litellm/team_management` (LiteLLM 1.103.0):
4
+ *
5
+ * read `getTeamInfoTeamInfo` GET /team/info?team_id=
6
+ * list `listTeamTeamListGet` GET /team/list (only to confirm a delete)
7
+ * create `postNewTeamTeamNew` POST /team/new
8
+ * update `updateTeamTeamUpdatePost` POST /team/update
9
+ * add `teamMemberAddTeamMemberAddPost` POST /team/member_add
10
+ * role `teamMemberUpdateTeamMemberUpdatePost` POST /team/member_update
11
+ * delete `deleteTeamTeamDeletePost` POST /team/delete
12
+ *
13
+ * ⛔ A "NOT FOUND" FROM `/team/info` IS NOT PROOF OF ABSENCE. Its lookup sits in `try … except Exception:
14
+ * raise HTTPException(404)` (`team_endpoints.py`, 1.103.0), so a database error answers exactly like a
15
+ * missing team, and `/team/delete` does the same. The SDK declares no 404 for `/team/info`; a 404
16
+ * decodes at run time as its `NotFound` class, which `readTeam` tests by CLASS (registry-support.ts,
17
+ * never a message). A wrong "absent" can only end in a `create`, which a duplicate team id turns into a
18
+ * 400 that fails the deploy; nothing is written on a guess.
19
+ * ⛔ DELETE DELETES THE TEAM'S KEYS (`delete_team`, `team_endpoints.py` line 4258: "delete team and associated team
20
+ * keys", and `prisma_client.delete_data(team_id_list=…, table_name="key")` at line 4374). It is the single most destructive
21
+ * call in this family, and the reason the resource defaults to `retain`.
22
+ * ★ DELETE IS IDEMPOTENT ONLY AFTER A REAL READ THAT CANNOT LIE. The SDK types `NotFound` for
23
+ * `/team/delete` (a distilled patch), so it is caught with `catchTag`; but the route's own 404 also
24
+ * covers a database error, so success is reported only when `/team/list` (a `find_many`, whose
25
+ * failures are not swallowed) no longer has the id. A team still listed re-raises the ORIGINAL error.
26
+ */
27
+ import * as team from '@distilled.cloud/litellm/team_management';
28
+ import * as Effect from 'effect/Effect';
29
+ import { throughFetch } from './operations.ts';
30
+ import { asRow, bodyOf, isNotFound } from './registry-support.ts';
31
+ import { toAttributes } from './team-form.ts';
32
+ import type { TeamMember } from './team-types.ts';
33
+
34
+ /** One team BY ID, or `undefined` when the proxy has no such team (see the file header). */
35
+ export const readTeam = (teamId: string) =>
36
+ throughFetch(team.getTeamInfoTeamInfo({ team_id: teamId })).pipe(
37
+ Effect.map((response) => {
38
+ const row = toAttributes(bodyOf(response));
39
+ return row?.teamId === teamId ? row : undefined;
40
+ }),
41
+ Effect.catch((error) => (isNotFound(error) ? Effect.succeed(undefined) : Effect.fail(error))),
42
+ );
43
+
44
+ export const createTeam = (body: team.PostNewTeamTeamNewRequest) =>
45
+ throughFetch(team.postNewTeamTeamNew(body)).pipe(Effect.asVoid);
46
+
47
+ export const updateTeam = (body: team.UpdateTeamTeamUpdatePostRequest) =>
48
+ throughFetch(team.updateTeamTeamUpdatePost(body)).pipe(Effect.asVoid);
49
+
50
+ /** One call adds every missing member; LiteLLM skips a user already on the roster. */
51
+ export const addMembers = (teamId: string, members: readonly TeamMember[]) =>
52
+ throughFetch(
53
+ team.teamMemberAddTeamMemberAddPost({
54
+ member: members.map((member) => ({ role: member.role ?? 'user', user_id: member.userId })),
55
+ team_id: teamId,
56
+ }),
57
+ ).pipe(Effect.asVoid);
58
+
59
+ export const setMemberRole = (teamId: string, member: TeamMember) =>
60
+ throughFetch(
61
+ team.teamMemberUpdateTeamMemberUpdatePost({
62
+ role: member.role ?? 'user',
63
+ team_id: teamId,
64
+ user_id: member.userId,
65
+ }),
66
+ ).pipe(Effect.asVoid);
67
+
68
+ /** Every team id on the proxy. ⚠️ HEAVY: `/team/list` also loads each team's keys. Used only on the delete path. */
69
+ const listTeamIds = () =>
70
+ throughFetch(team.listTeamTeamListGet({})).pipe(
71
+ Effect.map((response) => {
72
+ const rows: unknown = bodyOf(response);
73
+ return Array.isArray(rows)
74
+ ? rows.flatMap((row) => {
75
+ const id = asRow(row)?.['team_id'];
76
+ return typeof id === 'string' ? [id] : [];
77
+ })
78
+ : [];
79
+ }),
80
+ );
81
+
82
+ export const deleteTeam = (teamId: string) =>
83
+ throughFetch(team.deleteTeamTeamDeletePost({ team_ids: [teamId] })).pipe(
84
+ Effect.asVoid,
85
+ Effect.catchTag('NotFound', (original) =>
86
+ listTeamIds().pipe(
87
+ Effect.flatMap((ids) => (ids.includes(teamId) ? Effect.fail(original) : Effect.void)),
88
+ ),
89
+ ),
90
+ );
@@ -0,0 +1,159 @@
1
+ /**
2
+ * The `object_permission` half of `LiteLLM.Team`: reading it, comparing it, and the body that writes it.
3
+ *
4
+ * ★ THE WRITE IS A MERGE BY TOP-LEVEL FIELD (measured, `object_permission_utils.py` lines 114-118,
5
+ * 1.103.0, read from the live container): `prepare_object_permission_upsert` builds
6
+ * `{**existing_fields, **new_object_permission}`, so a field the request leaves out KEEPS its stored
7
+ * value, and a field sent as `[]` (or `{}`) REPLACES it with an empty one. That is what lets this
8
+ * resource manage five fields and leave the other seven of an adopted team alone. docs.litellm.ai/docs/
9
+ * mcp_grant_access says the same: "unset fields are left unchanged on update".
10
+ * ★ NULL AND `[]` ARE THE SAME "NOTHING GRANTED". A team that never had a grant reads `null` or `[]`
11
+ * (`LiteLLM_ObjectPermissionTable` defaults), so both normalise to an empty list before comparing.
12
+ * ⚠️ `mcp_tool_permissions` CAN COME BACK AS A JSON STRING (it is stored through `safe_dumps` "for
13
+ * GraphQL compatibility", and `_resolve_team_allowed_mcp_servers` itself handles both), so the read
14
+ * accepts an object or a string.
15
+ * ⚠️ THE SERVER REFUSES, AND THIS FILE DOES NOT REPEAT IT: a name or alias that matches several MCP
16
+ * servers cannot key `mcp_tool_permissions` (400, `reject_ambiguous_mcp_tool_permission_keys`), and a
17
+ * non-admin caller cannot grant `all-proxy-mcpservers` (403). The one refusal made here is that
18
+ * sentinel, because it silently grants every server on the proxy and is not something a declaration
19
+ * should carry by accident.
20
+ */
21
+ import type * as team from '@distilled.cloud/litellm/team_management';
22
+ import {
23
+ asRow,
24
+ canonical,
25
+ firstBadEntry,
26
+ firstDuplicate,
27
+ isBlank,
28
+ sameSet,
29
+ stringsOf,
30
+ } from './registry-support.ts';
31
+ import type { TeamObjectPermission, TeamObjectPermissionAttributes } from './team-types.ts';
32
+
33
+ /** The grant that reaches every MCP server on the proxy (`SpecialMCPServerName.all_proxy_servers`). */
34
+ const ALL_PROXY_SERVERS = 'all-proxy-mcpservers';
35
+
36
+ const LISTS = [
37
+ ['mcpServers', 'mcp_servers'],
38
+ ['mcpAccessGroups', 'mcp_access_groups'],
39
+ ['mcpToolsets', 'mcp_toolsets'],
40
+ ['blockedTools', 'blocked_tools'],
41
+ ] as const;
42
+
43
+ const parseToolPermissions = (value: unknown): Readonly<Record<string, readonly string[]>> => {
44
+ const parsed: unknown = typeof value === 'string' ? safeJson(value) : value;
45
+ const row = asRow(parsed);
46
+ if (row === undefined) return {};
47
+ return Object.fromEntries(
48
+ Object.keys(row)
49
+ .sort()
50
+ .map((server) => [server, canonical(stringsOf(row[server]))]),
51
+ );
52
+ };
53
+
54
+ const safeJson = (text: string): unknown => {
55
+ try {
56
+ return JSON.parse(text);
57
+ } catch {
58
+ return undefined;
59
+ }
60
+ };
61
+
62
+ /** A live `object_permission` (or `null`) as this resource compares it. */
63
+ export const toPermissionAttributes = (value: unknown): TeamObjectPermissionAttributes => {
64
+ const row = asRow(value);
65
+ return {
66
+ blockedTools: canonical(stringsOf(row?.['blocked_tools'])),
67
+ mcpAccessGroups: canonical(stringsOf(row?.['mcp_access_groups'])),
68
+ mcpServers: canonical(stringsOf(row?.['mcp_servers'])),
69
+ mcpToolPermissions: parseToolPermissions(row?.['mcp_tool_permissions']),
70
+ mcpToolsets: canonical(stringsOf(row?.['mcp_toolsets'])),
71
+ };
72
+ };
73
+
74
+ const sameToolPermissions = (
75
+ live: Readonly<Record<string, readonly string[]>>,
76
+ declared: Readonly<Record<string, readonly string[]>>,
77
+ ): boolean => {
78
+ const servers = Object.keys(declared).sort();
79
+ return (
80
+ sameSet(Object.keys(live), servers) &&
81
+ servers.every((server) => sameSet(live[server] ?? [], declared[server] ?? []))
82
+ );
83
+ };
84
+
85
+ /** Wire names of the DECLARED fields where live and declared disagree. An undeclared field never counts. */
86
+ export const permissionDiffers = (
87
+ live: TeamObjectPermissionAttributes,
88
+ declared: TeamObjectPermission | undefined,
89
+ ): readonly string[] => {
90
+ if (declared === undefined) return [];
91
+ const fields: string[] = [];
92
+ for (const [prop, wire] of LISTS) {
93
+ const wanted = declared[prop];
94
+ if (wanted !== undefined && !sameSet(live[prop], wanted)) fields.push(wire);
95
+ }
96
+ if (
97
+ declared.mcpToolPermissions !== undefined &&
98
+ !sameToolPermissions(live.mcpToolPermissions, declared.mcpToolPermissions)
99
+ ) {
100
+ fields.push('mcp_tool_permissions');
101
+ }
102
+ return fields;
103
+ };
104
+
105
+ /**
106
+ * The `object_permission` body: the declared fields named in `only` (all of them when `only` is
107
+ * absent, for a create). ⛔ Never a `null`: a merge would read it as "clear", and the declaration said
108
+ * a list.
109
+ */
110
+ export const permissionBody = (
111
+ declared: TeamObjectPermission,
112
+ only?: ReadonlySet<string>,
113
+ ): team.LiteLLMObjectPermissionBase => {
114
+ const body: Record<string, unknown> = {};
115
+ for (const [prop, wire] of LISTS) {
116
+ const wanted = declared[prop];
117
+ if (wanted !== undefined && (only === undefined || only.has(wire))) body[wire] = [...wanted];
118
+ }
119
+ if (
120
+ declared.mcpToolPermissions !== undefined &&
121
+ (only === undefined || only.has('mcp_tool_permissions'))
122
+ ) {
123
+ body['mcp_tool_permissions'] = Object.fromEntries(
124
+ Object.entries(declared.mcpToolPermissions).map(([server, tools]) => [server, [...tools]]),
125
+ );
126
+ }
127
+ return body as team.LiteLLMObjectPermissionBase;
128
+ };
129
+
130
+ /** The first reason a declared object permission is refused, or `undefined`. */
131
+ export const permissionProblem = (
132
+ declared: TeamObjectPermission | undefined,
133
+ ): string | undefined => {
134
+ if (declared === undefined) return undefined;
135
+ for (const [prop] of LISTS) {
136
+ const values = declared[prop] ?? [];
137
+ const bad = firstBadEntry(values);
138
+ if (bad !== undefined)
139
+ return `\`objectPermission.${prop}\` has a blank or padded entry (${JSON.stringify(bad)})`;
140
+ const twice = firstDuplicate(values);
141
+ if (twice !== undefined)
142
+ return `\`objectPermission.${prop}\` lists ${JSON.stringify(twice)} twice`;
143
+ }
144
+ if ((declared.mcpServers ?? []).includes(ALL_PROXY_SERVERS)) {
145
+ return `\`objectPermission.mcpServers\` carries \`${ALL_PROXY_SERVERS}\`, which grants EVERY MCP server on the proxy; list the servers instead`;
146
+ }
147
+ for (const [server, tools] of Object.entries(declared.mcpToolPermissions ?? {})) {
148
+ if (isBlank(server) || server !== server.trim()) {
149
+ return '`objectPermission.mcpToolPermissions` has a blank or padded server key';
150
+ }
151
+ const bad = firstBadEntry(tools);
152
+ if (bad !== undefined)
153
+ return `\`objectPermission.mcpToolPermissions\` lists a blank or padded tool for ${server}`;
154
+ const twice = firstDuplicate(tools);
155
+ if (twice !== undefined)
156
+ return `\`objectPermission.mcpToolPermissions\` lists ${JSON.stringify(twice)} twice for ${server}`;
157
+ }
158
+ return undefined;
159
+ };
@@ -0,0 +1,89 @@
1
+ /**
2
+ * `LiteLLM.Team`'s READ: what a lying `/team/info` and a proxy that drops an edit do to a deploy, and what
3
+ * the read must never copy. Over the fake proxy (`fake-team-litellm.ts`).
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 FakeTeamLitellm, startFakeTeamLitellm, teamRow } from './fake-team-litellm.ts';
16
+ import { fakeStack } from './fake-stack.ts';
17
+ import { LiteLLMTeam, teamHandlers } from './team.ts';
18
+ import type { TeamProps } from './team-types.ts';
19
+
20
+ const stack = (fake: FakeTeamLitellm) =>
21
+ fakeStack({ apiKey: FAKE_KEY, baseUrl: FAKE_BASE }, fake.fetch);
22
+ const declare = (props: TeamProps, name = 'Estate') =>
23
+ Effect.gen(function* () {
24
+ yield* LiteLLMTeam(name, props);
25
+ });
26
+
27
+ const estate: TeamProps = {
28
+ models: ['fake-code'],
29
+ teamAlias: 'FAKE-estate',
30
+ teamId: 'FAKE-team-estate',
31
+ };
32
+
33
+ test('a /team/info that lies 404 for an existing team ends in a loud 400 on the create, never a second team', async () => {
34
+ // ⛔ measured in the source: the lookup swallows every exception into a 404
35
+ const live = teamRow({ team_alias: 'FAKE-estate', team_id: 'FAKE-team-estate' });
36
+ const fake = startFakeTeamLitellm({ infoLies: true, seed: [live] });
37
+ await expect(stack(fake).deploy(declare(estate))).rejects.toThrow();
38
+ expect(fake.teams()).toHaveLength(1);
39
+ });
40
+
41
+ test('a proxy that keeps a stale field fails the deploy instead of claiming convergence', async () => {
42
+ const live = teamRow({ team_alias: 'FAKE-estate', team_id: 'FAKE-team-estate' });
43
+ // the fake has no update that drops a field, so declare one it cannot store: a blocked flag it ignores
44
+ const fake = startFakeTeamLitellm({ seed: [live] });
45
+ const original = fake.fetch;
46
+ const dropping = (async (input: string | URL | Request, init?: RequestInit) => {
47
+ const request =
48
+ input instanceof Request ? new Request(input, init) : new Request(String(input), init);
49
+ if (new URL(request.url).pathname === '/team/update') {
50
+ return new Response(JSON.stringify({ data: {} }), {
51
+ headers: { 'content-type': 'application/json' },
52
+ status: 200,
53
+ });
54
+ }
55
+ return original(input, init);
56
+ }) as typeof globalThis.fetch;
57
+ await expect(
58
+ fakeStack({ apiKey: FAKE_KEY, baseUrl: FAKE_BASE }, dropping).deploy(
59
+ declare({ blocked: true, teamAlias: 'FAKE-estate', teamId: 'FAKE-team-estate' }),
60
+ { adopt: true },
61
+ ),
62
+ ).rejects.toThrow();
63
+ });
64
+
65
+ test('nothing /team/info carries beyond the team itself can reach an attribute: keys, memberships, metadata', async () => {
66
+ // ⚠️ measured in the source: /team/info returns the team's keys (hashed tokens), its memberships and its
67
+ // metadata, and this resource copies none of them
68
+ const live = teamRow({ team_alias: 'FAKE-estate', team_id: 'FAKE-team-estate' });
69
+ const fake = startFakeTeamLitellm({ leaky: true, seed: [live] });
70
+ const read = await Effect.runPromise(
71
+ teamHandlers
72
+ .read({ id: 'Estate', instanceId: 'i', olds: estate, output: undefined })
73
+ .pipe(
74
+ Effect.provide(FetchHttpClient.layer),
75
+ Effect.provide(Layer.succeed(FetchHttpClient.Fetch, fake.fetch)),
76
+ Effect.provide(credentials({ apiKey: FAKE_KEY, baseUrl: FAKE_BASE })),
77
+ ) as Effect.Effect<unknown, unknown, never>,
78
+ );
79
+ const text = JSON.stringify(read);
80
+ expect(text).toContain('FAKE-team-estate');
81
+ for (const secret of [
82
+ 'FAKE-hashed-key',
83
+ 'FAKE-callback-secret',
84
+ 'FAKE-budget-secret',
85
+ 'FAKE-membership-secret',
86
+ ]) {
87
+ expect(text).not.toContain(secret);
88
+ }
89
+ });
@@ -0,0 +1,106 @@
1
+ /**
2
+ * What a `LiteLLM.Team` declares (props) and what is remembered about it (attributes).
3
+ *
4
+ * ★ A TEAM (`LiteLLM_TeamTable`, `/team/*`) owns keys, a member roster and an ACCESS CEILING: the
5
+ * models it may use, and an `object_permission` that says which MCP servers, MCP access groups,
6
+ * toolsets and tools its keys may reach. This resource manages exactly those, plus the team's
7
+ * attachment to unified access groups. Nothing else about a team is touched.
8
+ * ⛔ THE TEAM'S `mcpServers` LIST IS A CEILING THAT INTERSECTS EVERY KEY'S OWN GRANTS. Where both a team
9
+ * and a key list servers, the key reaches only the intersection
10
+ * (`user_api_key_auth_mcp.py` lines 1482-1503, 1.103.0; docs.litellm.ai/docs/mcp_grant_access). A
11
+ * NON-EMPTY team list therefore silently removes access from any key that was granted a server the
12
+ * team does not list, and `[]` is "this level does not restrict". Grant servers on keys, toolsets
13
+ * (`mcpToolsets`) or unified access groups, and leave the team's list `[]`, unless a ceiling is meant.
14
+ * ⛔ `models: []` MEANS EVERY MODEL, not none (LiteLLM's own field doc: "If empty, assumes all models
15
+ * are allowed"). Compared only when declared.
16
+ * ⚠️ NOT MODELLED, on purpose, so an adopted team keeps them and none is ever sent: budgets and rate
17
+ * limits (a team's `max_budget` is a HARD cap that 429s every key, the 2026-09-28 incident), the
18
+ * metadata-backed fields (`guardrails`, `policies`, `tags`, `prompts`, `logging`,
19
+ * `secret_manager_settings`, `allowed_passthrough_routes`, `team_member_key_duration`,
20
+ * `disable_global_guardrails` — Enterprise, each a 403 when set on a proxy without a licence,
21
+ * `common_utils.py` line 463 and `_types.py` lines 4843-4853), `model_max_budget` (Enterprise, 403,
22
+ * `common_utils.py` lines 73-86), `metadata`, `router_settings`, `model_aliases`, organisation and the
23
+ * other `object_permission` fields (vector stores, agents, models, search tools, skills).
24
+ */
25
+
26
+ /** The object permission fields this resource manages. Each one is compared and sent ONLY WHEN DECLARED. */
27
+ export interface TeamObjectPermission {
28
+ /**
29
+ * MCP servers the team's keys may reach, by `server_id`, alias or name. ⛔ A ceiling: see above.
30
+ * `[]` clears the list. The sentinel `all-proxy-mcpservers` is refused (Proxy admin only,
31
+ * `object_permission_utils.py` line 480, and it grants every server).
32
+ */
33
+ readonly mcpServers?: readonly string[];
34
+ /** MCP access group NAMES (the bare names on MCP server rows), not unified access group ids. */
35
+ readonly mcpAccessGroups?: readonly string[];
36
+ /** Toolset IDS (`toolset.toolsetId` of a `LiteLLM.Toolset`), not names. */
37
+ readonly mcpToolsets?: readonly string[];
38
+ /** Per-server tool allowlist: `server_id` (or alias or name) to the tools it may call. */
39
+ readonly mcpToolPermissions?: Readonly<Record<string, readonly string[]>>;
40
+ /**
41
+ * Tool names blocked for this team. ⚠️ The same list `POST /v1/tool/policy` writes for a team override,
42
+ * which is why `LiteLLM.ToolPolicy` does not model overrides.
43
+ */
44
+ readonly blockedTools?: readonly string[];
45
+ }
46
+
47
+ export interface TeamMember {
48
+ /** The user's `user_id`. A member is added by id only: an email would make LiteLLM allocate the id. */
49
+ readonly userId: string;
50
+ /** Default `user`. `admin` is an ENTERPRISE feature (400 on a proxy without a licence). */
51
+ readonly role?: 'user' | 'admin';
52
+ }
53
+
54
+ export interface TeamProps {
55
+ /** The team's alias. Not unique in LiteLLM (a policy attachment matches it as a pattern). Always compared. */
56
+ readonly teamAlias: string;
57
+ /**
58
+ * The team's id. Set it to ADOPT an existing team (it needs `--adopt`); without it a deterministic
59
+ * physical name is used for a create. ⛔ A DIFFERENT DECLARED ID IS A REPLACE (create-first, so the old
60
+ * team is only removed by an opt-in `RemovalPolicy.destroy()`, which also deletes its keys).
61
+ */
62
+ readonly teamId?: string;
63
+ /** Models the team's keys may use, compared as a set, only when declared. `[]` means every model. */
64
+ readonly models?: readonly string[];
65
+ /** Whether the team is blocked (every key stops). Compared only when declared. */
66
+ readonly blocked?: boolean;
67
+ /**
68
+ * Unified access group ids the team is attached to (`accessGroup.accessGroupId`), compared as a set,
69
+ * only when declared. LiteLLM mirrors it into each group's `assigned_team_ids` in the same transaction,
70
+ * so `LiteLLM.AccessGroup` does not declare teams.
71
+ */
72
+ readonly accessGroupIds?: readonly string[];
73
+ readonly objectPermission?: TeamObjectPermission;
74
+ /**
75
+ * Members that must exist, compared only when declared. ⛔ ADDITIVE ONLY: a live member the declaration
76
+ * does not list is left alone, because `/team/member_delete` also DELETES the keys that user created
77
+ * for the team (`team_endpoints.py` lines 3701-3748). A declared member with another role is updated.
78
+ * Adding a member creates its user row when the id is new. `/team/new` itself adds the caller as an
79
+ * `admin` member unless the proxy sets `disable_auto_add_proxy_admin_to_teams`.
80
+ */
81
+ readonly members?: readonly TeamMember[];
82
+ }
83
+
84
+ /** The object permission as a read returns it: every managed field, `[]` where LiteLLM holds none. */
85
+ export interface TeamObjectPermissionAttributes {
86
+ readonly mcpServers: readonly string[];
87
+ readonly mcpAccessGroups: readonly string[];
88
+ readonly mcpToolsets: readonly string[];
89
+ readonly mcpToolPermissions: Readonly<Record<string, readonly string[]>>;
90
+ readonly blockedTools: readonly string[];
91
+ }
92
+
93
+ export interface TeamMemberAttributes {
94
+ readonly userId: string;
95
+ readonly role: string;
96
+ }
97
+
98
+ export interface TeamAttributes {
99
+ readonly teamId: string;
100
+ readonly teamAlias: string;
101
+ readonly models: readonly string[];
102
+ readonly blocked: boolean;
103
+ readonly accessGroupIds: readonly string[];
104
+ readonly objectPermission: TeamObjectPermissionAttributes;
105
+ readonly members: readonly TeamMemberAttributes[];
106
+ }