Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion .github/workflows/nuke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ on:
description: "Eas"
type: boolean
default: false
resend:
description: "Resend"
type: boolean
default: false

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
Expand Down Expand Up @@ -98,7 +102,8 @@ jobs:
&& "${{ inputs.stripe }}" != "true" \
&& "${{ inputs.supabase }}" != "true" \
&& "${{ inputs.turso }}" != "true" \
&& "${{ inputs.workos }}" != "true" ]]; then
&& "${{ inputs.workos }}" != "true" \
&& "${{ inputs.resend }}" != "true" ]]; then
echo "::error::You must select at least one SDK to nuke (or choose 'all')"
exit 1
fi
Expand Down Expand Up @@ -321,3 +326,22 @@ jobs:
# runs-on: ubuntu-latest
# steps:
# - TODO: no nuke script yet — run `bun run generate-nuke turso`

# ── Resend ──
nuke-resend:
needs: gate
if: needs.gate.outputs.run == 'true' && (github.event_name == 'merge_group' || inputs.all || inputs.resend)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun install --frozen-lockfile
- run: bun run build
working-directory: packages/core
- name: Run nuke script
run: bun scripts/nuke.ts
working-directory: packages/resend
env:
RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}
1 change: 1 addition & 0 deletions .github/workflows/pr-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
{ "dir": "packages/planetscale", "name": "@distilled.cloud/planetscale", "install": "planetscale" },
{ "dir": "packages/posthog", "name": "@distilled.cloud/posthog", "install": "posthog" },
{ "dir": "packages/prisma-postgres", "name": "@distilled.cloud/prisma-postgres", "install": "prisma-postgres" },
{ "dir": "packages/resend", "name": "@distilled.cloud/resend", "install": "resend" },
{ "dir": "packages/stripe", "name": "@distilled.cloud/stripe", "install": "stripe" },
{ "dir": "packages/supabase", "name": "@distilled.cloud/supabase", "install": "supabase" },
{ "dir": "packages/turso", "name": "@distilled.cloud/turso", "install": "turso" },
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ jobs:
{ "dir": "packages/planetscale", "name": "@distilled.cloud/planetscale" },
{ "dir": "packages/posthog", "name": "@distilled.cloud/posthog" },
{ "dir": "packages/prisma-postgres", "name": "@distilled.cloud/prisma-postgres" },
{ "dir": "packages/resend", "name": "@distilled.cloud/resend" },
{ "dir": "packages/stripe", "name": "@distilled.cloud/stripe" },
{ "dir": "packages/supabase", "name": "@distilled.cloud/supabase" },
{ "dir": "packages/turso", "name": "@distilled.cloud/turso" },
Expand Down
24 changes: 24 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ jobs:
typesense: ${{ steps.force.outputs.all || steps.changes.outputs.typesense }}
workos: ${{ steps.force.outputs.all || steps.changes.outputs.workos }}
expo-eas: ${{ steps.force.outputs.all || steps.changes.outputs.expo-eas }}
resend: ${{ steps.force.outputs.all || steps.changes.outputs.resend }}
steps:
- id: force
if: contains(github.event.pull_request.labels.*.name, 'force-ci')
Expand Down Expand Up @@ -110,6 +111,9 @@ jobs:
expo-eas:
- 'packages/expo-eas/**'
- 'packages/core/**'
resend:
- 'packages/resend/**'
- 'packages/core/**'

ci-core:
needs: detect-changes
Expand Down Expand Up @@ -494,3 +498,23 @@ jobs:
working-directory: packages/expo-eas
env:
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}

ci-resend:
needs: detect-changes
if: needs.detect-changes.outputs.resend == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun install
- run: bun run build
working-directory: packages/core
- run: bun run check
working-directory: packages/resend
- run: bun run test
working-directory: packages/resend
env:
RESEND_API_BASE_URL: ${{ secrets.RESEND_API_BASE_URL }}
RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}
5 changes: 5 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,8 @@
shallow = true
ignore = dirty
fetchRecurseSubmodules = false
[submodule "packages/resend/specs/resend-openapi"]
path = packages/resend/specs/resend-openapi
url = https://github.com/resend/resend-openapi.git
shallow = true
ignore = dirty
60 changes: 40 additions & 20 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

71 changes: 71 additions & 0 deletions packages/resend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# @distilled.cloud/resend

Effect-native Resend SDK generated from the [Resend OpenAPI specification](https://github.com/resend/resend-openapi). Send transactional and broadcast email, manage domains, audiences, contacts, templates, webhooks, and more — with exhaustive error typing.

## Installation

```bash
npm install @distilled.cloud/resend effect
```

## Quick Start

```typescript
import { Effect, Layer } from "effect";
import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient";
import { listEmails } from "@distilled.cloud/resend/Operations";
import { CredentialsFromEnv } from "@distilled.cloud/resend";

const program = Effect.gen(function* () {
const emails = yield* listEmails({ limit: 20 });
return emails.data ?? [];
});

const ResendLive = Layer.mergeAll(FetchHttpClient.layer, CredentialsFromEnv);

program.pipe(Effect.provide(ResendLive), Effect.runPromise);
```

## Configuration

Set the following environment variable:

```bash
RESEND_API_KEY=re_your_api_key
```

Create an API key in the [Resend dashboard](https://resend.com/api-keys) under **API Keys**.

`RESEND_API_BASE_URL` is also recognized and overrides the default `https://api.resend.com` for self-hosted or proxied deployments.

## Error Handling

```typescript
import { Effect } from "effect";
import { getEmail } from "@distilled.cloud/resend/Operations";

getEmail({ email_id: "missing" }).pipe(
Effect.catchTags({
NotFound: () => Effect.succeed(null),
UnknownResendError: (e) => Effect.fail(new Error(`Unknown: ${e.message}`)),
}),
);
```

## Services

- **Emails** — `createEmail`, `listEmails`, `getEmail`, `updateEmail`, `cancelEmail`, `batchEmail`, plus receiving / attachment operations
- **Domains** — `createDomain`, `listDomains`, `getDomain`, `updateDomain`, `deleteDomain`, `verifyDomain`
- **API Keys** — `createApiKey`, `listApiKeys`, `deleteApiKey`
- **Audiences / Segments / Topics** — list / create / get / update / delete operations for each
- **Contacts** — `createContact`, `listContacts`, `getContact`, `updateContact`, `deleteContact`, contact imports and contact-property operations
- **Templates** — `createTemplate`, `listTemplates`, `getTemplate`, `updateTemplate`, `deleteTemplate`, `publishTemplate`, `duplicateTemplate`
- **Broadcasts** — `createBroadcast`, `listBroadcasts`, `getBroadcast`, `updateBroadcast`, `deleteBroadcast`, `sendBroadcast`
- **Webhooks** — `createWebhook`, `listWebhooks`, `getWebhook`, `updateWebhook`, `deleteWebhook`
- **Automations** — `createAutomation`, `listAutomations`, `getAutomation`, `updateAutomation`, `deleteAutomation`, `stopAutomation`, `listAutomationRuns`, `getAutomationRun`
- **Events** — `createEvent`, `sendEvent`, `listEvents`, `getEvent`, `updateEvent`, `deleteEvent`
- **Logs** — `listLogs`, `getLog`

## License

MIT
Loading