@homeflare/alchemy 0.42.0 → 0.44.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/budget-errors.d.ts +36 -0
- package/dist/litellm/budget-errors.d.ts.map +1 -0
- package/dist/litellm/budget-form.d.ts +50 -0
- package/dist/litellm/budget-form.d.ts.map +1 -0
- package/dist/litellm/budget-operations.d.ts +20 -0
- package/dist/litellm/budget-operations.d.ts.map +1 -0
- package/dist/litellm/budget.d.ts +61 -0
- package/dist/litellm/budget.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 +9 -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 +20 -0
- package/dist/litellm/index.d.ts.map +1 -1
- package/dist/litellm/index.js +3201 -2
- package/dist/litellm/index.js.map +70 -5
- 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/operations.d.ts +22 -0
- package/dist/litellm/operations.d.ts.map +1 -1
- 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/auth-role-form.d.ts +9 -0
- package/dist/openbao/auth-role-form.d.ts.map +1 -1
- package/dist/openbao/auth-role-wire.d.ts.map +1 -1
- package/dist/openbao/fake-engines-roles.d.ts.map +1 -1
- package/dist/openbao/index.js +43 -6
- package/dist/openbao/index.js.map +5 -5
- package/dist/ownership/rows.d.ts +11 -0
- package/dist/ownership/rows.d.ts.map +1 -1
- package/dist/postgres/connection.d.ts +32 -2
- package/dist/postgres/connection.d.ts.map +1 -1
- package/dist/postgres/database-sql.d.ts +28 -9
- package/dist/postgres/database-sql.d.ts.map +1 -1
- package/dist/postgres/database.d.ts +1 -1
- package/dist/postgres/database.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 +40 -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 +35 -8
- package/dist/postgres/index.d.ts.map +1 -1
- package/dist/postgres/index.js +2063 -39
- package/dist/postgres/index.js.map +47 -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 +17 -7
- package/dist/postgres/providers.d.ts.map +1 -1
- package/dist/postgres/psql-executor.d.ts +25 -0
- package/dist/postgres/psql-executor.d.ts.map +1 -0
- package/dist/postgres/role-attrs.d.ts +109 -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 +126 -0
- package/dist/postgres/role-errors.d.ts.map +1 -0
- package/dist/postgres/role-membership-sql.d.ts +75 -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 +6 -0
- package/dist/postgres/role-scram.d.ts.map +1 -0
- package/dist/postgres/role-secrets.d.ts +30 -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/ceph-flag-types.d.ts +57 -0
- package/dist/proxmox/ceph-flag-types.d.ts.map +1 -0
- package/dist/proxmox/ceph-flag-wire.d.ts +77 -0
- package/dist/proxmox/ceph-flag-wire.d.ts.map +1 -0
- package/dist/proxmox/ceph-flag.d.ts +15 -50
- package/dist/proxmox/ceph-flag.d.ts.map +1 -1
- package/dist/proxmox/ceph-osd-write.d.ts +10 -13
- package/dist/proxmox/ceph-osd-write.d.ts.map +1 -1
- package/dist/proxmox/index.js +806 -740
- package/dist/proxmox/index.js.map +9 -8
- 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-budget.md +55 -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 -8
- 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 +114 -0
- package/docs/postgres-schema.md +139 -0
- package/docs/postgres.md +39 -0
- package/docs/proxmox-sdk-migration.md +45 -0
- package/docs/valkey-transport.md +29 -0
- package/docs/valkey.md +187 -0
- package/package.json +7 -3
- 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/budget-errors.ts +38 -0
- package/src/litellm/budget-form.ts +94 -0
- package/src/litellm/budget-operations.ts +51 -0
- package/src/litellm/budget.test.ts +105 -0
- package/src/litellm/budget.ts +127 -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 +66 -7
- 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 +153 -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/operations.ts +1 -1
- 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 +25 -1
- 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/openbao/auth-role-form.test.ts +37 -0
- package/src/openbao/auth-role-form.ts +12 -1
- package/src/openbao/auth-role-wire.test.ts +1 -0
- package/src/openbao/auth-role-wire.ts +13 -1
- package/src/openbao/distilled-retry.test.ts +1 -0
- package/src/openbao/fake-engines-roles.ts +7 -1
- package/src/ownership/ownership.test.ts +33 -1
- package/src/ownership/rows.ts +53 -0
- package/src/postgres/connection.ts +72 -3
- 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 +40 -12
- package/src/postgres/database.ts +3 -2
- 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 +220 -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 +161 -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 +137 -7
- package/src/postgres/installed-classifier.ts +36 -0
- package/src/postgres/providers.ts +44 -7
- package/src/postgres/psql-executor-escaping.test.ts +67 -0
- package/src/postgres/psql-executor.test.ts +167 -0
- package/src/postgres/psql-executor.ts +170 -0
- package/src/postgres/role-adopt.test.ts +98 -0
- package/src/postgres/role-attrs.ts +134 -0
- package/src/postgres/role-diff.ts +89 -0
- package/src/postgres/role-errors.ts +198 -0
- package/src/postgres/role-guard.test.ts +60 -0
- package/src/postgres/role-identity.test.ts +185 -0
- package/src/postgres/role-lifecycle.test.ts +228 -0
- package/src/postgres/role-membership-sql.ts +198 -0
- package/src/postgres/role-password.test.ts +158 -0
- package/src/postgres/role-privilege.test.ts +80 -0
- package/src/postgres/role-provenance.test.ts +200 -0
- package/src/postgres/role-provider.ts +104 -0
- package/src/postgres/role-refusals.test.ts +250 -0
- package/src/postgres/role-scram.test.ts +38 -0
- package/src/postgres/role-scram.ts +38 -0
- package/src/postgres/role-secrets.ts +46 -0
- package/src/postgres/role-sql.ts +211 -0
- package/src/postgres/role-valid-until.test.ts +68 -0
- package/src/postgres/role.ts +218 -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 +161 -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/proxmox/ceph-flag-types.ts +70 -0
- package/src/proxmox/ceph-flag-wire.test.ts +72 -0
- package/src/proxmox/ceph-flag-wire.ts +123 -0
- package/src/proxmox/ceph-flag.ts +77 -130
- package/src/proxmox/ceph-osd-write.ts +10 -13
- 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,16 +1,28 @@
|
|
|
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
|
-
export type { PostgresConnectionConfig } from './connection.ts';
|
|
9
|
-
export {
|
|
12
|
+
export type { PostgresConnectionConfig, PostgresRunnerConfig } from './connection.ts';
|
|
13
|
+
export {
|
|
14
|
+
PostgresConnection,
|
|
15
|
+
postgresConnection,
|
|
16
|
+
postgresRunnerConnection,
|
|
17
|
+
withPg,
|
|
18
|
+
} from './connection.ts';
|
|
19
|
+
export type { PsqlResult, PsqlRunner } from './psql-executor.ts';
|
|
20
|
+
export { inlineParams, makePsqlExecutor } from './psql-executor.ts';
|
|
10
21
|
export type { PostgresDatabaseAttributes, PostgresDatabaseProps } from './database-attrs.ts';
|
|
11
22
|
export { POSTGRES_NAME_MAX_BYTES, nameByteRefusal, utf8ByteLength } from './database-attrs.ts';
|
|
12
23
|
export {
|
|
13
24
|
buildCreateDatabaseSql,
|
|
25
|
+
databaseExists,
|
|
14
26
|
firstDrift,
|
|
15
27
|
isDuplicateDatabaseRace,
|
|
16
28
|
quoteIdent,
|
|
@@ -19,6 +31,38 @@ export {
|
|
|
19
31
|
selectDatabase,
|
|
20
32
|
} from './database-sql.ts';
|
|
21
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';
|
|
22
66
|
export {
|
|
23
67
|
PostgresDatabaseDrift,
|
|
24
68
|
PostgresDatabaseDropRefused,
|
|
@@ -27,4 +71,90 @@ export {
|
|
|
27
71
|
PostgresDatabaseRenameRefused,
|
|
28
72
|
type PostgresDatabaseError,
|
|
29
73
|
} from './errors.ts';
|
|
30
|
-
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
|
+
PostgresRolePrivilegedRefused,
|
|
151
|
+
PostgresRoleRenameRefused,
|
|
152
|
+
PostgresRoleValidUntilRefused,
|
|
153
|
+
type PostgresRoleError,
|
|
154
|
+
} from './role-errors.ts';
|
|
155
|
+
export {
|
|
156
|
+
postgresProviders,
|
|
157
|
+
postgresRoleProviders,
|
|
158
|
+
postgresRoleRunnerProviders,
|
|
159
|
+
postgresRunnerProviders,
|
|
160
|
+
} 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,16 +1,53 @@
|
|
|
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';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
type PostgresConnectionConfig,
|
|
14
|
+
type PostgresRunnerConfig,
|
|
15
|
+
postgresConnection,
|
|
16
|
+
postgresRunnerConnection,
|
|
17
|
+
} from './connection.ts';
|
|
13
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';
|
|
14
22
|
|
|
23
|
+
// ⚠️ `Layer.provideMerge`, NEVER plain `Layer.provide`: the handlers' `withPg` reads
|
|
24
|
+
// `PostgresConnection` when the ENGINE later calls `read`/`reconcile`, and plain `provide`
|
|
25
|
+
// seals it away ("Service not found: Postgres.Connection" — measured for `caddyProviders`,
|
|
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`).
|
|
15
28
|
export const postgresProviders = (config: PostgresConnectionConfig) =>
|
|
16
|
-
|
|
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
|
+
);
|
|
34
|
+
|
|
35
|
+
/** The same providers over a command runner (`psql-executor.ts`) — for loopback-only clusters. */
|
|
36
|
+
export const postgresRunnerProviders = (config: PostgresRunnerConfig) =>
|
|
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
|
+
});
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
import * as Effect from 'effect/Effect';
|
|
3
|
+
import { postgresRunnerProviders } from './providers.ts';
|
|
4
|
+
import { postgresRunnerConnection, withPg } from './connection.ts';
|
|
5
|
+
import { reconcileWithClient } from './database.ts';
|
|
6
|
+
import { buildCreateDatabaseSql, isDuplicateDatabaseRace } from './database-sql.ts';
|
|
7
|
+
import { buildSetPasswordSql } from './role-sql.ts';
|
|
8
|
+
import { scramSha256Verifier } from './role-scram.ts';
|
|
9
|
+
import { type PsqlRunner, inlineParams, makePsqlExecutor } from './psql-executor.ts';
|
|
10
|
+
|
|
11
|
+
const target = { database: 'postgres', username: 'postgres' };
|
|
12
|
+
const ok = (stdout: string) => Promise.resolve({ code: 0, stdout, stderr: '' });
|
|
13
|
+
|
|
14
|
+
describe('psql executor', () => {
|
|
15
|
+
test('inlines string params as literals and refuses non-strings', () => {
|
|
16
|
+
expect(inlineParams('SELECT $1, $2', ["it's", 'b'])).toBe("SELECT E'it''s', E'b'");
|
|
17
|
+
expect(() => inlineParams('SELECT $1', [5])).toThrow('must be a string');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('a SELECT is wrapped in json_agg and parsed to rows', async () => {
|
|
21
|
+
const calls: { argv: readonly string[]; stdin: string }[] = [];
|
|
22
|
+
const run: PsqlRunner = (call) => {
|
|
23
|
+
calls.push(call);
|
|
24
|
+
return ok('[{"oid":"16400","name":"x"}]\n');
|
|
25
|
+
};
|
|
26
|
+
const rows = await Effect.runPromise(
|
|
27
|
+
makePsqlExecutor(run, target).unsafe('SELECT 1 FROM pg_database WHERE datname = $1', ['x']),
|
|
28
|
+
);
|
|
29
|
+
expect(rows).toEqual([{ oid: 16400, name: 'x' }]);
|
|
30
|
+
expect(calls[0]?.argv.slice(0, 1)).toEqual(['psql']);
|
|
31
|
+
expect(calls[0]?.stdin).toContain('json_agg');
|
|
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');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('a duplicate-database failure stays recognisable as the 42P04 race', async () => {
|
|
53
|
+
const run: PsqlRunner = () =>
|
|
54
|
+
Promise.resolve({
|
|
55
|
+
code: 3,
|
|
56
|
+
stdout: '',
|
|
57
|
+
stderr: 'ERROR: 42P04: database "x" already exists\n',
|
|
58
|
+
});
|
|
59
|
+
const error = await Effect.runPromise(
|
|
60
|
+
Effect.flip(makePsqlExecutor(run, target).unsafe('CREATE DATABASE "x"')),
|
|
61
|
+
);
|
|
62
|
+
expect(isDuplicateDatabaseRace(error)).toBe(true);
|
|
63
|
+
});
|
|
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
|
+
|
|
90
|
+
test('a runner that never reached psql is a ConnectionError', async () => {
|
|
91
|
+
const run: PsqlRunner = () =>
|
|
92
|
+
Promise.resolve({ code: 255, stdout: '', stderr: 'ssh: refused' });
|
|
93
|
+
const error = await Effect.runPromise(
|
|
94
|
+
Effect.flip(makePsqlExecutor(run, target).unsafe('SELECT 1')),
|
|
95
|
+
);
|
|
96
|
+
expect(error.reason._tag).toBe('ConnectionError');
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('runner transport through withPg', () => {
|
|
101
|
+
test('create uses template0 by default and the same adopt path on an existing row', async () => {
|
|
102
|
+
const stdins: string[] = [];
|
|
103
|
+
const row = {
|
|
104
|
+
oid: 1,
|
|
105
|
+
name: 'lite',
|
|
106
|
+
owner: 'litellm',
|
|
107
|
+
encoding: 'UTF8',
|
|
108
|
+
localeProvider: 'libc',
|
|
109
|
+
collate: 'C',
|
|
110
|
+
ctype: 'C',
|
|
111
|
+
allowConnections: true,
|
|
112
|
+
connectionLimit: -1,
|
|
113
|
+
isTemplate: false,
|
|
114
|
+
tablespace: 'pg_default',
|
|
115
|
+
};
|
|
116
|
+
let created = false;
|
|
117
|
+
const run: PsqlRunner = ({ stdin }) => {
|
|
118
|
+
stdins.push(stdin);
|
|
119
|
+
if (stdin.includes('pg_roles')) return ok('[{"present":1}]');
|
|
120
|
+
if (stdin.includes('FROM pg_database')) return ok(created ? JSON.stringify([row]) : '[]');
|
|
121
|
+
if (stdin.startsWith('CREATE DATABASE')) created = true;
|
|
122
|
+
return ok('');
|
|
123
|
+
};
|
|
124
|
+
const layer = postgresRunnerConnection({ run, ...target });
|
|
125
|
+
const props = { name: 'lite', owner: 'litellm' };
|
|
126
|
+
const attrs = await Effect.runPromise(
|
|
127
|
+
withPg((pg, ctx) => reconcileWithClient(pg, props, ctx.template)).pipe(Effect.provide(layer)),
|
|
128
|
+
);
|
|
129
|
+
expect(attrs.name).toBe('lite');
|
|
130
|
+
expect(stdins.find((s) => s.startsWith('CREATE DATABASE'))).toBe(
|
|
131
|
+
`${buildCreateDatabaseSql(props, 'template0')};`,
|
|
132
|
+
);
|
|
133
|
+
expect(stdins.find((s) => s.startsWith('CREATE DATABASE'))).toContain('TEMPLATE "template0"');
|
|
134
|
+
const before = stdins.length;
|
|
135
|
+
await Effect.runPromise(
|
|
136
|
+
withPg((pg, ctx) => reconcileWithClient(pg, props, ctx.template)).pipe(Effect.provide(layer)),
|
|
137
|
+
);
|
|
138
|
+
expect(stdins.slice(before).some((s) => s.startsWith('CREATE DATABASE'))).toBe(false);
|
|
139
|
+
});
|
|
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
|
+
|
|
158
|
+
test("postgresRunnerProviders keeps the connection live for the engine's later handler calls", async () => {
|
|
159
|
+
const run: PsqlRunner = () => ok('[]');
|
|
160
|
+
const rows = await Effect.runPromise(
|
|
161
|
+
withPg((pg) => pg.unsafe('SELECT 1')).pipe(
|
|
162
|
+
Effect.provide(postgresRunnerProviders({ run, ...target })),
|
|
163
|
+
),
|
|
164
|
+
);
|
|
165
|
+
expect(rows).toEqual([]);
|
|
166
|
+
});
|
|
167
|
+
});
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `PgExecutor` that runs SQL through a caller-supplied command runner instead of a socket.
|
|
3
|
+
*
|
|
4
|
+
* For a host whose Postgres listens on loopback only inside a container (CT100: rootful podman
|
|
5
|
+
* container `postgres`, local socket, user `postgres`, no password): the consumer's runner is
|
|
6
|
+
* `ssh <host> sudo -n podman exec -i postgres <argv…>`, and this file only builds the `psql`
|
|
7
|
+
* argv and stdin and parses the answer.
|
|
8
|
+
*
|
|
9
|
+
* ⛔ NO ESTATE VALUE LIVES HERE (public kit). The ssh destination, container name and sudo
|
|
10
|
+
* allowlist are the runner's, in the consuming stack.
|
|
11
|
+
* ⛔ `psql` HAS NO BIND PARAMETERS OVER STDIN. Every `$n` is replaced by a `quoteStringLiteral`
|
|
12
|
+
* literal, and ONLY string params are accepted — this family binds a database or role name,
|
|
13
|
+
* nothing else — so a number or object is a refusal, never silently stringified.
|
|
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).
|
|
17
|
+
* ★ `VERBOSITY=verbose` puts the SQLSTATE in the error line, so `42P04` (duplicate database)
|
|
18
|
+
* stays recognisable to `isDuplicateDatabaseRace`.
|
|
19
|
+
*/
|
|
20
|
+
import * as Effect from 'effect/Effect';
|
|
21
|
+
import {
|
|
22
|
+
ConnectionError,
|
|
23
|
+
SqlError,
|
|
24
|
+
SqlSyntaxError,
|
|
25
|
+
UnknownError,
|
|
26
|
+
} from 'effect/unstable/sql/SqlError';
|
|
27
|
+
import { type PgExecutor, quoteStringLiteral } from './database-sql.ts';
|
|
28
|
+
|
|
29
|
+
export interface PsqlResult {
|
|
30
|
+
readonly code: number;
|
|
31
|
+
readonly stdout: string;
|
|
32
|
+
readonly stderr: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Runs one `psql` argv (starting with `psql`) with `stdin` and answers its exit. The consumer's
|
|
36
|
+
* implementation prepends the transport (`ssh … sudo -n podman exec -i <container>`) and owns
|
|
37
|
+
* the timeout and output bound: the kit sets neither. */
|
|
38
|
+
export type PsqlRunner = (call: {
|
|
39
|
+
readonly argv: readonly string[];
|
|
40
|
+
readonly stdin: string;
|
|
41
|
+
}) => Promise<PsqlResult>;
|
|
42
|
+
|
|
43
|
+
export interface PsqlTarget {
|
|
44
|
+
readonly database: string;
|
|
45
|
+
readonly username: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Replace `$1…$n` with string literals; refuses a non-string param or a missing one. */
|
|
49
|
+
export const inlineParams = (sql: string, params: ReadonlyArray<unknown>): string =>
|
|
50
|
+
params.length === 0
|
|
51
|
+
? sql
|
|
52
|
+
: sql.replace(/\$(\d+)/g, (_match, index: string) => {
|
|
53
|
+
const value = params[Number(index) - 1];
|
|
54
|
+
if (typeof value !== 'string') {
|
|
55
|
+
throw new Error(`psql executor: param $${index} must be a string, got ${typeof value}`);
|
|
56
|
+
}
|
|
57
|
+
return quoteStringLiteral(value);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
/** Postgres `to_json` emits the `oid` type as a string; the socket driver returns a number. */
|
|
61
|
+
const normalizeRow = (row: unknown): unknown =>
|
|
62
|
+
typeof row === 'object' && row !== null && typeof (row as { oid?: unknown }).oid === 'string'
|
|
63
|
+
? { ...row, oid: Number((row as { oid: string }).oid) }
|
|
64
|
+
: row;
|
|
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);
|
|
70
|
+
|
|
71
|
+
const wrapRows = (sql: string): string =>
|
|
72
|
+
`SELECT coalesce(json_agg(t), '[]'::json)::text FROM (${sql}) t;`;
|
|
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
|
+
|
|
83
|
+
const failure = (operation: string, result: PsqlResult): SqlError => {
|
|
84
|
+
const state = /ERROR:\s+([0-9A-Z]{5}):/.exec(result.stderr)?.[1];
|
|
85
|
+
const stderr = redactPasswordLiterals(result.stderr.trim());
|
|
86
|
+
const fields = {
|
|
87
|
+
cause: Object.assign(new Error(stderr), state === undefined ? {} : { code: state }),
|
|
88
|
+
message: stderr,
|
|
89
|
+
operation: redactPasswordLiterals(operation),
|
|
90
|
+
};
|
|
91
|
+
const reason =
|
|
92
|
+
state === undefined
|
|
93
|
+
? new ConnectionError(fields)
|
|
94
|
+
: state.startsWith('42')
|
|
95
|
+
? new SqlSyntaxError(fields)
|
|
96
|
+
: new UnknownError(fields);
|
|
97
|
+
return new SqlError({ reason });
|
|
98
|
+
};
|
|
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
|
+
|
|
136
|
+
export const makePsqlExecutor = (run: PsqlRunner, target: PsqlTarget): PgExecutor => ({
|
|
137
|
+
unsafe: <A extends object>(sql: string, params: ReadonlyArray<unknown> = []) =>
|
|
138
|
+
Effect.gen(function* () {
|
|
139
|
+
const inlined = yield* Effect.try({
|
|
140
|
+
try: () => inlineParams(sql, params),
|
|
141
|
+
catch: (cause) =>
|
|
142
|
+
new SqlError({ reason: new UnknownError({ cause, operation: 'psql inline params' }) }),
|
|
143
|
+
});
|
|
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
|
+
);
|
|
151
|
+
if (!rows) return [] as ReadonlyArray<A>;
|
|
152
|
+
const parsed = yield* Effect.try({
|
|
153
|
+
try: () => (JSON.parse(result.stdout.trim() || '[]') as unknown[]).map(normalizeRow),
|
|
154
|
+
catch: (cause) =>
|
|
155
|
+
new SqlError({ reason: new UnknownError({ cause, operation: 'psql parse output' }) }),
|
|
156
|
+
});
|
|
157
|
+
return parsed as ReadonlyArray<A>;
|
|
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
|
+
}),
|
|
170
|
+
});
|