@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.
- package/README.md +10 -1
- package/dist/caddy/index.js +35 -1
- package/dist/caddy/index.js.map +3 -3
- package/dist/launchd/index.js +35 -1
- package/dist/launchd/index.js.map +3 -3
- package/dist/linux/index.js +35 -1
- package/dist/linux/index.js.map +3 -3
- package/dist/litellm/access-group-form.d.ts +26 -0
- package/dist/litellm/access-group-form.d.ts.map +1 -0
- package/dist/litellm/access-group-operations.d.ts +37 -0
- package/dist/litellm/access-group-operations.d.ts.map +1 -0
- package/dist/litellm/access-group-types.d.ts +49 -0
- package/dist/litellm/access-group-types.d.ts.map +1 -0
- package/dist/litellm/access-group.d.ts +55 -0
- package/dist/litellm/access-group.d.ts.map +1 -0
- package/dist/litellm/credential-errors.d.ts +131 -0
- package/dist/litellm/credential-errors.d.ts.map +1 -0
- package/dist/litellm/credential-form.d.ts +79 -0
- package/dist/litellm/credential-form.d.ts.map +1 -0
- package/dist/litellm/credential-operations.d.ts +84 -0
- package/dist/litellm/credential-operations.d.ts.map +1 -0
- package/dist/litellm/credential-rewrite.d.ts +6 -0
- package/dist/litellm/credential-rewrite.d.ts.map +1 -0
- package/dist/litellm/credential-types.d.ts +87 -0
- package/dist/litellm/credential-types.d.ts.map +1 -0
- package/dist/litellm/credential-values.d.ts +53 -0
- package/dist/litellm/credential-values.d.ts.map +1 -0
- package/dist/litellm/credential.d.ts +83 -0
- package/dist/litellm/credential.d.ts.map +1 -0
- package/dist/litellm/fake-access-group-litellm.d.ts +34 -0
- package/dist/litellm/fake-access-group-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-credential-litellm.d.ts +54 -0
- package/dist/litellm/fake-credential-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-keys.d.ts +53 -0
- package/dist/litellm/fake-keys.d.ts.map +1 -0
- package/dist/litellm/fake-litellm.d.ts +4 -1
- package/dist/litellm/fake-litellm.d.ts.map +1 -1
- package/dist/litellm/fake-mcp-litellm.d.ts +67 -0
- package/dist/litellm/fake-mcp-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-model-litellm-post-update.d.ts +49 -0
- package/dist/litellm/fake-model-litellm-post-update.d.ts.map +1 -0
- package/dist/litellm/fake-model-litellm.d.ts +48 -0
- package/dist/litellm/fake-model-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-policy-attachment-litellm.d.ts +33 -0
- package/dist/litellm/fake-policy-attachment-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-policy-litellm.d.ts +32 -0
- package/dist/litellm/fake-policy-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-registry-base.d.ts +42 -0
- package/dist/litellm/fake-registry-base.d.ts.map +1 -0
- package/dist/litellm/fake-stack.d.ts +8 -1
- package/dist/litellm/fake-stack.d.ts.map +1 -1
- package/dist/litellm/fake-team-litellm.d.ts +47 -0
- package/dist/litellm/fake-team-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-tool-litellm.d.ts +28 -0
- package/dist/litellm/fake-tool-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-toolset-litellm.d.ts +29 -0
- package/dist/litellm/fake-toolset-litellm.d.ts.map +1 -0
- package/dist/litellm/index.d.ts +18 -0
- package/dist/litellm/index.d.ts.map +1 -1
- package/dist/litellm/index.js +3078 -2
- package/dist/litellm/index.js.map +65 -4
- package/dist/litellm/key-errors.d.ts +169 -0
- package/dist/litellm/key-errors.d.ts.map +1 -0
- package/dist/litellm/key-form.d.ts +119 -0
- package/dist/litellm/key-form.d.ts.map +1 -0
- package/dist/litellm/key-harness.d.ts +41 -0
- package/dist/litellm/key-harness.d.ts.map +1 -0
- package/dist/litellm/key-metadata-errors.d.ts +30 -0
- package/dist/litellm/key-metadata-errors.d.ts.map +1 -0
- package/dist/litellm/key-metadata.d.ts +22 -0
- package/dist/litellm/key-metadata.d.ts.map +1 -0
- package/dist/litellm/key-operations.d.ts +63 -0
- package/dist/litellm/key-operations.d.ts.map +1 -0
- package/dist/litellm/key-secret.d.ts +33 -0
- package/dist/litellm/key-secret.d.ts.map +1 -0
- package/dist/litellm/key.d.ts +78 -0
- package/dist/litellm/key.d.ts.map +1 -0
- package/dist/litellm/mcp-server-credential.d.ts +50 -0
- package/dist/litellm/mcp-server-credential.d.ts.map +1 -0
- package/dist/litellm/mcp-server-errors.d.ts +101 -0
- package/dist/litellm/mcp-server-errors.d.ts.map +1 -0
- package/dist/litellm/mcp-server-form.d.ts +56 -0
- package/dist/litellm/mcp-server-form.d.ts.map +1 -0
- package/dist/litellm/mcp-server-locate.d.ts +26 -0
- package/dist/litellm/mcp-server-locate.d.ts.map +1 -0
- package/dist/litellm/mcp-server-operations.d.ts +63 -0
- package/dist/litellm/mcp-server-operations.d.ts.map +1 -0
- package/dist/litellm/mcp-server-shadow.d.ts +24 -0
- package/dist/litellm/mcp-server-shadow.d.ts.map +1 -0
- package/dist/litellm/mcp-server-types.d.ts +118 -0
- package/dist/litellm/mcp-server-types.d.ts.map +1 -0
- package/dist/litellm/mcp-server-url.d.ts +11 -0
- package/dist/litellm/mcp-server-url.d.ts.map +1 -0
- package/dist/litellm/mcp-server.d.ts +95 -0
- package/dist/litellm/mcp-server.d.ts.map +1 -0
- package/dist/litellm/model-claim.d.ts +24 -0
- package/dist/litellm/model-claim.d.ts.map +1 -0
- package/dist/litellm/model-credential.d.ts +12 -0
- package/dist/litellm/model-credential.d.ts.map +1 -0
- package/dist/litellm/model-errors.d.ts +119 -0
- package/dist/litellm/model-errors.d.ts.map +1 -0
- package/dist/litellm/model-form.d.ts +78 -0
- package/dist/litellm/model-form.d.ts.map +1 -0
- package/dist/litellm/model-locate.d.ts +13 -0
- package/dist/litellm/model-locate.d.ts.map +1 -0
- package/dist/litellm/model-operations.d.ts +59 -0
- package/dist/litellm/model-operations.d.ts.map +1 -0
- package/dist/litellm/model-types.d.ts +91 -0
- package/dist/litellm/model-types.d.ts.map +1 -0
- package/dist/litellm/model.d.ts +88 -0
- package/dist/litellm/model.d.ts.map +1 -0
- package/dist/litellm/policy-attachment-form.d.ts +19 -0
- package/dist/litellm/policy-attachment-form.d.ts.map +1 -0
- package/dist/litellm/policy-attachment-operations.d.ts +31 -0
- package/dist/litellm/policy-attachment-operations.d.ts.map +1 -0
- package/dist/litellm/policy-attachment-types.d.ts +48 -0
- package/dist/litellm/policy-attachment-types.d.ts.map +1 -0
- package/dist/litellm/policy-attachment.d.ts +61 -0
- package/dist/litellm/policy-attachment.d.ts.map +1 -0
- package/dist/litellm/policy-form.d.ts +22 -0
- package/dist/litellm/policy-form.d.ts.map +1 -0
- package/dist/litellm/policy-operations.d.ts +42 -0
- package/dist/litellm/policy-operations.d.ts.map +1 -0
- package/dist/litellm/policy-types.d.ts +57 -0
- package/dist/litellm/policy-types.d.ts.map +1 -0
- package/dist/litellm/policy.d.ts +65 -0
- package/dist/litellm/policy.d.ts.map +1 -0
- package/dist/litellm/providers.d.ts +1 -1
- package/dist/litellm/providers.d.ts.map +1 -1
- package/dist/litellm/registry-errors.d.ts +62 -0
- package/dist/litellm/registry-errors.d.ts.map +1 -0
- package/dist/litellm/registry-support.d.ts +42 -0
- package/dist/litellm/registry-support.d.ts.map +1 -0
- package/dist/litellm/team-form.d.ts +26 -0
- package/dist/litellm/team-form.d.ts.map +1 -0
- package/dist/litellm/team-members.d.ts +10 -0
- package/dist/litellm/team-members.d.ts.map +1 -0
- package/dist/litellm/team-operations.d.ts +38 -0
- package/dist/litellm/team-operations.d.ts.map +1 -0
- package/dist/litellm/team-permission.d.ts +35 -0
- package/dist/litellm/team-permission.d.ts.map +1 -0
- package/dist/litellm/team-types.d.ts +101 -0
- package/dist/litellm/team-types.d.ts.map +1 -0
- package/dist/litellm/team.d.ts +67 -0
- package/dist/litellm/team.d.ts.map +1 -0
- package/dist/litellm/tool-policy-form.d.ts +21 -0
- package/dist/litellm/tool-policy-form.d.ts.map +1 -0
- package/dist/litellm/tool-policy-operations.d.ts +30 -0
- package/dist/litellm/tool-policy-operations.d.ts.map +1 -0
- package/dist/litellm/tool-policy-types.d.ts +46 -0
- package/dist/litellm/tool-policy-types.d.ts.map +1 -0
- package/dist/litellm/tool-policy.d.ts +62 -0
- package/dist/litellm/tool-policy.d.ts.map +1 -0
- package/dist/litellm/toolset-form.d.ts +20 -0
- package/dist/litellm/toolset-form.d.ts.map +1 -0
- package/dist/litellm/toolset-operations.d.ts +39 -0
- package/dist/litellm/toolset-operations.d.ts.map +1 -0
- package/dist/litellm/toolset-types.d.ts +46 -0
- package/dist/litellm/toolset-types.d.ts.map +1 -0
- package/dist/litellm/toolset.d.ts +55 -0
- package/dist/litellm/toolset.d.ts.map +1 -0
- package/dist/openbao/index.js +35 -1
- package/dist/openbao/index.js.map +3 -3
- package/dist/ownership/rows.d.ts +11 -0
- package/dist/ownership/rows.d.ts.map +1 -1
- package/dist/postgres/connection.d.ts +14 -2
- package/dist/postgres/connection.d.ts.map +1 -1
- package/dist/postgres/database-sql.d.ts +27 -8
- package/dist/postgres/database-sql.d.ts.map +1 -1
- package/dist/postgres/fake-grants-parse.d.ts +37 -0
- package/dist/postgres/fake-grants-parse.d.ts.map +1 -0
- package/dist/postgres/fake-grants-read.d.ts +61 -0
- package/dist/postgres/fake-grants-read.d.ts.map +1 -0
- package/dist/postgres/fake-grants-sql.d.ts +46 -0
- package/dist/postgres/fake-grants-sql.d.ts.map +1 -0
- package/dist/postgres/fake-grants-write.d.ts +29 -0
- package/dist/postgres/fake-grants-write.d.ts.map +1 -0
- package/dist/postgres/fake-role-sql.d.ts +41 -0
- package/dist/postgres/fake-role-sql.d.ts.map +1 -0
- package/dist/postgres/fake-schema-sql.d.ts +42 -0
- package/dist/postgres/fake-schema-sql.d.ts.map +1 -0
- package/dist/postgres/fake-sql-parse.d.ts +23 -0
- package/dist/postgres/fake-sql-parse.d.ts.map +1 -0
- package/dist/postgres/fake-sql-quote.d.ts +12 -0
- package/dist/postgres/fake-sql-quote.d.ts.map +1 -0
- package/dist/postgres/fake-sql.d.ts +42 -0
- package/dist/postgres/fake-sql.d.ts.map +1 -1
- package/dist/postgres/grants-attrs.d.ts +115 -0
- package/dist/postgres/grants-attrs.d.ts.map +1 -0
- package/dist/postgres/grants-declare.d.ts +88 -0
- package/dist/postgres/grants-declare.d.ts.map +1 -0
- package/dist/postgres/grants-diff.d.ts +25 -0
- package/dist/postgres/grants-diff.d.ts.map +1 -0
- package/dist/postgres/grants-errors.d.ts +137 -0
- package/dist/postgres/grants-errors.d.ts.map +1 -0
- package/dist/postgres/grants-existence.d.ts +14 -0
- package/dist/postgres/grants-existence.d.ts.map +1 -0
- package/dist/postgres/grants-ops.d.ts +65 -0
- package/dist/postgres/grants-ops.d.ts.map +1 -0
- package/dist/postgres/grants-ownership.d.ts +18 -0
- package/dist/postgres/grants-ownership.d.ts.map +1 -0
- package/dist/postgres/grants-plan-restore.d.ts +22 -0
- package/dist/postgres/grants-plan-restore.d.ts.map +1 -0
- package/dist/postgres/grants-plan.d.ts +65 -0
- package/dist/postgres/grants-plan.d.ts.map +1 -0
- package/dist/postgres/grants-read-defaults.d.ts +17 -0
- package/dist/postgres/grants-read-defaults.d.ts.map +1 -0
- package/dist/postgres/grants-read.d.ts +77 -0
- package/dist/postgres/grants-read.d.ts.map +1 -0
- package/dist/postgres/grants-refuse.d.ts +25 -0
- package/dist/postgres/grants-refuse.d.ts.map +1 -0
- package/dist/postgres/grants-sql.d.ts +42 -0
- package/dist/postgres/grants-sql.d.ts.map +1 -0
- package/dist/postgres/grants-words.d.ts +29 -0
- package/dist/postgres/grants-words.d.ts.map +1 -0
- package/dist/postgres/grants.d.ts +37 -0
- package/dist/postgres/grants.d.ts.map +1 -0
- package/dist/postgres/index.d.ts +31 -6
- package/dist/postgres/index.d.ts.map +1 -1
- package/dist/postgres/index.js +1998 -37
- package/dist/postgres/index.js.map +46 -7
- package/dist/postgres/installed-classifier.d.ts +13 -0
- package/dist/postgres/installed-classifier.d.ts.map +1 -0
- package/dist/postgres/providers.d.ts +16 -8
- package/dist/postgres/providers.d.ts.map +1 -1
- package/dist/postgres/psql-executor.d.ts +4 -0
- package/dist/postgres/psql-executor.d.ts.map +1 -1
- package/dist/postgres/role-attrs.d.ts +112 -0
- package/dist/postgres/role-attrs.d.ts.map +1 -0
- package/dist/postgres/role-diff.d.ts +22 -0
- package/dist/postgres/role-diff.d.ts.map +1 -0
- package/dist/postgres/role-errors.d.ts +132 -0
- package/dist/postgres/role-errors.d.ts.map +1 -0
- package/dist/postgres/role-membership-sql.d.ts +78 -0
- package/dist/postgres/role-membership-sql.d.ts.map +1 -0
- package/dist/postgres/role-provider.d.ts +11 -0
- package/dist/postgres/role-provider.d.ts.map +1 -0
- package/dist/postgres/role-scram.d.ts +8 -0
- package/dist/postgres/role-scram.d.ts.map +1 -0
- package/dist/postgres/role-secrets.d.ts +38 -0
- package/dist/postgres/role-secrets.d.ts.map +1 -0
- package/dist/postgres/role-sql.d.ts +68 -0
- package/dist/postgres/role-sql.d.ts.map +1 -0
- package/dist/postgres/role.d.ts +57 -0
- package/dist/postgres/role.d.ts.map +1 -0
- package/dist/postgres/schema-assert.d.ts +50 -0
- package/dist/postgres/schema-assert.d.ts.map +1 -0
- package/dist/postgres/schema-attrs.d.ts +51 -0
- package/dist/postgres/schema-attrs.d.ts.map +1 -0
- package/dist/postgres/schema-delete.d.ts +28 -0
- package/dist/postgres/schema-delete.d.ts.map +1 -0
- package/dist/postgres/schema-diff.d.ts +14 -0
- package/dist/postgres/schema-diff.d.ts.map +1 -0
- package/dist/postgres/schema-errors.d.ts +139 -0
- package/dist/postgres/schema-errors.d.ts.map +1 -0
- package/dist/postgres/schema-identity.d.ts +8 -0
- package/dist/postgres/schema-identity.d.ts.map +1 -0
- package/dist/postgres/schema-reconcile.d.ts +12 -0
- package/dist/postgres/schema-reconcile.d.ts.map +1 -0
- package/dist/postgres/schema-sql.d.ts +45 -0
- package/dist/postgres/schema-sql.d.ts.map +1 -0
- package/dist/postgres/schema-test-kit.d.ts +67 -0
- package/dist/postgres/schema-test-kit.d.ts.map +1 -0
- package/dist/postgres/schema.d.ts +54 -0
- package/dist/postgres/schema.d.ts.map +1 -0
- package/dist/proxmox/index.js +35 -1
- package/dist/proxmox/index.js.map +3 -3
- package/dist/release/fake-engine.d.ts +10 -0
- package/dist/release/fake-engine.d.ts.map +1 -1
- package/dist/release/index.js +35 -1
- package/dist/release/index.js.map +3 -3
- package/dist/valkey/acl-attrs.d.ts +94 -0
- package/dist/valkey/acl-attrs.d.ts.map +1 -0
- package/dist/valkey/acl-compare.d.ts +28 -0
- package/dist/valkey/acl-compare.d.ts.map +1 -0
- package/dist/valkey/acl-connection.d.ts +6 -0
- package/dist/valkey/acl-connection.d.ts.map +1 -0
- package/dist/valkey/acl-form.d.ts +62 -0
- package/dist/valkey/acl-form.d.ts.map +1 -0
- package/dist/valkey/acl-managed.d.ts +4 -0
- package/dist/valkey/acl-managed.d.ts.map +1 -0
- package/dist/valkey/acl-ops.d.ts +37 -0
- package/dist/valkey/acl-ops.d.ts.map +1 -0
- package/dist/valkey/acl-profiles.d.ts +53 -0
- package/dist/valkey/acl-profiles.d.ts.map +1 -0
- package/dist/valkey/acl-reconcile.d.ts +26 -0
- package/dist/valkey/acl-reconcile.d.ts.map +1 -0
- package/dist/valkey/acl.d.ts +24 -0
- package/dist/valkey/acl.d.ts.map +1 -0
- package/dist/valkey/connection-service.d.ts +22 -0
- package/dist/valkey/connection-service.d.ts.map +1 -0
- package/dist/valkey/connection.d.ts +59 -0
- package/dist/valkey/connection.d.ts.map +1 -0
- package/dist/valkey/errors.d.ts +165 -0
- package/dist/valkey/errors.d.ts.map +1 -0
- package/dist/valkey/fake-acl.d.ts +29 -0
- package/dist/valkey/fake-acl.d.ts.map +1 -0
- package/dist/valkey/fake-valkey.d.ts +35 -0
- package/dist/valkey/fake-valkey.d.ts.map +1 -0
- package/dist/valkey/handler-test-fixture.d.ts +20 -0
- package/dist/valkey/handler-test-fixture.d.ts.map +1 -0
- package/dist/valkey/index.d.ts +18 -0
- package/dist/valkey/index.d.ts.map +1 -0
- package/dist/valkey/index.js +964 -0
- package/dist/valkey/index.js.map +27 -0
- package/dist/valkey/instance-attrs.d.ts +46 -0
- package/dist/valkey/instance-attrs.d.ts.map +1 -0
- package/dist/valkey/instance-form.d.ts +22 -0
- package/dist/valkey/instance-form.d.ts.map +1 -0
- package/dist/valkey/instance.d.ts +48 -0
- package/dist/valkey/instance.d.ts.map +1 -0
- package/dist/valkey/provider-socket-fixture.d.ts +8 -0
- package/dist/valkey/provider-socket-fixture.d.ts.map +1 -0
- package/dist/valkey/providers.d.ts +16 -0
- package/dist/valkey/providers.d.ts.map +1 -0
- package/dist/valkey/resp.d.ts +38 -0
- package/dist/valkey/resp.d.ts.map +1 -0
- package/dist/valkey/transport-error.d.ts +36 -0
- package/dist/valkey/transport-error.d.ts.map +1 -0
- package/dist/valkey/transport.d.ts +50 -0
- package/dist/valkey/transport.d.ts.map +1 -0
- package/docs/litellm-access-group.md +105 -0
- package/docs/litellm-credential.md +60 -0
- package/docs/litellm-key-metadata.md +56 -0
- package/docs/litellm-key.md +194 -0
- package/docs/litellm-mcp.md +187 -0
- package/docs/litellm-model.md +111 -0
- package/docs/litellm-policy-attachment.md +86 -0
- package/docs/litellm-policy.md +103 -0
- package/docs/litellm-team.md +117 -0
- package/docs/litellm-tool-policy.md +90 -0
- package/docs/litellm-toolset.md +92 -0
- package/docs/litellm.md +16 -9
- package/docs/peers.md +15 -6
- package/docs/postgres-grants-example.md +55 -0
- package/docs/postgres-grants.md +157 -0
- package/docs/postgres-role.md +126 -0
- package/docs/postgres-schema.md +139 -0
- package/docs/postgres.md +20 -3
- package/docs/valkey-transport.md +29 -0
- package/docs/valkey.md +187 -0
- package/package.json +6 -2
- package/src/ceph/ceph-argv.test.ts +1 -1
- package/src/launchd/sudo-allowlist.test.ts +2 -2
- package/src/linux/sudo-allowlist.test.ts +3 -3
- package/src/linux/sudo-runner.test.ts +2 -2
- package/src/litellm/access-group-form.ts +105 -0
- package/src/litellm/access-group-operations.ts +92 -0
- package/src/litellm/access-group-types.ts +49 -0
- package/src/litellm/access-group.test.ts +197 -0
- package/src/litellm/access-group.ts +151 -0
- package/src/litellm/credential-errors.ts +183 -0
- package/src/litellm/credential-form.test.ts +151 -0
- package/src/litellm/credential-form.ts +211 -0
- package/src/litellm/credential-guards.test.ts +241 -0
- package/src/litellm/credential-operations.ts +208 -0
- package/src/litellm/credential-recovery.test.ts +93 -0
- package/src/litellm/credential-rewrite.test.ts +164 -0
- package/src/litellm/credential-rewrite.ts +50 -0
- package/src/litellm/credential-types.ts +117 -0
- package/src/litellm/credential-values.ts +94 -0
- package/src/litellm/credential.test.ts +218 -0
- package/src/litellm/credential.ts +227 -0
- package/src/litellm/fake-access-group-litellm.ts +127 -0
- package/src/litellm/fake-credential-litellm.ts +216 -0
- package/src/litellm/fake-keys.ts +190 -0
- package/src/litellm/fake-litellm.ts +19 -9
- package/src/litellm/fake-mcp-litellm.ts +214 -0
- package/src/litellm/fake-model-litellm-post-update.ts +103 -0
- package/src/litellm/fake-model-litellm.ts +233 -0
- package/src/litellm/fake-policy-attachment-litellm.ts +97 -0
- package/src/litellm/fake-policy-litellm.ts +186 -0
- package/src/litellm/fake-registry-base.ts +69 -0
- package/src/litellm/fake-stack.ts +17 -1
- package/src/litellm/fake-team-litellm.ts +229 -0
- package/src/litellm/fake-tool-litellm.ts +88 -0
- package/src/litellm/fake-toolset-litellm.ts +110 -0
- package/src/litellm/index.ts +140 -0
- package/src/litellm/key-delete.test.ts +212 -0
- package/src/litellm/key-errors.ts +241 -0
- package/src/litellm/key-form.ts +200 -0
- package/src/litellm/key-harness.ts +121 -0
- package/src/litellm/key-metadata-errors.ts +49 -0
- package/src/litellm/key-metadata.test.ts +156 -0
- package/src/litellm/key-metadata.ts +74 -0
- package/src/litellm/key-operations.ts +184 -0
- package/src/litellm/key-rotation.test.ts +110 -0
- package/src/litellm/key-scope.test.ts +135 -0
- package/src/litellm/key-secret.test.ts +248 -0
- package/src/litellm/key-secret.ts +137 -0
- package/src/litellm/key-transport.test.ts +166 -0
- package/src/litellm/key.test.ts +231 -0
- package/src/litellm/key.ts +213 -0
- package/src/litellm/mcp-server-adopt.test.ts +86 -0
- package/src/litellm/mcp-server-alias.test.ts +184 -0
- package/src/litellm/mcp-server-credential.ts +85 -0
- package/src/litellm/mcp-server-errors.ts +141 -0
- package/src/litellm/mcp-server-exports.test.ts +15 -0
- package/src/litellm/mcp-server-form.test.ts +241 -0
- package/src/litellm/mcp-server-form.ts +233 -0
- package/src/litellm/mcp-server-handlers.test.ts +150 -0
- package/src/litellm/mcp-server-locate.ts +66 -0
- package/src/litellm/mcp-server-operations.ts +111 -0
- package/src/litellm/mcp-server-registry.test.ts +146 -0
- package/src/litellm/mcp-server-retype.test.ts +114 -0
- package/src/litellm/mcp-server-shadow.test.ts +91 -0
- package/src/litellm/mcp-server-shadow.ts +45 -0
- package/src/litellm/mcp-server-tools.test.ts +85 -0
- package/src/litellm/mcp-server-types.ts +143 -0
- package/src/litellm/mcp-server-url.ts +66 -0
- package/src/litellm/mcp-server.test.ts +213 -0
- package/src/litellm/mcp-server.ts +225 -0
- package/src/litellm/model-claim.ts +69 -0
- package/src/litellm/model-credential.ts +45 -0
- package/src/litellm/model-errors.ts +168 -0
- package/src/litellm/model-foreign-row.test.ts +173 -0
- package/src/litellm/model-form.test.ts +228 -0
- package/src/litellm/model-form.ts +223 -0
- package/src/litellm/model-locate.test.ts +128 -0
- package/src/litellm/model-locate.ts +67 -0
- package/src/litellm/model-operations.test.ts +93 -0
- package/src/litellm/model-operations.ts +146 -0
- package/src/litellm/model-params-preserve.test.ts +119 -0
- package/src/litellm/model-recovery.test.ts +57 -0
- package/src/litellm/model-types.ts +112 -0
- package/src/litellm/model.test.ts +222 -0
- package/src/litellm/model.ts +237 -0
- package/src/litellm/policy-attachment-form.ts +103 -0
- package/src/litellm/policy-attachment-operations.ts +74 -0
- package/src/litellm/policy-attachment-types.ts +48 -0
- package/src/litellm/policy-attachment.test.ts +198 -0
- package/src/litellm/policy-attachment.ts +178 -0
- package/src/litellm/policy-form.ts +122 -0
- package/src/litellm/policy-operations.ts +112 -0
- package/src/litellm/policy-types.ts +58 -0
- package/src/litellm/policy.test.ts +214 -0
- package/src/litellm/policy.ts +146 -0
- package/src/litellm/providers.ts +24 -3
- package/src/litellm/registry-errors.ts +88 -0
- package/src/litellm/registry-exports.test.ts +66 -0
- package/src/litellm/registry-support.ts +109 -0
- package/src/litellm/team-form.ts +140 -0
- package/src/litellm/team-members.test.ts +150 -0
- package/src/litellm/team-members.ts +58 -0
- package/src/litellm/team-operations.ts +90 -0
- package/src/litellm/team-permission.ts +159 -0
- package/src/litellm/team-read.test.ts +89 -0
- package/src/litellm/team-types.ts +106 -0
- package/src/litellm/team.test.ts +206 -0
- package/src/litellm/team.ts +159 -0
- package/src/litellm/tool-policy-form.ts +94 -0
- package/src/litellm/tool-policy-operations.ts +58 -0
- package/src/litellm/tool-policy-types.ts +48 -0
- package/src/litellm/tool-policy.test.ts +172 -0
- package/src/litellm/tool-policy.ts +125 -0
- package/src/litellm/toolset-form.ts +104 -0
- package/src/litellm/toolset-operations.ts +90 -0
- package/src/litellm/toolset-types.ts +47 -0
- package/src/litellm/toolset.test.ts +198 -0
- package/src/litellm/toolset.ts +151 -0
- package/src/ownership/ownership.test.ts +33 -1
- package/src/ownership/rows.ts +53 -0
- package/src/postgres/connection.ts +42 -7
- package/src/postgres/database-bigint-serialization.test.ts +1 -0
- package/src/postgres/database-refusals.test.ts +2 -2
- package/src/postgres/database-sql.ts +36 -9
- package/src/postgres/fake-grants-parse.ts +189 -0
- package/src/postgres/fake-grants-read.ts +250 -0
- package/src/postgres/fake-grants-sql.ts +207 -0
- package/src/postgres/fake-grants-write.ts +90 -0
- package/src/postgres/fake-role-sql.ts +240 -0
- package/src/postgres/fake-schema-semantics.test.ts +36 -0
- package/src/postgres/fake-schema-sql.ts +146 -0
- package/src/postgres/fake-sql-parse.ts +86 -0
- package/src/postgres/fake-sql-quote.ts +36 -0
- package/src/postgres/fake-sql.ts +166 -46
- package/src/postgres/fixtures/pg-REL_18_6-acl.h.txt +147 -0
- package/src/postgres/fixtures/pg-REL_18_6-aclexplode-func.txt +31 -0
- package/src/postgres/fixtures/pg-REL_18_6-alter-default-privileges-synopsis.txt +82 -0
- package/src/postgres/fixtures/pg-REL_18_6-alter_role.sgml.txt +44 -0
- package/src/postgres/fixtures/pg-REL_18_6-create_role.sgml.txt +26 -0
- package/src/postgres/fixtures/pg-REL_18_6-grant-synopsis.txt +95 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_attribute.h.txt +24 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_auth_members.h.txt +62 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_authid.h.txt +70 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_class.h.txt +33 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_default_acl.h.txt +81 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_namespace.h.txt +28 -0
- package/src/postgres/fixtures/pg-REL_18_6-revoke-synopsis.txt +124 -0
- package/src/postgres/grants-acl.test.ts +61 -0
- package/src/postgres/grants-attrs.ts +185 -0
- package/src/postgres/grants-database.test.ts +158 -0
- package/src/postgres/grants-declare.ts +172 -0
- package/src/postgres/grants-delete-proof.test.ts +154 -0
- package/src/postgres/grants-diff.ts +101 -0
- package/src/postgres/grants-errors.ts +215 -0
- package/src/postgres/grants-existence-guards.test.ts +113 -0
- package/src/postgres/grants-existence.ts +101 -0
- package/src/postgres/grants-lifecycle-guards.test.ts +208 -0
- package/src/postgres/grants-lifecycle-repair.test.ts +208 -0
- package/src/postgres/grants-lifecycle.test.ts +181 -0
- package/src/postgres/grants-ops.ts +229 -0
- package/src/postgres/grants-owner-revoke.test.ts +121 -0
- package/src/postgres/grants-ownership.ts +49 -0
- package/src/postgres/grants-plan-collateral.test.ts +202 -0
- package/src/postgres/grants-plan-diff.test.ts +204 -0
- package/src/postgres/grants-plan-restore.ts +43 -0
- package/src/postgres/grants-plan-revocations.test.ts +69 -0
- package/src/postgres/grants-plan.test.ts +148 -0
- package/src/postgres/grants-plan.ts +245 -0
- package/src/postgres/grants-provenance.test.ts +134 -0
- package/src/postgres/grants-psql-lifecycle.test.ts +105 -0
- package/src/postgres/grants-read-absent.test.ts +91 -0
- package/src/postgres/grants-read-defaults.ts +51 -0
- package/src/postgres/grants-read.ts +250 -0
- package/src/postgres/grants-refusals.test.ts +136 -0
- package/src/postgres/grants-refuse.ts +119 -0
- package/src/postgres/grants-relkind-wire.test.ts +111 -0
- package/src/postgres/grants-repair-plan.test.ts +201 -0
- package/src/postgres/grants-sql.test.ts +128 -0
- package/src/postgres/grants-sql.ts +144 -0
- package/src/postgres/grants-words.ts +34 -0
- package/src/postgres/grants.ts +110 -0
- package/src/postgres/index.ts +129 -5
- package/src/postgres/installed-classifier.ts +36 -0
- package/src/postgres/providers.ts +33 -9
- package/src/postgres/psql-executor-escaping.test.ts +67 -0
- package/src/postgres/psql-executor.test.ts +63 -2
- package/src/postgres/psql-executor.ts +74 -34
- package/src/postgres/role-adopt.test.ts +98 -0
- package/src/postgres/role-attrs.ts +137 -0
- package/src/postgres/role-diff.ts +93 -0
- package/src/postgres/role-errors.ts +206 -0
- package/src/postgres/role-guard.test.ts +60 -0
- package/src/postgres/role-identity.test.ts +197 -0
- package/src/postgres/role-lifecycle.test.ts +228 -0
- package/src/postgres/role-membership-options.test.ts +73 -0
- package/src/postgres/role-membership-repair.test.ts +153 -0
- package/src/postgres/role-membership-sql.ts +223 -0
- package/src/postgres/role-password-ascii.test.ts +53 -0
- package/src/postgres/role-password-transports.test.ts +123 -0
- package/src/postgres/role-password.test.ts +158 -0
- package/src/postgres/role-privilege.test.ts +107 -0
- package/src/postgres/role-provenance.test.ts +200 -0
- package/src/postgres/role-provider.ts +105 -0
- package/src/postgres/role-refusals.test.ts +225 -0
- package/src/postgres/role-scram.test.ts +38 -0
- package/src/postgres/role-scram.ts +40 -0
- package/src/postgres/role-secrets.ts +61 -0
- package/src/postgres/role-sql.ts +213 -0
- package/src/postgres/role-valid-until.test.ts +68 -0
- package/src/postgres/role.ts +226 -0
- package/src/postgres/schema-assert.ts +139 -0
- package/src/postgres/schema-attrs.ts +71 -0
- package/src/postgres/schema-delete-proofs.test.ts +192 -0
- package/src/postgres/schema-delete.ts +96 -0
- package/src/postgres/schema-diff.ts +44 -0
- package/src/postgres/schema-drop-2bp01.test.ts +146 -0
- package/src/postgres/schema-errors.ts +209 -0
- package/src/postgres/schema-handlers.test.ts +193 -0
- package/src/postgres/schema-identity.ts +39 -0
- package/src/postgres/schema-lifecycle.test.ts +246 -0
- package/src/postgres/schema-race.test.ts +70 -0
- package/src/postgres/schema-reconcile.ts +100 -0
- package/src/postgres/schema-refusals.test.ts +144 -0
- package/src/postgres/schema-socket.test.ts +162 -0
- package/src/postgres/schema-sql.ts +130 -0
- package/src/postgres/schema-takeover.test.ts +149 -0
- package/src/postgres/schema-test-kit.ts +85 -0
- package/src/postgres/schema.ts +130 -0
- package/src/release/binary-alias.test.ts +3 -3
- package/src/release/binary-claims.test.ts +3 -3
- package/src/release/binary-directory-umask.test.ts +65 -0
- package/src/release/fake-engine.ts +15 -0
- package/src/valkey/acl-attrs.ts +98 -0
- package/src/valkey/acl-compare.ts +57 -0
- package/src/valkey/acl-connection.ts +13 -0
- package/src/valkey/acl-delete.test.ts +127 -0
- package/src/valkey/acl-form.ts +239 -0
- package/src/valkey/acl-managed.ts +13 -0
- package/src/valkey/acl-ops.ts +122 -0
- package/src/valkey/acl-ownership.test.ts +118 -0
- package/src/valkey/acl-prefix.test.ts +38 -0
- package/src/valkey/acl-profiles.ts +81 -0
- package/src/valkey/acl-reconcile.ts +180 -0
- package/src/valkey/acl-reserved.test.ts +69 -0
- package/src/valkey/acl-revocation.test.ts +94 -0
- package/src/valkey/acl-seat-prefix.test.ts +111 -0
- package/src/valkey/acl-validation.test.ts +54 -0
- package/src/valkey/acl.test.ts +215 -0
- package/src/valkey/acl.ts +169 -0
- package/src/valkey/connection-service.ts +46 -0
- package/src/valkey/connection.ts +180 -0
- package/src/valkey/errors.ts +239 -0
- package/src/valkey/fake-acl.ts +128 -0
- package/src/valkey/fake-valkey.ts +224 -0
- package/src/valkey/handler-test-fixture.ts +43 -0
- package/src/valkey/handlers.test.ts +205 -0
- package/src/valkey/index.ts +54 -0
- package/src/valkey/instance-attrs.ts +48 -0
- package/src/valkey/instance-form.ts +104 -0
- package/src/valkey/instance.test.ts +108 -0
- package/src/valkey/instance.ts +160 -0
- package/src/valkey/provider-socket-fixture.ts +71 -0
- package/src/valkey/providers.test.ts +129 -0
- package/src/valkey/providers.ts +21 -0
- package/src/valkey/resp.ts +212 -0
- package/src/valkey/transport-bounds.test.ts +150 -0
- package/src/valkey/transport-error.ts +37 -0
- package/src/valkey/transport.test.ts +158 -0
- package/src/valkey/transport.ts +109 -0
- package/src/valkey/upstream-bounds.test.ts +14 -0
package/src/postgres/index.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* PostgreSQL providers for Alchemy — `Postgres.Database
|
|
3
|
-
* cluster,
|
|
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`
|
|
6
|
-
* test
|
|
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 {
|
|
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
|
|
2
|
+
* `Postgres.*` providers, pre-wired for one cluster:
|
|
3
3
|
*
|
|
4
|
-
* const providers = postgresProviders({ host: '/
|
|
4
|
+
* const providers = postgresProviders({ host: '/var/run/postgresql', database: 'postgres', username: 'tim' });
|
|
5
5
|
*
|
|
6
|
-
* ★ THE CLUSTER IS
|
|
7
|
-
* PUBLIC;
|
|
8
|
-
* never baked in here. A stack with more than one cluster calls this
|
|
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
|
-
|
|
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
|
|
35
|
+
/** The same providers over a command runner (`psql-executor.ts`) — for loopback-only clusters. */
|
|
28
36
|
export const postgresRunnerProviders = (config: PostgresRunnerConfig) =>
|
|
29
|
-
|
|
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
|
|
15
|
-
* arrive as JS numbers exactly as the socket client
|
|
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
|
-
|
|
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
|
-
|
|
75
|
-
|
|
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 =
|
|
98
|
-
const result = yield*
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
+
});
|