@homeflare/alchemy 0.43.0 → 0.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (612) hide show
  1. package/README.md +10 -1
  2. package/dist/caddy/index.js +35 -1
  3. package/dist/caddy/index.js.map +3 -3
  4. package/dist/launchd/index.js +35 -1
  5. package/dist/launchd/index.js.map +3 -3
  6. package/dist/linux/index.js +35 -1
  7. package/dist/linux/index.js.map +3 -3
  8. package/dist/litellm/access-group-form.d.ts +26 -0
  9. package/dist/litellm/access-group-form.d.ts.map +1 -0
  10. package/dist/litellm/access-group-operations.d.ts +37 -0
  11. package/dist/litellm/access-group-operations.d.ts.map +1 -0
  12. package/dist/litellm/access-group-types.d.ts +49 -0
  13. package/dist/litellm/access-group-types.d.ts.map +1 -0
  14. package/dist/litellm/access-group.d.ts +55 -0
  15. package/dist/litellm/access-group.d.ts.map +1 -0
  16. package/dist/litellm/credential-errors.d.ts +131 -0
  17. package/dist/litellm/credential-errors.d.ts.map +1 -0
  18. package/dist/litellm/credential-form.d.ts +79 -0
  19. package/dist/litellm/credential-form.d.ts.map +1 -0
  20. package/dist/litellm/credential-operations.d.ts +84 -0
  21. package/dist/litellm/credential-operations.d.ts.map +1 -0
  22. package/dist/litellm/credential-rewrite.d.ts +6 -0
  23. package/dist/litellm/credential-rewrite.d.ts.map +1 -0
  24. package/dist/litellm/credential-types.d.ts +87 -0
  25. package/dist/litellm/credential-types.d.ts.map +1 -0
  26. package/dist/litellm/credential-values.d.ts +53 -0
  27. package/dist/litellm/credential-values.d.ts.map +1 -0
  28. package/dist/litellm/credential.d.ts +83 -0
  29. package/dist/litellm/credential.d.ts.map +1 -0
  30. package/dist/litellm/fake-access-group-litellm.d.ts +34 -0
  31. package/dist/litellm/fake-access-group-litellm.d.ts.map +1 -0
  32. package/dist/litellm/fake-credential-litellm.d.ts +54 -0
  33. package/dist/litellm/fake-credential-litellm.d.ts.map +1 -0
  34. package/dist/litellm/fake-keys.d.ts +53 -0
  35. package/dist/litellm/fake-keys.d.ts.map +1 -0
  36. package/dist/litellm/fake-litellm.d.ts +4 -1
  37. package/dist/litellm/fake-litellm.d.ts.map +1 -1
  38. package/dist/litellm/fake-mcp-litellm.d.ts +67 -0
  39. package/dist/litellm/fake-mcp-litellm.d.ts.map +1 -0
  40. package/dist/litellm/fake-model-litellm-post-update.d.ts +49 -0
  41. package/dist/litellm/fake-model-litellm-post-update.d.ts.map +1 -0
  42. package/dist/litellm/fake-model-litellm.d.ts +48 -0
  43. package/dist/litellm/fake-model-litellm.d.ts.map +1 -0
  44. package/dist/litellm/fake-policy-attachment-litellm.d.ts +33 -0
  45. package/dist/litellm/fake-policy-attachment-litellm.d.ts.map +1 -0
  46. package/dist/litellm/fake-policy-litellm.d.ts +32 -0
  47. package/dist/litellm/fake-policy-litellm.d.ts.map +1 -0
  48. package/dist/litellm/fake-registry-base.d.ts +42 -0
  49. package/dist/litellm/fake-registry-base.d.ts.map +1 -0
  50. package/dist/litellm/fake-stack.d.ts +8 -1
  51. package/dist/litellm/fake-stack.d.ts.map +1 -1
  52. package/dist/litellm/fake-team-litellm.d.ts +47 -0
  53. package/dist/litellm/fake-team-litellm.d.ts.map +1 -0
  54. package/dist/litellm/fake-tool-litellm.d.ts +28 -0
  55. package/dist/litellm/fake-tool-litellm.d.ts.map +1 -0
  56. package/dist/litellm/fake-toolset-litellm.d.ts +29 -0
  57. package/dist/litellm/fake-toolset-litellm.d.ts.map +1 -0
  58. package/dist/litellm/index.d.ts +18 -0
  59. package/dist/litellm/index.d.ts.map +1 -1
  60. package/dist/litellm/index.js +3078 -2
  61. package/dist/litellm/index.js.map +65 -4
  62. package/dist/litellm/key-errors.d.ts +169 -0
  63. package/dist/litellm/key-errors.d.ts.map +1 -0
  64. package/dist/litellm/key-form.d.ts +119 -0
  65. package/dist/litellm/key-form.d.ts.map +1 -0
  66. package/dist/litellm/key-harness.d.ts +41 -0
  67. package/dist/litellm/key-harness.d.ts.map +1 -0
  68. package/dist/litellm/key-metadata-errors.d.ts +30 -0
  69. package/dist/litellm/key-metadata-errors.d.ts.map +1 -0
  70. package/dist/litellm/key-metadata.d.ts +22 -0
  71. package/dist/litellm/key-metadata.d.ts.map +1 -0
  72. package/dist/litellm/key-operations.d.ts +63 -0
  73. package/dist/litellm/key-operations.d.ts.map +1 -0
  74. package/dist/litellm/key-secret.d.ts +33 -0
  75. package/dist/litellm/key-secret.d.ts.map +1 -0
  76. package/dist/litellm/key.d.ts +78 -0
  77. package/dist/litellm/key.d.ts.map +1 -0
  78. package/dist/litellm/mcp-server-credential.d.ts +50 -0
  79. package/dist/litellm/mcp-server-credential.d.ts.map +1 -0
  80. package/dist/litellm/mcp-server-errors.d.ts +101 -0
  81. package/dist/litellm/mcp-server-errors.d.ts.map +1 -0
  82. package/dist/litellm/mcp-server-form.d.ts +56 -0
  83. package/dist/litellm/mcp-server-form.d.ts.map +1 -0
  84. package/dist/litellm/mcp-server-locate.d.ts +26 -0
  85. package/dist/litellm/mcp-server-locate.d.ts.map +1 -0
  86. package/dist/litellm/mcp-server-operations.d.ts +63 -0
  87. package/dist/litellm/mcp-server-operations.d.ts.map +1 -0
  88. package/dist/litellm/mcp-server-shadow.d.ts +24 -0
  89. package/dist/litellm/mcp-server-shadow.d.ts.map +1 -0
  90. package/dist/litellm/mcp-server-types.d.ts +118 -0
  91. package/dist/litellm/mcp-server-types.d.ts.map +1 -0
  92. package/dist/litellm/mcp-server-url.d.ts +11 -0
  93. package/dist/litellm/mcp-server-url.d.ts.map +1 -0
  94. package/dist/litellm/mcp-server.d.ts +95 -0
  95. package/dist/litellm/mcp-server.d.ts.map +1 -0
  96. package/dist/litellm/model-claim.d.ts +24 -0
  97. package/dist/litellm/model-claim.d.ts.map +1 -0
  98. package/dist/litellm/model-credential.d.ts +12 -0
  99. package/dist/litellm/model-credential.d.ts.map +1 -0
  100. package/dist/litellm/model-errors.d.ts +119 -0
  101. package/dist/litellm/model-errors.d.ts.map +1 -0
  102. package/dist/litellm/model-form.d.ts +78 -0
  103. package/dist/litellm/model-form.d.ts.map +1 -0
  104. package/dist/litellm/model-locate.d.ts +13 -0
  105. package/dist/litellm/model-locate.d.ts.map +1 -0
  106. package/dist/litellm/model-operations.d.ts +59 -0
  107. package/dist/litellm/model-operations.d.ts.map +1 -0
  108. package/dist/litellm/model-types.d.ts +91 -0
  109. package/dist/litellm/model-types.d.ts.map +1 -0
  110. package/dist/litellm/model.d.ts +88 -0
  111. package/dist/litellm/model.d.ts.map +1 -0
  112. package/dist/litellm/policy-attachment-form.d.ts +19 -0
  113. package/dist/litellm/policy-attachment-form.d.ts.map +1 -0
  114. package/dist/litellm/policy-attachment-operations.d.ts +31 -0
  115. package/dist/litellm/policy-attachment-operations.d.ts.map +1 -0
  116. package/dist/litellm/policy-attachment-types.d.ts +48 -0
  117. package/dist/litellm/policy-attachment-types.d.ts.map +1 -0
  118. package/dist/litellm/policy-attachment.d.ts +61 -0
  119. package/dist/litellm/policy-attachment.d.ts.map +1 -0
  120. package/dist/litellm/policy-form.d.ts +22 -0
  121. package/dist/litellm/policy-form.d.ts.map +1 -0
  122. package/dist/litellm/policy-operations.d.ts +42 -0
  123. package/dist/litellm/policy-operations.d.ts.map +1 -0
  124. package/dist/litellm/policy-types.d.ts +57 -0
  125. package/dist/litellm/policy-types.d.ts.map +1 -0
  126. package/dist/litellm/policy.d.ts +65 -0
  127. package/dist/litellm/policy.d.ts.map +1 -0
  128. package/dist/litellm/providers.d.ts +1 -1
  129. package/dist/litellm/providers.d.ts.map +1 -1
  130. package/dist/litellm/registry-errors.d.ts +62 -0
  131. package/dist/litellm/registry-errors.d.ts.map +1 -0
  132. package/dist/litellm/registry-support.d.ts +42 -0
  133. package/dist/litellm/registry-support.d.ts.map +1 -0
  134. package/dist/litellm/team-form.d.ts +26 -0
  135. package/dist/litellm/team-form.d.ts.map +1 -0
  136. package/dist/litellm/team-members.d.ts +10 -0
  137. package/dist/litellm/team-members.d.ts.map +1 -0
  138. package/dist/litellm/team-operations.d.ts +38 -0
  139. package/dist/litellm/team-operations.d.ts.map +1 -0
  140. package/dist/litellm/team-permission.d.ts +35 -0
  141. package/dist/litellm/team-permission.d.ts.map +1 -0
  142. package/dist/litellm/team-types.d.ts +101 -0
  143. package/dist/litellm/team-types.d.ts.map +1 -0
  144. package/dist/litellm/team.d.ts +67 -0
  145. package/dist/litellm/team.d.ts.map +1 -0
  146. package/dist/litellm/tool-policy-form.d.ts +21 -0
  147. package/dist/litellm/tool-policy-form.d.ts.map +1 -0
  148. package/dist/litellm/tool-policy-operations.d.ts +30 -0
  149. package/dist/litellm/tool-policy-operations.d.ts.map +1 -0
  150. package/dist/litellm/tool-policy-types.d.ts +46 -0
  151. package/dist/litellm/tool-policy-types.d.ts.map +1 -0
  152. package/dist/litellm/tool-policy.d.ts +62 -0
  153. package/dist/litellm/tool-policy.d.ts.map +1 -0
  154. package/dist/litellm/toolset-form.d.ts +20 -0
  155. package/dist/litellm/toolset-form.d.ts.map +1 -0
  156. package/dist/litellm/toolset-operations.d.ts +39 -0
  157. package/dist/litellm/toolset-operations.d.ts.map +1 -0
  158. package/dist/litellm/toolset-types.d.ts +46 -0
  159. package/dist/litellm/toolset-types.d.ts.map +1 -0
  160. package/dist/litellm/toolset.d.ts +55 -0
  161. package/dist/litellm/toolset.d.ts.map +1 -0
  162. package/dist/openbao/index.js +35 -1
  163. package/dist/openbao/index.js.map +3 -3
  164. package/dist/ownership/rows.d.ts +11 -0
  165. package/dist/ownership/rows.d.ts.map +1 -1
  166. package/dist/postgres/connection.d.ts +14 -2
  167. package/dist/postgres/connection.d.ts.map +1 -1
  168. package/dist/postgres/database-sql.d.ts +27 -8
  169. package/dist/postgres/database-sql.d.ts.map +1 -1
  170. package/dist/postgres/fake-grants-parse.d.ts +37 -0
  171. package/dist/postgres/fake-grants-parse.d.ts.map +1 -0
  172. package/dist/postgres/fake-grants-read.d.ts +61 -0
  173. package/dist/postgres/fake-grants-read.d.ts.map +1 -0
  174. package/dist/postgres/fake-grants-sql.d.ts +46 -0
  175. package/dist/postgres/fake-grants-sql.d.ts.map +1 -0
  176. package/dist/postgres/fake-grants-write.d.ts +29 -0
  177. package/dist/postgres/fake-grants-write.d.ts.map +1 -0
  178. package/dist/postgres/fake-role-sql.d.ts +41 -0
  179. package/dist/postgres/fake-role-sql.d.ts.map +1 -0
  180. package/dist/postgres/fake-schema-sql.d.ts +42 -0
  181. package/dist/postgres/fake-schema-sql.d.ts.map +1 -0
  182. package/dist/postgres/fake-sql-parse.d.ts +23 -0
  183. package/dist/postgres/fake-sql-parse.d.ts.map +1 -0
  184. package/dist/postgres/fake-sql-quote.d.ts +12 -0
  185. package/dist/postgres/fake-sql-quote.d.ts.map +1 -0
  186. package/dist/postgres/fake-sql.d.ts +42 -0
  187. package/dist/postgres/fake-sql.d.ts.map +1 -1
  188. package/dist/postgres/grants-attrs.d.ts +115 -0
  189. package/dist/postgres/grants-attrs.d.ts.map +1 -0
  190. package/dist/postgres/grants-declare.d.ts +88 -0
  191. package/dist/postgres/grants-declare.d.ts.map +1 -0
  192. package/dist/postgres/grants-diff.d.ts +25 -0
  193. package/dist/postgres/grants-diff.d.ts.map +1 -0
  194. package/dist/postgres/grants-errors.d.ts +137 -0
  195. package/dist/postgres/grants-errors.d.ts.map +1 -0
  196. package/dist/postgres/grants-existence.d.ts +14 -0
  197. package/dist/postgres/grants-existence.d.ts.map +1 -0
  198. package/dist/postgres/grants-ops.d.ts +65 -0
  199. package/dist/postgres/grants-ops.d.ts.map +1 -0
  200. package/dist/postgres/grants-ownership.d.ts +18 -0
  201. package/dist/postgres/grants-ownership.d.ts.map +1 -0
  202. package/dist/postgres/grants-plan-restore.d.ts +22 -0
  203. package/dist/postgres/grants-plan-restore.d.ts.map +1 -0
  204. package/dist/postgres/grants-plan.d.ts +65 -0
  205. package/dist/postgres/grants-plan.d.ts.map +1 -0
  206. package/dist/postgres/grants-read-defaults.d.ts +17 -0
  207. package/dist/postgres/grants-read-defaults.d.ts.map +1 -0
  208. package/dist/postgres/grants-read.d.ts +77 -0
  209. package/dist/postgres/grants-read.d.ts.map +1 -0
  210. package/dist/postgres/grants-refuse.d.ts +25 -0
  211. package/dist/postgres/grants-refuse.d.ts.map +1 -0
  212. package/dist/postgres/grants-sql.d.ts +42 -0
  213. package/dist/postgres/grants-sql.d.ts.map +1 -0
  214. package/dist/postgres/grants-words.d.ts +29 -0
  215. package/dist/postgres/grants-words.d.ts.map +1 -0
  216. package/dist/postgres/grants.d.ts +37 -0
  217. package/dist/postgres/grants.d.ts.map +1 -0
  218. package/dist/postgres/index.d.ts +31 -6
  219. package/dist/postgres/index.d.ts.map +1 -1
  220. package/dist/postgres/index.js +1998 -37
  221. package/dist/postgres/index.js.map +46 -7
  222. package/dist/postgres/installed-classifier.d.ts +13 -0
  223. package/dist/postgres/installed-classifier.d.ts.map +1 -0
  224. package/dist/postgres/providers.d.ts +16 -8
  225. package/dist/postgres/providers.d.ts.map +1 -1
  226. package/dist/postgres/psql-executor.d.ts +4 -0
  227. package/dist/postgres/psql-executor.d.ts.map +1 -1
  228. package/dist/postgres/role-attrs.d.ts +112 -0
  229. package/dist/postgres/role-attrs.d.ts.map +1 -0
  230. package/dist/postgres/role-diff.d.ts +22 -0
  231. package/dist/postgres/role-diff.d.ts.map +1 -0
  232. package/dist/postgres/role-errors.d.ts +132 -0
  233. package/dist/postgres/role-errors.d.ts.map +1 -0
  234. package/dist/postgres/role-membership-sql.d.ts +78 -0
  235. package/dist/postgres/role-membership-sql.d.ts.map +1 -0
  236. package/dist/postgres/role-provider.d.ts +11 -0
  237. package/dist/postgres/role-provider.d.ts.map +1 -0
  238. package/dist/postgres/role-scram.d.ts +8 -0
  239. package/dist/postgres/role-scram.d.ts.map +1 -0
  240. package/dist/postgres/role-secrets.d.ts +38 -0
  241. package/dist/postgres/role-secrets.d.ts.map +1 -0
  242. package/dist/postgres/role-sql.d.ts +68 -0
  243. package/dist/postgres/role-sql.d.ts.map +1 -0
  244. package/dist/postgres/role.d.ts +57 -0
  245. package/dist/postgres/role.d.ts.map +1 -0
  246. package/dist/postgres/schema-assert.d.ts +50 -0
  247. package/dist/postgres/schema-assert.d.ts.map +1 -0
  248. package/dist/postgres/schema-attrs.d.ts +51 -0
  249. package/dist/postgres/schema-attrs.d.ts.map +1 -0
  250. package/dist/postgres/schema-delete.d.ts +28 -0
  251. package/dist/postgres/schema-delete.d.ts.map +1 -0
  252. package/dist/postgres/schema-diff.d.ts +14 -0
  253. package/dist/postgres/schema-diff.d.ts.map +1 -0
  254. package/dist/postgres/schema-errors.d.ts +139 -0
  255. package/dist/postgres/schema-errors.d.ts.map +1 -0
  256. package/dist/postgres/schema-identity.d.ts +8 -0
  257. package/dist/postgres/schema-identity.d.ts.map +1 -0
  258. package/dist/postgres/schema-reconcile.d.ts +12 -0
  259. package/dist/postgres/schema-reconcile.d.ts.map +1 -0
  260. package/dist/postgres/schema-sql.d.ts +45 -0
  261. package/dist/postgres/schema-sql.d.ts.map +1 -0
  262. package/dist/postgres/schema-test-kit.d.ts +67 -0
  263. package/dist/postgres/schema-test-kit.d.ts.map +1 -0
  264. package/dist/postgres/schema.d.ts +54 -0
  265. package/dist/postgres/schema.d.ts.map +1 -0
  266. package/dist/proxmox/index.js +35 -1
  267. package/dist/proxmox/index.js.map +3 -3
  268. package/dist/release/fake-engine.d.ts +10 -0
  269. package/dist/release/fake-engine.d.ts.map +1 -1
  270. package/dist/release/index.js +35 -1
  271. package/dist/release/index.js.map +3 -3
  272. package/dist/valkey/acl-attrs.d.ts +94 -0
  273. package/dist/valkey/acl-attrs.d.ts.map +1 -0
  274. package/dist/valkey/acl-compare.d.ts +28 -0
  275. package/dist/valkey/acl-compare.d.ts.map +1 -0
  276. package/dist/valkey/acl-connection.d.ts +6 -0
  277. package/dist/valkey/acl-connection.d.ts.map +1 -0
  278. package/dist/valkey/acl-form.d.ts +62 -0
  279. package/dist/valkey/acl-form.d.ts.map +1 -0
  280. package/dist/valkey/acl-managed.d.ts +4 -0
  281. package/dist/valkey/acl-managed.d.ts.map +1 -0
  282. package/dist/valkey/acl-ops.d.ts +37 -0
  283. package/dist/valkey/acl-ops.d.ts.map +1 -0
  284. package/dist/valkey/acl-profiles.d.ts +53 -0
  285. package/dist/valkey/acl-profiles.d.ts.map +1 -0
  286. package/dist/valkey/acl-reconcile.d.ts +26 -0
  287. package/dist/valkey/acl-reconcile.d.ts.map +1 -0
  288. package/dist/valkey/acl.d.ts +24 -0
  289. package/dist/valkey/acl.d.ts.map +1 -0
  290. package/dist/valkey/connection-service.d.ts +22 -0
  291. package/dist/valkey/connection-service.d.ts.map +1 -0
  292. package/dist/valkey/connection.d.ts +59 -0
  293. package/dist/valkey/connection.d.ts.map +1 -0
  294. package/dist/valkey/errors.d.ts +165 -0
  295. package/dist/valkey/errors.d.ts.map +1 -0
  296. package/dist/valkey/fake-acl.d.ts +29 -0
  297. package/dist/valkey/fake-acl.d.ts.map +1 -0
  298. package/dist/valkey/fake-valkey.d.ts +35 -0
  299. package/dist/valkey/fake-valkey.d.ts.map +1 -0
  300. package/dist/valkey/handler-test-fixture.d.ts +20 -0
  301. package/dist/valkey/handler-test-fixture.d.ts.map +1 -0
  302. package/dist/valkey/index.d.ts +18 -0
  303. package/dist/valkey/index.d.ts.map +1 -0
  304. package/dist/valkey/index.js +964 -0
  305. package/dist/valkey/index.js.map +27 -0
  306. package/dist/valkey/instance-attrs.d.ts +46 -0
  307. package/dist/valkey/instance-attrs.d.ts.map +1 -0
  308. package/dist/valkey/instance-form.d.ts +22 -0
  309. package/dist/valkey/instance-form.d.ts.map +1 -0
  310. package/dist/valkey/instance.d.ts +48 -0
  311. package/dist/valkey/instance.d.ts.map +1 -0
  312. package/dist/valkey/provider-socket-fixture.d.ts +8 -0
  313. package/dist/valkey/provider-socket-fixture.d.ts.map +1 -0
  314. package/dist/valkey/providers.d.ts +16 -0
  315. package/dist/valkey/providers.d.ts.map +1 -0
  316. package/dist/valkey/resp.d.ts +38 -0
  317. package/dist/valkey/resp.d.ts.map +1 -0
  318. package/dist/valkey/transport-error.d.ts +36 -0
  319. package/dist/valkey/transport-error.d.ts.map +1 -0
  320. package/dist/valkey/transport.d.ts +50 -0
  321. package/dist/valkey/transport.d.ts.map +1 -0
  322. package/docs/litellm-access-group.md +105 -0
  323. package/docs/litellm-credential.md +60 -0
  324. package/docs/litellm-key-metadata.md +56 -0
  325. package/docs/litellm-key.md +194 -0
  326. package/docs/litellm-mcp.md +187 -0
  327. package/docs/litellm-model.md +111 -0
  328. package/docs/litellm-policy-attachment.md +86 -0
  329. package/docs/litellm-policy.md +103 -0
  330. package/docs/litellm-team.md +117 -0
  331. package/docs/litellm-tool-policy.md +90 -0
  332. package/docs/litellm-toolset.md +92 -0
  333. package/docs/litellm.md +16 -9
  334. package/docs/peers.md +15 -6
  335. package/docs/postgres-grants-example.md +55 -0
  336. package/docs/postgres-grants.md +157 -0
  337. package/docs/postgres-role.md +126 -0
  338. package/docs/postgres-schema.md +139 -0
  339. package/docs/postgres.md +20 -3
  340. package/docs/valkey-transport.md +29 -0
  341. package/docs/valkey.md +187 -0
  342. package/package.json +6 -2
  343. package/src/ceph/ceph-argv.test.ts +1 -1
  344. package/src/launchd/sudo-allowlist.test.ts +2 -2
  345. package/src/linux/sudo-allowlist.test.ts +3 -3
  346. package/src/linux/sudo-runner.test.ts +2 -2
  347. package/src/litellm/access-group-form.ts +105 -0
  348. package/src/litellm/access-group-operations.ts +92 -0
  349. package/src/litellm/access-group-types.ts +49 -0
  350. package/src/litellm/access-group.test.ts +197 -0
  351. package/src/litellm/access-group.ts +151 -0
  352. package/src/litellm/credential-errors.ts +183 -0
  353. package/src/litellm/credential-form.test.ts +151 -0
  354. package/src/litellm/credential-form.ts +211 -0
  355. package/src/litellm/credential-guards.test.ts +241 -0
  356. package/src/litellm/credential-operations.ts +208 -0
  357. package/src/litellm/credential-recovery.test.ts +93 -0
  358. package/src/litellm/credential-rewrite.test.ts +164 -0
  359. package/src/litellm/credential-rewrite.ts +50 -0
  360. package/src/litellm/credential-types.ts +117 -0
  361. package/src/litellm/credential-values.ts +94 -0
  362. package/src/litellm/credential.test.ts +218 -0
  363. package/src/litellm/credential.ts +227 -0
  364. package/src/litellm/fake-access-group-litellm.ts +127 -0
  365. package/src/litellm/fake-credential-litellm.ts +216 -0
  366. package/src/litellm/fake-keys.ts +190 -0
  367. package/src/litellm/fake-litellm.ts +19 -9
  368. package/src/litellm/fake-mcp-litellm.ts +214 -0
  369. package/src/litellm/fake-model-litellm-post-update.ts +103 -0
  370. package/src/litellm/fake-model-litellm.ts +233 -0
  371. package/src/litellm/fake-policy-attachment-litellm.ts +97 -0
  372. package/src/litellm/fake-policy-litellm.ts +186 -0
  373. package/src/litellm/fake-registry-base.ts +69 -0
  374. package/src/litellm/fake-stack.ts +17 -1
  375. package/src/litellm/fake-team-litellm.ts +229 -0
  376. package/src/litellm/fake-tool-litellm.ts +88 -0
  377. package/src/litellm/fake-toolset-litellm.ts +110 -0
  378. package/src/litellm/index.ts +140 -0
  379. package/src/litellm/key-delete.test.ts +212 -0
  380. package/src/litellm/key-errors.ts +241 -0
  381. package/src/litellm/key-form.ts +200 -0
  382. package/src/litellm/key-harness.ts +121 -0
  383. package/src/litellm/key-metadata-errors.ts +49 -0
  384. package/src/litellm/key-metadata.test.ts +156 -0
  385. package/src/litellm/key-metadata.ts +74 -0
  386. package/src/litellm/key-operations.ts +184 -0
  387. package/src/litellm/key-rotation.test.ts +110 -0
  388. package/src/litellm/key-scope.test.ts +135 -0
  389. package/src/litellm/key-secret.test.ts +248 -0
  390. package/src/litellm/key-secret.ts +137 -0
  391. package/src/litellm/key-transport.test.ts +166 -0
  392. package/src/litellm/key.test.ts +231 -0
  393. package/src/litellm/key.ts +213 -0
  394. package/src/litellm/mcp-server-adopt.test.ts +86 -0
  395. package/src/litellm/mcp-server-alias.test.ts +184 -0
  396. package/src/litellm/mcp-server-credential.ts +85 -0
  397. package/src/litellm/mcp-server-errors.ts +141 -0
  398. package/src/litellm/mcp-server-exports.test.ts +15 -0
  399. package/src/litellm/mcp-server-form.test.ts +241 -0
  400. package/src/litellm/mcp-server-form.ts +233 -0
  401. package/src/litellm/mcp-server-handlers.test.ts +150 -0
  402. package/src/litellm/mcp-server-locate.ts +66 -0
  403. package/src/litellm/mcp-server-operations.ts +111 -0
  404. package/src/litellm/mcp-server-registry.test.ts +146 -0
  405. package/src/litellm/mcp-server-retype.test.ts +114 -0
  406. package/src/litellm/mcp-server-shadow.test.ts +91 -0
  407. package/src/litellm/mcp-server-shadow.ts +45 -0
  408. package/src/litellm/mcp-server-tools.test.ts +85 -0
  409. package/src/litellm/mcp-server-types.ts +143 -0
  410. package/src/litellm/mcp-server-url.ts +66 -0
  411. package/src/litellm/mcp-server.test.ts +213 -0
  412. package/src/litellm/mcp-server.ts +225 -0
  413. package/src/litellm/model-claim.ts +69 -0
  414. package/src/litellm/model-credential.ts +45 -0
  415. package/src/litellm/model-errors.ts +168 -0
  416. package/src/litellm/model-foreign-row.test.ts +173 -0
  417. package/src/litellm/model-form.test.ts +228 -0
  418. package/src/litellm/model-form.ts +223 -0
  419. package/src/litellm/model-locate.test.ts +128 -0
  420. package/src/litellm/model-locate.ts +67 -0
  421. package/src/litellm/model-operations.test.ts +93 -0
  422. package/src/litellm/model-operations.ts +146 -0
  423. package/src/litellm/model-params-preserve.test.ts +119 -0
  424. package/src/litellm/model-recovery.test.ts +57 -0
  425. package/src/litellm/model-types.ts +112 -0
  426. package/src/litellm/model.test.ts +222 -0
  427. package/src/litellm/model.ts +237 -0
  428. package/src/litellm/policy-attachment-form.ts +103 -0
  429. package/src/litellm/policy-attachment-operations.ts +74 -0
  430. package/src/litellm/policy-attachment-types.ts +48 -0
  431. package/src/litellm/policy-attachment.test.ts +198 -0
  432. package/src/litellm/policy-attachment.ts +178 -0
  433. package/src/litellm/policy-form.ts +122 -0
  434. package/src/litellm/policy-operations.ts +112 -0
  435. package/src/litellm/policy-types.ts +58 -0
  436. package/src/litellm/policy.test.ts +214 -0
  437. package/src/litellm/policy.ts +146 -0
  438. package/src/litellm/providers.ts +24 -3
  439. package/src/litellm/registry-errors.ts +88 -0
  440. package/src/litellm/registry-exports.test.ts +66 -0
  441. package/src/litellm/registry-support.ts +109 -0
  442. package/src/litellm/team-form.ts +140 -0
  443. package/src/litellm/team-members.test.ts +150 -0
  444. package/src/litellm/team-members.ts +58 -0
  445. package/src/litellm/team-operations.ts +90 -0
  446. package/src/litellm/team-permission.ts +159 -0
  447. package/src/litellm/team-read.test.ts +89 -0
  448. package/src/litellm/team-types.ts +106 -0
  449. package/src/litellm/team.test.ts +206 -0
  450. package/src/litellm/team.ts +159 -0
  451. package/src/litellm/tool-policy-form.ts +94 -0
  452. package/src/litellm/tool-policy-operations.ts +58 -0
  453. package/src/litellm/tool-policy-types.ts +48 -0
  454. package/src/litellm/tool-policy.test.ts +172 -0
  455. package/src/litellm/tool-policy.ts +125 -0
  456. package/src/litellm/toolset-form.ts +104 -0
  457. package/src/litellm/toolset-operations.ts +90 -0
  458. package/src/litellm/toolset-types.ts +47 -0
  459. package/src/litellm/toolset.test.ts +198 -0
  460. package/src/litellm/toolset.ts +151 -0
  461. package/src/ownership/ownership.test.ts +33 -1
  462. package/src/ownership/rows.ts +53 -0
  463. package/src/postgres/connection.ts +42 -7
  464. package/src/postgres/database-bigint-serialization.test.ts +1 -0
  465. package/src/postgres/database-refusals.test.ts +2 -2
  466. package/src/postgres/database-sql.ts +36 -9
  467. package/src/postgres/fake-grants-parse.ts +189 -0
  468. package/src/postgres/fake-grants-read.ts +250 -0
  469. package/src/postgres/fake-grants-sql.ts +207 -0
  470. package/src/postgres/fake-grants-write.ts +90 -0
  471. package/src/postgres/fake-role-sql.ts +240 -0
  472. package/src/postgres/fake-schema-semantics.test.ts +36 -0
  473. package/src/postgres/fake-schema-sql.ts +146 -0
  474. package/src/postgres/fake-sql-parse.ts +86 -0
  475. package/src/postgres/fake-sql-quote.ts +36 -0
  476. package/src/postgres/fake-sql.ts +166 -46
  477. package/src/postgres/fixtures/pg-REL_18_6-acl.h.txt +147 -0
  478. package/src/postgres/fixtures/pg-REL_18_6-aclexplode-func.txt +31 -0
  479. package/src/postgres/fixtures/pg-REL_18_6-alter-default-privileges-synopsis.txt +82 -0
  480. package/src/postgres/fixtures/pg-REL_18_6-alter_role.sgml.txt +44 -0
  481. package/src/postgres/fixtures/pg-REL_18_6-create_role.sgml.txt +26 -0
  482. package/src/postgres/fixtures/pg-REL_18_6-grant-synopsis.txt +95 -0
  483. package/src/postgres/fixtures/pg-REL_18_6-pg_attribute.h.txt +24 -0
  484. package/src/postgres/fixtures/pg-REL_18_6-pg_auth_members.h.txt +62 -0
  485. package/src/postgres/fixtures/pg-REL_18_6-pg_authid.h.txt +70 -0
  486. package/src/postgres/fixtures/pg-REL_18_6-pg_class.h.txt +33 -0
  487. package/src/postgres/fixtures/pg-REL_18_6-pg_default_acl.h.txt +81 -0
  488. package/src/postgres/fixtures/pg-REL_18_6-pg_namespace.h.txt +28 -0
  489. package/src/postgres/fixtures/pg-REL_18_6-revoke-synopsis.txt +124 -0
  490. package/src/postgres/grants-acl.test.ts +61 -0
  491. package/src/postgres/grants-attrs.ts +185 -0
  492. package/src/postgres/grants-database.test.ts +158 -0
  493. package/src/postgres/grants-declare.ts +172 -0
  494. package/src/postgres/grants-delete-proof.test.ts +154 -0
  495. package/src/postgres/grants-diff.ts +101 -0
  496. package/src/postgres/grants-errors.ts +215 -0
  497. package/src/postgres/grants-existence-guards.test.ts +113 -0
  498. package/src/postgres/grants-existence.ts +101 -0
  499. package/src/postgres/grants-lifecycle-guards.test.ts +208 -0
  500. package/src/postgres/grants-lifecycle-repair.test.ts +208 -0
  501. package/src/postgres/grants-lifecycle.test.ts +181 -0
  502. package/src/postgres/grants-ops.ts +229 -0
  503. package/src/postgres/grants-owner-revoke.test.ts +121 -0
  504. package/src/postgres/grants-ownership.ts +49 -0
  505. package/src/postgres/grants-plan-collateral.test.ts +202 -0
  506. package/src/postgres/grants-plan-diff.test.ts +204 -0
  507. package/src/postgres/grants-plan-restore.ts +43 -0
  508. package/src/postgres/grants-plan-revocations.test.ts +69 -0
  509. package/src/postgres/grants-plan.test.ts +148 -0
  510. package/src/postgres/grants-plan.ts +245 -0
  511. package/src/postgres/grants-provenance.test.ts +134 -0
  512. package/src/postgres/grants-psql-lifecycle.test.ts +105 -0
  513. package/src/postgres/grants-read-absent.test.ts +91 -0
  514. package/src/postgres/grants-read-defaults.ts +51 -0
  515. package/src/postgres/grants-read.ts +250 -0
  516. package/src/postgres/grants-refusals.test.ts +136 -0
  517. package/src/postgres/grants-refuse.ts +119 -0
  518. package/src/postgres/grants-relkind-wire.test.ts +111 -0
  519. package/src/postgres/grants-repair-plan.test.ts +201 -0
  520. package/src/postgres/grants-sql.test.ts +128 -0
  521. package/src/postgres/grants-sql.ts +144 -0
  522. package/src/postgres/grants-words.ts +34 -0
  523. package/src/postgres/grants.ts +110 -0
  524. package/src/postgres/index.ts +129 -5
  525. package/src/postgres/installed-classifier.ts +36 -0
  526. package/src/postgres/providers.ts +33 -9
  527. package/src/postgres/psql-executor-escaping.test.ts +67 -0
  528. package/src/postgres/psql-executor.test.ts +63 -2
  529. package/src/postgres/psql-executor.ts +74 -34
  530. package/src/postgres/role-adopt.test.ts +98 -0
  531. package/src/postgres/role-attrs.ts +137 -0
  532. package/src/postgres/role-diff.ts +93 -0
  533. package/src/postgres/role-errors.ts +206 -0
  534. package/src/postgres/role-guard.test.ts +60 -0
  535. package/src/postgres/role-identity.test.ts +197 -0
  536. package/src/postgres/role-lifecycle.test.ts +228 -0
  537. package/src/postgres/role-membership-options.test.ts +73 -0
  538. package/src/postgres/role-membership-repair.test.ts +153 -0
  539. package/src/postgres/role-membership-sql.ts +223 -0
  540. package/src/postgres/role-password-ascii.test.ts +53 -0
  541. package/src/postgres/role-password-transports.test.ts +123 -0
  542. package/src/postgres/role-password.test.ts +158 -0
  543. package/src/postgres/role-privilege.test.ts +107 -0
  544. package/src/postgres/role-provenance.test.ts +200 -0
  545. package/src/postgres/role-provider.ts +105 -0
  546. package/src/postgres/role-refusals.test.ts +225 -0
  547. package/src/postgres/role-scram.test.ts +38 -0
  548. package/src/postgres/role-scram.ts +40 -0
  549. package/src/postgres/role-secrets.ts +61 -0
  550. package/src/postgres/role-sql.ts +213 -0
  551. package/src/postgres/role-valid-until.test.ts +68 -0
  552. package/src/postgres/role.ts +226 -0
  553. package/src/postgres/schema-assert.ts +139 -0
  554. package/src/postgres/schema-attrs.ts +71 -0
  555. package/src/postgres/schema-delete-proofs.test.ts +192 -0
  556. package/src/postgres/schema-delete.ts +96 -0
  557. package/src/postgres/schema-diff.ts +44 -0
  558. package/src/postgres/schema-drop-2bp01.test.ts +146 -0
  559. package/src/postgres/schema-errors.ts +209 -0
  560. package/src/postgres/schema-handlers.test.ts +193 -0
  561. package/src/postgres/schema-identity.ts +39 -0
  562. package/src/postgres/schema-lifecycle.test.ts +246 -0
  563. package/src/postgres/schema-race.test.ts +70 -0
  564. package/src/postgres/schema-reconcile.ts +100 -0
  565. package/src/postgres/schema-refusals.test.ts +144 -0
  566. package/src/postgres/schema-socket.test.ts +162 -0
  567. package/src/postgres/schema-sql.ts +130 -0
  568. package/src/postgres/schema-takeover.test.ts +149 -0
  569. package/src/postgres/schema-test-kit.ts +85 -0
  570. package/src/postgres/schema.ts +130 -0
  571. package/src/release/binary-alias.test.ts +3 -3
  572. package/src/release/binary-claims.test.ts +3 -3
  573. package/src/release/binary-directory-umask.test.ts +65 -0
  574. package/src/release/fake-engine.ts +15 -0
  575. package/src/valkey/acl-attrs.ts +98 -0
  576. package/src/valkey/acl-compare.ts +57 -0
  577. package/src/valkey/acl-connection.ts +13 -0
  578. package/src/valkey/acl-delete.test.ts +127 -0
  579. package/src/valkey/acl-form.ts +239 -0
  580. package/src/valkey/acl-managed.ts +13 -0
  581. package/src/valkey/acl-ops.ts +122 -0
  582. package/src/valkey/acl-ownership.test.ts +118 -0
  583. package/src/valkey/acl-prefix.test.ts +38 -0
  584. package/src/valkey/acl-profiles.ts +81 -0
  585. package/src/valkey/acl-reconcile.ts +180 -0
  586. package/src/valkey/acl-reserved.test.ts +69 -0
  587. package/src/valkey/acl-revocation.test.ts +94 -0
  588. package/src/valkey/acl-seat-prefix.test.ts +111 -0
  589. package/src/valkey/acl-validation.test.ts +54 -0
  590. package/src/valkey/acl.test.ts +215 -0
  591. package/src/valkey/acl.ts +169 -0
  592. package/src/valkey/connection-service.ts +46 -0
  593. package/src/valkey/connection.ts +180 -0
  594. package/src/valkey/errors.ts +239 -0
  595. package/src/valkey/fake-acl.ts +128 -0
  596. package/src/valkey/fake-valkey.ts +224 -0
  597. package/src/valkey/handler-test-fixture.ts +43 -0
  598. package/src/valkey/handlers.test.ts +205 -0
  599. package/src/valkey/index.ts +54 -0
  600. package/src/valkey/instance-attrs.ts +48 -0
  601. package/src/valkey/instance-form.ts +104 -0
  602. package/src/valkey/instance.test.ts +108 -0
  603. package/src/valkey/instance.ts +160 -0
  604. package/src/valkey/provider-socket-fixture.ts +71 -0
  605. package/src/valkey/providers.test.ts +129 -0
  606. package/src/valkey/providers.ts +21 -0
  607. package/src/valkey/resp.ts +212 -0
  608. package/src/valkey/transport-bounds.test.ts +150 -0
  609. package/src/valkey/transport-error.ts +37 -0
  610. package/src/valkey/transport.test.ts +158 -0
  611. package/src/valkey/transport.ts +109 -0
  612. package/src/valkey/upstream-bounds.test.ts +14 -0
@@ -0,0 +1,205 @@
1
+ /** Exercise actual handlers: a failed read must never become a CREATE or skip adoption. */
2
+ import { expect, test } from 'bun:test';
3
+ import { Unowned } from 'alchemy/AdoptPolicy';
4
+ import * as Effect from 'effect/Effect';
5
+ import { makeValkeyAclFileHandlers } from './acl.ts';
6
+ import { makeValkeyInstanceHandlers } from './instance.ts';
7
+ import { makeFakeValkey } from './fake-valkey.ts';
8
+ import { connection, context, required, run } from './handler-test-fixture.ts';
9
+ import { ValkeyServerError, ValkeySocketError } from './transport.ts';
10
+ import { ValkeyAclParseError } from './errors.ts';
11
+ import type { ValkeyAclFileProps } from './acl-attrs.ts';
12
+ import { reconcileWithExecutor } from './acl-reconcile.ts';
13
+
14
+ const props: ValkeyAclFileProps = { instance: 'scratch', users: {} };
15
+ const attrs = { instance: 'scratch', users: {} };
16
+ const instance = { name: 'scratch', port: 0 };
17
+ const fake = () => makeFakeValkey({ passwords: { admin: 'FAKE-admin' } });
18
+
19
+ for (const tag of [
20
+ 'ValkeyServerError',
21
+ 'ValkeySocketError',
22
+ 'ValkeyAuthPasswordMissing',
23
+ ] as const) {
24
+ test(`read and ACL delete propagate ${tag}, never absence/success`, async () => {
25
+ const ex =
26
+ tag === 'ValkeyAuthPasswordMissing'
27
+ ? fake()
28
+ : {
29
+ send: () =>
30
+ Effect.fail(
31
+ tag === 'ValkeyServerError'
32
+ ? new ValkeyServerError({ detail: 'WRONGPASS' })
33
+ : new ValkeySocketError({ reason: 'connection refused' }),
34
+ ),
35
+ };
36
+ const connect = connection(ex, {});
37
+ // Server/socket errors occur after resolving a present credential.
38
+ const session = tag === 'ValkeyAuthPasswordMissing' ? connect : connection(ex);
39
+ const acl = makeValkeyAclFileHandlers(session);
40
+ const inst = makeValkeyInstanceHandlers(session);
41
+ expect(
42
+ (await run(Effect.flip(required(acl.read)({ ...context, olds: props, output: undefined }))))
43
+ ._tag,
44
+ ).toBe(tag === 'ValkeySocketError' ? 'ValkeyInstanceUnreachable' : tag);
45
+ expect(
46
+ (
47
+ await run(
48
+ Effect.flip(required(inst.read)({ ...context, olds: instance, output: undefined })),
49
+ )
50
+ )._tag,
51
+ ).toBe(tag);
52
+ expect(
53
+ (await run(Effect.flip(acl.delete({ ...context, olds: props, output: attrs }))))._tag,
54
+ ).toBe(tag === 'ValkeySocketError' ? 'ValkeyInstanceUnreachable' : tag);
55
+ });
56
+ }
57
+
58
+ test('wrong AUTH reply fails both reads; successful reads retain the adoption gate', async () => {
59
+ const ex = fake();
60
+ for (const credentials of [
61
+ { TEST_VALKEY_ADMIN_PW: 'FAKE-wrong' },
62
+ { TEST_VALKEY_ADMIN_PW: 'FAKE-admin' },
63
+ ]) {
64
+ const acl = makeValkeyAclFileHandlers(connection(ex, credentials));
65
+ const inst = makeValkeyInstanceHandlers(connection(ex, credentials));
66
+ if (credentials.TEST_VALKEY_ADMIN_PW === 'FAKE-wrong') {
67
+ expect(
68
+ (await run(Effect.flip(required(acl.read)({ ...context, olds: props, output: undefined }))))
69
+ ._tag,
70
+ ).toBe('ValkeyServerError');
71
+ expect(
72
+ (
73
+ await run(
74
+ Effect.flip(required(inst.read)({ ...context, olds: instance, output: undefined })),
75
+ )
76
+ )._tag,
77
+ ).toBe('ValkeyServerError');
78
+ } else {
79
+ expect(
80
+ Unowned.is(await run(required(acl.read)({ ...context, olds: props, output: undefined }))),
81
+ ).toBe(true);
82
+ expect(
83
+ Unowned.is(
84
+ await run(required(inst.read)({ ...context, olds: instance, output: undefined })),
85
+ ),
86
+ ).toBe(true);
87
+ }
88
+ }
89
+ });
90
+
91
+ test('configured ACL file refuses reconcile and delete before SETUSER/DELUSER', async () => {
92
+ const ex = fake();
93
+ ex.config.set('aclfile', '/scratch/readonly.acl');
94
+ const acl = makeValkeyAclFileHandlers(connection(ex));
95
+ for (const effect of [
96
+ acl.reconcile({ ...context, news: props, olds: props, output: attrs }),
97
+ acl.delete({ ...context, olds: props, output: attrs }),
98
+ ]) {
99
+ expect((await run(Effect.flip(effect)))._tag).toBe('ValkeyAclFileRendered');
100
+ }
101
+ expect(
102
+ ex.commands.some(({ args }) => ['SETUSER', 'DELUSER', 'SAVE'].includes(args[1] ?? '')),
103
+ ).toBe(false);
104
+ expect(await run(required(acl.read)({ ...context, olds: props, output: attrs }))).toEqual({
105
+ ...attrs,
106
+ managedUsers: [],
107
+ });
108
+ });
109
+
110
+ test('delete is repeatable, removes only declared users and preserves admin/undeclared', async () => {
111
+ const ex = fake();
112
+ ex.acl.set('seat', 'user seat on >FAKE-seat -@all');
113
+ ex.acl.set('monitor', 'user monitor on >FAKE-monitor -@all');
114
+ const acl = makeValkeyAclFileHandlers(connection(ex));
115
+ const olds: ValkeyAclFileProps = {
116
+ ...props,
117
+ users: {
118
+ seat: { name: 'seat', profile: 'seat', password: { fromEnv: 'TEST_VALKEY_SEAT_PW' } },
119
+ },
120
+ };
121
+ await run(acl.delete({ ...context, olds, output: attrs }));
122
+ await run(acl.delete({ ...context, olds, output: attrs }));
123
+ expect([...ex.acl.keys()]).toEqual(['monitor']);
124
+ expect(ex.commands.filter(({ args }) => args[1] === 'DELUSER')).toHaveLength(1);
125
+ const inst = makeValkeyInstanceHandlers(connection(ex));
126
+ expect(
127
+ (
128
+ await run(
129
+ Effect.flip(
130
+ inst.delete({
131
+ ...context,
132
+ olds: instance,
133
+ output: {
134
+ ...instance,
135
+ version: '9.1.1',
136
+ maxmemory: '0',
137
+ maxmemoryPolicy: 'noeviction',
138
+ appendonly: 'no',
139
+ },
140
+ }),
141
+ ),
142
+ )
143
+ )._tag,
144
+ ).toBe('ValkeyInstanceDeleteRefused');
145
+ });
146
+
147
+ test('diff compares stored attributes; drift read makes out-of-band channel changes visible', async () => {
148
+ const ex = fake();
149
+ const news: ValkeyAclFileProps = {
150
+ ...props,
151
+ users: {
152
+ seat: { name: 'seat', profile: 'seat', password: { fromEnv: 'TEST_VALKEY_SEAT_PW' } },
153
+ },
154
+ };
155
+ const stored = await Effect.runPromise(
156
+ reconcileWithExecutor(ex, news, undefined, { TEST_VALKEY_SEAT_PW: 'FAKE-seat' }),
157
+ );
158
+ const acl = makeValkeyAclFileHandlers(connection(ex));
159
+ const diff = (output: typeof stored, exclusive = false) =>
160
+ run(required(acl.diff)({ ...context, olds: news, news: { ...news, exclusive }, output }));
161
+ expect(await diff(stored)).toEqual({ action: 'noop' });
162
+ ex.acl.set('seat', required(ex.acl.get('seat')).replace('&seat:*', '&*'));
163
+ expect(await diff(stored)).toEqual({ action: 'noop' });
164
+ const live = await run(required(acl.read)({ ...context, olds: news, output: stored }));
165
+ expect(live?.users.seat?.passwordSeal).toBe(stored.users.seat?.passwordSeal);
166
+ expect(await diff(required(live))).toEqual({ action: 'update' });
167
+ const extra = { ...stored, users: { ...stored.users, monitor: required(stored.users.seat) } };
168
+ expect(await diff(extra)).toEqual({ action: 'noop' });
169
+ expect(await diff(extra, true)).toEqual({ action: 'update' });
170
+ const inst = makeValkeyInstanceHandlers(connection(ex));
171
+ const output = {
172
+ ...instance,
173
+ version: '9.1.1',
174
+ maxmemory: '0',
175
+ maxmemoryPolicy: 'noeviction',
176
+ appendonly: 'no',
177
+ };
178
+ expect(
179
+ await run(required(inst.diff)({ ...context, olds: instance, news: instance, output })),
180
+ ).toEqual({
181
+ action: 'noop',
182
+ });
183
+ expect(
184
+ await run(
185
+ required(inst.diff)({ ...context, olds: instance, news: { ...instance, port: 1 }, output }),
186
+ ),
187
+ ).toEqual({ action: 'update' });
188
+ });
189
+
190
+ test('malformed ACL fails read without retaining the hash in message or data', async () => {
191
+ const ex = fake();
192
+ const executor = {
193
+ send: (args: ReadonlyArray<string>) =>
194
+ args[1] === 'LIST'
195
+ ? Effect.succeed({ kind: 'array' as const, values: ['invalid #FAKE-hash'] })
196
+ : ex.send(args),
197
+ };
198
+ const acl = makeValkeyAclFileHandlers(connection(executor));
199
+ const error = await run(
200
+ Effect.flip(required(acl.read)({ ...context, olds: props, output: undefined })),
201
+ );
202
+ expect(error).toBeInstanceOf(ValkeyAclParseError);
203
+ expect(String(error)).not.toContain('FAKE-hash');
204
+ expect(JSON.stringify(error)).not.toContain('FAKE-hash');
205
+ });
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Valkey providers for Alchemy — `Valkey.Instance` (assert-and-read a running server) and
3
+ * `Valkey.AclFile` (per-seat ACL users, key-prefix limited, passwords by reference). See
4
+ * `docs/valkey.md`.
5
+ *
6
+ * ⛔ THIS BARREL IS THE PUBLIC API, deliberately smaller than the directory: `fake-valkey.ts`,
7
+ * `transport.ts` and the form internals are test doubles and internals, not something a
8
+ * consuming stack should import (the same rule `postgres/index.ts` and `netbox/index.ts` use).
9
+ */
10
+ export type {
11
+ ValkeyAclFileAttributes,
12
+ ValkeyAclFileProps,
13
+ ValkeyAclProfile,
14
+ ValkeyAclUser,
15
+ ValkeyAclUserAttributes,
16
+ } from './acl-attrs.ts';
17
+ export { ValkeyAclFile, ValkeyAclFileProvider, isValkeyAclFile } from './acl.ts';
18
+ export type { ValkeyConnectionConfig } from './connection.ts';
19
+ export {
20
+ ValkeyConnection,
21
+ ValkeyConnectionMissing,
22
+ valkeyConnection,
23
+ withValkey,
24
+ } from './connection.ts';
25
+ export {
26
+ ValkeyAclChannelPatterns,
27
+ ValkeyAclFileRendered,
28
+ ValkeyAclMonitorKeyPrefix,
29
+ ValkeyAclNameGlob,
30
+ ValkeyAclPasswordMissing,
31
+ ValkeyAclParseError,
32
+ ValkeyAclReadbackFailed,
33
+ ValkeyAclReservedUser,
34
+ ValkeyAclSeatKeyPrefix,
35
+ ValkeyAclUserNameMismatch,
36
+ ValkeyAuthPasswordMissing,
37
+ ValkeyInstanceDrift,
38
+ ValkeyInstanceUnreachable,
39
+ type ValkeyError,
40
+ } from './errors.ts';
41
+ export type {
42
+ ValkeyInstanceAttributes,
43
+ ValkeyInstanceConfig,
44
+ ValkeyInstanceInfo,
45
+ ValkeyInstanceProps,
46
+ } from './instance-attrs.ts';
47
+ export {
48
+ ValkeyInstance,
49
+ ValkeyInstanceDeleteRefused,
50
+ ValkeyInstanceProvider,
51
+ isValkeyInstance,
52
+ type ValkeyInstanceError,
53
+ } from './instance.ts';
54
+ export { valkeyProviders } from './providers.ts';
@@ -0,0 +1,48 @@
1
+ /**
2
+ * `Valkey.Instance` props and attributes.
3
+ *
4
+ * ⛔ CREATE-AND-ASSERT, NEVER CREATE. A Valkey instance is a container the `Podman.Container`
5
+ * family owns (`homeflare-ct100/src/valkey.ts` already declares the two dormant Quadlets). This
6
+ * resource asserts a running instance's identity and configuration — it reads `INFO` and
7
+ * `CONFIG GET` — and refuses drift, never issues a `CONFIG SET` that could drop in-flight data.
8
+ * ⛔ NO PASSWORD AS A PROP (S25). An instance's own admin password is the connection's concern
9
+ * (`connection.ts`), not a field stored in state; `Valkey.AclFile` owns the per-seat users.
10
+ */
11
+ /** Declared, at-most-once-asserted properties of one running Valkey instance. */
12
+ export interface ValkeyInstanceProps {
13
+ /** The instance's logical identity — matches the Quadlet's `containerName`. */
14
+ readonly name: string;
15
+ /** The TCP port the instance listens on (the Quadlet's `--port`). */
16
+ readonly port: number;
17
+ /** `maxmemory` (`CONFIG GET maxmemory`). A declaration may be unit form (`"512mb"`);
18
+ * the live reply is the byte count. Compared with Valkey's `memtoull` rule. */
19
+ readonly maxmemory?: string | undefined;
20
+ /** `maxmemory-policy`, one of Valkey's eviction policies. */
21
+ readonly maxmemoryPolicy?: string | undefined;
22
+ /** `appendonly` (`yes`/`no`) — seat data is AOF, the LiteLLM cache is not. */
23
+ readonly appendonly?: string | undefined;
24
+ }
25
+
26
+ /** Live attributes read back after reconcile. Never holds a password (see file header). */
27
+ export interface ValkeyInstanceAttributes {
28
+ readonly name: string;
29
+ readonly port: number;
30
+ readonly version: string;
31
+ readonly maxmemory: string;
32
+ readonly maxmemoryPolicy: string;
33
+ readonly appendonly: string;
34
+ }
35
+
36
+ /** The subset of `INFO` fields `read` needs. `port` is `tcp_port`, not the declared prop:
37
+ * copying the declaration back would make a 6381 claim match a server on 6380. */
38
+ export interface ValkeyInstanceInfo {
39
+ readonly version: string;
40
+ readonly port: number;
41
+ }
42
+
43
+ /** The subset of `CONFIG GET` values `read` needs. */
44
+ export interface ValkeyInstanceConfig {
45
+ readonly maxmemory: string;
46
+ readonly maxmemoryPolicy: string;
47
+ readonly appendonly: string;
48
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Pure helpers for `Valkey.Instance`: parsing `INFO`/`CONFIG GET` replies, building drift checks,
3
+ * and normalising optional props.
4
+ *
5
+ * ⛔ NO SIDE EFFECTS. Everything in this file is a pure function that can be unit-tested without a
6
+ * socket or a fake executor.
7
+ */
8
+ import type {
9
+ ValkeyInstanceAttributes,
10
+ ValkeyInstanceConfig,
11
+ ValkeyInstanceInfo,
12
+ ValkeyInstanceProps,
13
+ } from './instance-attrs.ts';
14
+
15
+ /** Parse the `INFO` bulk reply into the fields `Instance` cares about. A missing `tcp_port`
16
+ * is 0, so a declaration of a real port drifts rather than matching a reply that omitted it. */
17
+ export const parseInfo = (value: string | null): ValkeyInstanceInfo => {
18
+ const fallback = '0.0.0';
19
+ if (value === null) return { version: fallback, port: 0 };
20
+ const match = /valkey_version:([0-9a-zA-Z._-]+)/.exec(value);
21
+ const port = /tcp_port:([0-9]+)/.exec(value);
22
+ return {
23
+ version: match?.[1] ?? fallback,
24
+ port: port?.[1] === undefined ? 0 : Number(port[1]),
25
+ };
26
+ };
27
+
28
+ /** Valkey `memtoull` (`src/util.c`, same on 8.1.10 and 9.1.1). `mb` is 1024², so `512mb` is
29
+ * 536870912 and `256mb` is 268435456 — the byte string `CONFIG GET` returns for `MEMORY_CONFIG`.
30
+ * Undefined on a parse error: a zero from the C function is "unlimited" only for the string `0`. */
31
+ const MEMORY_UNITS: Readonly<Record<string, bigint>> = {
32
+ '': 1n,
33
+ b: 1n,
34
+ k: 1000n,
35
+ kb: 1024n,
36
+ m: 1_000_000n,
37
+ mb: 1024n * 1024n,
38
+ g: 1_000_000_000n,
39
+ gb: 1024n * 1024n * 1024n,
40
+ };
41
+
42
+ export const memoryBytes = (value: string): bigint | undefined => {
43
+ if (value.startsWith('-')) return undefined;
44
+ const match = /^(\d+)([a-z]*)$/i.exec(value);
45
+ if (match === null) return undefined;
46
+ const digits = match[1];
47
+ const unit = (match[2] ?? '').toLowerCase();
48
+ const mul = MEMORY_UNITS[unit];
49
+ if (digits === undefined || mul === undefined) return undefined;
50
+ return BigInt(digits) * mul;
51
+ };
52
+
53
+ /** Byte equality for `maxmemory`. An unparseable side does not match, so a typo still drifts. */
54
+ const sameMemory = (declared: string, live: string): boolean => {
55
+ const left = memoryBytes(declared);
56
+ const right = memoryBytes(live);
57
+ return left !== undefined && right !== undefined && left === right;
58
+ };
59
+
60
+ /** Fill defaults for absent optional config so `diff` and drift checks compare a concrete string. */
61
+ const defaultedConfig = (raw: Partial<ValkeyInstanceConfig>): ValkeyInstanceConfig => ({
62
+ maxmemory: raw.maxmemory ?? '0',
63
+ maxmemoryPolicy: raw.maxmemoryPolicy ?? 'noeviction',
64
+ appendonly: raw.appendonly ?? 'no',
65
+ });
66
+
67
+ /** Build a live `ValkeyInstanceAttributes` from parsed `INFO` and `CONFIG GET` pairs. */
68
+ export const buildAttributes = (
69
+ props: Omit<ValkeyInstanceProps, 'maxmemory' | 'maxmemoryPolicy' | 'appendonly'>,
70
+ info: ValkeyInstanceInfo,
71
+ config: Partial<ValkeyInstanceConfig>,
72
+ ): ValkeyInstanceAttributes => ({
73
+ name: props.name,
74
+ port: info.port,
75
+ version: info.version,
76
+ ...defaultedConfig(config),
77
+ });
78
+
79
+ /** Compare every declared assert-once prop against the live row. Returns the first drift, or
80
+ * `undefined` when every declared prop matches. */
81
+ export const firstDrift = (
82
+ props: ValkeyInstanceProps,
83
+ live: ValkeyInstanceAttributes,
84
+ ): { readonly prop: string; readonly declared: unknown; readonly live: unknown } | undefined => {
85
+ const checks: ReadonlyArray<readonly [string, unknown, unknown]> = [
86
+ ['port', props.port, live.port],
87
+ ['maxmemory', props.maxmemory, live.maxmemory],
88
+ ['maxmemoryPolicy', props.maxmemoryPolicy, live.maxmemoryPolicy],
89
+ ['appendonly', props.appendonly, live.appendonly],
90
+ ];
91
+ for (const [prop, declared, liveValue] of checks) {
92
+ if (declared === undefined) continue;
93
+ if (
94
+ prop === 'maxmemory' &&
95
+ typeof declared === 'string' &&
96
+ typeof liveValue === 'string' &&
97
+ sameMemory(declared, liveValue)
98
+ ) {
99
+ continue;
100
+ }
101
+ if (declared !== liveValue) return { prop, declared, live: liveValue };
102
+ }
103
+ return undefined;
104
+ };
@@ -0,0 +1,108 @@
1
+ /**
2
+ * `Valkey.Instance` against `fake-valkey.ts`'s recording fake — read of a running instance,
3
+ * drift refusals, and no writes ever issued. Every case reverts cleanly by reverting
4
+ * `instance.ts`/`instance-form.ts` locally.
5
+ */
6
+ import { describe, expect, test } from 'bun:test';
7
+ import * as Effect from 'effect/Effect';
8
+ import { makeFakeValkey } from './fake-valkey.ts';
9
+ import { firstDrift, parseInfo } from './instance-form.ts';
10
+ import { readWithExecutor } from './instance.ts';
11
+ import type { ValkeyInstanceProps } from './instance-attrs.ts';
12
+
13
+ const run = <A, E>(eff: Effect.Effect<A, E>): Promise<A> => Effect.runPromise(eff);
14
+
15
+ const baseProps: Pick<ValkeyInstanceProps, 'name' | 'port'> = { name: 'valkey-seats', port: 6381 };
16
+
17
+ describe('read', () => {
18
+ test('reads INFO and CONFIG GET into attributes', async () => {
19
+ const fake = makeFakeValkey({
20
+ port: 6381,
21
+ config: { maxmemory: '512mb', 'maxmemory-policy': 'noeviction', appendonly: 'yes' },
22
+ });
23
+ const attrs = await run(readWithExecutor(fake, baseProps));
24
+ expect(attrs).toEqual({
25
+ name: 'valkey-seats',
26
+ port: 6381,
27
+ version: '8.1.10',
28
+ maxmemory: '536870912',
29
+ maxmemoryPolicy: 'noeviction',
30
+ appendonly: 'yes',
31
+ });
32
+ expect(firstDrift({ ...baseProps, maxmemory: '512mb' }, attrs)).toBeUndefined();
33
+ expect(fake.commands.map((c) => c.args[0])).toEqual(['INFO', 'CONFIG']);
34
+ });
35
+
36
+ test('defaults absent config to concrete values', async () => {
37
+ const fake = makeFakeValkey({});
38
+ const attrs = await run(readWithExecutor(fake, baseProps));
39
+ expect(attrs.maxmemory).toBe('0');
40
+ expect(attrs.maxmemoryPolicy).toBe('noeviction');
41
+ expect(attrs.appendonly).toBe('no');
42
+ });
43
+
44
+ test('port is INFO tcp_port, so a 6381 declaration drifts against a 6380 server', async () => {
45
+ const fake = makeFakeValkey({ port: 6380 });
46
+ const attrs = await run(readWithExecutor(fake, { name: 'valkey-seats', port: 6381 }));
47
+ expect(attrs.port).toBe(6380);
48
+ expect(firstDrift({ name: 'valkey-seats', port: 6381 }, attrs)).toEqual({
49
+ prop: 'port',
50
+ declared: 6381,
51
+ live: 6380,
52
+ });
53
+ });
54
+ });
55
+
56
+ describe('parseInfo', () => {
57
+ test('extracts the version line and falls back on garbage', () => {
58
+ expect(
59
+ parseInfo('redis_version:7.2.4\nvalkey_version:8.1.10\nredis_mode:standalone').version,
60
+ ).toBe('8.1.10');
61
+ expect(parseInfo(null).version).toBe('0.0.0');
62
+ expect(parseInfo('nothing here').version).toBe('0.0.0');
63
+ });
64
+ });
65
+
66
+ describe('firstDrift', () => {
67
+ const live = {
68
+ name: 'valkey-seats',
69
+ port: 6381,
70
+ version: '8.1.10',
71
+ maxmemory: '512mb',
72
+ maxmemoryPolicy: 'noeviction',
73
+ appendonly: 'yes',
74
+ };
75
+
76
+ test('reports the first mismatched declared prop', () => {
77
+ expect(firstDrift({ name: 'x', port: 6380 }, live)).toEqual({
78
+ prop: 'port',
79
+ declared: 6380,
80
+ live: 6381,
81
+ });
82
+ expect(firstDrift({ name: 'x', port: 6381, maxmemory: '1gb' }, live)).toEqual({
83
+ prop: 'maxmemory',
84
+ declared: '1gb',
85
+ live: '512mb',
86
+ });
87
+ });
88
+
89
+ test('ignores undefined (unasserted) props', () => {
90
+ expect(firstDrift({ name: 'x', port: 6381, maxmemory: undefined }, live)).toBeUndefined();
91
+ });
92
+
93
+ test("declaration '512mb' matches the byte count CONFIG GET returns", () => {
94
+ // Valkey memtoull: 512mb is 536870912, 256mb is 268435456 (8.1.10 and 9.1.1).
95
+ expect(
96
+ firstDrift(
97
+ { name: 'x', port: 6381, maxmemory: '512mb' },
98
+ { ...live, maxmemory: '536870912' },
99
+ ),
100
+ ).toBeUndefined();
101
+ expect(
102
+ firstDrift(
103
+ { name: 'x', port: 6381, maxmemory: '256mb' },
104
+ { ...live, maxmemory: '268435456' },
105
+ ),
106
+ ).toBeUndefined();
107
+ });
108
+ });
@@ -0,0 +1,160 @@
1
+ /**
2
+ * `Valkey.Instance` — assert-and-read over a running Valkey server, reached over RESP.
3
+ *
4
+ * ⛔ ADOPT-AND-ASSERT, NEVER CREATE OR RECONFIGURE. The instance itself is a container the
5
+ * `Podman.Container` family owns (`homeflare-ct100/src/valkey.ts` declares the two dormant
6
+ * Quadlets). This resource reads `INFO` and `CONFIG GET` to confirm the live instance matches the
7
+ * declaration, and refuses drift — it never issues `CONFIG SET` (which could drop in-flight
8
+ * data) and never starts a process.
9
+ * ⛔ `delete` NEVER STOPS AN INSTANCE. `ValkeyInstanceDeleteRefused` and
10
+ * `defaultRemovalPolicy: 'retain'` are two independent reasons the engine never shuts a server
11
+ * down through this provider.
12
+ * ★ NO OWNERSHIP MARK (H1). `read` always answers `Unowned` for a match, the same rule
13
+ * `Postgres.Database` uses, so every already-live instance needs `adopt(true)` in the stack
14
+ * that declares it.
15
+ */
16
+ import { Resource } from 'alchemy';
17
+ import { Unowned } from 'alchemy/AdoptPolicy';
18
+ import { isResolved } from 'alchemy/Diff';
19
+ import * as Provider from 'alchemy/Provider';
20
+ import * as Data from 'effect/Data';
21
+ import * as Effect from 'effect/Effect';
22
+ import { type ValkeyConnection, withValkey } from './connection.ts';
23
+ import { type ValkeyError, ValkeyInstanceDrift } from './errors.ts';
24
+ import { type ValkeyInstanceAttributes, type ValkeyInstanceProps } from './instance-attrs.ts';
25
+ import { buildAttributes, firstDrift, parseInfo } from './instance-form.ts';
26
+ import {
27
+ type ValkeyExecutor,
28
+ ValkeyServerError,
29
+ type ValkeyTransportError,
30
+ arrayPairs,
31
+ } from './transport.ts';
32
+
33
+ export interface ValkeyInstance extends Resource<
34
+ 'Valkey.Instance',
35
+ ValkeyInstanceProps,
36
+ ValkeyInstanceAttributes
37
+ > {}
38
+
39
+ export const ValkeyInstance = Resource<ValkeyInstance>('Valkey.Instance', {
40
+ defaultRemovalPolicy: 'retain',
41
+ });
42
+
43
+ export const isValkeyInstance = (value: unknown): value is ValkeyInstance =>
44
+ (typeof value === 'object' || typeof value === 'function') &&
45
+ value !== null &&
46
+ (value as { Type?: unknown }).Type === 'Valkey.Instance';
47
+
48
+ /** `delete` never stops an instance; dropping a server is a human act on the host. */
49
+ export class ValkeyInstanceDeleteRefused extends Data.TaggedError('ValkeyInstanceDeleteRefused')<{
50
+ readonly instance: string;
51
+ }> {
52
+ override get message(): string {
53
+ return (
54
+ `Valkey.Instance "${this.instance}": delete is refused. This provider never stops a ` +
55
+ 'running Valkey server. Stop it by hand on the host if you mean to remove it, then remove ' +
56
+ 'the declaration.'
57
+ );
58
+ }
59
+ }
60
+
61
+ export type ValkeyInstanceError = ValkeyError | ValkeyInstanceDeleteRefused;
62
+
63
+ /** Read the live instance: `INFO` then `CONFIG GET`, folded into attributes. */
64
+ export const readWithExecutor = (
65
+ executor: ValkeyExecutor,
66
+ props: Pick<ValkeyInstanceProps, 'name' | 'port'>,
67
+ ): Effect.Effect<ValkeyInstanceAttributes, ValkeyTransportError> =>
68
+ Effect.gen(function* () {
69
+ const infoReply = yield* executor.send(['INFO']);
70
+ if (infoReply.kind === 'error') {
71
+ return yield* Effect.fail(new ValkeyServerError({ detail: infoReply.message }));
72
+ }
73
+ const info = parseInfo(infoReply.kind === 'bulk' ? infoReply.value : null);
74
+ const configReply = yield* executor.send([
75
+ 'CONFIG',
76
+ 'GET',
77
+ 'maxmemory',
78
+ 'maxmemory-policy',
79
+ 'appendonly',
80
+ ]);
81
+ if (configReply.kind === 'error') {
82
+ return yield* Effect.fail(new ValkeyServerError({ detail: configReply.message }));
83
+ }
84
+ const pairs = configReply.kind === 'array' ? arrayPairs(configReply.values) : new Map();
85
+ return buildAttributes(props, info, {
86
+ maxmemory: pairs.get('maxmemory') ?? undefined,
87
+ maxmemoryPolicy: pairs.get('maxmemory-policy') ?? undefined,
88
+ appendonly: pairs.get('appendonly') ?? undefined,
89
+ });
90
+ });
91
+
92
+ /**
93
+ * The five lifecycle handlers. Exported separately from the provider layer so tests can call
94
+ * `valkeyInstanceHandlers.read(...)` directly against the real implementation without standing up
95
+ * the engine's provider machinery.
96
+ */
97
+ export const makeValkeyInstanceHandlers = (
98
+ connect: typeof withValkey = withValkey,
99
+ ): Provider.ProviderService<
100
+ ValkeyInstance,
101
+ ValkeyConnection,
102
+ never,
103
+ never,
104
+ ValkeyConnection,
105
+ ValkeyConnection
106
+ > =>
107
+ ValkeyInstance.Provider.of({
108
+ // ⚠️ EMPTY, NOT A LIVE SWEEP. A Valkey has no instance enumeration; adoption is one
109
+ // declaration at a time, matching `Postgres.Database`.
110
+ list: () => Effect.succeed([]),
111
+ nuke: { skip: true },
112
+
113
+ read: ({ output, olds }) =>
114
+ Effect.gen(function* () {
115
+ const props = output ?? olds;
116
+ // Neither AUTH failure nor an unreachable endpoint proves absence. Propagate the
117
+ // typed failure so Plan.ts cannot bypass the adoption gate with a CREATE.
118
+ return yield* connect(
119
+ (ex) => Effect.map(readWithExecutor(ex, { name: props.name, port: props.port }), Unowned),
120
+ props.name,
121
+ );
122
+ }),
123
+
124
+ diff: ({ news, output }) =>
125
+ Effect.sync(() => {
126
+ if (!isResolved(news)) return undefined;
127
+ if (output === undefined) return undefined;
128
+ const drift = firstDrift(news, output);
129
+ return drift !== undefined
130
+ ? ({ action: 'update' } as const)
131
+ : ({ action: 'noop' } as const);
132
+ }),
133
+
134
+ reconcile: ({ news }) =>
135
+ Effect.gen(function* () {
136
+ const live = yield* connect(
137
+ (ex) => readWithExecutor(ex, { name: news.name, port: news.port }),
138
+ news.name,
139
+ );
140
+ const drift = firstDrift(news, live);
141
+ if (drift !== undefined) {
142
+ return yield* Effect.fail(
143
+ new ValkeyInstanceDrift({
144
+ instance: news.name,
145
+ prop: drift.prop,
146
+ declared: drift.declared,
147
+ live: drift.live,
148
+ }),
149
+ );
150
+ }
151
+ return live;
152
+ }),
153
+
154
+ delete: ({ olds }) => Effect.fail(new ValkeyInstanceDeleteRefused({ instance: olds.name })),
155
+ });
156
+
157
+ export const valkeyInstanceHandlers = makeValkeyInstanceHandlers();
158
+
159
+ export const ValkeyInstanceProvider = () =>
160
+ Provider.succeed(ValkeyInstance, valkeyInstanceHandlers);