chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
import { createLogger } from '@sim/logger'
import type { CancelEmailParams, CancelEmailResult } from '@/tools/resend/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('ResendCancelEmailTool')
export const resendCancelEmailTool: ToolConfig<CancelEmailParams, CancelEmailResult> = {
id: 'resend_cancel_email',
name: 'Cancel Email',
description: 'Cancel a scheduled email before it is sent',
version: '1.0.0',
params: {
cancelEmailId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the scheduled email to cancel',
},
resendApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Resend API key',
},
},
request: {
url: (params: CancelEmailParams) =>
`https://api.resend.com/emails/${encodeURIComponent(params.cancelEmailId.trim())}/cancel`,
method: 'POST',
headers: (params: CancelEmailParams) => ({
Authorization: `Bearer ${params.resendApiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response): Promise<CancelEmailResult> => {
const data = await response.json()
if (!data.id) {
logger.error('Resend Cancel Email API error:', JSON.stringify(data, null, 2))
return {
success: false,
error: data.message || 'Failed to cancel email',
output: {
id: '',
},
}
}
return {
success: true,
output: {
id: data.id,
},
}
},
outputs: {
id: { type: 'string', description: 'Canceled email ID' },
},
}
+68
View File
@@ -0,0 +1,68 @@
import { createLogger } from '@sim/logger'
import type { CreateAudienceParams, CreateAudienceResult } from '@/tools/resend/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('ResendCreateAudienceTool')
export const resendCreateAudienceTool: ToolConfig<CreateAudienceParams, CreateAudienceResult> = {
id: 'resend_create_audience',
name: 'Create Audience',
description: 'Create a new audience in Resend',
version: '1.0.0',
params: {
audienceName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The name of the audience to create',
},
resendApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Resend API key',
},
},
request: {
url: 'https://api.resend.com/audiences',
method: 'POST',
headers: (params: CreateAudienceParams) => ({
Authorization: `Bearer ${params.resendApiKey}`,
'Content-Type': 'application/json',
}),
body: (params: CreateAudienceParams) => ({
name: params.audienceName,
}),
},
transformResponse: async (response: Response): Promise<CreateAudienceResult> => {
const data = await response.json()
if (!data.id) {
logger.error('Resend Create Audience API error:', JSON.stringify(data, null, 2))
return {
success: false,
error: data.message || 'Failed to create audience',
output: {
id: '',
name: '',
},
}
}
return {
success: true,
output: {
id: data.id,
name: data.name ?? '',
},
}
},
outputs: {
id: { type: 'string', description: 'Created audience ID' },
name: { type: 'string', description: 'Audience name' },
},
}
+115
View File
@@ -0,0 +1,115 @@
import { createLogger } from '@sim/logger'
import type { CreateBroadcastParams, CreateBroadcastResult } from '@/tools/resend/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('ResendCreateBroadcastTool')
export const resendCreateBroadcastTool: ToolConfig<CreateBroadcastParams, CreateBroadcastResult> = {
id: 'resend_create_broadcast',
name: 'Create Broadcast',
description: 'Create a broadcast email for an audience in Resend',
version: '1.0.0',
params: {
audienceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the audience to send the broadcast to',
},
broadcastFrom: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Sender email address (e.g., "sender@example.com" or "Sender Name <sender@example.com>")',
},
broadcastSubject: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Broadcast email subject line',
},
broadcastHtml: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'HTML content of the broadcast',
},
broadcastText: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Plain text content of the broadcast',
},
broadcastReplyTo: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Reply-to email address',
},
broadcastName: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Friendly internal name for the broadcast',
},
broadcastPreviewText: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Preview text shown in the inbox before the email is opened',
},
resendApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Resend API key',
},
},
request: {
url: 'https://api.resend.com/broadcasts',
method: 'POST',
headers: (params: CreateBroadcastParams) => ({
Authorization: `Bearer ${params.resendApiKey}`,
'Content-Type': 'application/json',
}),
body: (params: CreateBroadcastParams) => ({
audience_id: params.audienceId.trim(),
from: params.broadcastFrom,
subject: params.broadcastSubject,
...(params.broadcastHtml && { html: params.broadcastHtml }),
...(params.broadcastText && { text: params.broadcastText }),
...(params.broadcastReplyTo && { reply_to: params.broadcastReplyTo }),
...(params.broadcastName && { name: params.broadcastName }),
...(params.broadcastPreviewText && { preview_text: params.broadcastPreviewText }),
}),
},
transformResponse: async (response: Response): Promise<CreateBroadcastResult> => {
const data = await response.json()
if (!data.id) {
logger.error('Resend Create Broadcast API error:', JSON.stringify(data, null, 2))
return {
success: false,
error: data.message || 'Failed to create broadcast',
output: {
id: '',
},
}
}
return {
success: true,
output: {
id: data.id,
},
}
},
outputs: {
id: { type: 'string', description: 'Created broadcast ID' },
},
}
+86
View File
@@ -0,0 +1,86 @@
import { createLogger } from '@sim/logger'
import type { CreateContactParams, CreateContactResult } from '@/tools/resend/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('ResendCreateContactTool')
export const resendCreateContactTool: ToolConfig<CreateContactParams, CreateContactResult> = {
id: 'resend_create_contact',
name: 'Create Contact',
description: 'Create a new contact in Resend',
version: '1.0.0',
params: {
email: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Email address of the contact',
},
firstName: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'First name of the contact',
},
lastName: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Last name of the contact',
},
unsubscribed: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether the contact is unsubscribed from all broadcasts',
},
resendApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Resend API key',
},
},
request: {
url: 'https://api.resend.com/contacts',
method: 'POST',
headers: (params: CreateContactParams) => ({
Authorization: `Bearer ${params.resendApiKey}`,
'Content-Type': 'application/json',
}),
body: (params: CreateContactParams) => ({
email: params.email,
...(params.firstName && { first_name: params.firstName }),
...(params.lastName && { last_name: params.lastName }),
...(params.unsubscribed !== undefined && { unsubscribed: params.unsubscribed }),
}),
},
transformResponse: async (response: Response): Promise<CreateContactResult> => {
const data = await response.json()
if (!data.id) {
logger.error('Resend Create Contact API error:', JSON.stringify(data, null, 2))
return {
success: false,
error: data.message || 'Failed to create contact',
output: {
id: '',
},
}
}
return {
success: true,
output: {
id: data.id,
},
}
},
outputs: {
id: { type: 'string', description: 'Created contact ID' },
},
}
+66
View File
@@ -0,0 +1,66 @@
import { createLogger } from '@sim/logger'
import type { DeleteAudienceParams, DeleteAudienceResult } from '@/tools/resend/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('ResendDeleteAudienceTool')
export const resendDeleteAudienceTool: ToolConfig<DeleteAudienceParams, DeleteAudienceResult> = {
id: 'resend_delete_audience',
name: 'Delete Audience',
description: 'Delete an audience from Resend by ID',
version: '1.0.0',
params: {
audienceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the audience to delete',
},
resendApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Resend API key',
},
},
request: {
url: (params: DeleteAudienceParams) =>
`https://api.resend.com/audiences/${encodeURIComponent(params.audienceId.trim())}`,
method: 'DELETE',
headers: (params: DeleteAudienceParams) => ({
Authorization: `Bearer ${params.resendApiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response): Promise<DeleteAudienceResult> => {
const data = await response.json()
if (data.message && !data.deleted) {
logger.error('Resend Delete Audience API error:', JSON.stringify(data, null, 2))
return {
success: false,
error: data.message || 'Failed to delete audience',
output: {
id: '',
deleted: false,
},
}
}
return {
success: true,
output: {
id: data.id ?? '',
deleted: data.deleted ?? true,
},
}
},
outputs: {
id: { type: 'string', description: 'Deleted audience ID' },
deleted: { type: 'boolean', description: 'Whether the audience was successfully deleted' },
},
}
+66
View File
@@ -0,0 +1,66 @@
import { createLogger } from '@sim/logger'
import type { DeleteContactParams, DeleteContactResult } from '@/tools/resend/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('ResendDeleteContactTool')
export const resendDeleteContactTool: ToolConfig<DeleteContactParams, DeleteContactResult> = {
id: 'resend_delete_contact',
name: 'Delete Contact',
description: 'Delete a contact from Resend by ID or email',
version: '1.0.0',
params: {
contactId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The contact ID or email address to delete',
},
resendApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Resend API key',
},
},
request: {
url: (params: DeleteContactParams) =>
`https://api.resend.com/contacts/${encodeURIComponent(params.contactId.trim())}`,
method: 'DELETE',
headers: (params: DeleteContactParams) => ({
Authorization: `Bearer ${params.resendApiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response): Promise<DeleteContactResult> => {
const data = await response.json()
if (data.message && !data.deleted) {
logger.error('Resend Delete Contact API error:', JSON.stringify(data, null, 2))
return {
success: false,
error: data.message || 'Failed to delete contact',
output: {
id: '',
deleted: false,
},
}
}
return {
success: true,
output: {
id: data.contact ?? data.id ?? '',
deleted: data.deleted ?? true,
},
}
},
outputs: {
id: { type: 'string', description: 'Deleted contact ID' },
deleted: { type: 'boolean', description: 'Whether the contact was successfully deleted' },
},
}
+69
View File
@@ -0,0 +1,69 @@
import { createLogger } from '@sim/logger'
import type { GetAudienceParams, GetAudienceResult } from '@/tools/resend/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('ResendGetAudienceTool')
export const resendGetAudienceTool: ToolConfig<GetAudienceParams, GetAudienceResult> = {
id: 'resend_get_audience',
name: 'Get Audience',
description: 'Retrieve details of an audience by ID',
version: '1.0.0',
params: {
audienceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the audience to retrieve',
},
resendApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Resend API key',
},
},
request: {
url: (params: GetAudienceParams) =>
`https://api.resend.com/audiences/${encodeURIComponent(params.audienceId.trim())}`,
method: 'GET',
headers: (params: GetAudienceParams) => ({
Authorization: `Bearer ${params.resendApiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response): Promise<GetAudienceResult> => {
const data = await response.json()
if (!data.id) {
logger.error('Resend Get Audience API error:', JSON.stringify(data, null, 2))
return {
success: false,
error: data.message || 'Failed to retrieve audience',
output: {
id: '',
name: '',
createdAt: '',
},
}
}
return {
success: true,
output: {
id: data.id,
name: data.name ?? '',
createdAt: data.created_at ?? '',
},
}
},
outputs: {
id: { type: 'string', description: 'Audience ID' },
name: { type: 'string', description: 'Audience name' },
createdAt: { type: 'string', description: 'Audience creation timestamp' },
},
}
+100
View File
@@ -0,0 +1,100 @@
import { createLogger } from '@sim/logger'
import type { GetBroadcastParams, GetBroadcastResult } from '@/tools/resend/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('ResendGetBroadcastTool')
export const resendGetBroadcastTool: ToolConfig<GetBroadcastParams, GetBroadcastResult> = {
id: 'resend_get_broadcast',
name: 'Get Broadcast',
description: 'Retrieve details of a broadcast by ID',
version: '1.0.0',
params: {
broadcastId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the broadcast to retrieve',
},
resendApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Resend API key',
},
},
request: {
url: (params: GetBroadcastParams) =>
`https://api.resend.com/broadcasts/${encodeURIComponent(params.broadcastId.trim())}`,
method: 'GET',
headers: (params: GetBroadcastParams) => ({
Authorization: `Bearer ${params.resendApiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response): Promise<GetBroadcastResult> => {
const data = await response.json()
if (!data.id) {
logger.error('Resend Get Broadcast API error:', JSON.stringify(data, null, 2))
return {
success: false,
error: data.message || 'Failed to retrieve broadcast',
output: {
id: '',
name: '',
audienceId: null,
segmentId: null,
from: '',
subject: '',
replyTo: null,
previewText: null,
status: '',
createdAt: '',
scheduledAt: null,
sentAt: null,
},
}
}
return {
success: true,
output: {
id: data.id,
name: data.name ?? '',
audienceId: data.audience_id ?? null,
segmentId: data.segment_id ?? null,
from: data.from ?? '',
subject: data.subject ?? '',
replyTo: data.reply_to ?? null,
previewText: data.preview_text ?? null,
status: data.status ?? '',
createdAt: data.created_at ?? '',
scheduledAt: data.scheduled_at ?? null,
sentAt: data.sent_at ?? null,
},
}
},
outputs: {
id: { type: 'string', description: 'Broadcast ID' },
name: { type: 'string', description: 'Broadcast name' },
audienceId: { type: 'string', description: 'Audience ID (legacy)', optional: true },
segmentId: {
type: 'string',
description: 'Segment ID (the current recipient field)',
optional: true,
},
from: { type: 'string', description: 'Sender email address' },
subject: { type: 'string', description: 'Broadcast subject' },
replyTo: { type: 'string', description: 'Reply-to email address', optional: true },
previewText: { type: 'string', description: 'Inbox preview text', optional: true },
status: { type: 'string', description: 'Broadcast status (e.g., draft, sent)' },
createdAt: { type: 'string', description: 'Broadcast creation timestamp' },
scheduledAt: { type: 'string', description: 'Scheduled send timestamp', optional: true },
sentAt: { type: 'string', description: 'Timestamp the broadcast was sent', optional: true },
},
}
+78
View File
@@ -0,0 +1,78 @@
import { createLogger } from '@sim/logger'
import type { GetContactParams, GetContactResult } from '@/tools/resend/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('ResendGetContactTool')
export const resendGetContactTool: ToolConfig<GetContactParams, GetContactResult> = {
id: 'resend_get_contact',
name: 'Get Contact',
description: 'Retrieve details of a contact by ID or email',
version: '1.0.0',
params: {
contactId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The contact ID or email address to retrieve',
},
resendApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Resend API key',
},
},
request: {
url: (params: GetContactParams) =>
`https://api.resend.com/contacts/${encodeURIComponent(params.contactId.trim())}`,
method: 'GET',
headers: (params: GetContactParams) => ({
Authorization: `Bearer ${params.resendApiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response): Promise<GetContactResult> => {
const data = await response.json()
if (!data.id) {
logger.error('Resend Get Contact API error:', JSON.stringify(data, null, 2))
return {
success: false,
error: data.message || 'Failed to retrieve contact',
output: {
id: '',
email: '',
firstName: '',
lastName: '',
createdAt: '',
unsubscribed: false,
},
}
}
return {
success: true,
output: {
id: data.id,
email: data.email ?? '',
firstName: data.first_name ?? '',
lastName: data.last_name ?? '',
createdAt: data.created_at ?? '',
unsubscribed: data.unsubscribed ?? false,
},
}
},
outputs: {
id: { type: 'string', description: 'Contact ID' },
email: { type: 'string', description: 'Contact email address' },
firstName: { type: 'string', description: 'Contact first name' },
lastName: { type: 'string', description: 'Contact last name' },
createdAt: { type: 'string', description: 'Contact creation timestamp' },
unsubscribed: { type: 'boolean', description: 'Whether the contact is unsubscribed' },
},
}
+124
View File
@@ -0,0 +1,124 @@
import { createLogger } from '@sim/logger'
import type { GetEmailParams, GetEmailResult } from '@/tools/resend/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('ResendGetEmailTool')
export const resendGetEmailTool: ToolConfig<GetEmailParams, GetEmailResult> = {
id: 'resend_get_email',
name: 'Get Email',
description: 'Retrieve details of a previously sent email by its ID',
version: '1.0.0',
params: {
emailId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the email to retrieve',
},
resendApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Resend API key',
},
},
request: {
url: (params: GetEmailParams) => `https://api.resend.com/emails/${params.emailId.trim()}`,
method: 'GET',
headers: (params: GetEmailParams) => ({
Authorization: `Bearer ${params.resendApiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response): Promise<GetEmailResult> => {
const data = await response.json()
if (!data.id) {
logger.error('Resend Get Email API error:', JSON.stringify(data, null, 2))
return {
success: false,
error: data.message || 'Failed to retrieve email',
output: {
id: '',
from: '',
to: [],
subject: '',
html: '',
text: null,
cc: [],
bcc: [],
replyTo: [],
lastEvent: '',
createdAt: '',
scheduledAt: null,
tags: [],
},
}
}
return {
success: true,
output: {
id: data.id,
from: data.from ?? '',
to: data.to ?? [],
subject: data.subject ?? '',
html: data.html ?? '',
text: data.text ?? null,
cc: data.cc ?? [],
bcc: data.bcc ?? [],
replyTo: data.reply_to ?? [],
lastEvent: data.last_event ?? '',
createdAt: data.created_at ?? '',
scheduledAt: data.scheduled_at ?? null,
tags: data.tags ?? [],
},
}
},
outputs: {
id: { type: 'string', description: 'Email ID' },
from: { type: 'string', description: 'Sender email address' },
to: {
type: 'array',
description: 'Recipient email addresses',
items: { type: 'string', description: 'Recipient email address' },
},
subject: { type: 'string', description: 'Email subject' },
html: { type: 'string', description: 'HTML email content' },
text: { type: 'string', description: 'Plain text email content', optional: true },
cc: {
type: 'array',
description: 'CC email addresses',
items: { type: 'string', description: 'CC email address' },
},
bcc: {
type: 'array',
description: 'BCC email addresses',
items: { type: 'string', description: 'BCC email address' },
},
replyTo: {
type: 'array',
description: 'Reply-to email addresses',
items: { type: 'string', description: 'Reply-to email address' },
},
lastEvent: { type: 'string', description: 'Last event status (e.g., delivered, bounced)' },
createdAt: { type: 'string', description: 'Email creation timestamp' },
scheduledAt: { type: 'string', description: 'Scheduled send timestamp', optional: true },
tags: {
type: 'array',
description: 'Email tags as name-value pairs',
items: {
type: 'object',
properties: {
name: { type: 'string', description: 'Tag name' },
value: { type: 'string', description: 'Tag value' },
},
},
},
},
}
+17
View File
@@ -0,0 +1,17 @@
export { resendCancelEmailTool } from '@/tools/resend/cancel_email'
export { resendCreateAudienceTool } from '@/tools/resend/create_audience'
export { resendCreateBroadcastTool } from '@/tools/resend/create_broadcast'
export { resendCreateContactTool } from '@/tools/resend/create_contact'
export { resendDeleteAudienceTool } from '@/tools/resend/delete_audience'
export { resendDeleteContactTool } from '@/tools/resend/delete_contact'
export { resendGetAudienceTool } from '@/tools/resend/get_audience'
export { resendGetBroadcastTool } from '@/tools/resend/get_broadcast'
export { resendGetContactTool } from '@/tools/resend/get_contact'
export { resendGetEmailTool } from '@/tools/resend/get_email'
export { resendListAudiencesTool } from '@/tools/resend/list_audiences'
export { resendListContactsTool } from '@/tools/resend/list_contacts'
export { resendListDomainsTool } from '@/tools/resend/list_domains'
export { resendSendTool } from '@/tools/resend/send'
export { resendSendBroadcastTool } from '@/tools/resend/send_broadcast'
export { resendUpdateContactTool } from '@/tools/resend/update_contact'
export * from './types'
+70
View File
@@ -0,0 +1,70 @@
import { createLogger } from '@sim/logger'
import type { ListAudiencesParams, ListAudiencesResult } from '@/tools/resend/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('ResendListAudiencesTool')
export const resendListAudiencesTool: ToolConfig<ListAudiencesParams, ListAudiencesResult> = {
id: 'resend_list_audiences',
name: 'List Audiences',
description: 'List all audiences in Resend',
version: '1.0.0',
params: {
resendApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Resend API key',
},
},
request: {
url: 'https://api.resend.com/audiences',
method: 'GET',
headers: (params: ListAudiencesParams) => ({
Authorization: `Bearer ${params.resendApiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response): Promise<ListAudiencesResult> => {
const data = await response.json()
if (data.message) {
logger.error('Resend List Audiences API error:', JSON.stringify(data, null, 2))
return {
success: false,
error: data.message || 'Failed to list audiences',
output: {
audiences: [],
hasMore: false,
},
}
}
return {
success: true,
output: {
audiences: data.data ?? [],
hasMore: data.has_more ?? false,
},
}
},
outputs: {
audiences: {
type: 'array',
description: 'Array of audiences',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Audience ID' },
name: { type: 'string', description: 'Audience name' },
created_at: { type: 'string', description: 'Audience creation timestamp' },
},
},
},
hasMore: { type: 'boolean', description: 'Whether there are more audiences to retrieve' },
},
}
+73
View File
@@ -0,0 +1,73 @@
import { createLogger } from '@sim/logger'
import type { ListContactsParams, ListContactsResult } from '@/tools/resend/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('ResendListContactsTool')
export const resendListContactsTool: ToolConfig<ListContactsParams, ListContactsResult> = {
id: 'resend_list_contacts',
name: 'List Contacts',
description: 'List all contacts in Resend',
version: '1.0.0',
params: {
resendApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Resend API key',
},
},
request: {
url: 'https://api.resend.com/contacts',
method: 'GET',
headers: (params: ListContactsParams) => ({
Authorization: `Bearer ${params.resendApiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response): Promise<ListContactsResult> => {
const data = await response.json()
if (data.message) {
logger.error('Resend List Contacts API error:', JSON.stringify(data, null, 2))
return {
success: false,
error: data.message || 'Failed to list contacts',
output: {
contacts: [],
hasMore: false,
},
}
}
return {
success: true,
output: {
contacts: data.data ?? [],
hasMore: data.has_more ?? false,
},
}
},
outputs: {
contacts: {
type: 'array',
description: 'Array of contacts',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Contact ID' },
email: { type: 'string', description: 'Contact email address' },
first_name: { type: 'string', description: 'Contact first name' },
last_name: { type: 'string', description: 'Contact last name' },
created_at: { type: 'string', description: 'Contact creation timestamp' },
unsubscribed: { type: 'boolean', description: 'Whether the contact is unsubscribed' },
},
},
},
hasMore: { type: 'boolean', description: 'Whether there are more contacts to retrieve' },
},
}
+86
View File
@@ -0,0 +1,86 @@
import { createLogger } from '@sim/logger'
import type { ListDomainsParams, ListDomainsResult } from '@/tools/resend/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('ResendListDomainsTool')
export const resendListDomainsTool: ToolConfig<ListDomainsParams, ListDomainsResult> = {
id: 'resend_list_domains',
name: 'List Domains',
description: 'List all verified domains in your Resend account',
version: '1.0.0',
params: {
resendApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Resend API key',
},
},
request: {
url: 'https://api.resend.com/domains',
method: 'GET',
headers: (params: ListDomainsParams) => ({
Authorization: `Bearer ${params.resendApiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response): Promise<ListDomainsResult> => {
const data = await response.json()
if (data.message) {
logger.error('Resend List Domains API error:', JSON.stringify(data, null, 2))
return {
success: false,
error: data.message || 'Failed to list domains',
output: {
domains: [],
hasMore: false,
},
}
}
return {
success: true,
output: {
domains: (data.data ?? []).map(
(domain: {
id: string
name: string
status: string
region: string
created_at: string
}) => ({
id: domain.id,
name: domain.name,
status: domain.status,
region: domain.region,
createdAt: domain.created_at,
})
),
hasMore: data.has_more ?? false,
},
}
},
outputs: {
domains: {
type: 'array',
description: 'Array of domains',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Domain ID' },
name: { type: 'string', description: 'Domain name' },
status: { type: 'string', description: 'Domain verification status' },
region: { type: 'string', description: 'Region the domain is configured in' },
createdAt: { type: 'string', description: 'Domain creation timestamp' },
},
},
},
hasMore: { type: 'boolean', description: 'Whether there are more domains to retrieve' },
},
}
+126
View File
@@ -0,0 +1,126 @@
import type { MailSendParams, MailSendResult } from '@/tools/resend/types'
import type { ToolConfig } from '@/tools/types'
export const resendSendTool: ToolConfig<MailSendParams, MailSendResult> = {
id: 'resend_send',
name: 'Send Email',
description: 'Send an email using your own Resend API key and from address',
version: '1.0.0',
params: {
fromAddress: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Email address to send from (e.g., "sender@example.com" or "Sender Name <sender@example.com>")',
},
to: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Recipient email address (e.g., "recipient@example.com" or "Recipient Name <recipient@example.com>")',
},
subject: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Email subject line',
},
body: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Email body content (plain text or HTML based on contentType)',
},
contentType: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Content type for the email body: "text" for plain text or "html" for HTML content',
},
cc: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Carbon copy recipient email address',
},
bcc: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Blind carbon copy recipient email address',
},
replyTo: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Reply-to email address',
},
scheduledAt: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Schedule email to be sent later in ISO 8601 format',
},
tags: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated key:value pairs for email tags (e.g., "category:welcome,type:onboarding")',
},
resendApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Resend API key for sending emails',
},
},
request: {
url: '/api/tools/mail/send',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params: MailSendParams) => ({
resendApiKey: params.resendApiKey,
fromAddress: params.fromAddress,
to: params.to,
subject: params.subject,
body: params.body,
contentType: params.contentType || 'text',
...(params.cc && { cc: params.cc }),
...(params.bcc && { bcc: params.bcc }),
...(params.replyTo && { replyTo: params.replyTo }),
...(params.scheduledAt && { scheduledAt: params.scheduledAt }),
...(params.tags && { tags: params.tags }),
}),
},
transformResponse: async (response: Response, params): Promise<MailSendResult> => {
const result = await response.json()
return {
success: true,
output: {
success: true,
id: result.data?.id || '',
to: params?.to || '',
subject: params?.subject || '',
body: params?.body || '',
},
}
},
outputs: {
success: { type: 'boolean', description: 'Whether the email was sent successfully' },
id: { type: 'string', description: 'Email ID returned by Resend' },
to: { type: 'string', description: 'Recipient email address' },
subject: { type: 'string', description: 'Email subject' },
body: { type: 'string', description: 'Email body content' },
},
}
+73
View File
@@ -0,0 +1,73 @@
import { createLogger } from '@sim/logger'
import type { SendBroadcastParams, SendBroadcastResult } from '@/tools/resend/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('ResendSendBroadcastTool')
export const resendSendBroadcastTool: ToolConfig<SendBroadcastParams, SendBroadcastResult> = {
id: 'resend_send_broadcast',
name: 'Send Broadcast',
description: 'Send a broadcast immediately or schedule it for later',
version: '1.0.0',
params: {
broadcastId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the broadcast to send',
},
broadcastScheduledAt: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Schedule delivery in natural language (e.g., "in 1 min") or ISO 8601 format. Sends immediately if omitted',
},
resendApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Resend API key',
},
},
request: {
url: (params: SendBroadcastParams) =>
`https://api.resend.com/broadcasts/${encodeURIComponent(params.broadcastId.trim())}/send`,
method: 'POST',
headers: (params: SendBroadcastParams) => ({
Authorization: `Bearer ${params.resendApiKey}`,
'Content-Type': 'application/json',
}),
body: (params: SendBroadcastParams) => ({
...(params.broadcastScheduledAt && { scheduled_at: params.broadcastScheduledAt }),
}),
},
transformResponse: async (response: Response): Promise<SendBroadcastResult> => {
const data = await response.json()
if (!data.id) {
logger.error('Resend Send Broadcast API error:', JSON.stringify(data, null, 2))
return {
success: false,
error: data.message || 'Failed to send broadcast',
output: {
id: '',
},
}
}
return {
success: true,
output: {
id: data.id,
},
}
},
outputs: {
id: { type: 'string', description: 'Broadcast ID' },
},
}
+270
View File
@@ -0,0 +1,270 @@
import type { ToolResponse } from '@/tools/types'
/** Send Email */
export interface MailSendParams {
resendApiKey: string
fromAddress: string
to: string
subject: string
body: string
contentType?: 'text' | 'html'
cc?: string
bcc?: string
replyTo?: string
scheduledAt?: string
tags?: string
}
export interface MailSendResult extends ToolResponse {
output: {
success: boolean
id: string
to: string
subject: string
body: string
}
}
/** Get Email */
export interface GetEmailParams {
resendApiKey: string
emailId: string
}
export interface GetEmailResult extends ToolResponse {
output: {
id: string
from: string
to: string[]
subject: string
html: string
text: string | null
cc: string[]
bcc: string[]
replyTo: string[]
lastEvent: string
createdAt: string
scheduledAt: string | null
tags: Array<{ name: string; value: string }>
}
}
/** Create Contact */
export interface CreateContactParams {
resendApiKey: string
email: string
firstName?: string
lastName?: string
unsubscribed?: boolean
}
export interface CreateContactResult extends ToolResponse {
output: {
id: string
}
}
/** List Contacts */
export interface ListContactsParams {
resendApiKey: string
}
export interface ListContactsResult extends ToolResponse {
output: {
contacts: Array<{
id: string
email: string
first_name: string
last_name: string
created_at: string
unsubscribed: boolean
}>
hasMore: boolean
}
}
/** Get Contact */
export interface GetContactParams {
resendApiKey: string
contactId: string
}
export interface GetContactResult extends ToolResponse {
output: {
id: string
email: string
firstName: string
lastName: string
createdAt: string
unsubscribed: boolean
}
}
/** Update Contact */
export interface UpdateContactParams {
resendApiKey: string
contactId: string
firstName?: string
lastName?: string
unsubscribed?: boolean
}
export interface UpdateContactResult extends ToolResponse {
output: {
id: string
}
}
/** Delete Contact */
export interface DeleteContactParams {
resendApiKey: string
contactId: string
}
export interface DeleteContactResult extends ToolResponse {
output: {
id: string
deleted: boolean
}
}
/** List Domains */
export interface ListDomainsParams {
resendApiKey: string
}
export interface ListDomainsResult extends ToolResponse {
output: {
domains: Array<{
id: string
name: string
status: string
region: string
createdAt: string
}>
hasMore: boolean
}
}
/** Cancel Email */
export interface CancelEmailParams {
resendApiKey: string
cancelEmailId: string
}
export interface CancelEmailResult extends ToolResponse {
output: {
id: string
}
}
/** Create Audience */
export interface CreateAudienceParams {
resendApiKey: string
audienceName: string
}
export interface CreateAudienceResult extends ToolResponse {
output: {
id: string
name: string
}
}
/** Get Audience */
export interface GetAudienceParams {
resendApiKey: string
audienceId: string
}
export interface GetAudienceResult extends ToolResponse {
output: {
id: string
name: string
createdAt: string
}
}
/** List Audiences */
export interface ListAudiencesParams {
resendApiKey: string
}
export interface ListAudiencesResult extends ToolResponse {
output: {
audiences: Array<{
id: string
name: string
created_at: string
}>
hasMore: boolean
}
}
/** Delete Audience */
export interface DeleteAudienceParams {
resendApiKey: string
audienceId: string
}
export interface DeleteAudienceResult extends ToolResponse {
output: {
id: string
deleted: boolean
}
}
/** Create Broadcast */
export interface CreateBroadcastParams {
resendApiKey: string
audienceId: string
broadcastFrom: string
broadcastSubject: string
broadcastReplyTo?: string
broadcastHtml?: string
broadcastText?: string
broadcastName?: string
broadcastPreviewText?: string
}
export interface CreateBroadcastResult extends ToolResponse {
output: {
id: string
}
}
/** Send Broadcast */
export interface SendBroadcastParams {
resendApiKey: string
broadcastId: string
broadcastScheduledAt?: string
}
export interface SendBroadcastResult extends ToolResponse {
output: {
id: string
}
}
/** Get Broadcast */
export interface GetBroadcastParams {
resendApiKey: string
broadcastId: string
}
export interface GetBroadcastResult extends ToolResponse {
output: {
id: string
name: string
audienceId: string | null
segmentId: string | null
from: string
subject: string
replyTo: string | string[] | null
previewText: string | null
status: string
createdAt: string
scheduledAt: string | null
sentAt: string | null
}
}
+86
View File
@@ -0,0 +1,86 @@
import { createLogger } from '@sim/logger'
import type { UpdateContactParams, UpdateContactResult } from '@/tools/resend/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('ResendUpdateContactTool')
export const resendUpdateContactTool: ToolConfig<UpdateContactParams, UpdateContactResult> = {
id: 'resend_update_contact',
name: 'Update Contact',
description: 'Update an existing contact in Resend',
version: '1.0.0',
params: {
contactId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The contact ID or email address to update',
},
firstName: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated first name',
},
lastName: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated last name',
},
unsubscribed: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether the contact should be unsubscribed from all broadcasts',
},
resendApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Resend API key',
},
},
request: {
url: (params: UpdateContactParams) =>
`https://api.resend.com/contacts/${encodeURIComponent(params.contactId.trim())}`,
method: 'PATCH',
headers: (params: UpdateContactParams) => ({
Authorization: `Bearer ${params.resendApiKey}`,
'Content-Type': 'application/json',
}),
body: (params: UpdateContactParams) => ({
...(params.firstName !== undefined && { first_name: params.firstName }),
...(params.lastName !== undefined && { last_name: params.lastName }),
...(params.unsubscribed !== undefined && { unsubscribed: params.unsubscribed }),
}),
},
transformResponse: async (response: Response): Promise<UpdateContactResult> => {
const data = await response.json()
if (!data.id) {
logger.error('Resend Update Contact API error:', JSON.stringify(data, null, 2))
return {
success: false,
error: data.message || 'Failed to update contact',
output: {
id: '',
},
}
}
return {
success: true,
output: {
id: data.id,
},
}
},
outputs: {
id: { type: 'string', description: 'Updated contact ID' },
},
}