Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .changeset/mighty-dodos-study.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@trigger.dev/resend": patch
---

Upgrade resend integration to use resend-node 2.0.0
12 changes: 8 additions & 4 deletions docs/integrations/apis/resend.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ client.defineJob({
resend,
},
run: async (payload, io, ctx) => {
await io.resend.sendEmail("send-email", {
await io.resend.emails.send("send-email", {
to: payload.to,
subject: payload.subject,
text: payload.text,
Expand All @@ -79,6 +79,10 @@ client.defineJob({

## Tasks

| Function Name | Description |
| ------------- | ------------- |
| `sendEmail` | Send an email |
| Function Name | Description |
| --------------- | -------------------------------- |
| `emails.send` | Send an email |
| `emails.create` | Create an email |
| `emails.get` | Get an email |
| `batch.send` | Send a batch of emails at once |
| `batch.create` | Create a batch of emails at once |
6 changes: 3 additions & 3 deletions integrations/resend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
"dependencies": {
"@trigger.dev/integration-kit": "workspace:^2.2.4",
"@trigger.dev/sdk": "workspace:^2.2.4",
"resend": "^1.0.0"
"resend": "^2.0.0"
},
"engines": {
"node": ">=16.8.0"
"node": ">=18.0.0"
}
}
}
81 changes: 81 additions & 0 deletions integrations/resend/src/batch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { IntegrationTaskKey, retry } from "@trigger.dev/sdk";
import { Resend } from "resend";
import type { ResendRunTask } from "./index";
import { handleResendError } from "./utils";

type SendEmailResult = NonNullable<Awaited<ReturnType<Resend["batch"]["send"]>>["data"]>;
type CreateEmailResult = NonNullable<Awaited<ReturnType<Resend["batch"]["create"]>>["data"]>;

export class Batch {
constructor(private runTask: ResendRunTask) {}

send(
key: IntegrationTaskKey,
payload: Parameters<Resend["batch"]["send"]>[0],
options?: Parameters<Resend["batch"]["send"]>[1]
): Promise<SendEmailResult> {
return this.runTask(
key,
async (client, task) => {
const { error, data } = await client.batch.send(payload, options);

if (error) {
throw error;
}

if (!data) {
throw new Error("No data returned from Resend");
}

return data;
},
{
name: "Send Batch Email",
params: payload,
properties: [
{
label: "Count",
text: String(payload.length),
},
],
retry: retry.standardBackoff,
},
handleResendError
);
}

create(
key: IntegrationTaskKey,
payload: Parameters<Resend["batch"]["create"]>[0],
options?: Parameters<Resend["batch"]["create"]>[1]
): Promise<CreateEmailResult> {
return this.runTask(
key,
async (client, task) => {
const { error, data } = await client.batch.create(payload, options);

if (error) {
throw error;
}

if (!data) {
throw new Error("No data returned from Resend");
}

return data;
},
{
name: "Create Batch Email",
params: payload,
properties: [
{
label: "Count",
text: String(payload.length),
},
],
retry: retry.standardBackoff,
},
handleResendError
);
}
}
123 changes: 123 additions & 0 deletions integrations/resend/src/emails.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { IntegrationTaskKey, Prettify, retry } from "@trigger.dev/sdk";
import type { ResendRunTask } from "./index";
import { Resend } from "resend";
import { handleResendError } from "./utils";

type SendEmailResult = NonNullable<Awaited<ReturnType<Resend["emails"]["send"]>>["data"]>;
type CreateEmailResult = NonNullable<Awaited<ReturnType<Resend["emails"]["create"]>>["data"]>;
type GetEmailResult = NonNullable<Awaited<ReturnType<Resend["emails"]["get"]>>["data"]>;

export class Emails {
constructor(private runTask: ResendRunTask) {}

send(
key: IntegrationTaskKey,
payload: Parameters<Resend["emails"]["send"]>[0],
options?: Parameters<Resend["emails"]["send"]>[1]
): Promise<SendEmailResult> {
return this.runTask(
key,
async (client, task) => {
const { error, data } = await client.emails.send(payload, options);

if (error) {
throw error;
}

if (!data) {
throw new Error("No data returned from Resend");
}

return data;
},
{
name: "Send Email",
params: payload,
properties: [
{
label: "From",
text: payload.from,
},
{
label: "To",
text: Array.isArray(payload.to) ? payload.to.join(", ") : payload.to,
},
...(payload.subject ? [{ label: "Subject", text: payload.subject }] : []),
],
retry: retry.standardBackoff,
},
handleResendError
);
}

create(
key: IntegrationTaskKey,
payload: Parameters<Resend["emails"]["create"]>[0],
options?: Parameters<Resend["emails"]["create"]>[1]
): Promise<CreateEmailResult> {
return this.runTask(
key,
async (client, task) => {
const { error, data } = await client.emails.create(payload, options);

if (error) {
throw error;
}

if (!data) {
throw new Error("No data returned from Resend");
}

return data;
},
{
name: "Create Email",
params: payload,
properties: [
{
label: "From",
text: payload.from,
},
{
label: "To",
text: Array.isArray(payload.to) ? payload.to.join(", ") : payload.to,
},
...(payload.subject ? [{ label: "Subject", text: payload.subject }] : []),
],
retry: retry.standardBackoff,
},
handleResendError
);
}

get(key: IntegrationTaskKey, payload: string): Promise<GetEmailResult> {
return this.runTask(
key,
async (client, task) => {
const { error, data } = await client.emails.get(payload);

if (error) {
throw error;
}

if (!data) {
throw new Error("No data returned from Resend");
}

return data;
},
{
name: "Get Email",
params: payload,
properties: [
{
label: "ID",
text: payload,
},
],
retry: retry.standardBackoff,
},
handleResendError
);
}
}
74 changes: 41 additions & 33 deletions integrations/resend/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {
retry,
type ConnectionAuth,
type IO,
type IOTask,
Expand All @@ -10,10 +9,8 @@ import {
type TriggerIntegration,
} from "@trigger.dev/sdk";
import { Resend as ResendClient } from "resend";

type ResendType = InstanceType<typeof ResendClient>;
type SendEmailData = Parameters<ResendType["sendEmail"]>[0];
type SendEmailResponse = Awaited<ReturnType<ResendType["sendEmail"]>>;
import { Emails } from "./emails";
import { Batch } from "./batch";

type ErrorResponse = {
statusCode: number;
Expand Down Expand Up @@ -51,6 +48,8 @@ export type ResendIntegrationOptions = {
apiKey?: string;
};

export type ResendRunTask = InstanceType<typeof Resend>["runTask"];

export class Resend implements TriggerIntegration {
/**
* @internal
Expand Down Expand Up @@ -120,33 +119,42 @@ export class Resend implements TriggerIntegration {
);
}

sendEmail(key: IntegrationTaskKey, params: SendEmailData): Promise<SendEmailResponse> {
return this.runTask(
key,
async (client) => {
const response = await client.sendEmail(params);
if ("statusCode" in response) {
throw response;
}
return response;
},
{
name: "Send Email",
params,
properties: [
{
label: "From",
text: params.from,
},
{
label: "To",
text: Array.isArray(params.to) ? params.to.join(", ") : params.to,
},
...(params.subject ? [{ label: "Subject", text: params.subject }] : []),
],
retry: retry.standardBackoff,
},
onError
);
/**
* Access the Resend Emails API
* @example
* ```ts
* const response = await io.resend.emails.send("📧", {
* to: payload.to,
* subject: payload.subject,
* text: payload.text,
* from: "hello@trigger.dev"
* });
* ```
*/
get emails() {
return new Emails(this.runTask.bind(this));
}

/**
* Access the Resend Batch Emails API
* @example
* ```ts
* const response = await io.resend.batch.send("📧", [{
* to: payload.to,
* subject: payload.subject,
* text: payload.text,
* from: "hello@trigger.dev"
* }]);
* ```
*/
get batch() {
return new Batch(this.runTask.bind(this));
}

/**
* @deprecated Please use resend.emails.send instead
*/
async sendEmail(...args: Parameters<typeof this.emails.send>) {
return this.emails.send(...args);
}
}
Loading