distilled.cloud

Effect-native SDKs for cloud providers

Tagged errors. Retry policies. Streaming pagination.

import * as S3 from "distilled-aws/s3"

const bucket = yield* S3.getBucket({
  Bucket: "my-bucket"
}).pipe(
  Effect.catchTag("NoSuchBucket", () =>
    Effect.void
  )
)

SDKs

Effect-native clients for major cloud providers, with tagged errors and tree-shakeable imports.

AWS

distilled-aws

Complete AWS SDK with typed errors for S3, Lambda, DynamoDB, SQS, and 200+ services. Every API includes documented and undocumented error codes.

distilled-cloudflare

Cloudflare API client for Workers, R2, KV, D1, Queues, and more. Patched OpenAPI spec with complete error coverage.

distilled-planetscale

PlanetScale MySQL serverless database client. Type-safe queries with proper connection and query error handling.

distilled-neonComing Soon

Neon serverless Postgres client. Branching, autoscaling, and type-safe database operations with complete error coverage.

distilled-azureComing Soon

Azure cloud services SDK. Blob Storage, Functions, Cosmos DB, and more with tagged errors.

distilled-gcpComing Soon

Google Cloud Platform SDK. Cloud Storage, Cloud Functions, BigQuery, and Firestore with typed error handling.

The Problem

Cloud APIs are notoriously under-documented

Every cloud provider ships incomplete specs. Errors are discovered at runtime, not compile time.

Missing Error Codes

APIs return cryptic error codes that aren't in the documentation. You only discover them in production.

Incomplete Specs

OpenAPI and Smithy specs are missing properties, wrong types, or outdated. The docs lie.

Runtime Surprises

Errors you can't catch because they're not in the types. Your "exhaustive" switch statement isn't.

Bundle Bloat

Import one function, bundle hundreds. Class-based SDKs can't tree-shake.

Why distilled?

Effect-native cloud SDKs for modern TypeScript

Tagged Errors

Every API operation has properly typed, discriminated error unions. No more guessing what went wrong.

  • Specs patched to include undocumented errors
  • Exhaustive error handling with catchTag
  • IDE autocomplete for all error tags
const bucket = yield* S3.getBucket({
  Bucket: "my-bucket"
}).pipe(
  Effect.catchTag("NoSuchBucket", () =>
    Effect.succeed(null)
  ),
  Effect.catchTag("AccessDenied", () =>
    Effect.fail(new AuthError())
  )
)

Retry Policies

Declarative, composable retry logic with type-safe schedules. Handle transient failures without callback hell.

  • Exponential backoff, jitter, and more
  • Retry only on specific error tags
  • Compose schedules for complex policies
const result = yield* S3.getObject({
  Bucket: "my-bucket",
  Key: "data.json"
}).pipe(
  Effect.retry({
    while: (e) => e._tag === "SlowDown",
    schedule: Schedule.exponential("100 millis")
  }),
  Effect.timeout("5 seconds")
)

Streaming Pagination

Paginated APIs return Effect Streams. No manual token juggling—just iterate.

  • .pages() streams full response objects
  • .items() streams individual items
  • Lazy evaluation—fetch only what you need
// Stream all pages
yield* S3.listObjectsV2
  .pages({ Bucket: "my-bucket" })
  .pipe(Stream.runForEach(Console.log))

// Or stream individual items
yield* DynamoDB.scan
  .items({ TableName: "users" })
  .pipe(Stream.runCollect)

Streaming I/O

Upload and download with Effect Streams. Process data as it flows without buffering entire payloads.

  • Stream<Uint8Array> for uploads and downloads
  • Composable with all Stream operators
  • Backpressure handled automatically
// Upload a stream
yield* S3.putObject({
  Bucket: "my-bucket",
  Key: "large-file.bin",
  Body: Stream.fromIterable(chunks),
})

// Download as a stream
const { Body } = yield* S3.getObject({ ... })
const text = yield* Body.pipe(
  Stream.decodeText(),
  Stream.mkString
)

Tree-Shakeable

No monolithic client classes. Import only what you need—your bundle stays lean.

  • Module-scoped functions, not class methods
  • Config via Effect Layers, not constructors
  • Perfect for serverless and edge runtimes
// Only bundles getBucket and createBucket
import * as S3 from "distilled-aws/s3"

// NOT this:
// import { S3Client } from "@aws-sdk/client-s3"
// new S3Client() bundles ALL 100+ operations

The Mission

Documenting the world's APIs for AI

Type-safe, tagged error specs aren't just good for developers—they're essential for AI code generation.

distilled SDKs are built to power alchemy.run—next-generation Infrastructure-as-Code in native TypeScript. When AI generates infrastructure code, it needs to know every possible error and how to handle it.

Proper error tags mean sound, reliable tooling. No more hallucinated error handling. No more runtime surprises.

AI-Ready Specs
Exhaustive error unions
Typed request/response schemas
Patched and verified specs
Reliable code generation