@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
@@ -1,9 +1,13 @@
1
1
  /**
2
- * PostgreSQL providers for Alchemy — `Postgres.Database`, create-and-assert over a self-hosted
3
- * cluster, walked against PostgreSQL 18.6. See `docs/postgres.md`.
2
+ * PostgreSQL providers for Alchemy — `Postgres.Database` (create-and-assert over one
3
+ * self-hosted cluster), `Postgres.Schema` (create-and-assert over one schema inside one),
4
+ * `Postgres.Role` (create / adopt / alter / drop of a LOGIN or NOLOGIN role whose password is a
5
+ * reference) and `Postgres.Grants` (declarative grant set diffed against the catalogs), walked
6
+ * against PostgreSQL 18.6. See `docs/postgres.md`, `docs/postgres-schema.md`,
7
+ * `docs/postgres-role.md` and `docs/postgres-grants.md`.
4
8
  *
5
- * ⛔ THIS BARREL IS THE PUBLIC API, deliberately smaller than the directory: `fake-sql.ts` is a
6
- * test double, not something a consuming stack should import.
9
+ * ⛔ THIS BARREL IS THE PUBLIC API, deliberately smaller than the directory: `fake-sql.ts` and
10
+ * `fake-grants-sql.ts` are test doubles, not something a consuming stack should import.
7
11
  */
8
12
  export type { PostgresConnectionConfig, PostgresRunnerConfig } from './connection.ts';
9
13
  export {
@@ -18,6 +22,7 @@ export type { PostgresDatabaseAttributes, PostgresDatabaseProps } from './databa
18
22
  export { POSTGRES_NAME_MAX_BYTES, nameByteRefusal, utf8ByteLength } from './database-attrs.ts';
19
23
  export {
20
24
  buildCreateDatabaseSql,
25
+ databaseExists,
21
26
  firstDrift,
22
27
  isDuplicateDatabaseRace,
23
28
  quoteIdent,
@@ -26,6 +31,38 @@ export {
26
31
  selectDatabase,
27
32
  } from './database-sql.ts';
28
33
  export { PostgresDatabase, PostgresDatabaseProvider, isPostgresDatabase } from './database.ts';
34
+ export type { PostgresSchemaAttributes, PostgresSchemaProps } from './schema-attrs.ts';
35
+ export { normalizedComment, schemaNameByteRefusal } from './schema-attrs.ts';
36
+ export {
37
+ buildCommentSchemaSql,
38
+ buildCreateSchemaSql,
39
+ buildDropSchemaSql,
40
+ currentDatabase,
41
+ currentUser,
42
+ isDependentObjectsError,
43
+ schemaIsEmpty,
44
+ selectSchema,
45
+ } from './schema-sql.ts';
46
+ export {
47
+ PostgresSchema,
48
+ PostgresSchemaProvider,
49
+ diffPostgresSchema,
50
+ isPostgresSchema,
51
+ } from './schema.ts';
52
+ export {
53
+ PostgresSchemaCreateVanished,
54
+ PostgresSchemaExistsRefused,
55
+ PostgresSchemaIdentityRefused,
56
+ PostgresSchemaDatabaseRefused,
57
+ PostgresSchemaDeleteForeignRefused,
58
+ PostgresSchemaDrift,
59
+ PostgresSchemaDropNotEmptyError,
60
+ PostgresSchemaNameRefused,
61
+ PostgresSchemaOwnerMissing,
62
+ PostgresSchemaRenameRefused,
63
+ PostgresSchemaWrongDatabase,
64
+ type PostgresSchemaError,
65
+ } from './schema-errors.ts';
29
66
  export {
30
67
  PostgresDatabaseDrift,
31
68
  PostgresDatabaseDropRefused,
@@ -34,4 +71,91 @@ export {
34
71
  PostgresDatabaseRenameRefused,
35
72
  type PostgresDatabaseError,
36
73
  } from './errors.ts';
37
- export { postgresProviders, postgresRunnerProviders } from './providers.ts';
74
+ export type {
75
+ PostgresGrantsAttributes,
76
+ PostgresGrantsAttributesColumn,
77
+ PostgresGrantsAttributesDefault,
78
+ PostgresGrantsAttributesTable,
79
+ PostgresGrantsColumn,
80
+ PostgresGrantsDefault,
81
+ PostgresGrantsProps,
82
+ PostgresGrantsTable,
83
+ } from './grants-attrs.ts';
84
+ export {
85
+ COLUMN_PRIVILEGES,
86
+ SCHEMA_PRIVILEGES,
87
+ TABLE_PRIVILEGES,
88
+ grantsNameByteRefusal,
89
+ letterForPrivilege,
90
+ } from './grants-attrs.ts';
91
+ export {
92
+ grantColumnSql,
93
+ grantDefaultSql,
94
+ grantSchemaSql,
95
+ grantTableSql,
96
+ revokeColumnSql,
97
+ revokeDefaultSql,
98
+ revokePublicSchemaSql,
99
+ revokePublicTablesSql,
100
+ revokeSchemaSql,
101
+ revokeTableSql,
102
+ } from './grants-sql.ts';
103
+ export { PostgresGrants, PostgresGrantsProvider, isPostgresGrants } from './grants.ts';
104
+ export {
105
+ PostgresGrantsDatabaseMismatch,
106
+ PostgresGrantsDatabaseMissing,
107
+ PostgresGrantsDuplicateObject,
108
+ PostgresGrantsNameRefused,
109
+ PostgresGrantsPrivilegeRefused,
110
+ PostgresGrantsRepairRefused,
111
+ PostgresGrantsRetargetRefused,
112
+ PostgresGrantsRoleMissing,
113
+ PostgresGrantsSchemaMissing,
114
+ PostgresGrantsTableMissing,
115
+ PostgresGrantsColumnMissing,
116
+ type PostgresGrantsError,
117
+ } from './grants-errors.ts';
118
+ export type { PostgresRoleAttributes, PostgresRoleProps } from './role-attrs.ts';
119
+ export { sameValidUntil, validUntilRefusal } from './role-attrs.ts';
120
+ export {
121
+ buildAlterRoleSql,
122
+ buildCreateRoleSql,
123
+ buildDropRoleSql,
124
+ buildSetPasswordSql,
125
+ scalarDrift,
126
+ selectRole,
127
+ } from './role-sql.ts';
128
+ export {
129
+ buildGrantMembershipSql,
130
+ buildRepairMembershipSql,
131
+ buildRevokeGrantorMembershipSql,
132
+ membershipDrift,
133
+ selectRoleMemberships,
134
+ syncMemberships,
135
+ unsafeMemberships,
136
+ } from './role-membership-sql.ts';
137
+ export type { MembershipRow } from './role-membership-sql.ts';
138
+ export { PostgresRole, isPostgresRole } from './role.ts';
139
+ export { PostgresRoleProvider } from './role-provider.ts';
140
+ export { resolvePassword } from './role-secrets.ts';
141
+ export type { ResolvedPassword } from './role-secrets.ts';
142
+ export type { FromEnv } from '../secrets/write-only.ts';
143
+ export {
144
+ PostgresRoleCreateVanished,
145
+ PostgresRoleIdentityRefused,
146
+ PostgresRoleMembershipUnrepaired,
147
+ PostgresRoleNameRefused,
148
+ PostgresRoleParentMissing,
149
+ PostgresRolePasswordEnvUnsetError,
150
+ PostgresRolePasswordNonAsciiRefused,
151
+ PostgresRolePrivilegedRefused,
152
+ PostgresRoleRenameRefused,
153
+ PostgresRoleValidUntilRefused,
154
+ type PostgresRoleError,
155
+ } from './role-errors.ts';
156
+ export {
157
+ postgresProviders,
158
+ postgresRoleProviders,
159
+ postgresRoleRunnerProviders,
160
+ postgresRunnerProviders,
161
+ } from './providers.ts';
@@ -0,0 +1,36 @@
1
+ /**
2
+ * The installed `@effect/sql-pg` classifier, for tests that must pin real driver behavior
3
+ * instead of a hand-built error shape.
4
+ *
5
+ * ⛔ TEST-ONLY, PINNED TO THE INSTALLED DRIVER. `@effect/sql-pg` nulls the `./internal/*`
6
+ * export, so the public specifier cannot name `src/internal/sqlError.ts`; the file URL is
7
+ * resolved from the installed package's `package.json` — the same module
8
+ * `PgConnection.ts#classifyFields` calls. If the driver moves the file, the import fails
9
+ * loudly in the tests that use it rather than silently asserting a fabricated shape.
10
+ */
11
+ import { SqlError } from 'effect/unstable/sql/SqlError';
12
+
13
+ export const classifyInstalled = async (
14
+ code: string,
15
+ message = 'dependent objects still exist',
16
+ ): Promise<SqlError> => {
17
+ // `package.json` sets `"./internal/*": null`, so the specifier cannot name this file.
18
+ // `import.meta.resolve` finds the installed package; `src/internal/sqlError.ts` is the
19
+ // module `PgConnection.ts#classifyFields` calls.
20
+ const root = import.meta.resolve('@effect/sql-pg/package.json');
21
+ const href = new URL('./src/internal/sqlError.ts', root).href;
22
+ const mod = (await import(href)) as {
23
+ classifySqlState: (
24
+ code: string | undefined,
25
+ constraint: unknown,
26
+ props: { cause: unknown; message: string; operation: string },
27
+ ) => SqlError['reason'];
28
+ };
29
+ return new SqlError({
30
+ reason: mod.classifySqlState(code, undefined, {
31
+ cause: Object.assign(new Error(message), { code, message }),
32
+ message: `ERROR: ${code}: ${message}`,
33
+ operation: 'DROP SCHEMA',
34
+ }),
35
+ });
36
+ };
@@ -1,11 +1,11 @@
1
1
  /**
2
- * `Postgres.Database`'s provider, pre-wired to one cluster:
2
+ * `Postgres.*` providers, pre-wired for one cluster:
3
3
  *
4
- * const providers = postgresProviders({ host: '/opt/homeflare/postgres/sockets', database: 'postgres', username: 'tim' });
4
+ * const providers = postgresProviders({ host: '/var/run/postgresql', database: 'postgres', username: 'tim' });
5
5
  *
6
- * ★ THE CLUSTER IS A PARAMETER, NOT A DEFAULT (S15, and `docs/postgres.md#path`). This kit is
7
- * PUBLIC; the mini's socket directory, its user and its port are the CONSUMING stack's values,
8
- * never baked in here. A stack with more than one cluster calls this more than once and merges
6
+ * ★ THE CLUSTER IS THE PARAMETER, NOT A DEFAULT (S15, `docs/postgres.md#path`). This kit is
7
+ * PUBLIC; mini's socket directory, user and port are the CONSUMING stack's values,
8
+ * never baked in here. A stack with more than one cluster calls this once per cluster and merges
9
9
  * the results under whatever logical grouping it wants.
10
10
  */
11
11
  import * as Layer from 'effect/Layer';
@@ -16,14 +16,38 @@ import {
16
16
  postgresRunnerConnection,
17
17
  } from './connection.ts';
18
18
  import { PostgresDatabaseProvider } from './database.ts';
19
+ import { PostgresGrantsProvider } from './grants.ts';
20
+ import { PostgresRoleProvider } from './role-provider.ts';
21
+ import { PostgresSchemaProvider } from './schema.ts';
19
22
 
20
23
  // ⚠️ `Layer.provideMerge`, NEVER plain `Layer.provide`: the handlers' `withPg` reads
21
24
  // `PostgresConnection` when the ENGINE later calls `read`/`reconcile`, and plain `provide`
22
25
  // seals it away ("Service not found: Postgres.Connection" — measured for `caddyProviders`,
23
- // see `caddy/providers.ts`).
26
+ // see `caddy/providers.ts`). Each resource provider merges its own connection in; the three
27
+ // results are merged per resource (`Layer.mergeAll`, the same shape `unifi/providers.ts`).
24
28
  export const postgresProviders = (config: PostgresConnectionConfig) =>
25
- PostgresDatabaseProvider().pipe(Layer.provideMerge(postgresConnection(config)));
29
+ Layer.mergeAll(
30
+ PostgresDatabaseProvider().pipe(Layer.provideMerge(postgresConnection(config))),
31
+ PostgresSchemaProvider().pipe(Layer.provideMerge(postgresConnection(config))),
32
+ PostgresGrantsProvider().pipe(Layer.provideMerge(postgresConnection(config))),
33
+ );
26
34
 
27
- /** The same provider over a command runner (`psql-executor.ts`) — for a loopback-only cluster. */
35
+ /** The same providers over a command runner (`psql-executor.ts`) — for loopback-only clusters. */
28
36
  export const postgresRunnerProviders = (config: PostgresRunnerConfig) =>
29
- PostgresDatabaseProvider().pipe(Layer.provideMerge(postgresRunnerConnection(config)));
37
+ Layer.mergeAll(
38
+ PostgresDatabaseProvider().pipe(Layer.provideMerge(postgresRunnerConnection(config))),
39
+ PostgresSchemaProvider().pipe(Layer.provideMerge(postgresRunnerConnection(config))),
40
+ PostgresGrantsProvider().pipe(Layer.provideMerge(postgresRunnerConnection(config))),
41
+ );
42
+
43
+ /**
44
+ * `Postgres.Role`'s provider, over the same socket transport and the same cluster parameter.
45
+ *
46
+ * const providers = postgresRoleProviders({ host: '/opt/homeflare/postgres/sockets', database: 'postgres', username: 'tim' });
47
+ */
48
+ export const postgresRoleProviders = (config: PostgresConnectionConfig) =>
49
+ PostgresRoleProvider().pipe(Layer.provideMerge(postgresConnection(config)));
50
+
51
+ /** `Postgres.Role` over a command runner (`psql-executor.ts`) — for loopback-only clusters. */
52
+ export const postgresRoleRunnerProviders = (config: PostgresRunnerConfig) =>
53
+ PostgresRoleProvider().pipe(Layer.provideMerge(postgresRunnerConnection(config)));
@@ -0,0 +1,67 @@
1
+ /** PG18 lexical §4.1.2.2 regressions: exercise the fake and the executor's actual stdin. */
2
+ import { expect, test } from 'bun:test';
3
+ import * as Effect from 'effect/Effect';
4
+ import { makeFakeSql } from './fake-sql.ts';
5
+ import { parseLiteral } from './fake-sql-quote.ts';
6
+ import { buildCommentSchemaSql } from './schema-sql.ts';
7
+ import { buildSetPasswordSql } from './role-sql.ts';
8
+ import { makePsqlExecutor, redactPasswordLiterals } from './psql-executor.ts';
9
+
10
+ const payload = "\\'; CREATE SCHEMA injected; --";
11
+ const target = { database: 'postgres', username: 'postgres' };
12
+ const row = { name: 'ledger', database: 'postgres', owner: 'postgres', oid: 42, comment: null };
13
+
14
+ for (const on of [true, false]) {
15
+ test(`fake comment round-trips hostile text with standard_conforming_strings=${String(on)}`, async () => {
16
+ const fake = makeFakeSql({ schemas: [row], standardConformingStrings: on });
17
+ await Effect.runPromise(fake.unsafe(buildCommentSchemaSql('ledger', payload)));
18
+ expect(fake.schemas.get('ledger')?.comment).toBe(payload);
19
+ expect(fake.schemas.has('injected')).toBe(false);
20
+ });
21
+
22
+ test(`psql executor comment and bound param stay one literal with standard_conforming_strings=${String(on)}`, async () => {
23
+ const fake = makeFakeSql({ schemas: [row], standardConformingStrings: on });
24
+ const calls: string[] = [];
25
+ const pg = makePsqlExecutor(async ({ stdin }) => {
26
+ calls.push(stdin);
27
+ if (stdin.startsWith('COMMENT')) {
28
+ await Effect.runPromise(fake.unsafe(stdin.slice(0, -1)));
29
+ return { code: 0, stdout: '', stderr: '' };
30
+ }
31
+ const prefix = "SELECT coalesce(json_agg(t), '[]'::json)::text FROM (SELECT ";
32
+ expect(stdin.startsWith(prefix)).toBe(true);
33
+ const literal = stdin.slice(prefix.length, -' AS value) t;'.length);
34
+ const value = parseLiteral(literal, on);
35
+ return { code: 0, stdout: JSON.stringify([{ value }]), stderr: '' };
36
+ }, target);
37
+ await Effect.runPromise(pg.unsafe(buildCommentSchemaSql('ledger', payload)));
38
+ const rows = await Effect.runPromise(
39
+ pg.unsafe<{ value: string }>('SELECT $1 AS value', [payload]),
40
+ );
41
+ expect(rows).toEqual([{ value: payload }]);
42
+ expect(fake.schemas.get('ledger')?.comment).toBe(payload);
43
+ expect(fake.schemas.has('injected')).toBe(false);
44
+ expect(calls[0]).toContain("IS E'\\\\''; CREATE SCHEMA injected; --'");
45
+ });
46
+ }
47
+
48
+ test('escape-literal regression oracle rejects the old injection when the setting is off', () => {
49
+ expect(() => parseLiteral("'\\''; CREATE SCHEMA injected; --'", false)).toThrow('trailing SQL');
50
+ });
51
+
52
+ test('Role password redaction covers escape strings, including escaped quotes and backslashes', async () => {
53
+ const statement = buildSetPasswordSql('seat', "verifier\\'tail");
54
+ expect(redactPasswordLiterals(statement)).toBe('ALTER ROLE "seat" WITH PASSWORD \'[redacted]\'');
55
+ const pg = makePsqlExecutor(
56
+ async () => ({
57
+ code: 3,
58
+ stdout: '',
59
+ stderr: `ERROR: 42501: refused\nSTATEMENT: ${statement}`,
60
+ }),
61
+ target,
62
+ );
63
+ const error = await Effect.runPromise(Effect.flip(pg.unsafe(statement)));
64
+ expect(JSON.stringify(error)).not.toContain('verifier');
65
+ expect(JSON.stringify(error)).not.toContain('tail');
66
+ expect(redactPasswordLiterals("PASSWORD 'legacy'")).toBe("PASSWORD '[redacted]'");
67
+ });
@@ -4,6 +4,8 @@ import { postgresRunnerProviders } from './providers.ts';
4
4
  import { postgresRunnerConnection, withPg } from './connection.ts';
5
5
  import { reconcileWithClient } from './database.ts';
6
6
  import { buildCreateDatabaseSql, isDuplicateDatabaseRace } from './database-sql.ts';
7
+ import { buildSetPasswordSql } from './role-sql.ts';
8
+ import { scramSha256Verifier } from './role-scram.ts';
7
9
  import { type PsqlRunner, inlineParams, makePsqlExecutor } from './psql-executor.ts';
8
10
 
9
11
  const target = { database: 'postgres', username: 'postgres' };
@@ -11,7 +13,7 @@ const ok = (stdout: string) => Promise.resolve({ code: 0, stdout, stderr: '' });
11
13
 
12
14
  describe('psql executor', () => {
13
15
  test('inlines string params as literals and refuses non-strings', () => {
14
- expect(inlineParams('SELECT $1, $2', ["it's", 'b'])).toBe("SELECT 'it''s', 'b'");
16
+ expect(inlineParams('SELECT $1, $2', ["it's", 'b'])).toBe("SELECT E'it''s', E'b'");
15
17
  expect(() => inlineParams('SELECT $1', [5])).toThrow('must be a string');
16
18
  });
17
19
 
@@ -27,7 +29,24 @@ describe('psql executor', () => {
27
29
  expect(rows).toEqual([{ oid: 16400, name: 'x' }]);
28
30
  expect(calls[0]?.argv.slice(0, 1)).toEqual(['psql']);
29
31
  expect(calls[0]?.stdin).toContain('json_agg');
30
- expect(calls[0]?.stdin).toContain("datname = 'x'");
32
+ expect(calls[0]?.stdin).toContain("datname = E'x'");
33
+ });
34
+
35
+ test('a WITH-led row query is wrapped in json_agg too, not discarded as a write', async () => {
36
+ // The schema emptiness check is `WITH ns AS (…) SELECT …` — unwrapped, its answer rows
37
+ // are dropped and the check reads the empty-table fallback ("every schema is empty").
38
+ const calls: { argv: readonly string[]; stdin: string }[] = [];
39
+ const run: PsqlRunner = (call) => {
40
+ calls.push(call);
41
+ return ok('[{"empty":false}]\n');
42
+ };
43
+ const rows = await Effect.runPromise(
44
+ makePsqlExecutor(run, target).unsafe(
45
+ 'WITH ns AS (SELECT 1 AS oid) SELECT NOT EXISTS (SELECT 1 FROM pg_class) AS empty',
46
+ ),
47
+ );
48
+ expect(rows).toEqual([{ empty: false }]);
49
+ expect(calls[0]?.stdin).toContain('json_agg');
31
50
  });
32
51
 
33
52
  test('a duplicate-database failure stays recognisable as the 42P04 race', async () => {
@@ -43,6 +62,31 @@ describe('psql executor', () => {
43
62
  expect(isDuplicateDatabaseRace(error)).toBe(true);
44
63
  });
45
64
 
65
+ test('a failed password statement carries the SCRAM verifier on stdin, never the plain password', async () => {
66
+ // The red-team finding: the statement text is what the runner inlines into `psql`'s stdin and
67
+ // what a failed `ALTER` echoes back through stderr into the error. Since the fix the text
68
+ // holds only the verifier, so both the stdin side and the error side stay secret-free.
69
+ const placeholder = 'placeholder-password';
70
+ const statement = buildSetPasswordSql('hf_agent', scramSha256Verifier(placeholder));
71
+ let stdin = '';
72
+ const run: PsqlRunner = async (call) => {
73
+ stdin = call.stdin;
74
+ return {
75
+ code: 3,
76
+ stdout: '',
77
+ stderr: `ERROR: 42501: permission denied\nSTATEMENT: ${statement}\n`,
78
+ };
79
+ };
80
+ const error = await Effect.runPromise(
81
+ Effect.flip(makePsqlExecutor(run, target).unsafe(statement)),
82
+ );
83
+ const rendered = `${error.message}\n${String(error.reason.operation ?? '')}\n${JSON.stringify(error)}`;
84
+ expect(stdin).toContain('SCRAM-SHA-256$');
85
+ expect(stdin).not.toContain(placeholder);
86
+ expect(rendered).not.toContain(placeholder);
87
+ expect(rendered).not.toContain(`PASSWORD E'${placeholder.slice(0, 3)}`);
88
+ });
89
+
46
90
  test('a runner that never reached psql is a ConnectionError', async () => {
47
91
  const run: PsqlRunner = () =>
48
92
  Promise.resolve({ code: 255, stdout: '', stderr: 'ssh: refused' });
@@ -94,6 +138,23 @@ describe('runner transport through withPg', () => {
94
138
  expect(stdins.slice(before).some((s) => s.startsWith('CREATE DATABASE'))).toBe(false);
95
139
  });
96
140
 
141
+ test('transaction is one psql script from BEGIN through COMMIT', async () => {
142
+ const calls: string[] = [];
143
+ const run: PsqlRunner = (call) => {
144
+ calls.push(call.stdin);
145
+ return ok('');
146
+ };
147
+ await Effect.runPromise(
148
+ makePsqlExecutor(run, target).transaction([
149
+ 'CREATE ROLE "a" WITH NOLOGIN',
150
+ 'GRANT "p" TO "a" WITH SET FALSE',
151
+ ]),
152
+ );
153
+ expect(calls).toEqual([
154
+ 'BEGIN;\nCREATE ROLE "a" WITH NOLOGIN;\nGRANT "p" TO "a" WITH SET FALSE;\nCOMMIT;',
155
+ ]);
156
+ });
157
+
97
158
  test("postgresRunnerProviders keeps the connection live for the engine's later handler calls", async () => {
98
159
  const run: PsqlRunner = () => ok('[]');
99
160
  const rows = await Effect.runPromise(
@@ -11,8 +11,9 @@
11
11
  * ⛔ `psql` HAS NO BIND PARAMETERS OVER STDIN. Every `$n` is replaced by a `quoteStringLiteral`
12
12
  * literal, and ONLY string params are accepted — this family binds a database or role name,
13
13
  * nothing else — so a number or object is a refusal, never silently stringified.
14
- * ★ ROWS COME BACK AS JSON: a `SELECT` is wrapped in `json_agg`, so `oid` and `datconnlimit`
15
- * arrive as JS numbers exactly as the socket client decodes them (database-sql.ts, no bigint).
14
+ * ★ ROWS COME BACK AS JSON: a row-returning statement (`SELECT`, or a `WITH` query) is wrapped
15
+ * in `json_agg`, so `oid` and `datconnlimit` arrive as JS numbers exactly as the socket client
16
+ * decodes them (database-sql.ts, no bigint).
16
17
  * ★ `VERBOSITY=verbose` puts the SQLSTATE in the error line, so `42P04` (duplicate database)
17
18
  * stays recognisable to `isDuplicateDatabaseRace`.
18
19
  */
@@ -62,20 +63,30 @@ const normalizeRow = (row: unknown): unknown =>
62
63
  ? { ...row, oid: Number((row as { oid: string }).oid) }
63
64
  : row;
64
65
 
65
- const isSelect = (sql: string): boolean => /^\s*SELECT\b/i.test(sql);
66
+ /** Row-returning statements: a plain `SELECT`, or a CTE query (`WITH … SELECT …`). A `WITH`
67
+ * whose rows were discarded would answer an empty table instead of its result — the emptiness
68
+ * check is `WITH`-led, so a missing `WITH` here silently claims every schema is empty. */
69
+ const returnsRows = (sql: string): boolean => /^\s*(SELECT|WITH)\b/i.test(sql);
66
70
 
67
71
  const wrapRows = (sql: string): string =>
68
72
  `SELECT coalesce(json_agg(t), '[]'::json)::text FROM (${sql}) t;`;
69
73
 
74
+ /** A password literal must not survive into an error Alchemy logs. `ALTER ROLE … PASSWORD`
75
+ * inlines the value (Postgres has no bind form), and the runner turns the first 40 characters
76
+ * of that statement into `operation` and the full `stderr` into `message`. */
77
+ export const redactPasswordLiterals = (text: string): string =>
78
+ text.replace(
79
+ /PASSWORD\s+(?:E'(?:[^'\\]|\\[\s\S]|'')*'|'(?:[^']|'')*')/gi,
80
+ "PASSWORD '[redacted]'",
81
+ );
82
+
70
83
  const failure = (operation: string, result: PsqlResult): SqlError => {
71
84
  const state = /ERROR:\s+([0-9A-Z]{5}):/.exec(result.stderr)?.[1];
85
+ const stderr = redactPasswordLiterals(result.stderr.trim());
72
86
  const fields = {
73
- cause: Object.assign(
74
- new Error(result.stderr.trim()),
75
- state === undefined ? {} : { code: state },
76
- ),
77
- message: result.stderr.trim(),
78
- operation,
87
+ cause: Object.assign(new Error(stderr), state === undefined ? {} : { code: state }),
88
+ message: stderr,
89
+ operation: redactPasswordLiterals(operation),
79
90
  };
80
91
  const reason =
81
92
  state === undefined
@@ -86,6 +97,42 @@ const failure = (operation: string, result: PsqlResult): SqlError => {
86
97
  return new SqlError({ reason });
87
98
  };
88
99
 
100
+ const runScript = (
101
+ run: PsqlRunner,
102
+ target: PsqlTarget,
103
+ stdin: string,
104
+ operation: string,
105
+ ): Effect.Effect<PsqlResult, SqlError> =>
106
+ Effect.gen(function* () {
107
+ const result = yield* Effect.tryPromise({
108
+ try: () =>
109
+ run({
110
+ argv: [
111
+ 'psql',
112
+ '-X',
113
+ '-q',
114
+ '-A',
115
+ '-t',
116
+ '-v',
117
+ 'ON_ERROR_STOP=1',
118
+ '-v',
119
+ 'VERBOSITY=verbose',
120
+ '-U',
121
+ target.username,
122
+ '-d',
123
+ target.database,
124
+ ],
125
+ stdin,
126
+ }),
127
+ catch: (cause) =>
128
+ new SqlError({ reason: new ConnectionError({ cause, operation: 'psql exec' }) }),
129
+ });
130
+ if (result.code !== 0) {
131
+ return yield* Effect.fail(failure(operation, result));
132
+ }
133
+ return result;
134
+ });
135
+
89
136
  export const makePsqlExecutor = (run: PsqlRunner, target: PsqlTarget): PgExecutor => ({
90
137
  unsafe: <A extends object>(sql: string, params: ReadonlyArray<unknown> = []) =>
91
138
  Effect.gen(function* () {
@@ -94,31 +141,13 @@ export const makePsqlExecutor = (run: PsqlRunner, target: PsqlTarget): PgExecuto
94
141
  catch: (cause) =>
95
142
  new SqlError({ reason: new UnknownError({ cause, operation: 'psql inline params' }) }),
96
143
  });
97
- const rows = isSelect(inlined);
98
- const result = yield* Effect.tryPromise({
99
- try: () =>
100
- run({
101
- argv: [
102
- 'psql',
103
- '-X',
104
- '-q',
105
- '-A',
106
- '-t',
107
- '-v',
108
- 'ON_ERROR_STOP=1',
109
- '-v',
110
- 'VERBOSITY=verbose',
111
- '-U',
112
- target.username,
113
- '-d',
114
- target.database,
115
- ],
116
- stdin: rows ? wrapRows(inlined) : `${inlined};`,
117
- }),
118
- catch: (cause) =>
119
- new SqlError({ reason: new ConnectionError({ cause, operation: 'psql exec' }) }),
120
- });
121
- if (result.code !== 0) return yield* Effect.fail(failure(inlined.slice(0, 40), result));
144
+ const rows = returnsRows(inlined);
145
+ const result = yield* runScript(
146
+ run,
147
+ target,
148
+ rows ? wrapRows(inlined) : `${inlined};`,
149
+ redactPasswordLiterals(inlined).slice(0, 40),
150
+ );
122
151
  if (!rows) return [] as ReadonlyArray<A>;
123
152
  const parsed = yield* Effect.try({
124
153
  try: () => (JSON.parse(result.stdout.trim() || '[]') as unknown[]).map(normalizeRow),
@@ -127,4 +156,15 @@ export const makePsqlExecutor = (run: PsqlRunner, target: PsqlTarget): PgExecuto
127
156
  });
128
157
  return parsed as ReadonlyArray<A>;
129
158
  }),
159
+ /**
160
+ * One `psql` session: `BEGIN` … statements … `COMMIT`. `ON_ERROR_STOP` exits before `COMMIT`
161
+ * on a failure, and the backend aborts the open transaction when that session drops
162
+ * (`postgres.c@REL_18_6` `SocketBackend` EOF while `IsTransactionState`). Separate `unsafe`
163
+ * calls cannot do this — each is its own process and its own autocommit.
164
+ */
165
+ transaction: (statements) =>
166
+ Effect.gen(function* () {
167
+ const script = ['BEGIN', ...statements, 'COMMIT'].join(';\n');
168
+ yield* runScript(run, target, `${script};`, 'BEGIN');
169
+ }),
130
170
  });
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Apply-time ownership for `Postgres.Role`. The review of PR 336: `read` answers `Unowned` when
3
+ * the stack holds no state, but `reconcile` never called `refuseTakeover`, so a live role found
4
+ * between plan and apply (or one Alchemy skipped probing because a prop was still an Output) was
5
+ * altered and then recorded as ours.
6
+ *
7
+ * These tests construct `postgresRoleHandlers` — the lifecycle tests drive `reconcileWithClient`
8
+ * directly and cannot see this hole. The recording fake is reached the way the engine reaches a
9
+ * real cluster: `withPg` over the runner transport.
10
+ */
11
+ import { describe, expect, test } from 'bun:test';
12
+ import * as Effect from 'effect/Effect';
13
+ import { postgresRunnerConnection } from './connection.ts';
14
+ import { parseLiteral } from './fake-sql-quote.ts';
15
+ import { makeFakeSql } from './fake-sql.ts';
16
+ import { type PsqlRunner } from './psql-executor.ts';
17
+ import { postgresRoleHandlers } from './role-provider.ts';
18
+ import type { PostgresRoleAttributes, PostgresRoleProps } from './role-attrs.ts';
19
+
20
+ const baseProps: PostgresRoleProps = {
21
+ name: 'seat-observability',
22
+ login: false,
23
+ connectionLimit: 10,
24
+ inherit: true,
25
+ };
26
+
27
+ const liveRole = (): PostgresRoleAttributes => ({
28
+ name: 'seat-observability',
29
+ oid: 20000,
30
+ login: true,
31
+ connectionLimit: -1,
32
+ inherit: false,
33
+ validUntil: null,
34
+ memberOf: ['hf_agent'],
35
+ passwordSeal: '',
36
+ });
37
+
38
+ /**
39
+ * A runner that answers the handler's `psql` calls from the recording fake. `withPg` wraps a
40
+ * `SELECT` in `json_agg` and the executor inlines `$1` before the runner sees it, so this
41
+ * unwraps that envelope and binds the literal back to the param the fake's catalog read expects.
42
+ */
43
+ const runnerFor =
44
+ (fake: ReturnType<typeof makeFakeSql>): PsqlRunner =>
45
+ async ({ stdin }) => {
46
+ const wrapped = /^SELECT coalesce\(json_agg\(t\), '\[\]'::json\)::text FROM \((.*)\) t;$/s.exec(
47
+ stdin,
48
+ );
49
+ const body = (wrapped?.[1] ?? stdin).replace(/;\s*$/, '');
50
+ const bound = /^([\s\S]*) = (E'[\s\S]*')$/.exec(body);
51
+ const sql = bound === null ? body : `${bound[1]} = $1`;
52
+ const params = bound === null ? [] : [parseLiteral(bound[2] as string)];
53
+ const rows = await Effect.runPromise(fake.unsafe(sql, params));
54
+ return { code: 0, stdout: JSON.stringify(rows), stderr: '' };
55
+ };
56
+
57
+ const writes = (fake: ReturnType<typeof makeFakeSql>) =>
58
+ fake.statements.filter(
59
+ (s) =>
60
+ s.text.startsWith('ALTER') ||
61
+ s.text.startsWith('GRANT') ||
62
+ s.text.startsWith('REVOKE') ||
63
+ s.text.startsWith('CREATE'),
64
+ );
65
+
66
+ describe('adopt-off takeover', () => {
67
+ test('a live role and adopt-off produces no statement', async () => {
68
+ const fake = makeFakeSql({ roleRows: [liveRole()] });
69
+ fake.memberships.add('seat-observability\0hf_agent');
70
+ const refused = await Effect.runPromise(
71
+ postgresRoleHandlers
72
+ .reconcile({
73
+ id: 'seat-observability',
74
+ fqn: 'Postgres.Role/seat-observability',
75
+ instanceId: 'creating-1',
76
+ news: baseProps,
77
+ output: undefined,
78
+ olds: baseProps,
79
+ session: {} as never,
80
+ bindings: [],
81
+ })
82
+ .pipe(
83
+ Effect.provide(
84
+ postgresRunnerConnection({
85
+ run: runnerFor(fake),
86
+ database: 'postgres',
87
+ username: 'postgres',
88
+ }),
89
+ ),
90
+ Effect.exit,
91
+ ),
92
+ );
93
+ // refuseTakeover dies: a takeover is a defect, not a typed error the engine retries.
94
+ const rendered = refused._tag === 'Failure' ? String(refused.cause) : JSON.stringify(refused);
95
+ expect(rendered).toContain('already exists');
96
+ expect(writes(fake)).toEqual([]);
97
+ });
98
+ });