require "envless/sdk" loads one module, Envless. Everything below is a module function, a class or a constant on it, and the types are RBS aliases in the signatures the gem ships.
Clients
| Export | Signature |
|---|---|
Envless::Client.new | (token = nil, token: nil, base_url: nil, adapter: nil, max_retries: nil, timeout: nil, user_agent: nil, disable_update_notice: false) |
Envless.new | The same arguments, returning an Envless::Client |
Envless.create_client | The same, under the TypeScript name |
Envless.init | The same arguments. Installs the shared client and returns it |
Envless.client | () -> Envless::Client, the shared client, built from the environment on first use |
Envless.reset_client | () -> nil |
Envless.me, Envless.variables and the rest | Every namespace, on the shared client |
Every client reads ENVLESS_TOKEN and ENVLESS_API_ENDPOINT for the arguments you leave out. See Create a client.
require "envless/sdk"
Envless.init(timeout: 10)
Envless.products.listCrypto
| Export | Signature |
|---|---|
Envless.encrypt_value | (String plaintext, String passphrase, String workspace_unique_id) -> String |
Envless.decrypt_value | (String ciphertext, String passphrase, String workspace_unique_id) -> String |
Envless.encrypt_with_key | (WorkspaceKey | String key, String plaintext) -> String |
Envless.decrypt_with_key | (WorkspaceKey | String key, String ciphertext) -> String |
Envless.derive_workspace_key | (String passphrase, String workspace_unique_id) -> WorkspaceKey |
Envless.import_workspace_key | (String key) -> WorkspaceKey |
Envless.ciphertext? | (untyped value) -> bool |
Envless.passphrase_strength | (untyped passphrase) -> Validation |
Envless::WorkspaceKey | A derived or imported AES-256 key that prints as #<Envless::WorkspaceKey [redacted]> |
Envless::ENCRYPTION_PARAMETERS | The exact cryptographic constants, as a frozen Hash |
They are plain synchronous calls: encryption is CPU work. See Encryption for the recipe and for why you should derive the key once when writing a batch.
Helpers
| Export | Signature |
|---|---|
Envless.rotate_workspace_passphrase | (client:, workspace_unique_id:, from:, to:, project:, environment:, product: nil) -> RotationResult |
Envless.verify_webhook_signature | (payload:, headers:, secret:, tolerance_seconds: nil) -> webhook_event[Hash[Symbol, untyped]] |
Envless.variable_name_validation | (untyped name) -> Validation |
rotate_workspace_passphrase re-encrypts live variables and version history for one environment, which is the part that is easy to forget. verify_webhook_signature is the receiver side of Webhooks. variable_name_validation returns an Envless::Validation without raising, for checking a name in your own form or importer against the rule every write applies before it sends anything.
require "envless/sdk"
check = Envless.variable_name_validation("1_PASSWORD")
puts check.error unless check.valid?Exceptions
| Export | Notes |
|---|---|
Envless::Error | The base of every exception below, a StandardError. |
Envless::ApiError | The API answered with a failure. Carries status, code, message, resource, field, request_id, retry_after_seconds. |
Envless::NetworkError | Nothing came back: connection failure or timeout. Carries message, timeout? and the cause. |
Envless::DecryptionError | A value does not decrypt. |
Envless::WebhookVerificationError | A delivery fails verification. |
A mistake in the call itself raises Ruby's own ArgumentError. See Errors.
Results
| Export | Members |
|---|---|
Envless::Page | items, pagination, has_more?, total_count |
Envless::ProductAccessPage | The same, plus is_private and private? |
Envless::Validation | valid, valid?, error |
Envless::RotationResult | variables, version_entries, skipped, failures |
Envless::RotationIssue | scope, id, field, reason |
Envless::HttpRequest | method, url, headers, body, timeout, what an adapter receives |
Envless::HttpResponse | status, headers, body, reason, what an adapter may return |
They are Data values, so they are immutable, compare by value and work with pattern matching. Everything else the SDK returns is a plain Hash with Symbol keys.
Constants
Enum-like values, so you never hard-code a string the API might reject. Each is a frozen Hash with Symbol keys, such as Envless::SCOPE_LEVELS[:READ].
| Export | Keys |
|---|---|
Envless::SCOPE_RESOURCES | WORKSPACE, PRODUCTS, PRODUCT_ACCESS, PROJECTS, ENVIRONMENTS, VARIABLES, VERSIONS, MEMBERS, ROLES, KEYS, WEBHOOKS |
Envless::SCOPE_LEVELS | NONE, READ, WRITE |
Envless::VARIABLE_TYPE | STRING, NUMBER, BOOLEAN |
Envless::VARIABLE_VISIBILITY_LEVELS | SERVER, CLIENT |
Envless::WEBHOOK_SIGNATURE_HEADERS | ID, TIMESTAMP, SIGNATURE, EVENT, DELIVERY |
Envless::PAGE_LIMITS | MAX_LIMIT is 100, DEFAULT_LIMIT is 25 |
Envless::VERSION | The gem version, a String |
require "envless/sdk"
resources = Envless::SCOPE_RESOURCES
read = Envless::SCOPE_LEVELS[:READ]
Envless.keys.create(
name: "ci",
scopes: {
resources[:VARIABLES] => read,
resources[:VERSIONS] => read
}
)
passphrase = ENV.fetch("ENVLESS_PASSPHRASE")
workspace_id = Envless.me.get[:workspaceId]
url = Envless.encrypt_value("https://api.acme.com", passphrase,
workspace_id)
Envless.variables.create("web", "production",
name: "NEXT_PUBLIC_API_URL",
value: url,
visibility: Envless::VARIABLE_VISIBILITY_LEVELS[:CLIENT])Types
The gem ships RBS signatures in sig/, and every request body and every response has a type alias under Envless, named after its TypeScript twin in snake_case: VariableResource is Envless::variable_resource. They describe plain Hashes, so they cost nothing at runtime. Point Steep at the installed gem's signatures and it checks every key you send and read.
target :app do
check "app"
signature "sig"
library "envless-sdk"
endPages and pagination
Envless::Page[T], Envless::ProductAccessPage, pagination_envelope
Resources
identity_resource, user_summary, role_summary, actor_reference, actor_key_reference, workspace_resource, current_workspace_resource, updated_workspace_resource, deleted_workspace_resource, custom_domain_resource, custom_domain_record, removed_domain_resource, product_resource, deleted_product_resource, product_access_entry, granted_product_access_resource, revoked_product_access_resource, project_resource, deleted_project_resource, environment_resource, environment_summary_resource, deleted_environment_resource, variable_resource, deleted_variable_resource, deleted_variables_resource, created_variables_resource, variable_history_event, version_resource, version_detail_resource, version_entry_resource, rolled_back_version_resource, reencrypted_entries_resource, member_resource, deleted_member_resource, left_workspace_resource, invite_resource, revoked_invite_resource, role_resource, deleted_role_resource, permission_resource, permissions_resource, key_resource, created_key_resource, deleted_key_resource, webhook_resource, created_webhook_resource, deleted_webhook_resource, rotated_secret_resource, webhook_delivery_resource, webhook_delivery_detail_resource, redelivered_webhook_resource, event_types_resource
Inputs
workspace_create, workspace_patch, product_create, product_patch, project_create, project_patch, environment_create, environment_patch, variable_input, variable_patch, version_create, member_invite, member_patch, role_create, role_patch, key_create, key_patch, webhook_create, webhook_patch, apply_changes, apply_baseline_entry, apply_update_entry, apply_result, reencrypt_entry_input
Crypto and webhooks
encryption_parameters, webhook_event[T], plus the Envless::Validation, Envless::RotationResult and Envless::RotationIssue classes
A method that takes a body accepts the record type or any Hash[Symbol | String, untyped], so a Hash you build at runtime still type-checks, while a literal is checked key by key. Options are keywords rather than types, so there is no ListOptions or RequestScope in Ruby.
Read shapes are not always the write shapes. environments.get returns environment_summary_resource, while environments.update returns the full environment_resource. The method pages call these out individually.
A worked example
require "envless/sdk"
passphrase = ENV.fetch("ENVLESS_PASSPHRASE")
workspace_id = Envless.me.get[:workspaceId]
key = Envless.derive_workspace_key(passphrase, workspace_id)
product = Envless.products.create(name: "Internal tools",
slug: "internal-tools")
slug = product[:slug]
project = Envless.projects.create(name: "API", slug: "api",
product: slug)
%w[development staging production].each do |name|
Envless.environments.create(project[:slug], name:, slug: name,
product: slug)
end
database_url = ENV.fetch("DATABASE_URL")
Envless.variables.create_many("api", "production", [
{name: "DATABASE_URL",
value: Envless.encrypt_with_key(key, database_url)},
{name: "PORT", value: Envless.encrypt_with_key(key, "3000"),
type: "number"}
], product: slug)
Envless.versions.create("api", "production",
note: "Initial provisioning", product: slug)
runner = Envless.keys.create(
name: "api-runner",
scopes: {variables: Envless::SCOPE_LEVELS[:READ]},
projectIds: [project[:id]]
)
puts runner[:secret]