All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Releases are cut with mix git_ops.release (or the Release workflow), which inserts new sections below this marker:

v0.2.0 - 2026-09-01

Production-hardening release: constant-memory transfer, structured bounded log streaming, response/rate-limit metadata, retry correctness, credential redaction, a completed security facade, and injectable streaming transports. No breaking changes to 0.1.0 call sites.

Added

  • Constant-memory file transfer: ExDaytona.FS.upload_stream/4, upload_file/4, download_stream/4, and download_file/4 — lazy multipart uploads from Enumerables/IO devices/files, consumer-driven downloads, max_bytes/idle/overall limits, caller cancellation, incremental SHA-256 with optional verification, and atomic temp-file-then-rename downloads that never clobber an existing destination. Existing small-file helpers unchanged (buffering now documented).
  • Structured log streaming: ExDaytona.LogStream + ExDaytona.Session.open_log_stream/3 — pull-based (next/2, collect/2), owner-monitored, bounded (buffer/frame caps with explicit overflow errors), with idle and overall timeouts and no silent reconnect. Decodes the provider's stdout/stderr channel-marker protocol into separate :stdout/:stderr events; daemons that stream unlabeled output (the production daemon at release time — verified live) yield merged {:output, bytes} events instead of dropping data. Session.stream_logs/4 remains as the documented merged-output HTTP path and gains :halt cancellation and a :deadline.
  • Response metadata: response: :full on every generated operation returns %ExDaytona.Response{} (status, normalized headers, request id, rate-limit state, parsed Retry-After, transport retry count). ExDaytona.Error carries the same fields on every facade error, plus an outcome (:definite | :unknown) that refuses to claim a definite result for non-idempotent requests lost in transport.
  • Security facade: Sandbox.create/2 now exposes every CreateSandbox field (domain_allow_list, vault secrets bindings, auto_pause_interval, gpu_type, spot, linked_sandbox, outbound_proxy_url, otel_endpoint_override); Sandbox.update_network_settings/2 for runtime policy; ExDaytona.Secrets (manage, bind, resolve — resolved values redacted under inspect); ExDaytona.Platform (regions, sandbox classes, snapshots, usage/quota).
  • Injectable streaming transports: ExDaytona.Transport behaviours for streaming HTTP and websockets, selected via Client.new(transports: [...]) and carried into every derived stream — built for deterministic failure simulation in tests.
  • Dedicated Finch pool (ExDaytona.Finch.Stream, tunable via :stream_pool_size/:stream_pool_count) isolates long-lived streams and bulk transfers from lifecycle/control requests.

Changed

  • Credential redaction everywhere: every generated model, the client, errors, and the new SSH/preview/storage result structs render credential-shaped fields as "[REDACTED]" under inspect/1; error details/headers are deep-sanitized; URLs in messages have signed query parameters scrubbed; telemetry no longer carries the Tesla client (and its embedded bearer token). Note: field-name matching intentionally over-redacts (e.g. pagination nextToken cursors render redacted).
  • Retries now forward jitter_factor and honor Retry-After on safe (idempotent) retries by default (use_retry_after_header: true, capped by max_delay); POSTs remain never auto-retried.
  • Sandbox.ssh_access/2, preview_url/2, signed_preview_url/3, and ObjectStorage.push_access/1 return dedicated structs with redacted inspection — pattern-matching on the previous map shapes continues to work.

Migration notes

  • No call-site changes required. If you pattern-matched telemetry metadata's env.__client__, it is now nil (credential hygiene).
  • If your handlers relied on retries NOT honoring Retry-After, pass retry: [use_retry_after_header: false].

v0.1.0 - 2026-08-31

Added

  • Initial SDK generated from Daytona's OpenAPI specifications (main platform, toolbox, and analytics APIs merged by scripts/fetch-spec.sh)
  • ExDaytona.Toolbox.connection/2 — builds a connection to a sandbox's toolbox API from its toolboxProxyUrl
  • ExDaytona.Analytics.connection/1 — builds a connection to the analytics API (base URL configurable via config :ex_daytona, :analytics_base_url)
  • High-level SDK facade (hand-written, survives regeneration): ExDaytona.Client (API-key auth, DAYTONA_API_KEY fallback), ExDaytona.Error (all generated-client failure shapes normalized to {:error, %ExDaytona.Error{}}), and ExDaytona.Sandbox (create/get/list/start/stop/delete with state waiting, exec/3, write_file/3, read_file/2, list_files/2)
  • ExDaytona.Session — persistent shell sessions with shared state: synchronous run/2, asynchronous run_async/2 + await/3, raw logs/2, and real-time stream_logs/4 (incremental chunked-HTTP streaming)
  • ExDaytona.Git — clone/status/branches/create_branch/checkout/add/ commit/push/pull/history inside a sandbox, with credential options for authenticated remotes
  • ExDaytona.Sandbox.build_logs/1 and stream_build_logs/3 — fetch or follow a building sandbox's build logs
  • ExDaytona.Pty — interactive terminals: create/resize/list/delete plus a real websocket connection (connect/2, send_input/2) built on the new ExDaytona.WebSocket client (Mint.WebSocket)
  • SSH access on the sandbox facade: ssh_access/2, revoke_ssh_access/1, validate_ssh_access/2
  • Preview URLs on the sandbox facade: preview_url/2, signed_preview_url/3, expire_signed_preview_url/3; plus ExDaytona.PreviewProxy verification helpers for running a custom preview proxy
  • ExDaytona.Webhooks — organization webhook setup (initialize, status, Svix app portal access, endpoint refresh) and verify/4 for receiving: Svix/Standard-Webhooks HMAC signature verification with timestamp tolerance
  • ExDaytona.Image — declarative image DSL (from/run/env/workdir/user/ label/expose/entrypoint/cmd + raw Dockerfiles) wired into ExDaytona.Sandbox.create(client, image: ...) for building sandboxes from Dockerfiles
  • ExDaytona.FS — the full file-system facade: write_file/read_file/ write_files, local upload/download, mkdir, stat, delete (recursive), move, chmod, glob search, content grep, and text replace with per-file results (the Sandbox file helpers delegate here)
  • ExDaytona.Sandbox.run_code/3 — stateless code snippets (Python/ JavaScript/TypeScript) with argv/env/timeout and chart artifacts
  • ExDaytona.CodeInterpreter — stateful Python execution over the interpreter websocket: state persists between run/3 calls, isolated contexts (create_context/list_contexts/delete_context), streaming on_stdout/on_stderr/on_error callbacks, and structured execution errors
  • ExDaytona.Session.send_input/3 (with a retry for the daemon's stdin-pipe startup race and a suppress_input_echo option on run_async/3), plus entrypoint/1 and entrypoint_logs/1
  • Local build contexts: ExDaytona.Image.add_local_file/3 and add_local_dir/3 copy local files into declaratively built images — contexts are content-hashed, tarred, and uploaded to Daytona's object storage automatically on create (ExDaytona.ObjectStorage), with a dependency-free AWS SigV4 signer pinned by AWS's published test vectors

Fixed

  • Request bodies no longer send explicit JSON nulls for unset optional model fields — the Daytona API rejects them (500) where an empty object succeeds; models now omit nil fields when encoding

Changed

  • Cleaned generated function names via a spec patch: analytics endpoints that ship without operationIds get descriptive ones (get_organization_usage_aggregated/5 instead of organization_organization_id_usage_aggregated_get/5), and leaked NestJS controller prefixes are stripped (Health.check/2 instead of Health.health_controller_check/2)