diff --git a/apps/sim/blocks/blocks/sendgrid.ts b/apps/sim/blocks/blocks/sendgrid.ts index 9378083564d..2e68b9c6f15 100644 --- a/apps/sim/blocks/blocks/sendgrid.ts +++ b/apps/sim/blocks/blocks/sendgrid.ts @@ -1,7 +1,8 @@ import { SendgridIcon } from '@/components/icons' import type { BlockConfig, BlockMeta } from '@/blocks/types' -import { IntegrationType } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' +import { toActiveFlag } from '@/tools/sendgrid/create_template_version' import type { SendMailResult } from '@/tools/sendgrid/types' export const SendGridBlock: BlockConfig = { @@ -13,6 +14,7 @@ export const SendGridBlock: BlockConfig = { docsLink: 'https://docs.sim.ai/integrations/sendgrid', category: 'tools', integrationType: IntegrationType.Email, + authMode: AuthMode.ApiKey, bgColor: '#1A82E2', icon: SendgridIcon, @@ -387,6 +389,14 @@ Return ONLY the JSON array.`, condition: { field: 'operation', value: 'list_all_lists' }, mode: 'advanced', }, + { + id: 'listPageToken', + title: 'Page Token', + type: 'short-input', + placeholder: 'Page token from a previous response', + condition: { field: 'operation', value: 'list_all_lists' }, + mode: 'advanced', + }, // Template fields { id: 'templateName', @@ -434,6 +444,14 @@ Return ONLY the JSON array.`, condition: { field: 'operation', value: 'list_templates' }, mode: 'advanced', }, + { + id: 'templatePageToken', + title: 'Page Token', + type: 'short-input', + placeholder: 'Page token from a previous response (keep Page Size the same)', + condition: { field: 'operation', value: 'list_templates' }, + mode: 'advanced', + }, { id: 'versionName', title: 'Version Name', @@ -579,7 +597,10 @@ Return ONLY the HTML content.`, templateGenerations, listPageSize, templatePageSize, + listPageToken, + templatePageToken, attachments, + active, ...rest } = params @@ -599,7 +620,11 @@ Return ONLY the HTML content.`, ...(templateGenerations && { generations: templateGenerations }), ...(listPageSize && { pageSize: listPageSize }), ...(templatePageSize && { pageSize: templatePageSize }), + ...(operation === 'list_all_lists' && listPageToken && { pageToken: listPageToken }), + ...(operation === 'list_templates' && + templatePageToken && { pageToken: templatePageToken }), ...(normalizedAttachments && { attachments: normalizedAttachments }), + ...(active !== undefined && { active: toActiveFlag(active) }), } }, }, @@ -637,12 +662,14 @@ Return ONLY the HTML content.`, listName: { type: 'string', description: 'List name' }, listId: { type: 'string', description: 'List ID' }, listPageSize: { type: 'number', description: 'Page size for listing lists' }, + listPageToken: { type: 'string', description: 'Page token for listing lists' }, // Template inputs templateName: { type: 'string', description: 'Template name' }, templateId: { type: 'string', description: 'Template ID' }, generation: { type: 'string', description: 'Template generation' }, templateGenerations: { type: 'string', description: 'Filter templates by generation' }, templatePageSize: { type: 'number', description: 'Page size for listing templates' }, + templatePageToken: { type: 'string', description: 'Page token for listing templates' }, versionName: { type: 'string', description: 'Template version name' }, templateSubject: { type: 'string', description: 'Template subject' }, htmlContent: { type: 'string', description: 'HTML content' }, @@ -677,6 +704,10 @@ Return ONLY the HTML content.`, templates: { type: 'json', description: 'Array of templates' }, generation: { type: 'string', description: 'Template generation' }, versions: { type: 'json', description: 'Array of template versions' }, + nextPageToken: { + type: 'string', + description: 'Token for the next page of results (list_all_lists, list_templates)', + }, // Template version outputs templateId: { type: 'string', description: 'Template ID' }, active: { type: 'boolean', description: 'Whether template version is active' }, diff --git a/apps/sim/tools/sendgrid/add_contact.ts b/apps/sim/tools/sendgrid/add_contact.ts index 5c483e9737b..7c1a7a37986 100644 --- a/apps/sim/tools/sendgrid/add_contact.ts +++ b/apps/sim/tools/sendgrid/add_contact.ts @@ -1,4 +1,3 @@ -import { safeAssign } from '@/tools/safe-assign' import type { AddContactParams, ContactResult, @@ -73,7 +72,7 @@ export const sendGridAddContactTool: ToolConfig typeof params.customFields === 'string' ? JSON.parse(params.customFields) : params.customFields - safeAssign(contact, customFields as Record) + contact.custom_fields = customFields as Record } const body: SendGridContactRequest = { @@ -99,7 +98,7 @@ export const sendGridAddContactTool: ToolConfig return { success: true, output: { - jobId: data.job_id, + jobId: data.job_id ?? null, email: params?.email || '', firstName: params?.firstName, lastName: params?.lastName, @@ -110,10 +109,14 @@ export const sendGridAddContactTool: ToolConfig }, outputs: { - jobId: { type: 'string', description: 'Job ID for tracking the async contact creation' }, + jobId: { + type: 'string', + description: 'Job ID for tracking the async contact creation', + optional: true, + }, email: { type: 'string', description: 'Contact email address' }, - firstName: { type: 'string', description: 'Contact first name' }, - lastName: { type: 'string', description: 'Contact last name' }, + firstName: { type: 'string', description: 'Contact first name', optional: true }, + lastName: { type: 'string', description: 'Contact last name', optional: true }, message: { type: 'string', description: 'Status message' }, }, } diff --git a/apps/sim/tools/sendgrid/create_template_version.ts b/apps/sim/tools/sendgrid/create_template_version.ts index e41f43bb584..23267575d8b 100644 --- a/apps/sim/tools/sendgrid/create_template_version.ts +++ b/apps/sim/tools/sendgrid/create_template_version.ts @@ -5,6 +5,16 @@ import type { } from '@/tools/sendgrid/types' import type { ToolConfig } from '@/tools/types' +const INACTIVE_VALUES: unknown[] = [false, 'false', 0, '0'] + +/** Coerces any dynamic-reference form of SendGrid's active flag (boolean, string, or + * number) to the 0/1 integer the API requires. Shared with the block's own + * pre-coercion in blocks/blocks/sendgrid.ts so both layers stay in sync. */ +export function toActiveFlag(active: unknown): 0 | 1 { + if (active === undefined) return 1 + return INACTIVE_VALUES.includes(active) ? 0 : 1 +} + export const sendGridCreateTemplateVersionTool: ToolConfig< CreateTemplateVersionParams, TemplateVersionResult @@ -70,7 +80,7 @@ export const sendGridCreateTemplateVersionTool: ToolConfig< const body: SendGridTemplateVersionRequest = { name: params.name, subject: params.subject, - active: params.active !== undefined ? params.active : 1, + active: toActiveFlag(params.active), } if (params.htmlContent) { @@ -101,9 +111,9 @@ export const sendGridCreateTemplateVersionTool: ToolConfig< name: data.name, subject: data.subject, active: data.active === 1, - htmlContent: data.html_content, - plainContent: data.plain_content, - updatedAt: data.updated_at, + htmlContent: data.html_content ?? null, + plainContent: data.plain_content ?? null, + updatedAt: data.updated_at ?? null, }, } }, @@ -114,8 +124,8 @@ export const sendGridCreateTemplateVersionTool: ToolConfig< name: { type: 'string', description: 'Version name' }, subject: { type: 'string', description: 'Email subject' }, active: { type: 'boolean', description: 'Whether this version is active' }, - htmlContent: { type: 'string', description: 'HTML content' }, - plainContent: { type: 'string', description: 'Plain text content' }, - updatedAt: { type: 'string', description: 'Last update timestamp' }, + htmlContent: { type: 'string', description: 'HTML content', optional: true }, + plainContent: { type: 'string', description: 'Plain text content', optional: true }, + updatedAt: { type: 'string', description: 'Last update timestamp', optional: true }, }, } diff --git a/apps/sim/tools/sendgrid/get_contact.ts b/apps/sim/tools/sendgrid/get_contact.ts index f2870d854ff..549d96df0c2 100644 --- a/apps/sim/tools/sendgrid/get_contact.ts +++ b/apps/sim/tools/sendgrid/get_contact.ts @@ -47,8 +47,8 @@ export const sendGridGetContactTool: ToolConfig lastName: data.last_name, createdAt: data.created_at, updatedAt: data.updated_at, - listIds: data.list_ids, - customFields: data.custom_fields, + listIds: data.list_ids ?? [], + customFields: data.custom_fields ?? null, }, } }, @@ -56,11 +56,15 @@ export const sendGridGetContactTool: ToolConfig 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: 'Creation timestamp' }, - updatedAt: { type: 'string', description: 'Last update timestamp' }, - listIds: { type: 'json', description: 'Array of list IDs the contact belongs to' }, - customFields: { type: 'json', description: 'Custom field values' }, + firstName: { type: 'string', description: 'Contact first name', optional: true }, + lastName: { type: 'string', description: 'Contact last name', optional: true }, + createdAt: { type: 'string', description: 'Creation timestamp', optional: true }, + updatedAt: { type: 'string', description: 'Last update timestamp', optional: true }, + listIds: { + type: 'json', + description: 'Array of list IDs the contact belongs to', + optional: true, + }, + customFields: { type: 'json', description: 'Custom field values', optional: true }, }, } diff --git a/apps/sim/tools/sendgrid/list_all_lists.ts b/apps/sim/tools/sendgrid/list_all_lists.ts index 76adb3d1002..17861dae3ea 100644 --- a/apps/sim/tools/sendgrid/list_all_lists.ts +++ b/apps/sim/tools/sendgrid/list_all_lists.ts @@ -18,7 +18,13 @@ export const sendGridListAllListsTool: ToolConfig = outputs: { success: { type: 'boolean', description: 'Whether the email was sent successfully' }, - messageId: { type: 'string', description: 'SendGrid message ID' }, + messageId: { type: 'string', description: 'SendGrid message ID', optional: true }, to: { type: 'string', description: 'Recipient email address' }, subject: { type: 'string', description: 'Email subject' }, }, diff --git a/apps/sim/tools/sendgrid/types.ts b/apps/sim/tools/sendgrid/types.ts index 03eb10bfccb..fcd0c24ff2d 100644 --- a/apps/sim/tools/sendgrid/types.ts +++ b/apps/sim/tools/sendgrid/types.ts @@ -71,6 +71,7 @@ export interface SendGridContactObject { email: string first_name?: string last_name?: string + custom_fields?: Record [key: string]: unknown } @@ -82,7 +83,7 @@ export interface SendGridContactRequest { export interface SendGridTemplateVersionRequest { name: string subject: string - active: number | boolean + active: number html_content?: string plain_content?: string } @@ -127,15 +128,6 @@ export interface AddContactParams extends SendGridBaseParams { listIds?: string // Comma-separated list IDs } -interface UpdateContactParams extends SendGridBaseParams { - contactId?: string - email: string - firstName?: string - lastName?: string - customFields?: string // JSON string - listIds?: string // Comma-separated list IDs -} - export interface SearchContactsParams extends SendGridBaseParams { query: string } @@ -151,14 +143,14 @@ export interface DeleteContactParams extends SendGridBaseParams { export interface ContactResult extends ToolResponse { output: { id?: string - jobId?: string + jobId?: string | null email: string firstName?: string lastName?: string createdAt?: string updatedAt?: string listIds?: string[] - customFields?: Record + customFields?: Record | null message?: string } } @@ -166,7 +158,7 @@ export interface ContactResult extends ToolResponse { export interface ContactsResult extends ToolResponse { output: { contacts: SendGridContact[] - contactCount?: number + contactCount: number | null } } @@ -179,17 +171,13 @@ export interface GetListParams extends SendGridBaseParams { listId: string } -interface UpdateListParams extends SendGridBaseParams { - listId: string - name: string -} - export interface DeleteListParams extends SendGridBaseParams { listId: string } export interface ListAllListsParams extends SendGridBaseParams { pageSize?: number + pageToken?: string } export interface AddContactsToListParams extends SendGridBaseParams { @@ -213,24 +201,20 @@ export interface ListResult extends ToolResponse { export interface ListsResult extends ToolResponse { output: { lists: SendGridList[] + nextPageToken: string | null } } // Template types export interface CreateTemplateParams extends SendGridBaseParams { name: string - generation: 'legacy' | 'dynamic' + generation?: 'legacy' | 'dynamic' } export interface GetTemplateParams extends SendGridBaseParams { templateId: string } -interface UpdateTemplateParams extends SendGridBaseParams { - templateId: string - name: string -} - export interface DeleteTemplateParams extends SendGridBaseParams { templateId: string } @@ -238,6 +222,7 @@ export interface DeleteTemplateParams extends SendGridBaseParams { export interface ListTemplatesParams extends SendGridBaseParams { generations?: string // 'legacy' or 'dynamic' or both pageSize?: number + pageToken?: string } export interface CreateTemplateVersionParams extends SendGridBaseParams { @@ -262,6 +247,7 @@ export interface TemplateResult extends ToolResponse { export interface TemplatesResult extends ToolResponse { output: { templates: SendGridTemplate[] + nextPageToken: string | null } } @@ -272,8 +258,8 @@ export interface TemplateVersionResult extends ToolResponse { name: string subject: string active: boolean - htmlContent?: string - plainContent?: string - updatedAt?: string + htmlContent: string | null + plainContent: string | null + updatedAt: string | null } } diff --git a/scripts/check-api-validation-contracts.ts b/scripts/check-api-validation-contracts.ts index 80f935786b0..9f5d387d0a1 100644 --- a/scripts/check-api-validation-contracts.ts +++ b/scripts/check-api-validation-contracts.ts @@ -9,8 +9,8 @@ const QUERY_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/queries') const SELECTOR_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/selectors') const BASELINE = { - totalRoutes: 883, - zodRoutes: 883, + totalRoutes: 884, + zodRoutes: 884, nonZodRoutes: 0, } as const