@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
@@ -308,25 +308,3101 @@ var budgetHandlers = {
308
308
  list: () => Effect4.succeed([])
309
309
  };
310
310
  var LiteLLMBudgetProvider = () => Provider2.effect(LiteLLMBudget, Effect4.succeed(LiteLLMBudget.Provider.of(budgetHandlers)));
311
+ // src/litellm/credential.ts
312
+ import { Resource as Resource3 } from "alchemy";
313
+ import { Unowned as Unowned4 } from "alchemy/AdoptPolicy";
314
+ import { isResolved as isResolved3 } from "alchemy/Diff";
315
+ import * as Provider3 from "alchemy/Provider";
316
+ import * as Effect12 from "effect/Effect";
317
+ import * as Predicate4 from "effect/Predicate";
318
+
319
+ // src/ownership/adopt.ts
320
+ import { AdoptPolicy } from "alchemy/AdoptPolicy";
321
+ import { AlchemyContext } from "alchemy/AlchemyContext";
322
+ import { Stack as Stack3 } from "alchemy/Stack";
323
+ import * as Effect8 from "effect/Effect";
324
+ import * as Option4 from "effect/Option";
325
+
326
+ // src/ownership/resume.ts
327
+ import { Unowned as Unowned3 } from "alchemy/AdoptPolicy";
328
+ import { Artifacts } from "alchemy/Artifacts";
329
+ import * as Effect5 from "effect/Effect";
330
+ import * as Option from "effect/Option";
331
+ var PROVEN = "homeflare/ownership/resumes";
332
+ var UNFINISHED = "homeflare/ownership/unfinished";
333
+ var note = (key, instanceId) => Effect5.gen(function* () {
334
+ const bag = yield* Effect5.serviceOption(Artifacts);
335
+ if (Option.isSome(bag))
336
+ yield* bag.value.set(key, instanceId);
337
+ });
338
+ var noted = (key, instanceId) => Effect5.gen(function* () {
339
+ const bag = yield* Effect5.serviceOption(Artifacts);
340
+ if (Option.isNone(bag))
341
+ return false;
342
+ return (yield* bag.value.get(key)) === instanceId;
343
+ });
344
+ var noteUnfinished = (instanceId) => Effect5.as(note(UNFINISHED, instanceId), undefined);
345
+ var noteResume = (instanceId, recovered) => Effect5.gen(function* () {
346
+ yield* noteUnfinished(instanceId);
347
+ const unproven = () => Effect5.succeed(undefined);
348
+ const found = yield* recovered.pipe(Effect5.catch(unproven), Effect5.catchDefect(unproven));
349
+ if (found === undefined || found === null || Unowned3.is(found))
350
+ return;
351
+ yield* note(PROVEN, instanceId);
352
+ });
353
+ var resumes = (instanceId) => noted(PROVEN, instanceId);
354
+ var unfinished = (instanceId) => noted(UNFINISHED, instanceId);
355
+ var provingResumes = (service) => {
356
+ const { diff, read } = service;
357
+ if (diff === undefined || read === undefined)
358
+ return service;
359
+ const proving = (input) => Effect5.gen(function* () {
360
+ if (input.output === undefined) {
361
+ yield* noteResume(input.instanceId, read({ ...input, output: undefined }));
362
+ }
363
+ return yield* diff(input);
364
+ });
365
+ return { ...service, diff: proving };
366
+ };
367
+
368
+ // src/ownership/rows.ts
369
+ import { Stack as Stack2 } from "alchemy/Stack";
370
+ import { State, isActionState } from "alchemy/State/State";
371
+ import * as Effect7 from "effect/Effect";
372
+ import * as Option3 from "effect/Option";
373
+
374
+ // src/ownership/whole.ts
375
+ import { Stack } from "alchemy/Stack";
376
+ import * as Effect6 from "effect/Effect";
377
+ import * as Option2 from "effect/Option";
378
+ var absent = (value) => value === undefined || value === null;
379
+ var isPlainObject = (value) => {
380
+ if (typeof value !== "object" || value === null || Array.isArray(value))
381
+ return false;
382
+ const proto = Object.getPrototypeOf(value);
383
+ return proto === Object.prototype || proto === null;
384
+ };
385
+ var carries = (declared, recorded) => {
386
+ if (absent(declared))
387
+ return true;
388
+ if (absent(recorded))
389
+ return false;
390
+ if (Array.isArray(declared)) {
391
+ if (!Array.isArray(recorded))
392
+ return false;
393
+ return declared.every((each, index) => carries(each, recorded[index]));
394
+ }
395
+ if (isPlainObject(declared)) {
396
+ if (!isPlainObject(recorded))
397
+ return false;
398
+ return Object.entries(declared).every(([key, each]) => carries(each, recorded[key]));
399
+ }
400
+ return true;
401
+ };
402
+ var wholeDeclaration = (fqn, props) => Effect6.map(Effect6.serviceOption(Stack), (stack) => {
403
+ const declared = Option2.isSome(stack) ? stack.value.resources[fqn] : undefined;
404
+ return declared !== undefined && carries(declared.Props, props);
405
+ });
406
+
407
+ // src/ownership/rows.ts
408
+ var storeOf = Effect7.gen(function* () {
409
+ const stack = yield* Effect7.serviceOption(Stack2);
410
+ const state = yield* Effect7.serviceOption(State);
411
+ if (Option3.isNone(stack) || Option3.isNone(state))
412
+ return;
413
+ const store = yield* state.value;
414
+ const where = { stack: stack.value.name, stage: stack.value.stage };
415
+ return { resources: stack.value.resources, store, where };
416
+ });
417
+ var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect7.orElseSucceed(() => {
418
+ return;
419
+ }));
420
+ var generationOf = (row, instanceId) => {
421
+ let at = row;
422
+ while (typeof at === "object" && at !== null && !isActionState(at)) {
423
+ const generation = at;
424
+ if (generation.instanceId === instanceId)
425
+ return generation;
426
+ at = generation.old;
427
+ }
428
+ return;
429
+ };
430
+ var recordedGeneration = (fqn, instanceId) => Effect7.gen(function* () {
431
+ const found = yield* storeOf;
432
+ if (found === undefined)
433
+ return;
434
+ for (const at of [fqn, ...found.resources[fqn]?.FormerFqns ?? []]) {
435
+ const generation = generationOf(yield* rowAt(found.store, found.where, at), instanceId);
436
+ if (generation !== undefined)
437
+ return generation;
438
+ }
439
+ return;
440
+ });
441
+ var recordedInstance = (fqn, instanceId) => Effect7.gen(function* () {
442
+ const generation = yield* recordedGeneration(fqn, instanceId);
443
+ if (generation === undefined)
444
+ return "absent";
445
+ return (yield* wholeDeclaration(fqn, generation.props)) ? "whole" : "partial";
446
+ });
447
+ var isCreate = (fqn, instanceId) => Effect7.map(recordedGeneration(fqn, instanceId), (generation) => generation?.status === "creating");
448
+ var idOf2 = (attr) => {
449
+ if (typeof attr !== "object" || attr === null)
450
+ return;
451
+ const id = attr.id;
452
+ return typeof id === "string" && id !== "" ? id : undefined;
453
+ };
454
+ var olderGenerationIds = (fqn, instanceId) => Effect7.gen(function* () {
455
+ const found = yield* storeOf;
456
+ if (found === undefined)
457
+ return [];
458
+ const ids = [];
459
+ for (const at of [fqn, ...found.resources[fqn]?.FormerFqns ?? []]) {
460
+ collectOlder(yield* rowAt(found.store, found.where, at), instanceId, ids);
461
+ }
462
+ return ids;
463
+ });
464
+ var collectOlder = (row, instanceId, ids) => {
465
+ let at = row;
466
+ let seen = false;
467
+ while (typeof at === "object" && at !== null && !isActionState(at)) {
468
+ const generation = at;
469
+ if (!seen) {
470
+ seen = generation.instanceId === instanceId;
471
+ at = generation.old;
472
+ continue;
473
+ }
474
+ if (generation.instanceId !== instanceId) {
475
+ const id = idOf2(generation.attr);
476
+ if (id !== undefined)
477
+ ids.push(id);
478
+ }
479
+ at = generation.old;
480
+ }
481
+ };
482
+ var forgetRefusedCreate = (fqn, instanceId) => Effect7.gen(function* () {
483
+ const found = yield* storeOf;
484
+ if (found === undefined)
485
+ return;
486
+ const row = yield* rowAt(found.store, found.where, fqn);
487
+ const mine = row;
488
+ if (mine?.status !== "creating" || mine.instanceId !== instanceId || mine.attr !== undefined) {
489
+ return;
490
+ }
491
+ yield* found.store.delete({ ...found.where, fqn }).pipe(Effect7.ignore);
492
+ });
493
+
494
+ // src/ownership/adopt.ts
495
+ var adoptEnabled = (fqn) => Effect8.gen(function* () {
496
+ const stack = yield* Effect8.serviceOption(Stack3);
497
+ const scoped = Option4.isSome(stack) ? stack.value.resources[fqn]?.Adopt : undefined;
498
+ if (scoped !== undefined)
499
+ return scoped;
500
+ const policy = yield* Effect8.serviceOption(AdoptPolicy);
501
+ if (Option4.isSome(policy))
502
+ return policy.value;
503
+ const context = yield* Effect8.serviceOption(AlchemyContext);
504
+ return Option4.isSome(context) ? context.value.adopt : false;
505
+ });
506
+ var adoptable = (owner) => Effect8.gen(function* () {
507
+ if (yield* isCreate(owner.fqn, owner.instanceId))
508
+ return true;
509
+ return yield* unfinished(owner.instanceId);
510
+ });
511
+ var adoptsAtApply = (owner) => Effect8.gen(function* () {
512
+ if (!(yield* adoptEnabled(owner.fqn)))
513
+ return false;
514
+ return yield* adoptable(owner);
515
+ });
516
+ var refuseTakeover = (owner, what) => Effect8.gen(function* () {
517
+ if (owner.output !== undefined)
518
+ return;
519
+ if (yield* resumes(owner.instanceId))
520
+ return;
521
+ const may = yield* adoptable(owner);
522
+ if (may && (yield* adoptEnabled(owner.fqn)))
523
+ return;
524
+ yield* forgetRefusedCreate(owner.fqn, owner.instanceId);
525
+ const remedy = may ? "Deploy with --adopt (or wrap the resource in adopt(true)) to take it over, or remove it first." : "It is the new identity of a replace, which --adopt does not cover: remove it first.";
526
+ return yield* Effect8.die(new Error(`${what}: already exists, and this stack holds no state for it — the plan could not ask ` + "first (a prop was still an Output, a replace moved onto it, or it appeared after the " + `plan). Nothing was written. ${remedy}`));
527
+ });
528
+ var claimFor = (owner) => (what) => refuseTakeover(owner, what);
529
+
530
+ // src/litellm/credential-errors.ts
531
+ import * as Data3 from "effect/Data";
532
+
533
+ class LitellmCredentialInvalidError extends Data3.TaggedError("LitellmCredentialInvalidError") {
534
+ get message() {
535
+ return `LiteLLM.Credential "${this.credentialName}": ${this.problem}.`;
536
+ }
537
+ }
538
+
539
+ class LitellmCredentialTransportError extends Data3.TaggedError("LitellmCredentialTransportError") {
540
+ get message() {
541
+ return `LiteLLM.Credential "${this.credentialName}": a /credentials write failed ` + `(${this.reason}) before an answer could be read, so the credential MAY have been written. ` + "This error keeps neither the request nor its cause: the request body holds the credential " + "values. Look the name up in LiteLLM. A row that landed is taken over by the next deploy " + "with --adopt; one that did not is created by it.";
542
+ }
543
+ }
544
+
545
+ class LitellmCredentialDebugLoggingError extends Data3.TaggedError("LitellmCredentialDebugLoggingError") {
546
+ get message() {
547
+ return `LiteLLM.Credential "${this.credentialName}": DISTILLED_DEBUG_HTTP is set, so the SDK ` + "would print the credential values to stderr in /credentials' request and response. Unset " + "it and run again. Nothing was written.";
548
+ }
549
+ }
550
+
551
+ class LitellmCredentialEnvUnsetError extends Data3.TaggedError("LitellmCredentialEnvUnsetError") {
552
+ get message() {
553
+ return `LiteLLM.Credential "${this.credentialName}": ` + `the deploying process does not set ${this.variables.join(", ")}.`;
554
+ }
555
+ }
556
+
557
+ class LitellmCredentialUnreadableError extends Data3.TaggedError("LitellmCredentialUnreadableError") {
558
+ get message() {
559
+ return `LiteLLM.Credential: a credentials read is unreadable (${this.reason}).`;
560
+ }
561
+ }
562
+
563
+ class LitellmCredentialAbsentAfterWriteError extends Data3.TaggedError("LitellmCredentialAbsentAfterWriteError") {
564
+ get message() {
565
+ return `LiteLLM.Credential "${this.credentialName}": the write returned no error but the ` + "credential is absent from the by-name read.";
566
+ }
567
+ }
568
+
569
+ class LitellmCredentialNotConvergedError extends Data3.TaggedError("LitellmCredentialNotConvergedError") {
570
+ get message() {
571
+ return `LiteLLM.Credential "${this.credentialName}": after the write it still differs from the ` + `declaration in ${this.fields.join(", ")}.`;
572
+ }
573
+ }
574
+
575
+ class LitellmCredentialRewriteError extends Data3.TaggedError("LitellmCredentialRewriteError") {
576
+ get message() {
577
+ return `LiteLLM.Credential "${this.credentialName}": DELETE already ran, but the replacement ` + `POST failed (${this.reason}). The next deploy recreates the row if absent; keep all ` + "declared credential variables set. If the POST landed despite the failure, the next " + "deploy reads and reconciles that row.";
578
+ }
579
+ }
580
+
581
+ // src/litellm/credential-form.ts
582
+ import * as Redacted from "effect/Redacted";
583
+
584
+ // src/litellm/credential-types.ts
585
+ var isBlank = (value) => typeof value !== "string" || value.trim() === "";
586
+ var SENSITIVE_KEY_FRAGMENTS = [
587
+ "authorization",
588
+ "token",
589
+ "key",
590
+ "secret",
591
+ "vertex_credentials",
592
+ "credentials",
593
+ "password",
594
+ "passwd"
595
+ ];
596
+ var isSensitiveKey = (key) => {
597
+ const lower = key.toLowerCase();
598
+ return SENSITIVE_KEY_FRAGMENTS.some((fragment) => lower.includes(fragment));
599
+ };
600
+
601
+ // src/litellm/credential-form.ts
602
+ var firstProblem = (props) => {
603
+ if (isBlank(props.credentialName) || props.credentialName !== props.credentialName.trim()) {
604
+ return "`credentialName` must be a non-empty string without leading or trailing whitespace";
605
+ }
606
+ if (props.credentialInfo !== undefined && (typeof props.credentialInfo !== "object" || props.credentialInfo === null)) {
607
+ return "`credentialInfo` must be an object of metadata";
608
+ }
609
+ if (props.credentialInfo !== undefined) {
610
+ for (const key of Object.keys(props.credentialInfo)) {
611
+ if (isSensitiveKey(key)) {
612
+ return `\`credentialInfo\` must not declare "${key}": LiteLLM returns \`credential_info\` ` + "unmasked, so declare it in `credentialValues`, which LiteLLM stores encrypted";
613
+ }
614
+ }
615
+ }
616
+ if (Object.keys(props.credentialValues).length === 0) {
617
+ return "`credentialValues` needs at least one entry: LiteLLM refuses a credential with neither " + "`credential_values` nor a model_id, and `model_id` is not modelled here";
618
+ }
619
+ for (const key of Object.keys(props.credentialValues)) {
620
+ if (isBlank(key) || key !== key.trim()) {
621
+ return "`credentialValues` keys must be non-empty strings without padding";
622
+ }
623
+ const entry = props.credentialValues[key];
624
+ if (typeof entry !== "object" || entry === null || isBlank(entry.fromEnv)) {
625
+ return `\`credentialValues["${key}"]\` takes \`{ fromEnv: 'NAME' }\`, never a value: the value would land in Alchemy's unencrypted state`;
626
+ }
627
+ }
628
+ return;
629
+ };
630
+ var differing2 = (live, props) => {
631
+ const out = [];
632
+ if (props.credentialInfo !== undefined) {
633
+ for (const [key, declared] of Object.entries(props.credentialInfo)) {
634
+ if (!isSensitiveKey(key) && !jsonEquals(live.credentialInfo[key], declared)) {
635
+ out.push(`credential_info.${key}`);
636
+ }
637
+ }
638
+ }
639
+ return out;
640
+ };
641
+ var jsonEquals = (left, right) => JSON.stringify(canonicalise(left)) === JSON.stringify(canonicalise(right));
642
+ var canonicalise = (value2) => {
643
+ if (Array.isArray(value2))
644
+ return value2.map(canonicalise);
645
+ if (typeof value2 === "object" && value2 !== null) {
646
+ const out = {};
647
+ for (const key of Object.keys(value2).sort()) {
648
+ out[key] = canonicalise(value2[key]);
649
+ }
650
+ return out;
651
+ }
652
+ return value2;
653
+ };
654
+ var toAttributes3 = (row) => {
655
+ const info = row["credential_info"] ?? {};
656
+ const mirrored = {};
657
+ for (const [key, value2] of Object.entries(info)) {
658
+ if (!isSensitiveKey(key))
659
+ mirrored[key] = value2;
660
+ }
661
+ return {
662
+ credentialInfo: mirrored,
663
+ credentialName: String(row["credential_name"] ?? ""),
664
+ valueKeys: Object.keys(row["credential_values"] ?? {}).sort(),
665
+ infoKeys: Object.keys(info).sort(),
666
+ valuesSeal: ""
667
+ };
668
+ };
669
+ var isCredentialRow = (row) => typeof row === "object" && row !== null && typeof row["credential_name"] === "string";
670
+ var literalValues = (resolved) => Object.fromEntries(Object.entries(resolved.values).map(([key, value2]) => [key, Redacted.value(value2)]));
671
+ var createBody3 = (props, resolved) => {
672
+ const body = {
673
+ credential_info: { ...props.credentialInfo },
674
+ credential_name: props.credentialName,
675
+ credential_values: { ...literalValues(resolved) }
676
+ };
677
+ return body;
678
+ };
679
+ var patchBody = (props, values) => {
680
+ const body = {
681
+ credential_info: { ...props.credentialInfo },
682
+ credential_name: props.credentialName,
683
+ credential_name_body: props.credentialName
684
+ };
685
+ if (values !== undefined)
686
+ body.credential_values = { ...values };
687
+ return body;
688
+ };
689
+ var removedInfoKeys = (prior, props) => {
690
+ if (prior === undefined)
691
+ return [];
692
+ const declared = props.credentialInfo ?? {};
693
+ return (prior.infoKeys ?? Object.keys(prior.credentialInfo)).filter((key) => !Object.hasOwn(declared, key));
694
+ };
695
+ var removedValueKeys = (live, props) => (live?.valueKeys ?? []).filter((key) => !Object.hasOwn(props.credentialValues, key));
696
+
697
+ // src/litellm/credential-operations.ts
698
+ import * as credentials from "@distilled.cloud/litellm/credential_management";
699
+ import * as Effect9 from "effect/Effect";
700
+ import * as Predicate3 from "effect/Predicate";
701
+ import { isHttpClientError } from "effect/unstable/http/HttpClientError";
702
+ var readCredential = (credentialName) => throughFetch(credentials.getCredentialByNameCredentialsByNameCredentialNameGet({
703
+ credential_name: credentialName
704
+ })).pipe(Effect9.catchTag("CredentialNotFound", () => Effect9.succeed(undefined)), Effect9.flatMap((response) => {
705
+ if (response === undefined)
706
+ return Effect9.succeed(undefined);
707
+ if (!isCredentialRow(response)) {
708
+ return Effect9.fail(new LitellmCredentialUnreadableError({
709
+ reason: "the by-name read did not answer a credential row"
710
+ }));
711
+ }
712
+ const answer = String(response["credential_name"]);
713
+ return answer === credentialName ? Effect9.succeed(toAttributes3(response)) : Effect9.fail(new LitellmCredentialUnreadableError({
714
+ reason: "the by-name read answered a different credential name"
715
+ }));
716
+ }));
717
+ var createCredential = (body) => {
718
+ const credentialName = body.credential_name ?? "";
719
+ return Effect9.gen(function* () {
720
+ yield* throughFetch(credentials.createCredentialCredentialsPost(body)).pipe(Effect9.asVoid, Effect9.catchTag("HttpClientError", (error) => Effect9.fail(new LitellmCredentialTransportError({ credentialName, reason: error.reason._tag }))), Effect9.catchDefect((defect) => carriesRequest(defect) ? Effect9.fail(new LitellmCredentialTransportError({
721
+ credentialName,
722
+ reason: isHttpClientError(defect) ? defect.reason._tag : "Defect"
723
+ })) : Effect9.die(defect)));
724
+ });
725
+ };
726
+ var updateCredential = (body) => {
727
+ const credentialName = body.credential_name ?? "";
728
+ return Effect9.gen(function* () {
729
+ yield* throughFetch(credentials.updateCredentialCredentialsCredentialNamePatch(body)).pipe(Effect9.asVoid, Effect9.catchTag("HttpClientError", (error) => Effect9.fail(new LitellmCredentialTransportError({ credentialName, reason: error.reason._tag }))), Effect9.catchDefect((defect) => carriesRequest(defect) ? Effect9.fail(new LitellmCredentialTransportError({
730
+ credentialName,
731
+ reason: isHttpClientError(defect) ? defect.reason._tag : "Defect"
732
+ })) : Effect9.die(defect)));
733
+ });
734
+ };
735
+ var deleteCredential = (credentialName) => throughFetch(credentials.deleteCredentialCredentialsCredentialNameDelete({
736
+ credential_name: credentialName
737
+ })).pipe(Effect9.asVoid, Effect9.catchTag("CredentialNotFound", () => Effect9.void));
738
+ var refuseDebugLogging = (credentialName) => (globalThis.process?.env?.["DISTILLED_DEBUG_HTTP"] ?? "") !== "" ? Effect9.fail(new LitellmCredentialDebugLoggingError({ credentialName })) : Effect9.void;
739
+ var carriesRequest = (value2) => isHttpClientError(value2) || Predicate3.hasProperty(value2, "request");
740
+
741
+ // src/litellm/credential-rewrite.ts
742
+ import * as Effect10 from "effect/Effect";
743
+ var rewriteCredential = (body) => Effect10.gen(function* () {
744
+ const credentialName = body.credential_name;
745
+ yield* deleteCredential(credentialName);
746
+ const post = createCredential(body);
747
+ yield* post.pipe(Effect10.catchTag([
748
+ "BadGateway",
749
+ "BadRequest",
750
+ "ConfigError",
751
+ "Conflict",
752
+ "Forbidden",
753
+ "GatewayTimeout",
754
+ "HttpClientError",
755
+ "InternalServerError",
756
+ "LitellmCredentialTransportError",
757
+ "LitellmParseError",
758
+ "Locked",
759
+ "NotFound",
760
+ "ServiceUnavailable",
761
+ "TooManyRequests",
762
+ "Unauthorized",
763
+ "UnknownLitellmError",
764
+ "UnprocessableEntity"
765
+ ], (error) => Effect10.fail(new LitellmCredentialRewriteError({ credentialName, reason: error._tag }))));
766
+ });
767
+
768
+ // src/litellm/credential-values.ts
769
+ import * as Effect11 from "effect/Effect";
770
+ import * as Redacted2 from "effect/Redacted";
771
+
772
+ // src/secrets/write-only.ts
773
+ import { Buffer } from "node:buffer";
774
+ import { randomBytes, scryptSync, timingSafeEqual } from "node:crypto";
775
+ var resolveAll = (refs, env = process.env) => {
776
+ const values = {};
777
+ const missing = [];
778
+ for (const [key, ref] of Object.entries(refs)) {
779
+ const value2 = env[ref.fromEnv];
780
+ if (value2 === undefined || value2 === "")
781
+ missing.push(ref.fromEnv);
782
+ else
783
+ values[key] = value2;
784
+ }
785
+ return { missing: [...new Set(missing)].sort(), values };
786
+ };
787
+ var COST = { N: 16384, maxmem: 64 * 1024 * 1024, p: 1, r: 8 };
788
+ var PREFIX = "scrypt";
789
+ var canonical = (values) => JSON.stringify(Object.keys(values).sort().map((key) => [key, values[key]]));
790
+ var digest = (salt, values) => scryptSync(canonical(values), salt, 32, COST);
791
+ var seal = (values, salt) => {
792
+ if (Object.keys(values).length === 0)
793
+ return "";
794
+ const bytes = salt === undefined ? randomBytes(16) : Buffer.from(salt, "utf8");
795
+ return `${PREFIX}:${bytes.toString("base64url")}:${digest(bytes, values).toString("base64url")}`;
796
+ };
797
+ var sealMatches = (sealed, values) => {
798
+ if (sealed === "")
799
+ return Object.keys(values).length === 0;
800
+ const [prefix, salt, stored, extra] = sealed.split(":");
801
+ if (prefix !== PREFIX || salt === undefined || stored === undefined || extra !== undefined) {
802
+ return false;
803
+ }
804
+ const expected = Buffer.from(stored, "base64url");
805
+ const actual = digest(Buffer.from(salt, "base64url"), values);
806
+ return expected.length === actual.length && timingSafeEqual(expected, actual);
807
+ };
808
+
809
+ // src/litellm/credential-values.ts
810
+ var resolveValues = (props, env = process.env) => {
811
+ const { values, missing } = resolveAll(props.credentialValues, env);
812
+ return {
813
+ missing,
814
+ values: Object.fromEntries(Object.entries(values).map(([key, value3]) => [key, Redacted2.make(value3)]))
815
+ };
816
+ };
817
+ var sealable = (values) => Object.fromEntries(Object.entries(values).map(([key, value3]) => [key, Redacted2.value(value3)]));
818
+ var sealValues = (values) => seal(sealable(values));
819
+ var valuesState = (props, sealed, resolved = resolveValues(props)) => {
820
+ const declared = Object.keys(props.credentialValues);
821
+ if (declared.length === 0)
822
+ return "none";
823
+ if (resolved.missing.length > 0)
824
+ return "unknown";
825
+ if (sealed === "")
826
+ return "stale";
827
+ return sealMatches(sealed, sealable(resolved.values)) ? "match" : "stale";
828
+ };
829
+ var requireValues = (props, resolved) => resolved.missing.length === 0 ? Effect11.void : Effect11.fail(new LitellmCredentialEnvUnsetError({
830
+ credentialName: props.credentialName,
831
+ variables: resolved.missing
832
+ }));
833
+
834
+ // src/litellm/credential.ts
835
+ var LiteLLMCredential = Resource3("LiteLLM.Credential", {
836
+ defaultRemovalPolicy: "retain"
837
+ });
838
+ var isLiteLLMCredential = (value3) => Predicate4.hasProperty(value3, "Type") && value3.Type === "LiteLLM.Credential";
839
+ var refuse = (props) => {
840
+ const problem = firstProblem(props);
841
+ return problem === undefined ? Effect12.void : Effect12.fail(new LitellmCredentialInvalidError({
842
+ problem,
843
+ credentialName: String(props.credentialName)
844
+ }));
845
+ };
846
+ var credentialHandlers = {
847
+ read: ({ olds, output }) => Effect12.gen(function* () {
848
+ yield* refuseDebugLogging(olds.credentialName);
849
+ const problem = output === undefined ? firstProblem(olds) : undefined;
850
+ if (problem !== undefined) {
851
+ return yield* Effect12.die(new LitellmCredentialInvalidError({
852
+ problem,
853
+ credentialName: String(olds.credentialName)
854
+ }));
855
+ }
856
+ const found = yield* readCredential(olds.credentialName);
857
+ if (found === undefined)
858
+ return;
859
+ return output === undefined ? Unowned4(found) : { ...found, valuesSeal: output.valuesSeal };
860
+ }),
861
+ diff: ({
862
+ news,
863
+ output
864
+ }) => Effect12.gen(function* () {
865
+ if (!isResolved3(news))
866
+ return;
867
+ yield* refuse(news);
868
+ if (output === undefined)
869
+ return;
870
+ if (news.credentialName !== output.credentialName) {
871
+ return { action: "replace", deleteFirst: false };
872
+ }
873
+ const state = valuesState(news, output.valuesSeal);
874
+ const removed = [...removedInfoKeys(output, news), ...removedValueKeys(output, news)];
875
+ return differing2(output, news).length === 0 && removed.length === 0 && state !== "stale" ? { action: "noop" } : { action: "update" };
876
+ }),
877
+ reconcile: ({ fqn, instanceId, news, output }) => Effect12.gen(function* () {
878
+ yield* refuse(news);
879
+ yield* refuseDebugLogging(news.credentialName);
880
+ const resolved = resolveValues(news);
881
+ const before = yield* readCredential(news.credentialName);
882
+ let sealed = output?.valuesSeal ?? "";
883
+ if (before === undefined) {
884
+ yield* requireValues(news, resolved);
885
+ yield* createCredential(createBody3(news, resolved));
886
+ sealed = sealValues(resolved.values);
887
+ } else {
888
+ yield* refuseTakeover({ fqn, instanceId, output }, `LiteLLM.Credential ${news.credentialName}`);
889
+ const removed = [...removedInfoKeys(before, news), ...removedValueKeys(before, news)];
890
+ const infoDrift = differing2(before, news).length > 0;
891
+ const valuesStale = valuesState(news, sealed) === "stale";
892
+ if (removed.length > 0) {
893
+ yield* requireValues(news, resolved);
894
+ yield* rewriteCredential(createBody3(news, resolved));
895
+ sealed = sealValues(resolved.values);
896
+ } else if (infoDrift || valuesStale) {
897
+ if (valuesStale)
898
+ yield* requireValues(news, resolved);
899
+ yield* updateCredential(patchBody(news, valuesStale ? literalValues(resolved) : undefined));
900
+ if (valuesStale)
901
+ sealed = sealValues(resolved.values);
902
+ }
903
+ }
904
+ const after = yield* readCredential(news.credentialName);
905
+ if (after === undefined) {
906
+ return yield* Effect12.fail(new LitellmCredentialAbsentAfterWriteError({ credentialName: news.credentialName }));
907
+ }
908
+ const left = [
909
+ ...differing2(after, news),
910
+ ...removedInfoKeys(after, news).map((key) => `credential_info.${key}`),
911
+ ...removedValueKeys(after, news).map((key) => `credential_values.${key}`)
912
+ ];
913
+ if (left.length > 0) {
914
+ return yield* Effect12.fail(new LitellmCredentialNotConvergedError({
915
+ fields: left,
916
+ credentialName: news.credentialName
917
+ }));
918
+ }
919
+ return { ...after, valuesSeal: sealed };
920
+ }),
921
+ delete: ({ output }) => deleteCredential(output.credentialName),
922
+ list: () => Effect12.succeed([])
923
+ };
924
+ var LiteLLMCredentialProvider = () => Provider3.effect(LiteLLMCredential, Effect12.succeed(LiteLLMCredential.Provider.of(credentialHandlers)));
925
+ // src/litellm/mcp-server.ts
926
+ import { Resource as Resource4 } from "alchemy";
927
+ import { Unowned as Unowned5 } from "alchemy/AdoptPolicy";
928
+ import { isResolved as isResolved4 } from "alchemy/Diff";
929
+ import * as Provider4 from "alchemy/Provider";
930
+ import * as Effect17 from "effect/Effect";
931
+ import * as Predicate5 from "effect/Predicate";
932
+
933
+ // src/litellm/mcp-server-errors.ts
934
+ import * as Data4 from "effect/Data";
935
+
936
+ class LitellmMcpServerInvalidError extends Data4.TaggedError("LitellmMcpServerInvalidError") {
937
+ get message() {
938
+ return `LiteLLM.MCPServer "${this.serverName}": ${this.problem}.`;
939
+ }
940
+ }
941
+
942
+ class LitellmMcpServerCredentialEnvUnsetError extends Data4.TaggedError("LitellmMcpServerCredentialEnvUnsetError") {
943
+ get message() {
944
+ return `LiteLLM.MCPServer "${this.serverName}": this write must send its credential, and ` + `${this.variable} is unset or empty in the deploying environment. Export it and deploy again.`;
945
+ }
946
+ }
947
+
948
+ class LitellmMcpServerAmbiguousNameError extends Data4.TaggedError("LitellmMcpServerAmbiguousNameError") {
949
+ get message() {
950
+ return `LiteLLM.MCPServer "${this.serverName}": ${this.serverIds.length} live rows carry that ` + `server_name (${this.serverIds.join(", ")}). Declare \`serverId\` to choose one.`;
951
+ }
952
+ }
953
+
954
+ class LitellmMcpServerUnreadableError extends Data4.TaggedError("LitellmMcpServerUnreadableError") {
955
+ get message() {
956
+ return `LiteLLM.MCPServer: the server list is unreadable (${this.reason}).`;
957
+ }
958
+ }
959
+
960
+ class LitellmMcpServerAbsentAfterWriteError extends Data4.TaggedError("LitellmMcpServerAbsentAfterWriteError") {
961
+ get message() {
962
+ return `LiteLLM.MCPServer "${this.serverName}": the write of ${this.serverId} returned no error ` + "but the row is absent from the list and from the database read.";
963
+ }
964
+ }
965
+
966
+ class LitellmMcpServerNotConvergedError extends Data4.TaggedError("LitellmMcpServerNotConvergedError") {
967
+ get message() {
968
+ return `LiteLLM.MCPServer "${this.serverName}": after the write, ${this.serverId} still differs ` + `from the declaration in ${this.fields.join(", ")}.`;
969
+ }
970
+ }
971
+
972
+ class LitellmMcpServerDescriptionShadowedError extends Data4.TaggedError("LitellmMcpServerDescriptionShadowedError") {
973
+ get message() {
974
+ return `LiteLLM.MCPServer "${this.serverName}": ${this.serverId} has a \`description\` in \`mcp_info\`, ` + "which LiteLLM shows instead of the column this resource writes, and it differs from the " + "declaration. Edit it in LiteLLM, or remove `description` from the declaration.";
975
+ }
976
+ }
977
+
978
+ // src/litellm/mcp-server-credential.ts
979
+ import * as Effect13 from "effect/Effect";
980
+ import * as Redacted3 from "effect/Redacted";
981
+
982
+ // src/litellm/mcp-server-types.ts
983
+ var isBlank2 = (value3) => typeof value3 !== "string" || value3.trim() === "";
984
+ var STATIC = new Set([
985
+ "api_key",
986
+ "bearer_token",
987
+ "basic",
988
+ "authorization",
989
+ "token"
990
+ ]);
991
+ var isStaticAuthType = (authType) => STATIC.has(authType);
992
+ var AUTH_TYPES = [
993
+ "none",
994
+ "oauth2",
995
+ "api_key",
996
+ "bearer_token",
997
+ "basic",
998
+ "authorization",
999
+ "token"
1000
+ ];
1001
+ var TRANSPORTS = ["sse", "http"];
1002
+
1003
+ // src/litellm/mcp-server-credential.ts
1004
+ var resolveCredential = (props, env = process.env) => {
1005
+ if (props.authValue === undefined)
1006
+ return { value: undefined, variable: undefined };
1007
+ const { values } = resolveAll({ authValue: props.authValue }, env);
1008
+ const raw = values["authValue"];
1009
+ return {
1010
+ value: raw === undefined ? undefined : Redacted3.make(raw),
1011
+ variable: props.authValue.fromEnv
1012
+ };
1013
+ };
1014
+ var sealable2 = (value4) => ({ authValue: Redacted3.value(value4) });
1015
+ var sealCredential = (value4) => seal(sealable2(value4));
1016
+ var credentialState = (props, sealed, resolved = resolveCredential(props)) => {
1017
+ if (props.authValue === undefined || !isStaticAuthType(props.authType))
1018
+ return "none";
1019
+ if (resolved.value === undefined)
1020
+ return "unknown";
1021
+ if (sealed === "")
1022
+ return "stale";
1023
+ return sealMatches(sealed, sealable2(resolved.value)) ? "match" : "stale";
1024
+ };
1025
+ var requireCredential = (props, credential) => isStaticAuthType(props.authType) && credential.value === undefined ? Effect13.fail(new LitellmMcpServerCredentialEnvUnsetError({
1026
+ serverName: props.serverName,
1027
+ variable: credential.variable ?? "(undeclared)"
1028
+ })) : Effect13.void;
1029
+
1030
+ // src/litellm/mcp-server-form.ts
1031
+ import * as Redacted4 from "effect/Redacted";
1032
+
1033
+ // src/litellm/mcp-server-url.ts
1034
+ var SECRET_PARAM = /token|secret|passw|api.?key|auth|credential|signature|^key$|^sig$/i;
1035
+ var urlProblem = (raw) => {
1036
+ if (isBlank2(raw))
1037
+ return "`url` must be a non-empty string";
1038
+ let url;
1039
+ try {
1040
+ url = new URL(raw);
1041
+ } catch {
1042
+ return "`url` must be a full http(s) URL including the scheme";
1043
+ }
1044
+ if (url.protocol !== "http:" && url.protocol !== "https:")
1045
+ return "`url` must be http or https";
1046
+ if (url.username !== "" || url.password !== "") {
1047
+ return "`url` must not carry userinfo; declare the credential as `authValue`";
1048
+ }
1049
+ if (url.hash !== "")
1050
+ return "`url` must not carry a fragment";
1051
+ for (const name of url.searchParams.keys()) {
1052
+ if (SECRET_PARAM.test(name)) {
1053
+ return `\`url\` carries the query parameter "${name}", which looks like a credential; declare it as \`authValue\` instead, because the URL is stored in Alchemy's state`;
1054
+ }
1055
+ }
1056
+ return;
1057
+ };
1058
+ var redactUrl = (raw) => {
1059
+ let url;
1060
+ try {
1061
+ url = new URL(raw);
1062
+ } catch {
1063
+ return raw;
1064
+ }
1065
+ let changed = false;
1066
+ if (url.username !== "") {
1067
+ url.username = "REDACTED";
1068
+ changed = true;
1069
+ }
1070
+ if (url.password !== "") {
1071
+ url.password = "REDACTED";
1072
+ changed = true;
1073
+ }
1074
+ for (const name of new Set(url.searchParams.keys())) {
1075
+ if (!SECRET_PARAM.test(name))
1076
+ continue;
1077
+ url.searchParams.set(name, "REDACTED");
1078
+ changed = true;
1079
+ }
1080
+ return changed ? url.toString() : raw;
1081
+ };
1082
+
1083
+ // src/litellm/mcp-server-form.ts
1084
+ var listProblem = (name, list) => list !== undefined && list.some((entry) => isBlank2(entry)) ? `\`${name}\` must hold non-empty strings` : undefined;
1085
+ var TOOL_NAME = /^[A-Za-z0-9._]{1,128}$/;
1086
+ var toolNameProblem = (field, value5) => TOOL_NAME.test(value5) ? undefined : `\`${field}\` must match ^[A-Za-z0-9._]{1,128}$: LiteLLM 1.103 rejects a space, "/", ":", "@", "-" or more than 128 characters only at apply`;
1087
+ var aliasProblem = (alias) => {
1088
+ if (alias === undefined)
1089
+ return;
1090
+ if (isBlank2(alias))
1091
+ return "`alias` must be a non-empty string when declared";
1092
+ return toolNameProblem("alias", alias);
1093
+ };
1094
+ var firstProblem2 = (props) => {
1095
+ if (isBlank2(props.serverName) || props.serverName !== props.serverName.trim()) {
1096
+ return "`serverName` must be a non-empty string without leading or trailing whitespace";
1097
+ }
1098
+ const named = toolNameProblem("serverName", props.serverName) ?? aliasProblem(props.alias);
1099
+ if (named !== undefined)
1100
+ return named;
1101
+ if (props.description !== undefined && isBlank2(props.description)) {
1102
+ return "`description` must be a non-empty string when declared: LiteLLM copies it into mcp_info only when it is truthy, so a blank one never converges";
1103
+ }
1104
+ if (props.serverId !== undefined && isBlank2(props.serverId)) {
1105
+ return "`serverId` must be a non-empty string when declared";
1106
+ }
1107
+ const url = urlProblem(props.url);
1108
+ if (url !== undefined)
1109
+ return url;
1110
+ if (!TRANSPORTS.includes(props.transport)) {
1111
+ return '`transport` must be "sse" or "http" (`stdio` runs a command on the proxy host and is not modelled)';
1112
+ }
1113
+ if (!AUTH_TYPES.includes(props.authType)) {
1114
+ return `\`authType\` must be one of ${AUTH_TYPES.join(", ")}; the others need credential fields this resource does not model`;
1115
+ }
1116
+ const declared = props.authValue !== undefined;
1117
+ if (isStaticAuthType(props.authType) && !declared) {
1118
+ return `\`authType: "${props.authType}"\` needs \`authValue: { fromEnv: … }\``;
1119
+ }
1120
+ if (!isStaticAuthType(props.authType) && declared) {
1121
+ return `\`authValue\` is the static credential for api_key, bearer_token, basic, authorization and token; this server is "${props.authType}"`;
1122
+ }
1123
+ if (declared && isBlank2(props.authValue?.fromEnv)) {
1124
+ return "`authValue.fromEnv` must name an environment variable";
1125
+ }
1126
+ return listProblem("allowedTools", props.allowedTools) ?? listProblem("mcpAccessGroups", props.mcpAccessGroups);
1127
+ };
1128
+ var toAttributes4 = (row) => ({
1129
+ alias: row.alias ?? null,
1130
+ allowAllKeys: row.allow_all_keys ?? false,
1131
+ allowedTools: [...row.allowed_tools ?? []],
1132
+ authType: row.auth_type ?? "none",
1133
+ credentialSeal: "",
1134
+ description: row.description ?? null,
1135
+ mcpAccessGroups: [...row.mcp_access_groups ?? []],
1136
+ serverId: row.server_id,
1137
+ serverName: row.server_name ?? null,
1138
+ transport: row.transport,
1139
+ url: row.url === undefined || row.url === null ? null : redactUrl(row.url)
1140
+ });
1141
+ var sameSet = (live, declared) => new Set(live).size === new Set(declared).size && declared.every((entry) => live.includes(entry));
1142
+ var differing3 = (live, props) => {
1143
+ const out = [];
1144
+ if (live.serverName !== props.serverName)
1145
+ out.push("server_name");
1146
+ if (live.url !== props.url)
1147
+ out.push("url");
1148
+ if (live.transport !== props.transport)
1149
+ out.push("transport");
1150
+ if (live.authType !== props.authType)
1151
+ out.push("auth_type");
1152
+ if (live.allowAllKeys !== (props.allowAllKeys ?? false))
1153
+ out.push("allow_all_keys");
1154
+ if (props.allowedTools !== undefined && !sameSet(live.allowedTools, props.allowedTools)) {
1155
+ out.push("allowed_tools");
1156
+ }
1157
+ if (!sameSet(live.mcpAccessGroups, props.mcpAccessGroups ?? []))
1158
+ out.push("mcp_access_groups");
1159
+ if (props.alias !== undefined && live.alias !== props.alias)
1160
+ out.push("alias");
1161
+ if (props.description !== undefined && live.description !== props.description) {
1162
+ out.push("description");
1163
+ }
1164
+ return out;
1165
+ };
1166
+ var managed = (props) => ({
1167
+ allow_all_keys: props.allowAllKeys ?? false,
1168
+ ...props.allowedTools === undefined ? {} : { allowed_tools: [...props.allowedTools] },
1169
+ auth_type: props.authType,
1170
+ ...props.description === undefined ? {} : { description: props.description },
1171
+ mcp_access_groups: [...props.mcpAccessGroups ?? []],
1172
+ transport: props.transport,
1173
+ url: props.url
1174
+ });
1175
+ var identityOnCreate = (props) => ({
1176
+ ...props.alias === undefined ? {} : { alias: props.alias },
1177
+ server_name: props.serverName
1178
+ });
1179
+ var identityOnUpdate = (props, live) => {
1180
+ const renamed = live.serverName !== props.serverName;
1181
+ const alias = props.alias ?? (renamed && live.alias !== null ? live.alias : undefined);
1182
+ return {
1183
+ ...alias === undefined ? {} : { alias },
1184
+ ...renamed ? { server_name: props.serverName } : {}
1185
+ };
1186
+ };
1187
+ var credentialsOf = (credential) => credential === undefined ? {} : { credentials: { auth_value: Redacted4.value(credential) } };
1188
+ var createBody4 = (props, serverId, credential) => ({
1189
+ ...managed(props),
1190
+ ...identityOnCreate(props),
1191
+ ...credentialsOf(credential),
1192
+ server_id: serverId
1193
+ });
1194
+ var updateBody3 = (props, serverId, credential, clearCredentials, live) => ({
1195
+ ...managed(props),
1196
+ ...identityOnUpdate(props, live),
1197
+ ...clearCredentials ? { credentials: null } : credentialsOf(credential),
1198
+ server_id: serverId
1199
+ });
1200
+
1201
+ // src/litellm/mcp-server-locate.ts
1202
+ import { createPhysicalName as createPhysicalName3 } from "alchemy/PhysicalName";
1203
+ import * as Effect15 from "effect/Effect";
1204
+
1205
+ // src/litellm/mcp-server-operations.ts
1206
+ import * as mcp from "@distilled.cloud/litellm/mcp_management";
1207
+ import { NotFound } from "@distilled.cloud/litellm/Errors";
1208
+ import * as Effect14 from "effect/Effect";
1209
+ var hasServerId = (row) => typeof row === "object" && row !== null && typeof row.server_id === "string";
1210
+ var listMcpServers = () => throughFetch(mcp.fetchAllMcpServersV1McpServerGet({})).pipe(Effect14.flatMap((response) => {
1211
+ const rows = Array.isArray(response) ? response : response.body;
1212
+ return Array.isArray(rows) && rows.every(hasServerId) ? Effect14.succeed(rows) : Effect14.fail(new LitellmMcpServerUnreadableError({
1213
+ reason: Array.isArray(rows) ? "a row has no server_id" : "not an array"
1214
+ }));
1215
+ }));
1216
+ var readMcpServer = (serverId) => throughFetch(mcp.fetchMcpServerV1McpServerServerIdGet({ server_id: serverId })).pipe(Effect14.map((row) => row.server_id === serverId ? row : undefined), Effect14.catch((error) => error instanceof NotFound ? Effect14.succeed(undefined) : Effect14.fail(error)));
1217
+ var createMcpServer = (body) => throughFetch(mcp.addMcpServerV1McpServerPost(body));
1218
+ var updateMcpServer = (body) => throughFetch(mcp.editMcpServerV1McpServerPut(body)).pipe(Effect14.asVoid);
1219
+ var deleteMcpServer = (serverId) => throughFetch(mcp.removeMcpServerV1McpServerServerIdDelete({ server_id: serverId })).pipe(Effect14.asVoid, Effect14.catch((original) => readMcpServer(serverId).pipe(Effect14.catch(() => Effect14.fail(original)), Effect14.flatMap((row) => row === undefined ? Effect14.void : Effect14.fail(original)))));
1220
+
1221
+ // src/litellm/mcp-server-locate.ts
1222
+ var locate2 = (rows, props, output) => {
1223
+ const pinned = output?.serverId ?? props.serverId;
1224
+ if (pinned !== undefined)
1225
+ return Effect15.succeed(rows.find((row) => row.server_id === pinned));
1226
+ const named = rows.filter((row) => row.server_name === props.serverName);
1227
+ return named.length > 1 ? Effect15.fail(new LitellmMcpServerAmbiguousNameError({
1228
+ serverIds: named.map((row) => row.server_id),
1229
+ serverName: props.serverName
1230
+ })) : Effect15.succeed(named[0]);
1231
+ };
1232
+ var wantedId = (id, instanceId, props, output) => output?.serverId !== undefined ? Effect15.succeed(output.serverId) : props.serverId !== undefined ? Effect15.succeed(props.serverId) : createPhysicalName3({ id, instanceId, lowercase: true, maxLength: 64 });
1233
+ var findLive = (id, instanceId, props, output) => Effect15.gen(function* () {
1234
+ const listed = yield* locate2(yield* listMcpServers(), props, output);
1235
+ if (listed !== undefined)
1236
+ return listed;
1237
+ return yield* readMcpServer(yield* wantedId(id, instanceId, props, output));
1238
+ });
1239
+
1240
+ // src/litellm/mcp-server-shadow.ts
1241
+ import * as Effect16 from "effect/Effect";
1242
+ var refuseShadowedDescription = (props, serverId) => props.description === undefined ? Effect16.void : readMcpServer(serverId).pipe(Effect16.flatMap((row) => {
1243
+ const info = row?.mcp_info;
1244
+ const shadowed = info !== undefined && info !== null && "description" in info && info["description"] !== props.description;
1245
+ return shadowed ? Effect16.fail(new LitellmMcpServerDescriptionShadowedError({
1246
+ serverId,
1247
+ serverName: props.serverName
1248
+ })) : Effect16.void;
1249
+ }));
1250
+
1251
+ // src/litellm/mcp-server.ts
1252
+ var LiteLLMMCPServer = Resource4("LiteLLM.MCPServer", {
1253
+ defaultRemovalPolicy: "retain"
1254
+ });
1255
+ var isLiteLLMMCPServer = (value5) => Predicate5.hasProperty(value5, "Type") && value5.Type === "LiteLLM.MCPServer";
1256
+ var refuse2 = (props) => {
1257
+ const problem = firstProblem2(props);
1258
+ return problem === undefined ? Effect17.void : Effect17.fail(new LitellmMcpServerInvalidError({ problem, serverName: String(props.serverName) }));
1259
+ };
1260
+ var mcpServerHandlers = {
1261
+ read: ({ id, instanceId, olds, output }) => Effect17.gen(function* () {
1262
+ const problem = output === undefined ? firstProblem2(olds) : undefined;
1263
+ if (problem !== undefined) {
1264
+ return yield* Effect17.die(new LitellmMcpServerInvalidError({ problem, serverName: String(olds.serverName) }));
1265
+ }
1266
+ const found = yield* findLive(id, instanceId, olds, output);
1267
+ if (found === undefined)
1268
+ return;
1269
+ const live = toAttributes4(found);
1270
+ return output === undefined ? Unowned5(live) : { ...live, credentialSeal: output.credentialSeal };
1271
+ }),
1272
+ diff: ({
1273
+ news,
1274
+ output
1275
+ }) => Effect17.gen(function* () {
1276
+ if (!isResolved4(news))
1277
+ return;
1278
+ yield* refuse2(news);
1279
+ if (output === undefined)
1280
+ return;
1281
+ if (news.serverId !== undefined && news.serverId !== output.serverId) {
1282
+ return { action: "replace", deleteFirst: false };
1283
+ }
1284
+ return differing3(output, news).length === 0 && credentialState(news, output.credentialSeal) !== "stale" ? { action: "noop" } : { action: "update" };
1285
+ }),
1286
+ reconcile: ({ id, instanceId, news, output }) => Effect17.gen(function* () {
1287
+ yield* refuse2(news);
1288
+ const before = yield* findLive(id, instanceId, news, output);
1289
+ const credential = resolveCredential(news);
1290
+ let sealed = output?.credentialSeal ?? "";
1291
+ let serverId;
1292
+ if (before === undefined) {
1293
+ yield* requireCredential(news, credential);
1294
+ const wanted = yield* wantedId(id, instanceId, news, output);
1295
+ const created = yield* createMcpServer(createBody4(news, wanted, credential.value));
1296
+ serverId = typeof created?.server_id === "string" ? created.server_id : wanted;
1297
+ sealed = credential.value === undefined ? "" : sealCredential(credential.value);
1298
+ } else {
1299
+ serverId = before.server_id;
1300
+ const live = toAttributes4(before);
1301
+ const state = credentialState(news, sealed, credential);
1302
+ if (differing3(live, news).length > 0 || state === "stale") {
1303
+ if (live.authType !== news.authType)
1304
+ yield* requireCredential(news, credential);
1305
+ if (differing3(live, news).includes("description")) {
1306
+ yield* refuseShadowedDescription(news, serverId);
1307
+ }
1308
+ const send = isStaticAuthType(news.authType) ? credential.value : undefined;
1309
+ const leavingStatic = !isStaticAuthType(news.authType) && (sealed !== "" || isStaticAuthType(live.authType));
1310
+ yield* updateMcpServer(updateBody3(news, serverId, send, leavingStatic, live));
1311
+ if (send !== undefined)
1312
+ sealed = sealCredential(send);
1313
+ else if (leavingStatic)
1314
+ sealed = "";
1315
+ }
1316
+ }
1317
+ const found = (yield* listMcpServers()).find((row) => row.server_id === serverId) ?? (yield* readMcpServer(serverId));
1318
+ if (found === undefined) {
1319
+ return yield* Effect17.fail(new LitellmMcpServerAbsentAfterWriteError({ serverId, serverName: news.serverName }));
1320
+ }
1321
+ const after = toAttributes4(found);
1322
+ const left = differing3(after, news);
1323
+ if (left.length > 0) {
1324
+ return yield* Effect17.fail(new LitellmMcpServerNotConvergedError({
1325
+ fields: left,
1326
+ serverId,
1327
+ serverName: news.serverName
1328
+ }));
1329
+ }
1330
+ return { ...after, credentialSeal: sealed };
1331
+ }),
1332
+ delete: ({ output }) => deleteMcpServer(output.serverId),
1333
+ list: () => Effect17.succeed([])
1334
+ };
1335
+ var LiteLLMMCPServerProvider = () => Provider4.effect(LiteLLMMCPServer, Effect17.succeed(LiteLLMMCPServer.Provider.of(mcpServerHandlers)));
1336
+ // src/litellm/access-group.ts
1337
+ import { Resource as Resource5 } from "alchemy";
1338
+ import { Unowned as Unowned6 } from "alchemy/AdoptPolicy";
1339
+ import { isResolved as isResolved5 } from "alchemy/Diff";
1340
+ import * as Provider5 from "alchemy/Provider";
1341
+ import * as Effect20 from "effect/Effect";
1342
+ import * as Predicate6 from "effect/Predicate";
1343
+
1344
+ // src/litellm/registry-support.ts
1345
+ import { NotFound as NotFound2 } from "@distilled.cloud/litellm/Errors";
1346
+ import * as Effect18 from "effect/Effect";
1347
+
1348
+ // src/litellm/registry-errors.ts
1349
+ import * as Data5 from "effect/Data";
1350
+
1351
+ class LitellmRegistryInvalidError extends Data5.TaggedError("LitellmRegistryInvalidError") {
1352
+ get message() {
1353
+ return `${this.resource} "${this.name}": ${this.problem}.`;
1354
+ }
1355
+ }
1356
+
1357
+ class LitellmRegistryUnreadableError extends Data5.TaggedError("LitellmRegistryUnreadableError") {
1358
+ get message() {
1359
+ return `${this.resource}: the proxy's answer is unreadable (${this.reason}).`;
1360
+ }
1361
+ }
1362
+
1363
+ class LitellmRegistryAmbiguousError extends Data5.TaggedError("LitellmRegistryAmbiguousError") {
1364
+ get message() {
1365
+ return `${this.resource} "${this.name}": ${this.ids.length} live rows match (${this.ids.join(", ")}). ` + "Declare the id to choose one.";
1366
+ }
1367
+ }
1368
+
1369
+ class LitellmRegistryAbsentAfterWriteError extends Data5.TaggedError("LitellmRegistryAbsentAfterWriteError") {
1370
+ get message() {
1371
+ return `${this.resource} "${this.name}": the write returned no error but the row is absent on the read back.`;
1372
+ }
1373
+ }
1374
+
1375
+ class LitellmRegistryNotConvergedError extends Data5.TaggedError("LitellmRegistryNotConvergedError") {
1376
+ get message() {
1377
+ return `${this.resource} "${this.name}": after the write, the row still differs in ${this.fields.join(", ")}.`;
1378
+ }
1379
+ }
1380
+
1381
+ // src/litellm/registry-support.ts
1382
+ var isNotFound = (error) => error instanceof NotFound2;
1383
+ var bodyOf = (response) => typeof response === "object" && response !== null && !Array.isArray(response) && ("body" in response) ? response.body : response;
1384
+ var asRow = (value5) => typeof value5 === "object" && value5 !== null && !Array.isArray(value5) ? value5 : undefined;
1385
+ var stringsOf = (value5) => Array.isArray(value5) ? value5.filter((each) => typeof each === "string") : [];
1386
+ var stringOrNull = (value5) => typeof value5 === "string" ? value5 : null;
1387
+ var numberOrNull2 = (value5) => {
1388
+ if (value5 === null || value5 === undefined || value5 === "")
1389
+ return null;
1390
+ const parsed = typeof value5 === "number" ? value5 : Number(value5);
1391
+ return Number.isFinite(parsed) ? parsed : null;
1392
+ };
1393
+ var canonical2 = (values) => [...new Set(values)].sort();
1394
+ var sameSet2 = (left, right) => {
1395
+ const a = canonical2(left);
1396
+ const b = canonical2(right);
1397
+ return a.length === b.length && a.every((each, index) => each === b[index]);
1398
+ };
1399
+ var isBlank3 = (value5) => typeof value5 !== "string" || value5.trim() === "";
1400
+ var firstBadEntry = (values) => {
1401
+ for (const each of values) {
1402
+ if (isBlank3(each) || each !== each.trim())
1403
+ return String(each);
1404
+ }
1405
+ return;
1406
+ };
1407
+ var firstDuplicate = (values) => values.find((each, index) => values.indexOf(each) !== index);
1408
+ var failIfInvalid = (resource, name, problem) => problem === undefined ? Effect18.void : Effect18.fail(new LitellmRegistryInvalidError({ name, problem, resource }));
1409
+ var dieIfInvalid = (resource, name, problem) => problem === undefined ? Effect18.void : Effect18.die(new LitellmRegistryInvalidError({ name, problem, resource }));
1410
+
1411
+ // src/litellm/access-group-form.ts
1412
+ var firstProblem3 = (props) => {
1413
+ if (isBlank3(props.accessGroupName) || props.accessGroupName !== props.accessGroupName.trim()) {
1414
+ return "`accessGroupName` must be a non-blank name with no leading or trailing space";
1415
+ }
1416
+ if (props.description !== undefined && isBlank3(props.description)) {
1417
+ return "`description` is blank; leave it out to keep the live text";
1418
+ }
1419
+ for (const [field, values] of [
1420
+ ["modelNames", props.modelNames ?? []],
1421
+ ["mcpServerIds", props.mcpServerIds ?? []]
1422
+ ]) {
1423
+ const bad = firstBadEntry(values);
1424
+ if (bad !== undefined)
1425
+ return `\`${field}\` has a blank or padded entry (${JSON.stringify(bad)})`;
1426
+ const twice = firstDuplicate(values);
1427
+ if (twice !== undefined)
1428
+ return `\`${field}\` lists ${JSON.stringify(twice)} twice`;
1429
+ }
1430
+ return;
1431
+ };
1432
+ var toAttributes5 = (value5) => {
1433
+ const row = asRow(value5);
1434
+ if (row === undefined)
1435
+ return;
1436
+ const accessGroupId = row["access_group_id"];
1437
+ const accessGroupName = row["access_group_name"];
1438
+ if (typeof accessGroupId !== "string" || typeof accessGroupName !== "string")
1439
+ return;
1440
+ return {
1441
+ accessGroupId,
1442
+ accessGroupName,
1443
+ description: stringOrNull(row["description"]),
1444
+ mcpServerIds: canonical2(stringsOf(row["access_mcp_server_ids"])),
1445
+ modelNames: canonical2(stringsOf(row["access_model_names"]))
1446
+ };
1447
+ };
1448
+ var differing4 = (live, props) => {
1449
+ const fields = [];
1450
+ if (live.accessGroupName !== props.accessGroupName)
1451
+ fields.push("access_group_name");
1452
+ if (props.description !== undefined && live.description !== props.description) {
1453
+ fields.push("description");
1454
+ }
1455
+ if (!sameSet2(live.modelNames, props.modelNames ?? []))
1456
+ fields.push("access_model_names");
1457
+ if (!sameSet2(live.mcpServerIds, props.mcpServerIds ?? []))
1458
+ fields.push("access_mcp_server_ids");
1459
+ return fields;
1460
+ };
1461
+ var createBody5 = (props) => ({
1462
+ access_group_name: props.accessGroupName,
1463
+ access_mcp_server_ids: [...props.mcpServerIds ?? []],
1464
+ access_model_names: [...props.modelNames ?? []],
1465
+ ...props.description === undefined ? {} : { description: props.description }
1466
+ });
1467
+ var updateBody4 = (props, live) => {
1468
+ const changed = new Set(differing4(live, props));
1469
+ return {
1470
+ ...changed.has("access_group_name") ? { access_group_name: props.accessGroupName } : {},
1471
+ ...changed.has("description") ? { description: props.description ?? null } : {},
1472
+ ...changed.has("access_model_names") ? { access_model_names: [...props.modelNames ?? []] } : {},
1473
+ ...changed.has("access_mcp_server_ids") ? { access_mcp_server_ids: [...props.mcpServerIds ?? []] } : {}
1474
+ };
1475
+ };
1476
+
1477
+ // src/litellm/access-group-operations.ts
1478
+ import * as ag from "@distilled.cloud/litellm/access_groups";
1479
+ import * as Effect19 from "effect/Effect";
1480
+ var RESOURCE = "LiteLLM.AccessGroup";
1481
+ var listAccessGroups = () => throughFetch(ag.listAccessGroupsV1UnifiedAccessGroupGet({})).pipe(Effect19.flatMap((response) => {
1482
+ const rows = bodyOf(response);
1483
+ if (!Array.isArray(rows)) {
1484
+ return Effect19.fail(new LitellmRegistryUnreadableError({ reason: "not an array", resource: RESOURCE }));
1485
+ }
1486
+ const parsed = rows.map(toAttributes5);
1487
+ return parsed.every((row) => row !== undefined) ? Effect19.succeed(parsed) : Effect19.fail(new LitellmRegistryUnreadableError({
1488
+ reason: "a row has no id or name",
1489
+ resource: RESOURCE
1490
+ }));
1491
+ }));
1492
+ var createAccessGroup = (body) => throughFetch(ag.createAccessGroupV1UnifiedAccessGroupPost(body)).pipe(Effect19.asVoid);
1493
+ var updateAccessGroup = (accessGroupId, body) => throughFetch(ag.updateAccessGroupV1UnifiedAccessGroupAccessGroupIdPut({
1494
+ ...body,
1495
+ access_group_id: accessGroupId
1496
+ })).pipe(Effect19.asVoid);
1497
+ var deleteAccessGroup = (accessGroupId) => throughFetch(ag.deleteAccessGroupV1UnifiedAccessGroupAccessGroupIdDelete({ access_group_id: accessGroupId })).pipe(Effect19.asVoid, Effect19.catch((original) => listAccessGroups().pipe(Effect19.catch(() => Effect19.fail(original)), Effect19.flatMap((rows) => rows.some((row) => row.accessGroupId === accessGroupId) ? Effect19.fail(original) : Effect19.void))));
1498
+
1499
+ // src/litellm/access-group.ts
1500
+ var RESOURCE2 = "LiteLLM.AccessGroup";
1501
+ var LiteLLMAccessGroup = Resource5("LiteLLM.AccessGroup", {
1502
+ defaultRemovalPolicy: "retain"
1503
+ });
1504
+ var isLiteLLMAccessGroup = (value5) => Predicate6.hasProperty(value5, "Type") && value5.Type === "LiteLLM.AccessGroup";
1505
+ var locate3 = (rows, props, output) => output !== undefined ? rows.find((row) => row.accessGroupId === output.accessGroupId) : rows.find((row) => row.accessGroupName === props.accessGroupName);
1506
+ var accessGroupHandlers = {
1507
+ read: ({ olds, output }) => Effect20.gen(function* () {
1508
+ if (output === undefined) {
1509
+ yield* dieIfInvalid(RESOURCE2, String(olds.accessGroupName), firstProblem3(olds));
1510
+ }
1511
+ const live = locate3(yield* listAccessGroups(), olds, output);
1512
+ if (live === undefined)
1513
+ return;
1514
+ return output === undefined ? Unowned6(live) : live;
1515
+ }),
1516
+ diff: ({
1517
+ news,
1518
+ output
1519
+ }) => Effect20.gen(function* () {
1520
+ if (!isResolved5(news))
1521
+ return;
1522
+ yield* failIfInvalid(RESOURCE2, String(news.accessGroupName), firstProblem3(news));
1523
+ if (output === undefined)
1524
+ return;
1525
+ return differing4(output, news).length === 0 ? { action: "noop" } : { action: "update" };
1526
+ }),
1527
+ reconcile: ({
1528
+ news,
1529
+ output
1530
+ }) => Effect20.gen(function* () {
1531
+ yield* failIfInvalid(RESOURCE2, String(news.accessGroupName), firstProblem3(news));
1532
+ const before = locate3(yield* listAccessGroups(), news, output);
1533
+ if (before === undefined)
1534
+ yield* createAccessGroup(createBody5(news));
1535
+ else if (differing4(before, news).length > 0) {
1536
+ yield* updateAccessGroup(before.accessGroupId, updateBody4(news, before));
1537
+ }
1538
+ const rows = yield* listAccessGroups();
1539
+ const after = before === undefined ? rows.find((row) => row.accessGroupName === news.accessGroupName) : rows.find((row) => row.accessGroupId === before.accessGroupId);
1540
+ if (after === undefined) {
1541
+ return yield* Effect20.fail(new LitellmRegistryAbsentAfterWriteError({
1542
+ name: news.accessGroupName,
1543
+ resource: RESOURCE2
1544
+ }));
1545
+ }
1546
+ const left = differing4(after, news);
1547
+ if (left.length > 0) {
1548
+ return yield* Effect20.fail(new LitellmRegistryNotConvergedError({
1549
+ fields: left,
1550
+ name: news.accessGroupName,
1551
+ resource: RESOURCE2
1552
+ }));
1553
+ }
1554
+ return after;
1555
+ }),
1556
+ delete: ({ output }) => deleteAccessGroup(output.accessGroupId),
1557
+ list: () => Effect20.succeed([])
1558
+ };
1559
+ var LiteLLMAccessGroupProvider = () => Provider5.effect(LiteLLMAccessGroup, Effect20.succeed(LiteLLMAccessGroup.Provider.of(accessGroupHandlers)));
1560
+ // src/litellm/policy-attachment.ts
1561
+ import { Resource as Resource6 } from "alchemy";
1562
+ import { Unowned as Unowned7 } from "alchemy/AdoptPolicy";
1563
+ import { isResolved as isResolved6 } from "alchemy/Diff";
1564
+ import * as Provider6 from "alchemy/Provider";
1565
+ import * as Effect22 from "effect/Effect";
1566
+ import * as Predicate7 from "effect/Predicate";
1567
+
1568
+ // src/litellm/policy-attachment-form.ts
1569
+ var SELECTORS = ["teams", "keys", "models", "tags"];
1570
+ var firstProblem4 = (props) => {
1571
+ if (isBlank3(props.policyName) || props.policyName !== props.policyName.trim()) {
1572
+ return "`policyName` must be a non-blank name with no leading or trailing space";
1573
+ }
1574
+ if (props.scope !== undefined && props.scope !== "*")
1575
+ return "`scope` can only be '*'";
1576
+ for (const field of SELECTORS) {
1577
+ const values = props[field] ?? [];
1578
+ const bad = firstBadEntry(values);
1579
+ if (bad !== undefined)
1580
+ return `\`${field}\` has a blank or padded entry (${JSON.stringify(bad)})`;
1581
+ const twice = firstDuplicate(values);
1582
+ if (twice !== undefined)
1583
+ return `\`${field}\` lists ${JSON.stringify(twice)} twice`;
1584
+ }
1585
+ if (props.scope === undefined && SELECTORS.every((field) => (props[field] ?? []).length === 0)) {
1586
+ return "no `scope`, `teams`, `keys`, `models` or `tags`: LiteLLM treats an attachment with no selector as GLOBAL, so declare `scope: '*'` if that is meant";
1587
+ }
1588
+ if (props.priority !== undefined && !(Number.isInteger(props.priority) && props.priority >= -2147483648 && props.priority <= 2147483647)) {
1589
+ return "`priority` must be a 32-bit integer";
1590
+ }
1591
+ return;
1592
+ };
1593
+ var toAttributes6 = (value5) => {
1594
+ const row = asRow(value5);
1595
+ if (row === undefined)
1596
+ return;
1597
+ const attachmentId = row["attachment_id"];
1598
+ const policyName = row["policy_name"];
1599
+ if (typeof attachmentId !== "string" || typeof policyName !== "string")
1600
+ return;
1601
+ return {
1602
+ attachmentId,
1603
+ keys: canonical2(stringsOf(row["keys"])),
1604
+ models: canonical2(stringsOf(row["models"])),
1605
+ policyName,
1606
+ priority: numberOrNull2(row["priority"]),
1607
+ scope: stringOrNull(row["scope"]),
1608
+ tags: canonical2(stringsOf(row["tags"])),
1609
+ teams: canonical2(stringsOf(row["teams"]))
1610
+ };
1611
+ };
1612
+ var isConfigRow = (value5) => asRow(value5)?.["definition_location"] === "config";
1613
+ var differing5 = (live, props) => {
1614
+ const fields = [];
1615
+ if (live.policyName !== props.policyName)
1616
+ fields.push("policy_name");
1617
+ if ((live.scope ?? null) !== (props.scope ?? null))
1618
+ fields.push("scope");
1619
+ for (const field of SELECTORS)
1620
+ if (!sameSet2(live[field], props[field] ?? []))
1621
+ fields.push(field);
1622
+ if (live.priority !== (props.priority ?? null))
1623
+ fields.push("priority");
1624
+ return fields;
1625
+ };
1626
+ var createBody6 = (props) => ({
1627
+ policy_name: props.policyName,
1628
+ ...props.scope === undefined ? {} : { scope: props.scope },
1629
+ ...props.teams === undefined ? {} : { teams: [...props.teams] },
1630
+ ...props.keys === undefined ? {} : { keys: [...props.keys] },
1631
+ ...props.models === undefined ? {} : { models: [...props.models] },
1632
+ ...props.tags === undefined ? {} : { tags: [...props.tags] },
1633
+ ...props.priority === undefined ? {} : { priority: props.priority }
1634
+ });
1635
+
1636
+ // src/litellm/policy-attachment-operations.ts
1637
+ import * as policies from "@distilled.cloud/litellm/policy_engine";
1638
+ import * as Effect21 from "effect/Effect";
1639
+ var RESOURCE3 = "LiteLLM.PolicyAttachment";
1640
+ var unreadable = (reason) => new LitellmRegistryUnreadableError({ reason, resource: RESOURCE3 });
1641
+ var listAttachments = () => throughFetch(policies.listPolicyAttachmentsPoliciesAttachmentsListGet({})).pipe(Effect21.flatMap((response) => {
1642
+ const rows = asRow(bodyOf(response))?.["attachments"];
1643
+ if (rows === undefined)
1644
+ return Effect21.succeed([]);
1645
+ if (!Array.isArray(rows))
1646
+ return Effect21.fail(unreadable("attachments is not an array"));
1647
+ const parsed = rows.filter((row) => !isConfigRow(row)).map(toAttributes6);
1648
+ return parsed.every((each) => each !== undefined) ? Effect21.succeed(parsed) : Effect21.fail(unreadable("an attachment has no id or policy name"));
1649
+ }));
1650
+ var createAttachment = (body) => throughFetch(policies.createPolicyAttachmentPoliciesAttachmentsPost(body)).pipe(Effect21.map((response) => toAttributes6(bodyOf(response))));
1651
+ var deleteAttachment = (attachmentId) => throughFetch(policies.deletePolicyAttachmentPoliciesAttachmentsAttachmentIdDelete({
1652
+ attachment_id: attachmentId
1653
+ })).pipe(Effect21.asVoid, Effect21.catch((original) => listAttachments().pipe(Effect21.catch(() => Effect21.fail(original)), Effect21.flatMap((rows) => rows.some((row) => row.attachmentId === attachmentId) ? Effect21.fail(original) : Effect21.void))));
1654
+
1655
+ // src/litellm/policy-attachment.ts
1656
+ var RESOURCE4 = "LiteLLM.PolicyAttachment";
1657
+ var LiteLLMPolicyAttachment = Resource6("LiteLLM.PolicyAttachment");
1658
+ var isLiteLLMPolicyAttachment = (value5) => Predicate7.hasProperty(value5, "Type") && value5.Type === "LiteLLM.PolicyAttachment";
1659
+ var locate4 = (rows, props, output) => {
1660
+ if (output !== undefined) {
1661
+ return Effect22.succeed(rows.find((row) => row.attachmentId === output.attachmentId));
1662
+ }
1663
+ const equal = rows.filter((row) => differing5(row, props).length === 0);
1664
+ return equal.length > 1 ? Effect22.fail(new LitellmRegistryAmbiguousError({
1665
+ ids: equal.map((row) => row.attachmentId),
1666
+ name: props.policyName,
1667
+ resource: RESOURCE4
1668
+ })) : Effect22.succeed(equal[0]);
1669
+ };
1670
+ var policyAttachmentHandlers = {
1671
+ read: ({
1672
+ olds,
1673
+ output
1674
+ }) => Effect22.gen(function* () {
1675
+ if (output === undefined) {
1676
+ yield* dieIfInvalid(RESOURCE4, String(olds.policyName), firstProblem4(olds));
1677
+ }
1678
+ const live = yield* locate4(yield* listAttachments(), olds, output);
1679
+ if (live === undefined)
1680
+ return;
1681
+ return output === undefined ? Unowned7(live) : live;
1682
+ }),
1683
+ diff: ({
1684
+ news,
1685
+ output
1686
+ }) => Effect22.gen(function* () {
1687
+ if (!isResolved6(news))
1688
+ return;
1689
+ yield* failIfInvalid(RESOURCE4, String(news.policyName), firstProblem4(news));
1690
+ if (output === undefined)
1691
+ return;
1692
+ return differing5(output, news).length === 0 ? { action: "noop" } : { action: "replace", deleteFirst: false };
1693
+ }),
1694
+ reconcile: ({
1695
+ news,
1696
+ output
1697
+ }) => Effect22.gen(function* () {
1698
+ yield* failIfInvalid(RESOURCE4, String(news.policyName), firstProblem4(news));
1699
+ const before = yield* locate4(yield* listAttachments(), news, output);
1700
+ if (before !== undefined && differing5(before, news).length === 0)
1701
+ return before;
1702
+ const created = yield* createAttachment(createBody6(news));
1703
+ if (created === undefined) {
1704
+ return yield* Effect22.fail(new LitellmRegistryUnreadableError({
1705
+ reason: "the create answered something that is not an attachment",
1706
+ resource: RESOURCE4
1707
+ }));
1708
+ }
1709
+ const after = (yield* listAttachments()).find((row) => row.attachmentId === created.attachmentId);
1710
+ if (after === undefined) {
1711
+ return yield* Effect22.fail(new LitellmRegistryAbsentAfterWriteError({ name: news.policyName, resource: RESOURCE4 }));
1712
+ }
1713
+ const left = differing5(after, news);
1714
+ if (left.length > 0) {
1715
+ return yield* Effect22.fail(new LitellmRegistryNotConvergedError({
1716
+ fields: left,
1717
+ name: news.policyName,
1718
+ resource: RESOURCE4
1719
+ }));
1720
+ }
1721
+ return after;
1722
+ }),
1723
+ delete: ({ output }) => deleteAttachment(output.attachmentId),
1724
+ list: () => Effect22.succeed([])
1725
+ };
1726
+ var LiteLLMPolicyAttachmentProvider = () => Provider6.effect(LiteLLMPolicyAttachment, Effect22.succeed(LiteLLMPolicyAttachment.Provider.of(policyAttachmentHandlers)));
1727
+ // src/litellm/policy.ts
1728
+ import { Resource as Resource7 } from "alchemy";
1729
+ import { Unowned as Unowned8 } from "alchemy/AdoptPolicy";
1730
+ import { isResolved as isResolved7 } from "alchemy/Diff";
1731
+ import * as Provider7 from "alchemy/Provider";
1732
+ import * as Effect24 from "effect/Effect";
1733
+ import * as Predicate8 from "effect/Predicate";
1734
+
1735
+ // src/litellm/policy-form.ts
1736
+ var firstProblem5 = (props) => {
1737
+ if (isBlank3(props.policyName) || props.policyName !== props.policyName.trim()) {
1738
+ return "`policyName` must be a non-blank name with no leading or trailing space";
1739
+ }
1740
+ for (const [field, value5] of [
1741
+ ["description", props.description],
1742
+ ["inherit", props.inherit],
1743
+ ["conditionModel", props.conditionModel]
1744
+ ]) {
1745
+ if (value5 !== undefined && isBlank3(value5)) {
1746
+ return `\`${field}\` is blank; leave it out to keep the live value (a policy field cannot be cleared)`;
1747
+ }
1748
+ }
1749
+ if (props.inherit === props.policyName)
1750
+ return "`inherit` names the policy itself";
1751
+ for (const [field, values] of [
1752
+ ["guardrailsAdd", props.guardrailsAdd ?? []],
1753
+ ["guardrailsRemove", props.guardrailsRemove ?? []]
1754
+ ]) {
1755
+ const bad = firstBadEntry(values);
1756
+ if (bad !== undefined)
1757
+ return `\`${field}\` has a blank or padded entry (${JSON.stringify(bad)})`;
1758
+ const twice = firstDuplicate(values);
1759
+ if (twice !== undefined)
1760
+ return `\`${field}\` lists ${JSON.stringify(twice)} twice`;
1761
+ }
1762
+ const both = (props.guardrailsAdd ?? []).find((name) => (props.guardrailsRemove ?? []).includes(name));
1763
+ if (both !== undefined)
1764
+ return `guardrail ${JSON.stringify(both)} is both added and removed`;
1765
+ return;
1766
+ };
1767
+ var toVersion = (value5) => {
1768
+ const row = asRow(value5);
1769
+ if (row === undefined)
1770
+ return;
1771
+ const policyId = row["policy_id"];
1772
+ const policyName = row["policy_name"];
1773
+ if (typeof policyId !== "string" || typeof policyName !== "string")
1774
+ return;
1775
+ const condition = asRow(row["condition"]);
1776
+ return {
1777
+ conditionModel: stringOrNull(condition?.["model"]),
1778
+ description: stringOrNull(row["description"]),
1779
+ guardrailsAdd: canonical2(stringsOf(row["guardrails_add"])),
1780
+ guardrailsRemove: canonical2(stringsOf(row["guardrails_remove"])),
1781
+ inherit: stringOrNull(row["inherit"]),
1782
+ policyId,
1783
+ policyName,
1784
+ versionNumber: numberOrNull2(row["version_number"]) ?? 1,
1785
+ versionStatus: typeof row["version_status"] === "string" ? row["version_status"] : "production"
1786
+ };
1787
+ };
1788
+ var toAttributes7 = (version) => {
1789
+ const { versionStatus: _status, ...attributes } = version;
1790
+ return attributes;
1791
+ };
1792
+ var differing6 = (live, props) => {
1793
+ const fields = [];
1794
+ if (props.description !== undefined && live.description !== props.description) {
1795
+ fields.push("description");
1796
+ }
1797
+ if (props.inherit !== undefined && live.inherit !== props.inherit)
1798
+ fields.push("inherit");
1799
+ if (!sameSet2(live.guardrailsAdd, props.guardrailsAdd ?? []))
1800
+ fields.push("guardrails_add");
1801
+ if (!sameSet2(live.guardrailsRemove, props.guardrailsRemove ?? []))
1802
+ fields.push("guardrails_remove");
1803
+ if (props.conditionModel !== undefined && live.conditionModel !== props.conditionModel) {
1804
+ fields.push("condition");
1805
+ }
1806
+ return fields;
1807
+ };
1808
+ var createBody7 = (props) => ({
1809
+ guardrails_add: [...props.guardrailsAdd ?? []],
1810
+ guardrails_remove: [...props.guardrailsRemove ?? []],
1811
+ policy_name: props.policyName,
1812
+ ...props.description === undefined ? {} : { description: props.description },
1813
+ ...props.inherit === undefined ? {} : { inherit: props.inherit },
1814
+ ...props.conditionModel === undefined ? {} : { condition: { model: props.conditionModel } }
1815
+ });
1816
+ var updateBody5 = (props, live) => {
1817
+ const changed = new Set(differing6(live, props));
1818
+ return {
1819
+ ...changed.has("description") ? { description: props.description ?? null } : {},
1820
+ ...changed.has("inherit") ? { inherit: props.inherit ?? null } : {},
1821
+ ...changed.has("guardrails_add") ? { guardrails_add: [...props.guardrailsAdd ?? []] } : {},
1822
+ ...changed.has("guardrails_remove") ? { guardrails_remove: [...props.guardrailsRemove ?? []] } : {},
1823
+ ...changed.has("condition") ? { condition: { model: props.conditionModel ?? null } } : {}
1824
+ };
1825
+ };
1826
+
1827
+ // src/litellm/policy-operations.ts
1828
+ import * as policies2 from "@distilled.cloud/litellm/policy_engine";
1829
+ import * as Effect23 from "effect/Effect";
1830
+ var RESOURCE5 = "LiteLLM.Policy";
1831
+ var unreadable2 = (reason) => new LitellmRegistryUnreadableError({ reason, resource: RESOURCE5 });
1832
+ var listPolicyVersions = (policyName) => throughFetch(policies2.listPolicyVersionsPoliciesNamePolicyNameVersionsGet({ policy_name: policyName })).pipe(Effect23.flatMap((response) => {
1833
+ const versions = asRow(bodyOf(response))?.["versions"];
1834
+ if (versions === undefined)
1835
+ return Effect23.succeed([]);
1836
+ if (!Array.isArray(versions))
1837
+ return Effect23.fail(unreadable2("versions is not an array"));
1838
+ const parsed = versions.map(toVersion);
1839
+ return parsed.every((each) => each !== undefined) ? Effect23.succeed(parsed) : Effect23.fail(unreadable2("a version has no id or name"));
1840
+ }));
1841
+ var configPolicyNames = () => throughFetch(policies2.listPoliciesPoliciesListGet({ version_status: "production" })).pipe(Effect23.flatMap((response) => {
1842
+ const rows = asRow(bodyOf(response))?.["policies"];
1843
+ if (!Array.isArray(rows))
1844
+ return Effect23.fail(unreadable2("policies is not an array"));
1845
+ return Effect23.succeed(rows.flatMap((row) => {
1846
+ const each = asRow(row);
1847
+ return each?.["definition_location"] === "config" && typeof each["policy_name"] === "string" ? [each["policy_name"]] : [];
1848
+ }));
1849
+ }));
1850
+ var createPolicy = (body) => throughFetch(policies2.createPolicyPoliciesPost(body)).pipe(Effect23.asVoid);
1851
+ var createDraft = (policyName) => throughFetch(policies2.createPolicyVersionPoliciesNamePolicyNameVersionsPost({ policy_name: policyName })).pipe(Effect23.flatMap((response) => {
1852
+ const draft = toVersion(bodyOf(response));
1853
+ return draft === undefined ? Effect23.fail(unreadable2("the new draft is not a policy")) : Effect23.succeed(draft);
1854
+ }));
1855
+ var editDraft = (policyId, body) => throughFetch(policies2.updatePolicyPoliciesPolicyIdPut({ ...body, policy_id: policyId })).pipe(Effect23.asVoid);
1856
+ var setVersionStatus = (policyId, status) => throughFetch(policies2.updatePolicyVersionStatusPoliciesPolicyIdStatusPut({
1857
+ policy_id: policyId,
1858
+ version_status: status
1859
+ })).pipe(Effect23.asVoid);
1860
+ var deleteAllVersions = (policyName) => throughFetch(policies2.deleteAllPolicyVersionsPoliciesNamePolicyNameAllVersionsDelete({
1861
+ policy_name: policyName
1862
+ })).pipe(Effect23.asVoid);
1863
+
1864
+ // src/litellm/policy.ts
1865
+ var RESOURCE6 = "LiteLLM.Policy";
1866
+ var LiteLLMPolicy = Resource7("LiteLLM.Policy", {
1867
+ defaultRemovalPolicy: "retain"
1868
+ });
1869
+ var isLiteLLMPolicy = (value5) => Predicate8.hasProperty(value5, "Type") && value5.Type === "LiteLLM.Policy";
1870
+ var production = (versions) => versions.find((version) => version.versionStatus === "production");
1871
+ var invalid = (name, problem) => Effect24.fail(new LitellmRegistryInvalidError({ name, problem, resource: RESOURCE6 }));
1872
+ var policyHandlers = {
1873
+ read: ({ olds, output }) => Effect24.gen(function* () {
1874
+ if (output === undefined) {
1875
+ yield* dieIfInvalid(RESOURCE6, String(olds.policyName), firstProblem5(olds));
1876
+ }
1877
+ const live = production(yield* listPolicyVersions(output?.policyName ?? olds.policyName));
1878
+ if (live === undefined)
1879
+ return;
1880
+ return output === undefined ? Unowned8(toAttributes7(live)) : toAttributes7(live);
1881
+ }),
1882
+ diff: ({ news, output }) => Effect24.gen(function* () {
1883
+ if (!isResolved7(news))
1884
+ return;
1885
+ yield* failIfInvalid(RESOURCE6, String(news.policyName), firstProblem5(news));
1886
+ if (output === undefined)
1887
+ return;
1888
+ if (news.policyName !== output.policyName) {
1889
+ return { action: "replace", deleteFirst: false };
1890
+ }
1891
+ return differing6(output, news).length === 0 ? { action: "noop" } : { action: "update" };
1892
+ }),
1893
+ reconcile: ({ news }) => Effect24.gen(function* () {
1894
+ yield* failIfInvalid(RESOURCE6, String(news.policyName), firstProblem5(news));
1895
+ const versions = yield* listPolicyVersions(news.policyName);
1896
+ const live = production(versions);
1897
+ if (versions.length === 0) {
1898
+ if ((yield* configPolicyNames()).includes(news.policyName)) {
1899
+ return yield* invalid(news.policyName, "a policy of this name is defined in config.yaml, and a production DB policy would override it at runtime; rename this one or remove the config policy first");
1900
+ }
1901
+ yield* createPolicy(createBody7(news));
1902
+ } else if (live === undefined) {
1903
+ return yield* invalid(news.policyName, `${versions.length} version(s) exist and none is production, so the policy is inactive; promote one in LiteLLM (or delete its versions) instead of letting this guess`);
1904
+ } else if (differing6(live, news).length > 0) {
1905
+ const draft = yield* createDraft(news.policyName);
1906
+ yield* editDraft(draft.policyId, updateBody5(news, live));
1907
+ yield* setVersionStatus(draft.policyId, "published");
1908
+ yield* setVersionStatus(draft.policyId, "production");
1909
+ }
1910
+ const after = production(yield* listPolicyVersions(news.policyName));
1911
+ if (after === undefined) {
1912
+ return yield* Effect24.fail(new LitellmRegistryAbsentAfterWriteError({ name: news.policyName, resource: RESOURCE6 }));
1913
+ }
1914
+ const left = differing6(after, news);
1915
+ if (left.length > 0) {
1916
+ return yield* Effect24.fail(new LitellmRegistryNotConvergedError({
1917
+ fields: left,
1918
+ name: news.policyName,
1919
+ resource: RESOURCE6
1920
+ }));
1921
+ }
1922
+ return toAttributes7(after);
1923
+ }),
1924
+ delete: ({ output }) => deleteAllVersions(output.policyName),
1925
+ list: () => Effect24.succeed([])
1926
+ };
1927
+ var LiteLLMPolicyProvider = () => Provider7.effect(LiteLLMPolicy, Effect24.succeed(LiteLLMPolicy.Provider.of(policyHandlers)));
1928
+ // src/litellm/team.ts
1929
+ import { Resource as Resource8 } from "alchemy";
1930
+ import { Unowned as Unowned9 } from "alchemy/AdoptPolicy";
1931
+ import { isResolved as isResolved8 } from "alchemy/Diff";
1932
+ import { createPhysicalName as createPhysicalName4 } from "alchemy/PhysicalName";
1933
+ import * as Provider8 from "alchemy/Provider";
1934
+ import * as Effect26 from "effect/Effect";
1935
+ import * as Predicate9 from "effect/Predicate";
1936
+
1937
+ // src/litellm/team-members.ts
1938
+ var toMemberAttributes = (value5) => {
1939
+ if (!Array.isArray(value5))
1940
+ return [];
1941
+ const members = [];
1942
+ for (const entry of value5) {
1943
+ const row = asRow(entry);
1944
+ if (typeof row?.["user_id"] === "string" && row["user_id"] !== "") {
1945
+ members.push({
1946
+ role: typeof row["role"] === "string" ? row["role"] : "user",
1947
+ userId: row["user_id"]
1948
+ });
1949
+ }
1950
+ }
1951
+ return members.sort((a, b) => a.userId.localeCompare(b.userId));
1952
+ };
1953
+ var roleOf = (member) => member.role ?? "user";
1954
+ var membersToAdd = (live, declared) => (declared ?? []).filter((member) => !live.some((each) => each.userId === member.userId));
1955
+ var roleChanges = (live, declared) => (declared ?? []).filter((member) => live.some((each) => each.userId === member.userId && each.role !== roleOf(member)));
1956
+ var rosterPending = (live, declared) => membersToAdd(live, declared).length + roleChanges(live, declared).length > 0;
1957
+
1958
+ // src/litellm/team-permission.ts
1959
+ var ALL_PROXY_SERVERS = "all-proxy-mcpservers";
1960
+ var LISTS = [
1961
+ ["mcpServers", "mcp_servers"],
1962
+ ["mcpAccessGroups", "mcp_access_groups"],
1963
+ ["mcpToolsets", "mcp_toolsets"],
1964
+ ["blockedTools", "blocked_tools"]
1965
+ ];
1966
+ var parseToolPermissions = (value5) => {
1967
+ const parsed = typeof value5 === "string" ? safeJson(value5) : value5;
1968
+ const row = asRow(parsed);
1969
+ if (row === undefined)
1970
+ return {};
1971
+ return Object.fromEntries(Object.keys(row).sort().map((server) => [server, canonical2(stringsOf(row[server]))]));
1972
+ };
1973
+ var safeJson = (text) => {
1974
+ try {
1975
+ return JSON.parse(text);
1976
+ } catch {
1977
+ return;
1978
+ }
1979
+ };
1980
+ var toPermissionAttributes = (value5) => {
1981
+ const row = asRow(value5);
1982
+ return {
1983
+ blockedTools: canonical2(stringsOf(row?.["blocked_tools"])),
1984
+ mcpAccessGroups: canonical2(stringsOf(row?.["mcp_access_groups"])),
1985
+ mcpServers: canonical2(stringsOf(row?.["mcp_servers"])),
1986
+ mcpToolPermissions: parseToolPermissions(row?.["mcp_tool_permissions"]),
1987
+ mcpToolsets: canonical2(stringsOf(row?.["mcp_toolsets"]))
1988
+ };
1989
+ };
1990
+ var sameToolPermissions = (live, declared) => {
1991
+ const servers = Object.keys(declared).sort();
1992
+ return sameSet2(Object.keys(live), servers) && servers.every((server) => sameSet2(live[server] ?? [], declared[server] ?? []));
1993
+ };
1994
+ var permissionDiffers = (live, declared) => {
1995
+ if (declared === undefined)
1996
+ return [];
1997
+ const fields = [];
1998
+ for (const [prop, wire] of LISTS) {
1999
+ const wanted = declared[prop];
2000
+ if (wanted !== undefined && !sameSet2(live[prop], wanted))
2001
+ fields.push(wire);
2002
+ }
2003
+ if (declared.mcpToolPermissions !== undefined && !sameToolPermissions(live.mcpToolPermissions, declared.mcpToolPermissions)) {
2004
+ fields.push("mcp_tool_permissions");
2005
+ }
2006
+ return fields;
2007
+ };
2008
+ var permissionBody = (declared, only) => {
2009
+ const body = {};
2010
+ for (const [prop, wire] of LISTS) {
2011
+ const wanted = declared[prop];
2012
+ if (wanted !== undefined && (only === undefined || only.has(wire)))
2013
+ body[wire] = [...wanted];
2014
+ }
2015
+ if (declared.mcpToolPermissions !== undefined && (only === undefined || only.has("mcp_tool_permissions"))) {
2016
+ body["mcp_tool_permissions"] = Object.fromEntries(Object.entries(declared.mcpToolPermissions).map(([server, tools]) => [server, [...tools]]));
2017
+ }
2018
+ return body;
2019
+ };
2020
+ var permissionProblem = (declared) => {
2021
+ if (declared === undefined)
2022
+ return;
2023
+ for (const [prop] of LISTS) {
2024
+ const values = declared[prop] ?? [];
2025
+ const bad = firstBadEntry(values);
2026
+ if (bad !== undefined)
2027
+ return `\`objectPermission.${prop}\` has a blank or padded entry (${JSON.stringify(bad)})`;
2028
+ const twice = firstDuplicate(values);
2029
+ if (twice !== undefined)
2030
+ return `\`objectPermission.${prop}\` lists ${JSON.stringify(twice)} twice`;
2031
+ }
2032
+ if ((declared.mcpServers ?? []).includes(ALL_PROXY_SERVERS)) {
2033
+ return `\`objectPermission.mcpServers\` carries \`${ALL_PROXY_SERVERS}\`, which grants EVERY MCP server on the proxy; list the servers instead`;
2034
+ }
2035
+ for (const [server, tools] of Object.entries(declared.mcpToolPermissions ?? {})) {
2036
+ if (isBlank3(server) || server !== server.trim()) {
2037
+ return "`objectPermission.mcpToolPermissions` has a blank or padded server key";
2038
+ }
2039
+ const bad = firstBadEntry(tools);
2040
+ if (bad !== undefined)
2041
+ return `\`objectPermission.mcpToolPermissions\` lists a blank or padded tool for ${server}`;
2042
+ const twice = firstDuplicate(tools);
2043
+ if (twice !== undefined)
2044
+ return `\`objectPermission.mcpToolPermissions\` lists ${JSON.stringify(twice)} twice for ${server}`;
2045
+ }
2046
+ return;
2047
+ };
2048
+
2049
+ // src/litellm/team-form.ts
2050
+ var firstProblem6 = (props) => {
2051
+ if (isBlank3(props.teamAlias) || props.teamAlias !== props.teamAlias.trim()) {
2052
+ return "`teamAlias` must be a non-blank name with no leading or trailing space";
2053
+ }
2054
+ if (props.teamId !== undefined && (isBlank3(props.teamId) || props.teamId !== props.teamId.trim())) {
2055
+ return "`teamId` must be a non-blank id with no leading or trailing space";
2056
+ }
2057
+ for (const [field, values] of [
2058
+ ["models", props.models ?? []],
2059
+ ["accessGroupIds", props.accessGroupIds ?? []]
2060
+ ]) {
2061
+ const bad = firstBadEntry(values);
2062
+ if (bad !== undefined)
2063
+ return `\`${field}\` has a blank or padded entry (${JSON.stringify(bad)})`;
2064
+ const twice = firstDuplicate(values);
2065
+ if (twice !== undefined)
2066
+ return `\`${field}\` lists ${JSON.stringify(twice)} twice`;
2067
+ }
2068
+ const ids = (props.members ?? []).map((member) => member.userId);
2069
+ const badId = firstBadEntry(ids);
2070
+ if (badId !== undefined)
2071
+ return `\`members\` has a blank or padded userId (${JSON.stringify(badId)})`;
2072
+ const twiceId = firstDuplicate(ids);
2073
+ if (twiceId !== undefined)
2074
+ return `\`members\` lists ${JSON.stringify(twiceId)} twice`;
2075
+ for (const member of props.members ?? []) {
2076
+ if (member.role !== undefined && member.role !== "user" && member.role !== "admin") {
2077
+ return `member ${member.userId} has a role other than user or admin`;
2078
+ }
2079
+ }
2080
+ return permissionProblem(props.objectPermission);
2081
+ };
2082
+ var toAttributes8 = (value5) => {
2083
+ const row = asRow(asRow(value5)?.["team_info"]);
2084
+ if (row === undefined)
2085
+ return;
2086
+ const teamId = row["team_id"];
2087
+ if (typeof teamId !== "string")
2088
+ return;
2089
+ return {
2090
+ accessGroupIds: canonical2(stringsOf(row["access_group_ids"])),
2091
+ blocked: row["blocked"] === true,
2092
+ members: toMemberAttributes(row["members_with_roles"]),
2093
+ models: canonical2(stringsOf(row["models"])),
2094
+ objectPermission: toPermissionAttributes(row["object_permission"]),
2095
+ teamAlias: typeof row["team_alias"] === "string" ? row["team_alias"] : "",
2096
+ teamId
2097
+ };
2098
+ };
2099
+ var teamFieldsDiffering = (live, props) => {
2100
+ const fields = [];
2101
+ if (live.teamAlias !== props.teamAlias)
2102
+ fields.push("team_alias");
2103
+ if (props.models !== undefined && !sameSet2(live.models, props.models))
2104
+ fields.push("models");
2105
+ if (props.blocked !== undefined && live.blocked !== props.blocked)
2106
+ fields.push("blocked");
2107
+ if (props.accessGroupIds !== undefined && !sameSet2(live.accessGroupIds, props.accessGroupIds)) {
2108
+ fields.push("access_group_ids");
2109
+ }
2110
+ for (const wire of permissionDiffers(live.objectPermission, props.objectPermission)) {
2111
+ fields.push(`object_permission.${wire}`);
2112
+ }
2113
+ return fields;
2114
+ };
2115
+ var differing7 = (live, props) => [
2116
+ ...teamFieldsDiffering(live, props),
2117
+ ...rosterPending(live.members, props.members) ? ["members"] : []
2118
+ ];
2119
+ var createBody8 = (props, teamId) => ({
2120
+ team_alias: props.teamAlias,
2121
+ team_id: teamId,
2122
+ ...props.models === undefined ? {} : { models: [...props.models] },
2123
+ ...props.blocked === undefined ? {} : { blocked: props.blocked },
2124
+ ...props.accessGroupIds === undefined ? {} : { access_group_ids: [...props.accessGroupIds] },
2125
+ ...props.objectPermission === undefined ? {} : { object_permission: permissionBody(props.objectPermission) }
2126
+ });
2127
+ var updateBody6 = (props, live) => {
2128
+ const changed = new Set(teamFieldsDiffering(live, props));
2129
+ if (changed.size === 0)
2130
+ return;
2131
+ const permission = new Set([...changed].filter((field) => field.startsWith("object_permission.")).map((field) => field.slice(18)));
2132
+ return {
2133
+ team_id: live.teamId,
2134
+ ...changed.has("team_alias") ? { team_alias: props.teamAlias } : {},
2135
+ ...changed.has("models") ? { models: [...props.models ?? []] } : {},
2136
+ ...changed.has("blocked") ? { blocked: props.blocked ?? false } : {},
2137
+ ...changed.has("access_group_ids") ? { access_group_ids: [...props.accessGroupIds ?? []] } : {},
2138
+ ...props.objectPermission !== undefined && permission.size > 0 ? { object_permission: permissionBody(props.objectPermission, permission) } : {}
2139
+ };
2140
+ };
2141
+
2142
+ // src/litellm/team-operations.ts
2143
+ import * as team from "@distilled.cloud/litellm/team_management";
2144
+ import * as Effect25 from "effect/Effect";
2145
+ var readTeam = (teamId) => throughFetch(team.getTeamInfoTeamInfo({ team_id: teamId })).pipe(Effect25.map((response) => {
2146
+ const row = toAttributes8(bodyOf(response));
2147
+ return row?.teamId === teamId ? row : undefined;
2148
+ }), Effect25.catch((error) => isNotFound(error) ? Effect25.succeed(undefined) : Effect25.fail(error)));
2149
+ var createTeam = (body) => throughFetch(team.postNewTeamTeamNew(body)).pipe(Effect25.asVoid);
2150
+ var updateTeam = (body) => throughFetch(team.updateTeamTeamUpdatePost(body)).pipe(Effect25.asVoid);
2151
+ var addMembers = (teamId, members) => throughFetch(team.teamMemberAddTeamMemberAddPost({
2152
+ member: members.map((member) => ({ role: member.role ?? "user", user_id: member.userId })),
2153
+ team_id: teamId
2154
+ })).pipe(Effect25.asVoid);
2155
+ var setMemberRole = (teamId, member) => throughFetch(team.teamMemberUpdateTeamMemberUpdatePost({
2156
+ role: member.role ?? "user",
2157
+ team_id: teamId,
2158
+ user_id: member.userId
2159
+ })).pipe(Effect25.asVoid);
2160
+ var listTeamIds = () => throughFetch(team.listTeamTeamListGet({})).pipe(Effect25.map((response) => {
2161
+ const rows = bodyOf(response);
2162
+ return Array.isArray(rows) ? rows.flatMap((row) => {
2163
+ const id = asRow(row)?.["team_id"];
2164
+ return typeof id === "string" ? [id] : [];
2165
+ }) : [];
2166
+ }));
2167
+ var deleteTeam = (teamId) => throughFetch(team.deleteTeamTeamDeletePost({ team_ids: [teamId] })).pipe(Effect25.asVoid, Effect25.catchTag("NotFound", (original) => listTeamIds().pipe(Effect25.flatMap((ids) => ids.includes(teamId) ? Effect25.fail(original) : Effect25.void))));
2168
+
2169
+ // src/litellm/team.ts
2170
+ var RESOURCE7 = "LiteLLM.Team";
2171
+ var LiteLLMTeam = Resource8("LiteLLM.Team", {
2172
+ defaultRemovalPolicy: "retain"
2173
+ });
2174
+ var isLiteLLMTeam = (value5) => Predicate9.hasProperty(value5, "Type") && value5.Type === "LiteLLM.Team";
2175
+ var idOf3 = (id, instanceId, props, output) => output?.teamId !== undefined ? Effect26.succeed(output.teamId) : props.teamId !== undefined ? Effect26.succeed(props.teamId) : createPhysicalName4({ id, instanceId, lowercase: true, maxLength: 64 });
2176
+ var teamHandlers = {
2177
+ read: ({ id, instanceId, olds, output }) => Effect26.gen(function* () {
2178
+ if (output === undefined) {
2179
+ yield* dieIfInvalid(RESOURCE7, String(olds.teamAlias), firstProblem6(olds));
2180
+ }
2181
+ const live = yield* readTeam(yield* idOf3(id, instanceId, olds, output));
2182
+ if (live === undefined)
2183
+ return;
2184
+ return output === undefined ? Unowned9(live) : live;
2185
+ }),
2186
+ diff: ({ news, output }) => Effect26.gen(function* () {
2187
+ if (!isResolved8(news))
2188
+ return;
2189
+ yield* failIfInvalid(RESOURCE7, String(news.teamAlias), firstProblem6(news));
2190
+ if (output === undefined)
2191
+ return;
2192
+ if (news.teamId !== undefined && news.teamId !== output.teamId) {
2193
+ return { action: "replace", deleteFirst: false };
2194
+ }
2195
+ return differing7(output, news).length === 0 ? { action: "noop" } : { action: "update" };
2196
+ }),
2197
+ reconcile: ({ id, instanceId, news, output }) => Effect26.gen(function* () {
2198
+ yield* failIfInvalid(RESOURCE7, String(news.teamAlias), firstProblem6(news));
2199
+ const teamId = yield* idOf3(id, instanceId, news, output);
2200
+ const before = yield* readTeam(teamId);
2201
+ if (before === undefined)
2202
+ yield* createTeam(createBody8(news, teamId));
2203
+ else {
2204
+ const body = updateBody6(news, before);
2205
+ if (body !== undefined)
2206
+ yield* updateTeam(body);
2207
+ }
2208
+ if (news.members !== undefined) {
2209
+ const live = yield* readTeam(teamId);
2210
+ if (live === undefined) {
2211
+ return yield* Effect26.fail(new LitellmRegistryAbsentAfterWriteError({ name: news.teamAlias, resource: RESOURCE7 }));
2212
+ }
2213
+ const missing = membersToAdd(live.members, news.members);
2214
+ if (missing.length > 0)
2215
+ yield* addMembers(teamId, missing);
2216
+ for (const member of roleChanges(live.members, news.members)) {
2217
+ yield* setMemberRole(teamId, member);
2218
+ }
2219
+ }
2220
+ const after = yield* readTeam(teamId);
2221
+ if (after === undefined) {
2222
+ return yield* Effect26.fail(new LitellmRegistryAbsentAfterWriteError({ name: news.teamAlias, resource: RESOURCE7 }));
2223
+ }
2224
+ const left = differing7(after, news);
2225
+ if (left.length > 0) {
2226
+ return yield* Effect26.fail(new LitellmRegistryNotConvergedError({
2227
+ fields: left,
2228
+ name: news.teamAlias,
2229
+ resource: RESOURCE7
2230
+ }));
2231
+ }
2232
+ return after;
2233
+ }),
2234
+ delete: ({ output }) => deleteTeam(output.teamId),
2235
+ list: () => Effect26.succeed([])
2236
+ };
2237
+ var LiteLLMTeamProvider = () => Provider8.effect(LiteLLMTeam, Effect26.succeed(LiteLLMTeam.Provider.of(teamHandlers)));
2238
+ // src/litellm/tool-policy.ts
2239
+ import { Resource as Resource9 } from "alchemy";
2240
+ import { Unowned as Unowned10 } from "alchemy/AdoptPolicy";
2241
+ import { isResolved as isResolved9 } from "alchemy/Diff";
2242
+ import * as Provider9 from "alchemy/Provider";
2243
+ import * as Effect28 from "effect/Effect";
2244
+ import * as Predicate10 from "effect/Predicate";
2245
+
2246
+ // src/litellm/tool-policy-types.ts
2247
+ var DEFAULT_TOOL_POLICY = "untrusted";
2248
+ var INPUT_POLICIES = ["untrusted", "trusted", "blocked"];
2249
+ var OUTPUT_POLICIES = ["untrusted", "trusted"];
2250
+
2251
+ // src/litellm/tool-policy-form.ts
2252
+ var shadowed = (name) => name === "list" || name === "spend" || name === "policy/options" || ["/detail", "/logs"].some((suffix) => name.endsWith(suffix));
2253
+ var firstProblem7 = (props) => {
2254
+ if (isBlank3(props.toolName) || props.toolName !== props.toolName.trim()) {
2255
+ return "`toolName` must be a non-blank name with no leading or trailing space";
2256
+ }
2257
+ if (shadowed(props.toolName)) {
2258
+ return "`toolName` is one the /v1/tool route table answers itself (list, spend, policy/options, …/detail, …/logs), so it could never be read back";
2259
+ }
2260
+ if (props.inputPolicy === undefined && props.outputPolicy === undefined) {
2261
+ return "declare `inputPolicy`, `outputPolicy` or both (LiteLLM answers 400 to neither)";
2262
+ }
2263
+ if (props.inputPolicy !== undefined && !INPUT_POLICIES.includes(props.inputPolicy)) {
2264
+ return `\`inputPolicy\` must be one of ${INPUT_POLICIES.join(", ")}`;
2265
+ }
2266
+ if (props.outputPolicy !== undefined && !OUTPUT_POLICIES.includes(props.outputPolicy)) {
2267
+ return `\`outputPolicy\` must be one of ${OUTPUT_POLICIES.join(", ")}`;
2268
+ }
2269
+ return;
2270
+ };
2271
+ var toAttributes9 = (value5) => {
2272
+ const row = asRow(value5);
2273
+ if (row === undefined)
2274
+ return;
2275
+ const toolId = row["tool_id"];
2276
+ const toolName = row["tool_name"];
2277
+ if (typeof toolId !== "string" || typeof toolName !== "string")
2278
+ return;
2279
+ const policy = (field) => typeof row[field] === "string" && row[field] !== "" ? row[field] : "untrusted";
2280
+ return {
2281
+ inputPolicy: policy("input_policy"),
2282
+ outputPolicy: policy("output_policy"),
2283
+ toolId,
2284
+ toolName
2285
+ };
2286
+ };
2287
+ var differing8 = (live, props) => {
2288
+ const fields = [];
2289
+ if (props.inputPolicy !== undefined && live.inputPolicy !== props.inputPolicy) {
2290
+ fields.push("input_policy");
2291
+ }
2292
+ if (props.outputPolicy !== undefined && live.outputPolicy !== props.outputPolicy) {
2293
+ fields.push("output_policy");
2294
+ }
2295
+ return fields;
2296
+ };
2297
+ var updateBody7 = (props, live) => {
2298
+ const changed = live === undefined ? undefined : new Set(differing8(live, props));
2299
+ return {
2300
+ tool_name: props.toolName,
2301
+ ...props.inputPolicy !== undefined && (changed === undefined || changed.has("input_policy")) ? { input_policy: props.inputPolicy } : {},
2302
+ ...props.outputPolicy !== undefined && (changed === undefined || changed.has("output_policy")) ? { output_policy: props.outputPolicy } : {}
2303
+ };
2304
+ };
2305
+
2306
+ // src/litellm/tool-policy-operations.ts
2307
+ import * as tools from "@distilled.cloud/litellm/tools";
2308
+ import * as Effect27 from "effect/Effect";
2309
+ var readTool = (toolName) => throughFetch(tools.getToolV1ToolToolNameGet({ tool_name: toolName })).pipe(Effect27.map((response) => {
2310
+ const row = toAttributes9(bodyOf(response));
2311
+ return row?.toolName === toolName ? row : undefined;
2312
+ }), Effect27.catch((error) => isNotFound(error) ? Effect27.succeed(undefined) : Effect27.fail(error)));
2313
+ var writeToolPolicy = (body) => throughFetch(tools.updateToolPolicyV1ToolPolicyPost(body)).pipe(Effect27.asVoid);
2314
+ var resetToolPolicy = (props) => readTool(props.toolName).pipe(Effect27.flatMap((live) => {
2315
+ if (live === undefined)
2316
+ return Effect27.void;
2317
+ const inputStale = props.inputPolicy !== undefined && live.inputPolicy !== DEFAULT_TOOL_POLICY;
2318
+ const outputStale = props.outputPolicy !== undefined && live.outputPolicy !== DEFAULT_TOOL_POLICY;
2319
+ if (!inputStale && !outputStale)
2320
+ return Effect27.void;
2321
+ return writeToolPolicy({
2322
+ tool_name: props.toolName,
2323
+ ...inputStale ? { input_policy: DEFAULT_TOOL_POLICY } : {},
2324
+ ...outputStale ? { output_policy: DEFAULT_TOOL_POLICY } : {}
2325
+ });
2326
+ }));
2327
+
2328
+ // src/litellm/tool-policy.ts
2329
+ var RESOURCE8 = "LiteLLM.ToolPolicy";
2330
+ var LiteLLMToolPolicy = Resource9("LiteLLM.ToolPolicy", {
2331
+ defaultRemovalPolicy: "retain"
2332
+ });
2333
+ var isLiteLLMToolPolicy = (value5) => Predicate10.hasProperty(value5, "Type") && value5.Type === "LiteLLM.ToolPolicy";
2334
+ var toolPolicyHandlers = {
2335
+ read: ({ olds, output }) => Effect28.gen(function* () {
2336
+ if (output === undefined) {
2337
+ yield* dieIfInvalid(RESOURCE8, String(olds.toolName), firstProblem7(olds));
2338
+ }
2339
+ const live = yield* readTool(output?.toolName ?? olds.toolName);
2340
+ if (live === undefined)
2341
+ return;
2342
+ return output === undefined ? Unowned10(live) : live;
2343
+ }),
2344
+ diff: ({
2345
+ news,
2346
+ output
2347
+ }) => Effect28.gen(function* () {
2348
+ if (!isResolved9(news))
2349
+ return;
2350
+ yield* failIfInvalid(RESOURCE8, String(news.toolName), firstProblem7(news));
2351
+ if (output === undefined)
2352
+ return;
2353
+ if (news.toolName !== output.toolName) {
2354
+ return { action: "replace", deleteFirst: false };
2355
+ }
2356
+ return differing8(output, news).length === 0 ? { action: "noop" } : { action: "update" };
2357
+ }),
2358
+ reconcile: ({ news }) => Effect28.gen(function* () {
2359
+ yield* failIfInvalid(RESOURCE8, String(news.toolName), firstProblem7(news));
2360
+ const before = yield* readTool(news.toolName);
2361
+ if (before === undefined || differing8(before, news).length > 0) {
2362
+ yield* writeToolPolicy(updateBody7(news, before));
2363
+ }
2364
+ const after = yield* readTool(news.toolName);
2365
+ if (after === undefined) {
2366
+ return yield* Effect28.fail(new LitellmRegistryAbsentAfterWriteError({ name: news.toolName, resource: RESOURCE8 }));
2367
+ }
2368
+ const left = differing8(after, news);
2369
+ if (left.length > 0) {
2370
+ return yield* Effect28.fail(new LitellmRegistryNotConvergedError({
2371
+ fields: left,
2372
+ name: news.toolName,
2373
+ resource: RESOURCE8
2374
+ }));
2375
+ }
2376
+ return after;
2377
+ }),
2378
+ delete: ({ olds }) => resetToolPolicy(olds),
2379
+ list: () => Effect28.succeed([])
2380
+ };
2381
+ var LiteLLMToolPolicyProvider = () => Provider9.effect(LiteLLMToolPolicy, Effect28.succeed(LiteLLMToolPolicy.Provider.of(toolPolicyHandlers)));
2382
+ // src/litellm/toolset.ts
2383
+ import { Resource as Resource10 } from "alchemy";
2384
+ import { Unowned as Unowned11 } from "alchemy/AdoptPolicy";
2385
+ import { isResolved as isResolved10 } from "alchemy/Diff";
2386
+ import * as Provider10 from "alchemy/Provider";
2387
+ import * as Effect30 from "effect/Effect";
2388
+ import * as Predicate11 from "effect/Predicate";
2389
+
2390
+ // src/litellm/toolset-form.ts
2391
+ var pairKey = (tool) => JSON.stringify([tool.serverId, tool.toolName]);
2392
+ var canonicalTools = (tools2) => [...new Map(tools2.map((tool) => [pairKey(tool), tool])).values()].sort((a, b) => pairKey(a).localeCompare(pairKey(b)));
2393
+ var sameTools = (left, right) => {
2394
+ const a = canonicalTools(left).map(pairKey);
2395
+ const b = canonicalTools(right).map(pairKey);
2396
+ return a.length === b.length && a.every((each, index) => each === b[index]);
2397
+ };
2398
+ var firstProblem8 = (props) => {
2399
+ if (isBlank3(props.toolsetName) || props.toolsetName !== props.toolsetName.trim()) {
2400
+ return "`toolsetName` must be a non-blank name with no leading or trailing space";
2401
+ }
2402
+ if (props.toolsetName.includes("/")) {
2403
+ return "`toolsetName` contains `/`: a toolset is served at /toolset/{toolset_name}/mcp, so that name can never be addressed";
2404
+ }
2405
+ if (props.description !== undefined && isBlank3(props.description)) {
2406
+ return "`description` is blank; leave it out to keep the live text";
2407
+ }
2408
+ if (!Array.isArray(props.tools))
2409
+ return "`tools` must be a list (an empty one is `[]`)";
2410
+ const bad = firstBadEntry(props.tools.map((tool) => tool.serverId)) ?? firstBadEntry(props.tools.map((tool) => tool.toolName));
2411
+ if (bad !== undefined)
2412
+ return `a tool has a blank or padded serverId or toolName (${JSON.stringify(bad)})`;
2413
+ const keys = props.tools.map(pairKey);
2414
+ const twice = keys.find((key, index) => keys.indexOf(key) !== index);
2415
+ if (twice !== undefined)
2416
+ return `\`tools\` lists ${twice} twice`;
2417
+ return;
2418
+ };
2419
+ var toAttributes10 = (value5) => {
2420
+ const row = asRow(value5);
2421
+ if (row === undefined)
2422
+ return;
2423
+ const toolsetId = row["toolset_id"];
2424
+ const toolsetName = row["toolset_name"];
2425
+ if (typeof toolsetId !== "string" || typeof toolsetName !== "string")
2426
+ return;
2427
+ const tools2 = [];
2428
+ for (const entry of Array.isArray(row["tools"]) ? row["tools"] : []) {
2429
+ const pair = asRow(entry);
2430
+ if (typeof pair?.["server_id"] === "string" && typeof pair["tool_name"] === "string") {
2431
+ tools2.push({ serverId: pair["server_id"], toolName: pair["tool_name"] });
2432
+ }
2433
+ }
2434
+ return {
2435
+ description: stringOrNull(row["description"]),
2436
+ toolsetId,
2437
+ toolsetName,
2438
+ tools: canonicalTools(tools2)
2439
+ };
2440
+ };
2441
+ var differing9 = (live, props) => {
2442
+ const fields = [];
2443
+ if (live.toolsetName !== props.toolsetName)
2444
+ fields.push("toolset_name");
2445
+ if (props.description !== undefined && live.description !== props.description) {
2446
+ fields.push("description");
2447
+ }
2448
+ if (!sameTools(live.tools, props.tools))
2449
+ fields.push("tools");
2450
+ return fields;
2451
+ };
2452
+ var wireTools = (tools2) => tools2.map((tool) => ({ server_id: tool.serverId, tool_name: tool.toolName }));
2453
+ var createBody9 = (props) => ({
2454
+ toolset_name: props.toolsetName,
2455
+ tools: wireTools(props.tools),
2456
+ ...props.description === undefined ? {} : { description: props.description }
2457
+ });
2458
+ var updateBody8 = (props, live) => {
2459
+ const changed = new Set(differing9(live, props));
2460
+ return {
2461
+ toolset_id: live.toolsetId,
2462
+ ...changed.has("toolset_name") ? { toolset_name: props.toolsetName } : {},
2463
+ ...changed.has("description") ? { description: props.description ?? null } : {},
2464
+ ...changed.has("tools") ? { tools: wireTools(props.tools) } : {}
2465
+ };
2466
+ };
2467
+
2468
+ // src/litellm/toolset-operations.ts
2469
+ import * as mcp2 from "@distilled.cloud/litellm/mcp_management";
2470
+ import * as Effect29 from "effect/Effect";
2471
+ var RESOURCE9 = "LiteLLM.Toolset";
2472
+ var listToolsets = () => throughFetch(mcp2.fetchMcpToolsetsV1McpToolsetGet({})).pipe(Effect29.flatMap((response) => {
2473
+ const rows = bodyOf(response);
2474
+ if (!Array.isArray(rows)) {
2475
+ return Effect29.fail(new LitellmRegistryUnreadableError({ reason: "not an array", resource: RESOURCE9 }));
2476
+ }
2477
+ const parsed = rows.map(toAttributes10);
2478
+ return parsed.every((row) => row !== undefined) ? Effect29.succeed(parsed) : Effect29.fail(new LitellmRegistryUnreadableError({
2479
+ reason: "a row has no id or name",
2480
+ resource: RESOURCE9
2481
+ }));
2482
+ }));
2483
+ var readToolset = (toolsetId) => throughFetch(mcp2.fetchMcpToolsetV1McpToolsetToolsetIdGet({ toolset_id: toolsetId })).pipe(Effect29.map((response) => {
2484
+ const row = toAttributes10(bodyOf(response));
2485
+ return row?.toolsetId === toolsetId ? row : undefined;
2486
+ }), Effect29.catch((error) => isNotFound(error) ? Effect29.succeed(undefined) : Effect29.fail(error)));
2487
+ var createToolset = (body) => throughFetch(mcp2.addMcpToolsetV1McpToolsetPost(body)).pipe(Effect29.map((response) => toAttributes10(bodyOf(response))));
2488
+ var updateToolset = (body) => throughFetch(mcp2.editMcpToolsetV1McpToolsetPut(body)).pipe(Effect29.asVoid);
2489
+ var deleteToolset = (toolsetId) => throughFetch(mcp2.removeMcpToolsetV1McpToolsetToolsetIdDelete({ toolset_id: toolsetId })).pipe(Effect29.asVoid, Effect29.catch((original) => readToolset(toolsetId).pipe(Effect29.catch(() => Effect29.fail(original)), Effect29.flatMap((row) => row === undefined ? Effect29.void : Effect29.fail(original)))));
2490
+
2491
+ // src/litellm/toolset.ts
2492
+ var RESOURCE10 = "LiteLLM.Toolset";
2493
+ var LiteLLMToolset = Resource10("LiteLLM.Toolset", {
2494
+ defaultRemovalPolicy: "retain"
2495
+ });
2496
+ var isLiteLLMToolset = (value5) => Predicate11.hasProperty(value5, "Type") && value5.Type === "LiteLLM.Toolset";
2497
+ var locate5 = (props, output) => Effect30.gen(function* () {
2498
+ if (output !== undefined)
2499
+ return yield* readToolset(output.toolsetId);
2500
+ const named = (yield* listToolsets()).filter((row) => row.toolsetName === props.toolsetName);
2501
+ if (named.length > 1) {
2502
+ return yield* Effect30.fail(new LitellmRegistryAmbiguousError({
2503
+ ids: named.map((row) => row.toolsetId),
2504
+ name: props.toolsetName,
2505
+ resource: RESOURCE10
2506
+ }));
2507
+ }
2508
+ return named[0];
2509
+ });
2510
+ var toolsetHandlers = {
2511
+ read: ({ olds, output }) => Effect30.gen(function* () {
2512
+ if (output === undefined) {
2513
+ yield* dieIfInvalid(RESOURCE10, String(olds.toolsetName), firstProblem8(olds));
2514
+ }
2515
+ const live = yield* locate5(olds, output);
2516
+ if (live === undefined)
2517
+ return;
2518
+ return output === undefined ? Unowned11(live) : live;
2519
+ }),
2520
+ diff: ({ news, output }) => Effect30.gen(function* () {
2521
+ if (!isResolved10(news))
2522
+ return;
2523
+ yield* failIfInvalid(RESOURCE10, String(news.toolsetName), firstProblem8(news));
2524
+ if (output === undefined)
2525
+ return;
2526
+ return differing9(output, news).length === 0 ? { action: "noop" } : { action: "update" };
2527
+ }),
2528
+ reconcile: ({ news, output }) => Effect30.gen(function* () {
2529
+ yield* failIfInvalid(RESOURCE10, String(news.toolsetName), firstProblem8(news));
2530
+ const before = yield* locate5(news, output);
2531
+ let toolsetId;
2532
+ if (before === undefined) {
2533
+ const created = yield* createToolset(createBody9(news));
2534
+ if (created === undefined) {
2535
+ return yield* Effect30.fail(new LitellmRegistryUnreadableError({
2536
+ reason: "the create answered something that is not a toolset",
2537
+ resource: RESOURCE10
2538
+ }));
2539
+ }
2540
+ toolsetId = created.toolsetId;
2541
+ } else {
2542
+ toolsetId = before.toolsetId;
2543
+ if (differing9(before, news).length > 0)
2544
+ yield* updateToolset(updateBody8(news, before));
2545
+ }
2546
+ const after = yield* readToolset(toolsetId);
2547
+ if (after === undefined) {
2548
+ return yield* Effect30.fail(new LitellmRegistryAbsentAfterWriteError({ name: news.toolsetName, resource: RESOURCE10 }));
2549
+ }
2550
+ const left = differing9(after, news);
2551
+ if (left.length > 0) {
2552
+ return yield* Effect30.fail(new LitellmRegistryNotConvergedError({
2553
+ fields: left,
2554
+ name: news.toolsetName,
2555
+ resource: RESOURCE10
2556
+ }));
2557
+ }
2558
+ return after;
2559
+ }),
2560
+ delete: ({ output }) => deleteToolset(output.toolsetId),
2561
+ list: () => Effect30.succeed([])
2562
+ };
2563
+ var LiteLLMToolsetProvider = () => Provider10.effect(LiteLLMToolset, Effect30.succeed(LiteLLMToolset.Provider.of(toolsetHandlers)));
2564
+ // src/litellm/model.ts
2565
+ import { Resource as Resource11 } from "alchemy";
2566
+ import { Unowned as Unowned13 } from "alchemy/AdoptPolicy";
2567
+ import { isResolved as isResolved11 } from "alchemy/Diff";
2568
+ import { createPhysicalName as createPhysicalName6 } from "alchemy/PhysicalName";
2569
+ import * as Provider11 from "alchemy/Provider";
2570
+ import * as Effect36 from "effect/Effect";
2571
+ import * as Predicate12 from "effect/Predicate";
2572
+
2573
+ // src/litellm/model-errors.ts
2574
+ import * as Data6 from "effect/Data";
2575
+
2576
+ class LitellmModelInvalidError extends Data6.TaggedError("LitellmModelInvalidError") {
2577
+ get message() {
2578
+ return `LiteLLM.Model "${this.modelName}": ${this.problem}.`;
2579
+ }
2580
+ }
2581
+
2582
+ class LitellmModelAmbiguousNameError extends Data6.TaggedError("LitellmModelAmbiguousNameError") {
2583
+ get message() {
2584
+ return `LiteLLM.Model "${this.modelName}": ${this.ids.length} live deployments carry that name ` + `(${this.ids.join(", ")}). Declare \`id\` to choose one.`;
2585
+ }
2586
+ }
2587
+
2588
+ class LitellmModelUnreadableError extends Data6.TaggedError("LitellmModelUnreadableError") {
2589
+ get message() {
2590
+ return `LiteLLM.Model: the deployment list is unreadable (${this.reason}).`;
2591
+ }
2592
+ }
2593
+
2594
+ class LitellmModelAbsentAfterWriteError extends Data6.TaggedError("LitellmModelAbsentAfterWriteError") {
2595
+ get message() {
2596
+ return `LiteLLM.Model "${this.modelName}": the write of ${this.id} returned no error but the ` + "deployment is absent from the list and from the by-id read.";
2597
+ }
2598
+ }
2599
+
2600
+ class LitellmModelNotConvergedError extends Data6.TaggedError("LitellmModelNotConvergedError") {
2601
+ get message() {
2602
+ return `LiteLLM.Model "${this.modelName}": after the write, ${this.id} still differs from the ` + `declaration in ${this.fields.join(", ")}.`;
2603
+ }
2604
+ }
2605
+
2606
+ class LitellmModelForeignRowError extends Data6.TaggedError("LitellmModelForeignRowError") {
2607
+ get message() {
2608
+ const remedy = this.replace ? "It is the new identity of a replace, which --adopt does not cover: remove it first." : "Deploy with --adopt to take it over, or remove it first.";
2609
+ return `LiteLLM.Model "${this.modelName}": the live row ${this.id} already exists and this stack ` + `holds no state for it. Nothing was written. ${remedy}`;
2610
+ }
2611
+ }
2612
+
2613
+ class LitellmModelPriorGenerationError extends Data6.TaggedError("LitellmModelPriorGenerationError") {
2614
+ get message() {
2615
+ return `LiteLLM.Model "${this.modelName}": the live row ${this.id} is an older generation still ` + `recorded on ${this.fqn}. Nothing was written. Taking it over would store that id on the ` + "in-flight replacement, and destroy() then deletes the old generation by the same id. " + "Drop this resource's state row (alchemy state rm, which leaves the deployment) and " + "deploy again with --adopt. Do not delete the live row.";
2616
+ }
2617
+ }
2618
+
2619
+ class LitellmModelConfigFileRowError extends Data6.TaggedError("LitellmModelConfigFileRowError") {
2620
+ get message() {
2621
+ return `LiteLLM.Model "${this.modelName}": the live row ${this.id} is served from the proxy's ` + "config file (db_model: false), not from the database, so the DB API cannot manage it. " + "Remove it from the config file first.";
2622
+ }
2623
+ }
2624
+
2625
+ // src/litellm/model-claim.ts
2626
+ import * as Effect33 from "effect/Effect";
2627
+
2628
+ // src/ownership/adopting.ts
2629
+ import * as Effect32 from "effect/Effect";
2630
+
2631
+ // src/ownership/probe.ts
2632
+ import { Unowned as Unowned12 } from "alchemy/AdoptPolicy";
2633
+ import * as Effect31 from "effect/Effect";
2634
+ var provenOurs = (ask, settled2) => Effect31.gen(function* () {
2635
+ const recorded = yield* recordedInstance(ask.fqn, ask.instanceId);
2636
+ if (recorded === "absent")
2637
+ return false;
2638
+ if (recorded === "partial") {
2639
+ yield* Effect31.logWarning(`${ask.fqn}: the interrupted create's state row lacks part of the declaration (a prop ` + "was still an Output when it was written), so the live object is not proven ours");
2640
+ return false;
2641
+ }
2642
+ const unproven = (reason) => Effect31.as(Effect31.logWarning(`${ask.fqn}: the interrupted create's object could not be compared with its props ` + `(${reason instanceof Error ? reason.message : String(reason)}), so it is not treated as ours`), false);
2643
+ return yield* settled2.pipe(Effect31.catch(unproven), Effect31.catchDefect(unproven));
2644
+ });
2645
+ var ownedRead = (ask, found, settled2) => Effect31.gen(function* () {
2646
+ if (found === undefined || ask.output !== undefined)
2647
+ return found;
2648
+ return (yield* provenOurs(ask, settled2)) ? found : Unowned12(found);
2649
+ });
2650
+
2651
+ // src/ownership/adopting.ts
2652
+ var adopting = (owner, settled2) => Effect32.gen(function* () {
2653
+ if (owner.output === undefined)
2654
+ return false;
2655
+ const generation = yield* recordedGeneration(owner.fqn, owner.instanceId);
2656
+ if (generation === undefined || generation.adopting === true)
2657
+ return true;
2658
+ if (generation.attr !== undefined && generation.attr !== null)
2659
+ return false;
2660
+ return !(yield* provenOurs(owner, settled2(generation.props)));
2661
+ });
2662
+
2663
+ // src/litellm/model-claim.ts
2664
+ var claimStatelessRow = (args) => Effect33.gen(function* () {
2665
+ const older = yield* olderGenerationIds(args.fqn, args.instanceId);
2666
+ if (older.includes(args.beforeId)) {
2667
+ return yield* Effect33.fail(new LitellmModelPriorGenerationError({
2668
+ fqn: args.fqn,
2669
+ id: args.beforeId,
2670
+ modelName: args.news.modelName
2671
+ }));
2672
+ }
2673
+ const unpinned = args.news.id === undefined;
2674
+ const ours = unpinned && args.beforeId === args.wanted;
2675
+ const owner = { fqn: args.fqn, instanceId: args.instanceId, output: args.output };
2676
+ const isAdoption = yield* adopting(owner, () => Effect33.succeed(false));
2677
+ const creating = yield* isCreate(args.fqn, args.instanceId);
2678
+ const mayAdopt = unpinned ? creating && (yield* adoptEnabled(args.fqn)) : yield* adoptsAtApply(owner);
2679
+ if (!ours && !isAdoption && !mayAdopt) {
2680
+ const replace = unpinned ? !creating : !creating && !(yield* unfinished(args.instanceId));
2681
+ return yield* Effect33.fail(new LitellmModelForeignRowError({
2682
+ id: args.beforeId,
2683
+ modelName: args.news.modelName,
2684
+ replace
2685
+ }));
2686
+ }
2687
+ });
2688
+
2689
+ // src/litellm/model-types.ts
2690
+ var isBlank4 = (value5) => typeof value5 !== "string" || value5.trim() === "";
2691
+ var hasProviderPrefix = (model) => /^[a-z0-9_-]+\//i.test(model);
2692
+
2693
+ // src/litellm/model-credential.ts
2694
+ var declaredValues = (props) => {
2695
+ const values = { model: props.model };
2696
+ if (props.apiBase !== undefined)
2697
+ values["api_base"] = props.apiBase;
2698
+ if (props.apiKey !== undefined)
2699
+ values["api_key"] = `os.environ/${props.apiKey.fromEnv}`;
2700
+ return values;
2701
+ };
2702
+ var sealFromValues = (values) => seal(values);
2703
+ var sealState = (props, sealed) => sealMatches(sealed, declaredValues(props)) ? "match" : "stale";
2704
+
2705
+ // src/litellm/model-form.ts
2706
+ var firstProblem9 = (props) => {
2707
+ if (isBlank4(props.modelName) || props.modelName !== props.modelName.trim()) {
2708
+ return "`modelName` must be a non-empty string without leading or trailing whitespace";
2709
+ }
2710
+ if (props.id !== undefined && isBlank4(props.id)) {
2711
+ return "`id` must be a non-empty string when declared";
2712
+ }
2713
+ if (isBlank4(props.model))
2714
+ return "`model` must be a non-empty string";
2715
+ if (!hasProviderPrefix(props.model)) {
2716
+ return `\`model\` must carry a provider prefix, e.g. "xai/${props.model}": LiteLLM routes by it`;
2717
+ }
2718
+ if (props.model.toLowerCase().startsWith("openai/") && props.modelName.toLowerCase().startsWith("grok")) {
2719
+ return '`model` must not use the "openai/" prefix on a grok group: Grok is xAI, declare "xai/…"';
2720
+ }
2721
+ if (props.apiBase !== undefined) {
2722
+ const url = urlProblem(props.apiBase);
2723
+ if (url !== undefined)
2724
+ return url;
2725
+ }
2726
+ if (props.apiKey !== undefined && (typeof props.apiKey !== "object" || typeof props.apiKey.fromEnv !== "string")) {
2727
+ return "`apiKey` takes `{ fromEnv: 'NAME' }`, never a value: the value would land in Alchemy's unencrypted state";
2728
+ }
2729
+ if (props.apiKey !== undefined && isBlank4(props.apiKey.fromEnv)) {
2730
+ return "`apiKey.fromEnv` must name an environment variable";
2731
+ }
2732
+ return;
2733
+ };
2734
+ var declaredDigest = (props) => sealFromValues(declaredValues(props));
2735
+ var sameSet3 = (live, declared) => new Set(live).size === new Set(declared).size && declared.every((entry) => live.includes(entry));
2736
+ var differing10 = (live, props) => {
2737
+ const out = [];
2738
+ if (live.modelName !== props.modelName)
2739
+ out.push("model_name");
2740
+ if (live.model !== null && live.model !== props.model) {
2741
+ out.push("model");
2742
+ }
2743
+ if (props.mode !== undefined && live.mode !== props.mode)
2744
+ out.push("mode");
2745
+ if (props.baseModel !== undefined && live.baseModel !== props.baseModel)
2746
+ out.push("base_model");
2747
+ if (!sameSet3(live.accessGroups, props.accessGroups ?? []))
2748
+ out.push("access_groups");
2749
+ return out;
2750
+ };
2751
+ var toAttributes11 = (row) => {
2752
+ const info = row["model_info"] ?? {};
2753
+ const params = row["litellm_params"];
2754
+ const carriedModel = typeof params === "object" && params !== null ? params["model"] : undefined;
2755
+ const id = row["id"] ?? info["id"];
2756
+ return {
2757
+ accessGroups: Array.isArray(info["access_groups"]) ? info["access_groups"].map(String) : [],
2758
+ baseModel: typeof info["base_model"] === "string" ? info["base_model"] : null,
2759
+ dbModel: info["db_model"] === false ? false : true,
2760
+ id: String(id),
2761
+ mode: typeof info["mode"] === "string" ? info["mode"] : null,
2762
+ model: typeof carriedModel === "string" ? redactUrl(carriedModel) : null,
2763
+ modelName: String(row["model_name"] ?? ""),
2764
+ paramsSeal: ""
2765
+ };
2766
+ };
2767
+ var LEAVE_ALONE_PARAMS = [
2768
+ "allow_client_keepalive_override",
2769
+ "merge_reasoning_content_in_choices",
2770
+ "use_in_pass_through",
2771
+ "use_litellm_proxy",
2772
+ "use_xai_oauth"
2773
+ ];
2774
+ var managedParams = (props) => {
2775
+ const params = { model: props.model };
2776
+ if (props.apiBase !== undefined)
2777
+ params["api_base"] = props.apiBase;
2778
+ if (props.apiKey !== undefined)
2779
+ params["api_key"] = `os.environ/${props.apiKey.fromEnv}`;
2780
+ return params;
2781
+ };
2782
+ var patchParams = (props) => ({
2783
+ ...managedParams(props),
2784
+ ...Object.fromEntries(LEAVE_ALONE_PARAMS.map((key) => [key, null]))
2785
+ });
2786
+ var modelInfoOf = (props) => ({
2787
+ ...props.baseModel === undefined ? {} : { base_model: props.baseModel },
2788
+ ...props.mode === undefined ? {} : { mode: props.mode },
2789
+ access_groups: [...props.accessGroups ?? []],
2790
+ id: null
2791
+ });
2792
+ var createBody10 = (props, modelId) => {
2793
+ const body = {
2794
+ litellm_params: managedParams(props),
2795
+ model_info: { ...modelInfoOf(props), id: modelId },
2796
+ model_name: props.modelName
2797
+ };
2798
+ return body;
2799
+ };
2800
+ var patchBody2 = (props, live) => {
2801
+ const renamed = live.modelName !== props.modelName;
2802
+ return {
2803
+ model_id: live.id,
2804
+ litellm_params: patchParams(props),
2805
+ model_info: { ...modelInfoOf(props), id: live.id },
2806
+ ...renamed ? { model_name: props.modelName } : {}
2807
+ };
2808
+ };
2809
+
2810
+ // src/litellm/model-locate.ts
2811
+ import { createPhysicalName as createPhysicalName5 } from "alchemy/PhysicalName";
2812
+ import * as Effect35 from "effect/Effect";
2813
+
2814
+ // src/litellm/model-operations.ts
2815
+ import * as models from "@distilled.cloud/litellm/model_management";
2816
+ import * as Effect34 from "effect/Effect";
2817
+ var hasRowId = (row) => {
2818
+ if (typeof row !== "object" || row === null)
2819
+ return false;
2820
+ const record = row;
2821
+ const info = typeof record["model_info"] === "object" && record["model_info"] !== null ? record["model_info"] : {};
2822
+ return typeof record["id"] === "string" || typeof info["id"] === "string";
2823
+ };
2824
+ var rowsOf = (response) => {
2825
+ const rows = Array.isArray(response) ? response : Array.isArray(response?.data) ? response.data : response?.body;
2826
+ return Array.isArray(rows) && rows.every(hasRowId) ? Effect34.succeed(rows.map(toAttributes11)) : Effect34.fail(new LitellmModelUnreadableError({
2827
+ reason: Array.isArray(rows) ? "a row has no model id" : "not a list of deployments"
2828
+ }));
2829
+ };
2830
+ var listModels = () => throughFetch(models.getModelInfoV1ModelInfo({})).pipe(Effect34.flatMap(rowsOf));
2831
+ var readModelRow = (modelId) => throughFetch(models.getModelInfoV1ModelInfo({ litellm_model_id: modelId })).pipe(Effect34.mapError((error) => error), Effect34.catchTag("NotFound", () => Effect34.succeed(undefined)), Effect34.catchTag("BadRequest", (error) => listModels().pipe(Effect34.flatMap((rows) => rows.some((row) => row.id === modelId) ? Effect34.fail(error) : Effect34.succeed(undefined)))), Effect34.flatMap((response) => response === undefined ? Effect34.succeed(undefined) : rowsOf(response).pipe(Effect34.map((rows) => rows.find((row) => row.id === modelId)))));
2832
+ var createModel = (body) => throughFetch(models.addNewModelModelNewPost(body)).pipe(Effect34.asVoid);
2833
+ var patchModel = (body) => throughFetch(models.patchModelModelModelIdUpdatePatch(body)).pipe(Effect34.asVoid);
2834
+ var deleteModel = (modelId) => throughFetch(models.deleteModelModelDeletePost({ id: modelId })).pipe(Effect34.asVoid, Effect34.catchTag("BadRequest", (original) => listModels().pipe(Effect34.flatMap((rows) => rows.some((row) => row.id === modelId) ? Effect34.fail(original) : Effect34.void))));
2835
+
2836
+ // src/litellm/model-locate.ts
2837
+ var locate6 = (rows, props, output) => {
2838
+ const pinned = output?.id ?? props.id;
2839
+ if (pinned !== undefined)
2840
+ return Effect35.succeed(rows.find((row) => row.id === pinned));
2841
+ const named = rows.filter((row) => row.modelName === props.modelName);
2842
+ return named.length > 1 ? Effect35.fail(new LitellmModelAmbiguousNameError({
2843
+ ids: named.map((row) => row.id),
2844
+ modelName: props.modelName
2845
+ })) : Effect35.succeed(named[0]);
2846
+ };
2847
+ var wantedId2 = (id, instanceId, props, output) => output?.id !== undefined ? Effect35.succeed(output.id) : props.id !== undefined ? Effect35.succeed(props.id) : createPhysicalName5({ id, instanceId, lowercase: true, maxLength: 64 });
2848
+ var findLive2 = (id, instanceId, props, output) => Effect35.gen(function* () {
2849
+ const listed = yield* locate6(yield* listModels(), props, output);
2850
+ if (listed !== undefined)
2851
+ return listed;
2852
+ return yield* readModelRow(yield* wantedId2(id, instanceId, props, output));
2853
+ });
2854
+
2855
+ // src/litellm/model.ts
2856
+ var LiteLLMModel = Resource11("LiteLLM.Model", {
2857
+ defaultRemovalPolicy: "retain"
2858
+ });
2859
+ var isLiteLLMModel = (value5) => Predicate12.hasProperty(value5, "Type") && value5.Type === "LiteLLM.Model";
2860
+ var refuse3 = (props) => {
2861
+ const problem = firstProblem9(props);
2862
+ return problem === undefined ? Effect36.void : Effect36.fail(new LitellmModelInvalidError({ problem, modelName: String(props.modelName) }));
2863
+ };
2864
+ var modelHandlers = {
2865
+ read: ({ id, instanceId, olds, output }) => Effect36.gen(function* () {
2866
+ const problem = output === undefined ? firstProblem9(olds) : undefined;
2867
+ if (problem !== undefined) {
2868
+ return yield* Effect36.die(new LitellmModelInvalidError({ problem, modelName: String(olds.modelName) }));
2869
+ }
2870
+ const found = yield* findLive2(id, instanceId, olds, output);
2871
+ if (found === undefined)
2872
+ return;
2873
+ if (output === undefined && olds.id === undefined) {
2874
+ const physical = yield* createPhysicalName6({
2875
+ id,
2876
+ instanceId,
2877
+ lowercase: true,
2878
+ maxLength: 64
2879
+ });
2880
+ if (found.id === physical)
2881
+ return found;
2882
+ }
2883
+ return output === undefined ? Unowned13(found) : { ...found, paramsSeal: output.paramsSeal };
2884
+ }),
2885
+ diff: ({
2886
+ instanceId,
2887
+ news,
2888
+ output
2889
+ }) => Effect36.gen(function* () {
2890
+ if (!isResolved11(news))
2891
+ return;
2892
+ yield* refuse3(news);
2893
+ if (output === undefined)
2894
+ return yield* noteUnfinished(instanceId);
2895
+ if (news.id !== undefined && news.id !== output.id) {
2896
+ return { action: "replace", deleteFirst: false };
2897
+ }
2898
+ if (news.modelName !== output.modelName && news.id === undefined) {
2899
+ return { action: "replace", deleteFirst: false };
2900
+ }
2901
+ return differing10(output, news).length === 0 && sealState(news, output.paramsSeal) === "match" ? { action: "noop" } : { action: "update" };
2902
+ }),
2903
+ reconcile: ({ fqn, id, instanceId, news, output }) => Effect36.gen(function* () {
2904
+ yield* refuse3(news);
2905
+ const before = yield* findLive2(id, instanceId, news, output);
2906
+ let sealed = output?.paramsSeal ?? "";
2907
+ let modelId;
2908
+ if (before === undefined) {
2909
+ const wanted = yield* wantedId2(id, instanceId, news, output);
2910
+ yield* createModel(createBody10(news, wanted));
2911
+ modelId = wanted;
2912
+ sealed = declaredDigest(news);
2913
+ } else {
2914
+ if (before.dbModel === false) {
2915
+ return yield* Effect36.fail(new LitellmModelConfigFileRowError({ id: before.id, modelName: news.modelName }));
2916
+ }
2917
+ const stateless = output === undefined || output.paramsSeal === "";
2918
+ if (stateless) {
2919
+ yield* claimStatelessRow({
2920
+ beforeId: before.id,
2921
+ fqn,
2922
+ instanceId,
2923
+ news,
2924
+ output,
2925
+ wanted: yield* wantedId2(id, instanceId, news, output)
2926
+ });
2927
+ }
2928
+ modelId = before.id;
2929
+ const drifted = differing10(before, news);
2930
+ const sealStale = sealState(news, sealed) === "stale";
2931
+ const sealNeedsStamp = sealStale && (sealed !== "" || news.apiKey !== undefined || news.apiBase !== undefined);
2932
+ if (drifted.length > 0 || sealNeedsStamp) {
2933
+ yield* patchModel(patchBody2(news, before));
2934
+ }
2935
+ if (drifted.length > 0 || sealStale)
2936
+ sealed = declaredDigest(news);
2937
+ }
2938
+ const after = (yield* listModels()).find((row) => row.id === modelId) ?? (yield* readModelRow(modelId));
2939
+ if (after === undefined) {
2940
+ return yield* Effect36.fail(new LitellmModelAbsentAfterWriteError({ id: modelId, modelName: news.modelName }));
2941
+ }
2942
+ const left = differing10(after, news);
2943
+ if (left.length > 0) {
2944
+ return yield* Effect36.fail(new LitellmModelNotConvergedError({
2945
+ fields: left,
2946
+ id: modelId,
2947
+ modelName: news.modelName
2948
+ }));
2949
+ }
2950
+ return { ...after, paramsSeal: sealed };
2951
+ }),
2952
+ delete: ({ output }) => deleteModel(output.id),
2953
+ list: () => Effect36.succeed([])
2954
+ };
2955
+ var LiteLLMModelProvider = () => Provider11.effect(LiteLLMModel, Effect36.succeed(LiteLLMModel.Provider.of(modelHandlers)));
2956
+ // src/litellm/key.ts
2957
+ import { Resource as Resource12 } from "alchemy";
2958
+ import { Unowned as Unowned14 } from "alchemy/AdoptPolicy";
2959
+ import { isResolved as isResolved12 } from "alchemy/Diff";
2960
+ import * as Provider12 from "alchemy/Provider";
2961
+ import * as Effect39 from "effect/Effect";
2962
+ import * as Predicate14 from "effect/Predicate";
2963
+
2964
+ // src/litellm/key-errors.ts
2965
+ import * as Data7 from "effect/Data";
2966
+
2967
+ class LitellmKeyValueRequiredError extends Data7.TaggedError("LitellmKeyValueRequiredError") {
2968
+ get message() {
2969
+ return `LiteLLM.Key '${this.keyAlias}' does not exist and declares no \`key\`. Creating it would ` + 'mint a value nobody holds. Declare `key: { fromEnv: "NAME" }`, or adopt an existing key.';
2970
+ }
2971
+ }
2972
+
2973
+ class LitellmKeyDebugLoggingError extends Data7.TaggedError("LitellmKeyDebugLoggingError") {
2974
+ get message() {
2975
+ return `LiteLLM.Key '${this.keyAlias}': DISTILLED_DEBUG_HTTP is set, so the SDK would print the ` + "key to stderr in /key/generate's request and response. Unset it and run again. Nothing was written.";
2976
+ }
2977
+ }
2978
+
2979
+ class LitellmKeyTransportError extends Data7.TaggedError("LitellmKeyTransportError") {
2980
+ get message() {
2981
+ return `LiteLLM.Key '${this.keyAlias}': the /key/generate request failed (${this.reason}) before an ` + "answer could be read, so the key MAY have been created. This error keeps neither the request " + "nor its cause: the request body holds the key's value. Look for the alias in LiteLLM. A key " + "that landed is taken over by the next deploy with --adopt; one that did not is created by it.";
2982
+ }
2983
+ }
2984
+
2985
+ class LitellmKeyAliasEmptyError extends Data7.TaggedError("LitellmKeyAliasEmptyError") {
2986
+ get message() {
2987
+ return "LiteLLM.Key: keyAlias is empty. The alias is the key's identity. Nothing was written.";
2988
+ }
2989
+ }
2990
+
2991
+ class LitellmKeyValueMissingError extends Data7.TaggedError("LitellmKeyValueMissingError") {
2992
+ get message() {
2993
+ return `LiteLLM.Key '${this.keyAlias}': the environment variable ${this.variable} is unset or empty ` + "in the deploying process. Nothing was written.";
2994
+ }
2995
+ }
2996
+
2997
+ class LitellmKeyValueMalformedError extends Data7.TaggedError("LitellmKeyValueMalformedError") {
2998
+ get message() {
2999
+ return `LiteLLM.Key '${this.keyAlias}': the value of ${this.variable} is not usable — ${this.rule}. ` + "Nothing was written.";
3000
+ }
3001
+ }
3002
+
3003
+ class LitellmKeyValueNotHonouredError extends Data7.TaggedError("LitellmKeyValueNotHonouredError") {
3004
+ get message() {
3005
+ const outcome = this.removed ? "The row was deleted again." : "The row could NOT be deleted again: remove it by hand.";
3006
+ return `LiteLLM.Key '${this.keyAlias}': /key/generate answered with a different value than the one ` + `sent, so the key would authenticate nobody. ${outcome}`;
3007
+ }
3008
+ }
3009
+
3010
+ class LitellmKeyValueMismatchError extends Data7.TaggedError("LitellmKeyValueMismatchError") {
3011
+ get message() {
3012
+ return `LiteLLM.Key '${this.keyAlias}': the value of ${this.variable} is not the key this alias ` + "holds. Nothing was written. /key/update cannot change a key value, so fix the variable or " + "drop the `key` and manage the existing key without one.";
3013
+ }
3014
+ }
3015
+
3016
+ class LitellmKeyAliasChangedError extends Data7.TaggedError("LitellmKeyAliasChangedError") {
3017
+ get message() {
3018
+ return `LiteLLM.Key alias changed from '${this.from}' to '${this.to}'. The alias is the key's ` + "identity and a rename would need the same value under a new row: declare the new alias as " + "a new resource and remove the old one with RemovalPolicy.destroy(). Nothing was written.";
3019
+ }
3020
+ }
3021
+
3022
+ class LitellmKeyAmbiguousAliasError extends Data7.TaggedError("LitellmKeyAmbiguousAliasError") {
3023
+ get message() {
3024
+ return `LiteLLM.Key '${this.keyAlias}': ${this.count} live keys carry this alias, so none can be ` + "called the declared one. Resolve the duplicates in LiteLLM first. Nothing was written.";
3025
+ }
3026
+ }
3027
+
3028
+ class LitellmKeyUnreadableError extends Data7.TaggedError("LitellmKeyUnreadableError") {
3029
+ get message() {
3030
+ return `LiteLLM.Key '${this.keyAlias}': /key/list did not answer full key rows (a hash list means ` + "return_full_object was ignored). Nothing was written.";
3031
+ }
3032
+ }
3033
+
3034
+ class LitellmKeyAbsentAfterWriteError extends Data7.TaggedError("LitellmKeyAbsentAfterWriteError") {
3035
+ get message() {
3036
+ return `LiteLLM.Key '${this.keyAlias}': the write returned no error but the alias is not listed.`;
3037
+ }
3038
+ }
3039
+
3040
+ class LitellmKeyFieldNotAppliedError extends Data7.TaggedError("LitellmKeyFieldNotAppliedError") {
3041
+ get message() {
3042
+ return `LiteLLM.Key '${this.keyAlias}': the write returned no error but ${this.fields.join(", ")} ` + "still differ from the declaration.";
3043
+ }
3044
+ }
3045
+
3046
+ // src/litellm/key-form.ts
3047
+ import * as Redacted5 from "effect/Redacted";
3048
+
3049
+ // src/litellm/key-metadata.ts
3050
+ import { deepEqual as deepEqual2 } from "alchemy/Diff";
3051
+ var CALLBACK_SLOTS = ["callback_settings", "logging", "secret_manager_settings"];
3052
+ var isObject = (value5) => typeof value5 === "object" && value5 !== null && !Array.isArray(value5);
3053
+ var callbackSlotsIn = (metadata) => metadata === undefined ? [] : CALLBACK_SLOTS.filter((slot) => Object.hasOwn(metadata, slot));
3054
+ var splitMetadata = (raw) => {
3055
+ if (!isObject(raw))
3056
+ return { metadata: {}, withheld: [] };
3057
+ const withheld = callbackSlotsIn(raw);
3058
+ return {
3059
+ metadata: Object.fromEntries(Object.entries(raw).filter(([name]) => !withheld.includes(name))),
3060
+ withheld
3061
+ };
3062
+ };
3063
+ var metadataDiffers = (live, declared) => declared !== undefined && Object.entries(declared).some(([name, value5]) => !deepEqual2(live[name], value5));
3064
+ var mergedMetadata = (live, declared) => ({
3065
+ ...live,
3066
+ ...declared
3067
+ });
3068
+
3069
+ // src/litellm/key-form.ts
3070
+ var sameSet4 = (a, b) => {
3071
+ const left = [...a].sort();
3072
+ const right = [...b].sort();
3073
+ return left.length === right.length && left.every((value6, i) => value6 === right[i]);
3074
+ };
3075
+ var expiryDiffers = (live, wanted) => live.duration !== wanted || wanted === null !== (live.expires === null);
3076
+ var differing11 = (live, props) => {
3077
+ const out = [];
3078
+ if (props.budgetId !== undefined && live.budgetId !== props.budgetId)
3079
+ out.push("budget_id");
3080
+ if (props.models !== undefined && !sameSet4(live.models, props.models))
3081
+ out.push("models");
3082
+ if (props.allowedRoutes !== undefined && !sameSet4(live.allowedRoutes, props.allowedRoutes)) {
3083
+ out.push("allowed_routes");
3084
+ }
3085
+ if (props.teamId !== undefined && live.teamId !== props.teamId)
3086
+ out.push("team_id");
3087
+ if (metadataDiffers(live.metadata, props.metadata))
3088
+ out.push("metadata");
3089
+ if (props.duration !== undefined && expiryDiffers(live, props.duration))
3090
+ out.push("duration");
3091
+ return out;
3092
+ };
3093
+ var createBody11 = (props, secret) => {
3094
+ const body = {
3095
+ key: Redacted5.value(secret),
3096
+ key_alias: props.keyAlias
3097
+ };
3098
+ if (typeof props.budgetId === "string")
3099
+ body.budget_id = props.budgetId;
3100
+ if (props.models !== undefined)
3101
+ body.models = [...props.models];
3102
+ if (props.allowedRoutes !== undefined)
3103
+ body.allowed_routes = [...props.allowedRoutes];
3104
+ if (typeof props.teamId === "string")
3105
+ body.team_id = props.teamId;
3106
+ if (props.metadata !== undefined)
3107
+ body.metadata = { ...props.metadata };
3108
+ if (typeof props.duration === "string")
3109
+ body.duration = props.duration;
3110
+ return body;
3111
+ };
3112
+ var updateBody9 = (props, live) => {
3113
+ const body = { key_alias: live.keyAlias };
3114
+ for (const field of differing11(live, props)) {
3115
+ if (field === "budget_id")
3116
+ body.budget_id = props.budgetId ?? null;
3117
+ if (field === "models")
3118
+ body.models = [...props.models ?? []];
3119
+ if (field === "allowed_routes")
3120
+ body.allowed_routes = [...props.allowedRoutes ?? []];
3121
+ if (field === "team_id")
3122
+ body.team_id = props.teamId ?? null;
3123
+ if (field === "metadata")
3124
+ body.metadata = { ...mergedMetadata(live.metadata, props.metadata) };
3125
+ if (field === "duration")
3126
+ body.duration = props.duration ?? null;
3127
+ }
3128
+ return body;
3129
+ };
3130
+ var strings = (value6) => Array.isArray(value6) ? value6.filter((item) => typeof item === "string") : [];
3131
+ var stringOrNull2 = (value6) => typeof value6 === "string" ? value6 : null;
3132
+ var toAttributes12 = (row) => {
3133
+ const { metadata, withheld } = splitMetadata(row["metadata"]);
3134
+ return {
3135
+ allowedRoutes: strings(row["allowed_routes"]),
3136
+ budgetId: stringOrNull2(row["budget_id"]),
3137
+ duration: null,
3138
+ expires: stringOrNull2(row["expires"]),
3139
+ keyAlias: String(row["key_alias"]),
3140
+ metadata,
3141
+ models: strings(row["models"]),
3142
+ teamId: stringOrNull2(row["team_id"]),
3143
+ withheld
3144
+ };
3145
+ };
3146
+
3147
+ // src/litellm/key-metadata-errors.ts
3148
+ import * as Data8 from "effect/Data";
3149
+
3150
+ class LitellmKeyCallbackMetadataDeclaredError extends Data8.TaggedError("LitellmKeyCallbackMetadataDeclaredError") {
3151
+ get message() {
3152
+ return `LiteLLM.Key '${this.keyAlias}': metadata declares ${this.slots.join(", ")}, which carry ` + "callback credentials. LiteLLM stores them encrypted, so they would never read back equal, " + "and Alchemy state is unencrypted. Configure the key's logging in LiteLLM itself. Nothing was written.";
3153
+ }
3154
+ }
3155
+
3156
+ class LitellmKeyCallbackMetadataLiveError extends Data8.TaggedError("LitellmKeyCallbackMetadataLiveError") {
3157
+ get message() {
3158
+ return `LiteLLM.Key '${this.keyAlias}': the live key holds ${this.slots.join(", ")} in its metadata ` + "(callback credentials this resource never reads), and /key/update replaces the whole " + "metadata, so writing the declared metadata would strip them. Change that metadata in LiteLLM, " + "or stop declaring metadata for this key. Nothing was written.";
3159
+ }
3160
+ }
3161
+
3162
+ // src/litellm/key-operations.ts
3163
+ import * as keys from "@distilled.cloud/litellm/key_management";
3164
+ import * as Effect37 from "effect/Effect";
3165
+ import * as Predicate13 from "effect/Predicate";
3166
+ import { isHttpClientError as isHttpClientError2 } from "effect/unstable/http/HttpClientError";
3167
+ var findKey = (keyAlias) => keyAlias.trim() === "" ? Effect37.fail(new LitellmKeyAliasEmptyError) : findKeyByAlias(keyAlias);
3168
+ var findKeyByAlias = (keyAlias) => findKeyRowByAlias(keyAlias).pipe(Effect37.map((row) => row === undefined ? undefined : toAttributes12(row)));
3169
+ var findKeyRowByAlias = (keyAlias) => throughFetch(keys.listKeysKeyListGet({ key_alias: keyAlias, return_full_object: true })).pipe(Effect37.flatMap((response) => Effect37.gen(function* () {
3170
+ const rows = response.keys ?? [];
3171
+ if (rows.some((row) => typeof row !== "object" || row === null)) {
3172
+ return yield* new LitellmKeyUnreadableError({ keyAlias });
3173
+ }
3174
+ const mine = rows.filter((row) => row["key_alias"] === keyAlias);
3175
+ if (mine.length > 1) {
3176
+ return yield* new LitellmKeyAmbiguousAliasError({ count: mine.length, keyAlias });
3177
+ }
3178
+ return mine[0];
3179
+ })));
3180
+ var readKeyToken = (keyAlias) => keyAlias.trim() === "" ? Effect37.fail(new LitellmKeyAliasEmptyError) : findKeyRowByAlias(keyAlias).pipe(Effect37.map((row) => row === undefined ? undefined : typeof row["token"] === "string" ? row["token"] : null));
3181
+ var carriesRequest2 = (value6) => isHttpClientError2(value6) || Predicate13.hasProperty(value6, "request");
3182
+ var generateKey = (body) => {
3183
+ const keyAlias = body.key_alias ?? "";
3184
+ return throughFetch(keys.generateKeyFnKeyGeneratePost(body)).pipe(Effect37.catchTag("HttpClientError", (error) => Effect37.fail(new LitellmKeyTransportError({ keyAlias, reason: error.reason._tag }))), Effect37.catchDefect((defect) => carriesRequest2(defect) ? Effect37.fail(new LitellmKeyTransportError({
3185
+ keyAlias,
3186
+ reason: isHttpClientError2(defect) ? defect.reason._tag : "Defect"
3187
+ })) : Effect37.die(defect)));
3188
+ };
3189
+ var updateKey = (body) => throughFetch(keys.updateKeyFnKeyUpdatePost(body)).pipe(Effect37.asVoid);
3190
+ var deleteKey = (keyAlias) => findKey(keyAlias).pipe(Effect37.flatMap((live) => live === undefined ? Effect37.void : throughFetch(keys.deleteKeyFnKeyDeletePost({ key_aliases: [keyAlias] })).pipe(Effect37.asVoid, Effect37.catchTag("KeyNotFound", (original) => findKey(keyAlias).pipe(Effect37.flatMap((still) => still === undefined ? Effect37.void : Effect37.fail(original)))))));
3191
+
3192
+ // src/litellm/key-secret.ts
3193
+ import { createHash } from "node:crypto";
3194
+ import * as Effect38 from "effect/Effect";
3195
+ import * as Redacted6 from "effect/Redacted";
3196
+ var PREFIX2 = "sk-";
3197
+ var MIN_LENGTH = 16;
3198
+ var RULE = `a user-defined key must start with '${PREFIX2}', be at least ${MIN_LENGTH} characters and contain no whitespace`;
3199
+ var resolveKeyValue = (keyAlias, ref) => Effect38.gen(function* () {
3200
+ if (ref === undefined)
3201
+ return yield* new LitellmKeyValueRequiredError({ keyAlias });
3202
+ const variable = ref.fromEnv;
3203
+ const value7 = resolveAll({ key: ref }).values["key"];
3204
+ if (value7 === undefined)
3205
+ return yield* new LitellmKeyValueMissingError({ keyAlias, variable });
3206
+ if (!value7.startsWith(PREFIX2) || value7.length < MIN_LENGTH || /\s/.test(value7)) {
3207
+ return yield* new LitellmKeyValueMalformedError({ keyAlias, rule: RULE, variable });
3208
+ }
3209
+ return Redacted6.make(value7);
3210
+ });
3211
+ var echoes = (returned, sent) => (Redacted6.isRedacted(returned) ? Redacted6.value(returned) : returned) === Redacted6.value(sent);
3212
+ var sha256 = (value7) => createHash("sha256").update(value7).digest("hex");
3213
+ var verifyKeyValue = (keyAlias, ref, token) => Effect38.gen(function* () {
3214
+ if (ref === undefined)
3215
+ return;
3216
+ const variable = ref.fromEnv;
3217
+ const value7 = resolveAll({ key: ref }).values["key"];
3218
+ if (value7 === undefined)
3219
+ return;
3220
+ if (token === null || sha256(value7) !== token) {
3221
+ return yield* new LitellmKeyValueMismatchError({ keyAlias, variable });
3222
+ }
3223
+ });
3224
+ var refuseDebugLogging2 = (keyAlias) => (globalThis.process?.env?.["DISTILLED_DEBUG_HTTP"] ?? "") !== "" ? Effect38.fail(new LitellmKeyDebugLoggingError({ keyAlias })) : Effect38.void;
3225
+ var hasKeyValue = (ref) => ref !== undefined && resolveAll({ key: ref }).values["key"] !== undefined;
3226
+
3227
+ // src/litellm/key.ts
3228
+ var LiteLLMKey = Resource12("LiteLLM.Key", { defaultRemovalPolicy: "retain" });
3229
+ var isLiteLLMKey = (value7) => Predicate14.hasProperty(value7, "Type") && value7.Type === "LiteLLM.Key";
3230
+ var remembering = (live, output) => ({
3231
+ ...live,
3232
+ duration: output?.duration ?? null
3233
+ });
3234
+ var remembered = (news, before) => news.duration !== undefined ? news.duration : before?.duration ?? null;
3235
+ var refuseMetadata = (news, live) => Effect39.gen(function* () {
3236
+ const declared = callbackSlotsIn(news.metadata);
3237
+ if (declared.length > 0) {
3238
+ return yield* new LitellmKeyCallbackMetadataDeclaredError({
3239
+ keyAlias: news.keyAlias,
3240
+ slots: declared
3241
+ });
3242
+ }
3243
+ if (live !== undefined && live.withheld.length > 0 && differing11(live, news).includes("metadata")) {
3244
+ return yield* new LitellmKeyCallbackMetadataLiveError({
3245
+ keyAlias: news.keyAlias,
3246
+ slots: live.withheld
3247
+ });
3248
+ }
3249
+ });
3250
+ var createKey = (news) => Effect39.gen(function* () {
3251
+ yield* refuseDebugLogging2(news.keyAlias);
3252
+ const secret = yield* resolveKeyValue(news.keyAlias, news.key);
3253
+ const created = yield* generateKey(createBody11(news, secret));
3254
+ if (echoes(created.key, secret))
3255
+ return;
3256
+ const removed = yield* deleteKey(news.keyAlias).pipe(Effect39.as(true), Effect39.orElseSucceed(() => false));
3257
+ return yield* new LitellmKeyValueNotHonouredError({ keyAlias: news.keyAlias, removed });
3258
+ });
3259
+ var keyHandlers = {
3260
+ read: ({ olds, output }) => Effect39.gen(function* () {
3261
+ const live = yield* findKey(output?.keyAlias ?? olds.keyAlias);
3262
+ if (live === undefined)
3263
+ return;
3264
+ return output === undefined ? Unowned14(live) : remembering(live, output);
3265
+ }),
3266
+ diff: ({ news, output }) => Effect39.gen(function* () {
3267
+ if (!isResolved12(news))
3268
+ return;
3269
+ yield* refuseMetadata(news, output);
3270
+ if (output === undefined)
3271
+ return;
3272
+ if (news.keyAlias !== output.keyAlias) {
3273
+ return yield* new LitellmKeyAliasChangedError({ from: output.keyAlias, to: news.keyAlias });
3274
+ }
3275
+ if (hasKeyValue(news.key)) {
3276
+ const token = yield* readKeyToken(news.keyAlias);
3277
+ if (token === undefined)
3278
+ return { action: "update" };
3279
+ yield* verifyKeyValue(news.keyAlias, news.key, token);
3280
+ }
3281
+ return differing11(output, news).length === 0 ? { action: "noop" } : { action: "update" };
3282
+ }),
3283
+ reconcile: ({
3284
+ fqn,
3285
+ instanceId,
3286
+ news,
3287
+ output
3288
+ }) => Effect39.gen(function* () {
3289
+ const alias = news.keyAlias;
3290
+ yield* refuseMetadata(news, undefined);
3291
+ const found = yield* findKey(alias);
3292
+ const before = found === undefined ? undefined : remembering(found, output);
3293
+ if (before === undefined) {
3294
+ yield* createKey(news);
3295
+ } else {
3296
+ yield* refuseTakeover({ fqn, instanceId, output }, `LiteLLM.Key ${alias}`);
3297
+ if (hasKeyValue(news.key)) {
3298
+ yield* verifyKeyValue(alias, news.key, (yield* readKeyToken(alias)) ?? null);
3299
+ }
3300
+ yield* refuseMetadata(news, before);
3301
+ if (differing11(before, news).length > 0)
3302
+ yield* updateKey(updateBody9(news, before));
3303
+ }
3304
+ const after = yield* findKey(alias);
3305
+ if (after === undefined)
3306
+ return yield* new LitellmKeyAbsentAfterWriteError({ keyAlias: alias });
3307
+ const settled2 = { ...after, duration: remembered(news, before) };
3308
+ const left = differing11(settled2, news);
3309
+ if (left.length > 0) {
3310
+ return yield* new LitellmKeyFieldNotAppliedError({ fields: left, keyAlias: alias });
3311
+ }
3312
+ return settled2;
3313
+ }),
3314
+ delete: ({ output }) => deleteKey(output.keyAlias),
3315
+ list: () => Effect39.succeed([])
3316
+ };
3317
+ var LiteLLMKeyProvider = () => Provider12.effect(LiteLLMKey, Effect39.succeed(LiteLLMKey.Provider.of(keyHandlers)));
311
3318
  // src/litellm/providers.ts
312
3319
  import { CredentialsFromEnv } from "@distilled.cloud/litellm/Credentials";
313
3320
  import * as Layer from "effect/Layer";
314
- var litellmProviders = (creds = CredentialsFromEnv) => Layer.mergeAll(LiteLLMPassThroughEndpointProvider(), LiteLLMBudgetProvider()).pipe(Layer.provideMerge(creds));
3321
+ var litellmProviders = (creds = CredentialsFromEnv) => Layer.mergeAll(LiteLLMPassThroughEndpointProvider(), LiteLLMBudgetProvider(), LiteLLMCredentialProvider(), LiteLLMMCPServerProvider(), LiteLLMAccessGroupProvider(), LiteLLMToolsetProvider(), LiteLLMToolPolicyProvider(), LiteLLMPolicyProvider(), LiteLLMPolicyAttachmentProvider(), LiteLLMTeamProvider(), LiteLLMKeyProvider(), LiteLLMModelProvider()).pipe(Layer.provideMerge(creds));
315
3322
  export {
3323
+ LiteLLMAccessGroup,
3324
+ LiteLLMAccessGroupProvider,
316
3325
  LiteLLMBudget,
317
3326
  LiteLLMBudgetProvider,
3327
+ LiteLLMCredential,
3328
+ LiteLLMCredentialProvider,
3329
+ LiteLLMKey,
3330
+ LiteLLMKeyProvider,
3331
+ LiteLLMMCPServer,
3332
+ LiteLLMMCPServerProvider,
3333
+ LiteLLMModel,
3334
+ LiteLLMModelProvider,
318
3335
  LiteLLMPassThroughEndpoint,
319
3336
  LiteLLMPassThroughEndpointProvider,
3337
+ LiteLLMPolicy,
3338
+ LiteLLMPolicyAttachment,
3339
+ LiteLLMPolicyAttachmentProvider,
3340
+ LiteLLMPolicyProvider,
3341
+ LiteLLMTeam,
3342
+ LiteLLMTeamProvider,
3343
+ LiteLLMToolPolicy,
3344
+ LiteLLMToolPolicyProvider,
3345
+ LiteLLMToolset,
3346
+ LiteLLMToolsetProvider,
320
3347
  LitellmBudgetFieldNotClearedError,
321
3348
  LitellmBudgetHardCapUnjustifiedError,
322
3349
  LitellmBudgetUnreadableError,
323
3350
  LitellmConfigPathConflictError,
3351
+ LitellmCredentialAbsentAfterWriteError,
3352
+ LitellmCredentialEnvUnsetError,
3353
+ LitellmCredentialInvalidError,
3354
+ LitellmCredentialNotConvergedError,
3355
+ LitellmCredentialUnreadableError,
3356
+ LitellmKeyAbsentAfterWriteError,
3357
+ LitellmKeyAliasChangedError,
3358
+ LitellmKeyAliasEmptyError,
3359
+ LitellmKeyAmbiguousAliasError,
3360
+ LitellmKeyCallbackMetadataDeclaredError,
3361
+ LitellmKeyCallbackMetadataLiveError,
3362
+ LitellmKeyDebugLoggingError,
3363
+ LitellmKeyFieldNotAppliedError,
3364
+ LitellmKeyTransportError,
3365
+ LitellmKeyUnreadableError,
3366
+ LitellmKeyValueMalformedError,
3367
+ LitellmKeyValueMissingError,
3368
+ LitellmKeyValueNotHonouredError,
3369
+ LitellmKeyValueRequiredError,
324
3370
  LitellmLiteralSecretHeaderError,
3371
+ LitellmMcpServerAbsentAfterWriteError,
3372
+ LitellmMcpServerAmbiguousNameError,
3373
+ LitellmMcpServerCredentialEnvUnsetError,
3374
+ LitellmMcpServerDescriptionShadowedError,
3375
+ LitellmMcpServerInvalidError,
3376
+ LitellmMcpServerNotConvergedError,
3377
+ LitellmMcpServerUnreadableError,
3378
+ LitellmModelAbsentAfterWriteError,
3379
+ LitellmModelAmbiguousNameError,
3380
+ LitellmModelConfigFileRowError,
3381
+ LitellmModelForeignRowError,
3382
+ LitellmModelInvalidError,
3383
+ LitellmModelNotConvergedError,
3384
+ LitellmModelPriorGenerationError,
3385
+ LitellmModelUnreadableError,
3386
+ LitellmRegistryAbsentAfterWriteError,
3387
+ LitellmRegistryAmbiguousError,
3388
+ LitellmRegistryInvalidError,
3389
+ LitellmRegistryNotConvergedError,
3390
+ LitellmRegistryUnreadableError,
325
3391
  LitellmUnaddressableRowError,
3392
+ isLiteLLMAccessGroup,
326
3393
  isLiteLLMBudget,
3394
+ isLiteLLMCredential,
3395
+ isLiteLLMKey,
3396
+ isLiteLLMMCPServer,
3397
+ isLiteLLMModel,
327
3398
  isLiteLLMPassThroughEndpoint,
3399
+ isLiteLLMPolicy,
3400
+ isLiteLLMPolicyAttachment,
3401
+ isLiteLLMTeam,
3402
+ isLiteLLMToolPolicy,
3403
+ isLiteLLMToolset,
328
3404
  litellmProviders
329
3405
  };
330
3406
 
331
- //# debugId=0E62C0ABB834992A64756E2164756E21
3407
+ //# debugId=2E47E5AC1835F31A64756E2164756E21
332
3408
  //# sourceMappingURL=index.js.map