Getting started

Changelog

Version history for envless-sdk, the Ruby SDK.

Version history for envless-sdk, the Ruby client for the Envless API, published on RubyGems. Pin it for the latest coverage, security patches and type fixes. When a newer version is out, the client says so once on a terminal, with a link to this page.

The TypeScript SDK, @goenvless/sdk, has its own changelog, and so does the Python SDK. They cover the same API, and a change to one lands in the others.

Unreleased

Next release

Each list method takes only the options its route reads. An option the API ignored is now an ArgumentError for an unknown keyword instead of a silent no-op, so drop it from the call.

  • workspaces.list and products.access.list take limit: and offset:; products.list, products.list_projects, keys.list and webhooks.list add search: and order:; projects.list and environments.list add product: as well
  • variables.list, variables.list_history, versions.list and versions.list_entries take limit:, offset: and product:; invites.list takes search:; webhooks.list_deliveries takes status:. The list_all and iterate forms follow their list
  • New: members.list(role_id:) keeps only the members holding one role, and roles.list(sort_by:) orders by name, updated or created
  • variables.get_by_id, variables.update_by_id, variables.delete_by_id, versions.get and versions.rollback no longer take product:, which their routes never read
  • variables.create, create_many, update and update_by_id accept isSecret:, and an updates entry passed to variables.apply may carry name: to rename the variable in the same transaction

Initial release. The Ruby twin of the TypeScript SDK, covering 100% of the public HTTP API: all 113 methods across 13 namespaces, under their TypeScript names in snake_case. A parity check replays every method against the requests the TypeScript SDK records, with no options, with every option set and with the body passed as keywords, and fails the build on any difference in the request, the retries, the errors or the result.

Client

  • Envless::Client.new with a reader for every namespace: me, workspace (with workspace.domain), workspaces, products (with products.access), projects, environments, variables, versions, members, invites, roles, keys, webhooks
  • Envless.variables and every other namespace reach a shared client built from ENVLESS_TOKEN and ENVLESS_API_ENDPOINT the first time one is touched, and Envless.init(...) configures it once at startup. Envless.client returns it and Envless.reset_client drops it
  • A request body goes in as keyword arguments or as one Hash, keyed by the API's own field names, and every result is a Hash with Symbol keys. Options are snake_case keywords: product:, limit:, offset:, search:, order:, status:, reattempt:, and timeout: on every method
  • client.raw.request(path, method:, query:, body:) reaches an endpoint no method wraps yet, with the client's key, base URL, timeout and retries
  • Bring your own adapter:, anything that responds to call(request), for a different HTTP library or for tests. Redirects, retries and the deadline stay in the client
  • A client is frozen once built, safe to share between threads, and keeps a pool of kept-alive connections that it rebuilds after a fork

Pagination

  • Every collection has list for one page as an Envless::Page, list_all for everything as an Array, and iterate, which yields to a block or returns a lazy Enumerator
  • Secondary collections get their own trio: products.list_projects, products.access.list, variables.list_history, versions.list_entries, webhooks.list_deliveries, each with list_all_* and iterate_* forms
  • The walk ends on hasMore being false or an empty page, and advances by the items actually received

Errors

  • Envless::ApiError carries the stable code plus status, message, resource, field, request_id and retry_after_seconds, with predicates for the common branches: auth?, scope_missing?, validation?, needs_upgrade?, not_found?, conflict?, rate_limited?
  • Envless::NetworkError for transport failures, with timeout? when the deadline passed. Envless::DecryptionError and Envless::WebhookVerificationError for the crypto and webhook helpers. All of them inherit Envless::Error, and a mistake in the call itself raises ArgumentError before anything is sent
  • GET, HEAD, PUT and DELETE are retried on 408, 429, 500, 502, 503 and 504 with exponential backoff capped at 30 seconds, honouring Retry-After. POST and PATCH are never retried
  • timeout is a hard deadline for each attempt, redirects and the response body included. 0 turns it off
  • A variable name is checked before anything is sent, and an unusable one raises the same Envless::ApiError the API would, with request_id set to nil

Encryption

  • encrypt_value and decrypt_value, byte-for-byte compatible with the TypeScript and Python SDKs, the CLI, the dashboard and @goenvless/env: AES-256-GCM under a PBKDF2-SHA-256 key with 200,000 iterations and the workspace salt. v1: and v2:<iterations>: envelopes both decrypt
  • derive_workspace_key and import_workspace_key return an Envless::WorkspaceKey that never prints its bytes, for encrypt_with_key and decrypt_with_key across a batch
  • ciphertext?, passphrase_strength, variable_name_validation and ENCRYPTION_PARAMETERS
  • rotate_workspace_passphrase(client:, ...) re-encrypts an environment's live variables and its version history, and lists in failures any version entry whose encrypted default cannot be rewritten because the entry's own value is not ciphertext
  • Plaintext, passphrases and workspace ids must be valid UTF-8, and a raw key goes in only as 32 binary bytes, so binary data or a passphrase passed by mistake raises ArgumentError instead of producing ciphertext nothing else can read

Webhooks

  • verify_webhook_signature(payload:, headers:, secret:) checks the HMAC-SHA256 signature in constant time and the timestamp drift, then returns the parsed event. It takes the raw body and headers from a Hash in any case, a Rack env or Rails' request.headers

Runtime

  • Ruby 3.2 or newer, with no runtime dependencies: Net::HTTP and OpenSSL from the standard library
  • RBS signatures for every method, body and response, with a manifest that declares the standard libraries they use, so library "envless-sdk" in a Steepfile is all a project needs
  • Every request carries User-Agent: envless-sdk-ruby/0.0.1