UNPKG

n8n-nodes-mautic-advanced

Version:

Enhanced n8n node for Mautic with comprehensive API coverage including tags, campaigns, categories, and advanced contact management

688 lines (687 loc) 29.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getRuntimeSchemaBuilders = exports.buildUnifiedSchema = void 0; // nodes/MauticAdvanced/ai-tools/schema-generator.ts // NOTE: z is a compile-time VALUE import — we need z.object(), z.string() etc. at build time. // Only runtime classes (DynamicStructuredTool, ZodType) come from runtime.ts. const zod_1 = require("zod"); // --------------------------------------------------------------------------- // Shared field schemas // --------------------------------------------------------------------------- const idSchema = zod_1.z .number() .int() .positive() .describe('Numeric record ID (from a prior getAll result). Must be an integer.'); const limitSchema = zod_1.z .number() .int() .min(1) .max(100) .optional() .default(25) .describe('Maximum records to return (default 25, max 100). Increase to 100 if you expect many matching records.'); const contactIdSchema = zod_1.z .number() .int() .positive() .describe("Numeric contact ID. If unknown, call mauticadvanced_contact with operation 'getAll' and 'search' to find the contact and get its id."); const segmentIdSchema = zod_1.z .number() .int() .positive() .describe("Numeric segment ID. If unknown, call mauticadvanced_segment with operation 'getAll' and 'search' to find the segment and get its id."); const campaignIdSchema = zod_1.z .number() .int() .positive() .describe("Numeric campaign ID. If unknown, call mauticadvanced_campaign with operation 'getAll' and 'search' to find the campaign and get its id."); const companyIdSchema = zod_1.z .number() .int() .positive() .describe("Numeric company ID. If unknown, call mauticadvanced_company with operation 'getAll' and 'search' to find the company and get its id."); const emailIdSchema = zod_1.z .number() .int() .positive() .describe("Numeric email ID. If unknown, call mauticadvanced_email with operation 'getAll' and 'search' to find the email and get its id."); // --------------------------------------------------------------------------- // Operation labels // --------------------------------------------------------------------------- const OPERATION_LABELS = { get: 'Get by ID', getAll: 'Get many', create: 'Create', update: 'Update', delete: 'Delete', sendEmail: 'Send email to contact', addToSegments: 'Add contact to segments', removeFromSegments: 'Remove contact from segments', addToCampaigns: 'Add contact to campaigns', removeFromCampaigns: 'Remove contact from campaigns', addContact: 'Add contact', removeContact: 'Remove contact', add: 'Add association', remove: 'Remove association', send: 'Send segment email', }; function isValidOperation(op) { return op in OPERATION_LABELS; } // --------------------------------------------------------------------------- // Per-resource getAll schemas — search MUST precede name in property order // --------------------------------------------------------------------------- function getContactGetAllSchema() { return zod_1.z.object({ search: zod_1.z .string() .optional() .describe('Partial text match across contact fields (name, email, company, etc). ALWAYS use this first for any text lookup.'), limit: limitSchema, }); } function getCompanyGetAllSchema() { return zod_1.z.object({ search: zod_1.z .string() .optional() .describe('Partial text match across company name, city, phone, website. ALWAYS use this first for any name or text lookup.'), limit: limitSchema, }); } function getCampaignGetAllSchema() { return zod_1.z.object({ search: zod_1.z .string() .optional() .describe('Partial text match across campaign name and description. ALWAYS use this first for any name or text lookup.'), limit: limitSchema, }); } function getEmailGetAllSchema() { return zod_1.z.object({ search: zod_1.z .string() .optional() .describe('Partial text match across email name and subject. ALWAYS use this first for any name or text lookup.'), limit: limitSchema, }); } function getSegmentGetAllSchema() { return zod_1.z.object({ search: zod_1.z .string() .optional() .describe('Partial text match across segment name. ALWAYS use this first for any name or text lookup.'), limit: limitSchema, }); } function getTagGetAllSchema() { return zod_1.z.object({ search: zod_1.z .string() .optional() .describe('Partial text match across tag name. ALWAYS use this first for any name or text lookup.'), limit: limitSchema, }); } function getNoteGetAllSchema() { return zod_1.z.object({ search: zod_1.z .string() .optional() .describe('Partial text match across note content. ALWAYS use this first for any text lookup.'), limit: limitSchema, }); } function getCategoryGetAllSchema() { return zod_1.z.object({ search: zod_1.z .string() .optional() .describe('Partial text match across category title. ALWAYS use this first for any name or text lookup.'), limit: limitSchema, }); } function getFieldGetAllSchema() { return zod_1.z.object({ fieldObject: zod_1.z .enum(['contact', 'company']) .describe("Type of field to list: 'contact' for contact fields, 'company' for company fields."), limit: limitSchema, }); } function getUserGetAllSchema() { return zod_1.z.object({ search: zod_1.z .string() .optional() .describe('Partial text match across username, name, email. ALWAYS use this first for any text lookup.'), limit: limitSchema, }); } // --------------------------------------------------------------------------- // Per-resource create schemas // --------------------------------------------------------------------------- function getContactCreateSchema() { return zod_1.z.object({ email: zod_1.z.string().describe('Email address for the contact (recommended for identification).'), firstname: zod_1.z.string().optional().describe('First name of the contact.'), lastname: zod_1.z.string().optional().describe('Last name of the contact.'), company: zod_1.z.string().optional().describe('Company name for the contact.'), position: zod_1.z.string().optional().describe('Job position/title of the contact.'), title: zod_1.z.string().optional().describe("Contact's title (Mr, Mrs, etc)."), phone: zod_1.z.string().optional().describe('Phone number.'), mobile: zod_1.z.string().optional().describe('Mobile phone number.'), address1: zod_1.z.string().optional().describe('Street address line 1.'), address2: zod_1.z.string().optional().describe('Street address line 2.'), city: zod_1.z.string().optional().describe('City.'), state: zod_1.z.string().optional().describe('State/province.'), country: zod_1.z.string().optional().describe('Country.'), zipcode: zod_1.z.string().optional().describe('Postal/zip code.'), preferred_locale: zod_1.z.string().optional().describe('Preferred locale (e.g., en_US).'), timezone: zod_1.z.string().optional().describe('Timezone (e.g., America/New_York).'), owner_id: zod_1.z .number() .int() .positive() .optional() .describe("Numeric user ID for the contact owner. If unknown, call mauticadvanced_user with operation 'getAll' and 'search' to find the user."), tags: zod_1.z.string().optional().describe('Comma-separated list of tags to apply to the contact.'), customFields: zod_1.z .string() .optional() .describe('JSON object of custom field alias→value pairs (e.g., {"custom_field_alias": "value"}). Use mauticadvanced_field with operation getAll to discover field aliases.'), }); } function getContactUpdateSchema() { return zod_1.z.object({ id: idSchema, email: zod_1.z.string().optional().describe('Email address.'), firstname: zod_1.z.string().optional().describe('First name.'), lastname: zod_1.z.string().optional().describe('Last name.'), company: zod_1.z.string().optional().describe('Company name.'), position: zod_1.z.string().optional().describe('Job position.'), title: zod_1.z.string().optional().describe('Title (Mr, Mrs, etc).'), phone: zod_1.z.string().optional().describe('Phone number.'), mobile: zod_1.z.string().optional().describe('Mobile phone number.'), address1: zod_1.z.string().optional().describe('Street address line 1.'), address2: zod_1.z.string().optional().describe('Street address line 2.'), city: zod_1.z.string().optional().describe('City.'), state: zod_1.z.string().optional().describe('State/province.'), country: zod_1.z.string().optional().describe('Country.'), zipcode: zod_1.z.string().optional().describe('Postal/zip code.'), owner_id: zod_1.z.number().int().positive().optional().describe('Numeric user ID for owner.'), tags: zod_1.z.string().optional().describe('Comma-separated list of tags.'), customFields: zod_1.z.string().optional().describe('JSON object of custom field alias→value pairs.'), }); } function getContactSendEmailSchema() { return zod_1.z.object({ id: contactIdSchema.describe("Numeric contact ID to send email to. If unknown, call mauticadvanced_contact with operation 'getAll' and 'search' to find the contact."), emailId: emailIdSchema.describe("Numeric email template ID to send. If unknown, call mauticadvanced_email with operation 'getAll' and 'search' to find the email."), }); } function getContactSegmentBatchSchema() { return zod_1.z.object({ id: contactIdSchema.describe('Numeric contact ID.'), segmentIds: zod_1.z .string() .describe("Comma-separated segment IDs (e.g., '1,2,3'). If unknown, call mauticadvanced_segment with operation 'getAll' to find segment IDs."), }); } function getContactCampaignBatchSchema() { return zod_1.z.object({ id: contactIdSchema.describe('Numeric contact ID.'), campaignIds: zod_1.z .string() .describe("Comma-separated campaign IDs (e.g., '1,2,3'). If unknown, call mauticadvanced_campaign with operation 'getAll' to find campaign IDs."), }); } function getCompanyCreateSchema() { return zod_1.z.object({ companyname: zod_1.z.string().describe('Company name (required).'), companyemail: zod_1.z.string().optional().describe('Company email address.'), companyphone: zod_1.z.string().optional().describe('Company phone number.'), companywebsite: zod_1.z.string().optional().describe('Company website URL.'), companyindustry: zod_1.z.string().optional().describe('Industry sector.'), companycity: zod_1.z.string().optional().describe('City.'), companystate: zod_1.z.string().optional().describe('State/province.'), companycountry: zod_1.z.string().optional().describe('Country.'), companydescription: zod_1.z.string().optional().describe('Company description.'), }); } function getCompanyUpdateSchema() { return zod_1.z.object({ id: idSchema, companyname: zod_1.z.string().optional().describe('Company name.'), companyemail: zod_1.z.string().optional().describe('Company email address.'), companyphone: zod_1.z.string().optional().describe('Company phone number.'), companywebsite: zod_1.z.string().optional().describe('Company website URL.'), companyindustry: zod_1.z.string().optional().describe('Industry sector.'), companycity: zod_1.z.string().optional().describe('City.'), companystate: zod_1.z.string().optional().describe('State/province.'), companycountry: zod_1.z.string().optional().describe('Country.'), companydescription: zod_1.z.string().optional().describe('Company description.'), }); } function getCampaignCreateSchema() { return zod_1.z.object({ name: zod_1.z.string().describe('Campaign name (required).'), description: zod_1.z.string().optional().describe('Campaign description.'), isPublished: zod_1.z.boolean().optional().describe('Whether the campaign is published.'), }); } function getCampaignUpdateSchema() { return zod_1.z.object({ id: idSchema, name: zod_1.z.string().optional().describe('Campaign name.'), description: zod_1.z.string().optional().describe('Campaign description.'), isPublished: zod_1.z.boolean().optional().describe('Whether the campaign is published.'), }); } function getEmailCreateSchema() { return zod_1.z.object({ name: zod_1.z.string().describe('Internal email name (required).'), subject: zod_1.z.string().describe('Email subject line (required).'), customHtml: zod_1.z.string().optional().describe('HTML content of the email body.'), emailType: zod_1.z .enum(['template', 'list']) .optional() .describe("Email type: 'template' for campaign/transactional emails, 'list' for segment broadcast emails."), fromAddress: zod_1.z.string().optional().describe('Sender email address.'), fromName: zod_1.z.string().optional().describe('Sender display name.'), isPublished: zod_1.z.boolean().optional().describe('Whether the email is published.'), }); } function getEmailUpdateSchema() { return zod_1.z.object({ id: idSchema, name: zod_1.z.string().optional().describe('Internal email name.'), subject: zod_1.z.string().optional().describe('Email subject line.'), customHtml: zod_1.z.string().optional().describe('HTML content of the email body.'), emailType: zod_1.z .enum(['template', 'list']) .optional() .describe("Email type: 'template' or 'list'."), fromAddress: zod_1.z.string().optional().describe('Sender email address.'), fromName: zod_1.z.string().optional().describe('Sender display name.'), isPublished: zod_1.z.boolean().optional().describe('Whether the email is published.'), }); } function getSegmentCreateSchema() { return zod_1.z.object({ name: zod_1.z.string().describe('Segment name (required).'), description: zod_1.z.string().optional().describe('Segment description.'), isPublished: zod_1.z.boolean().optional().describe('Whether the segment is published.'), isGlobal: zod_1.z .boolean() .optional() .describe('Whether the segment is global (visible to all users).'), }); } function getSegmentUpdateSchema() { return zod_1.z.object({ id: idSchema, name: zod_1.z.string().optional().describe('Segment name.'), description: zod_1.z.string().optional().describe('Segment description.'), isPublished: zod_1.z.boolean().optional().describe('Whether the segment is published.'), }); } function getSegmentContactSchema() { return zod_1.z.object({ id: segmentIdSchema.describe('Numeric segment ID.'), contactId: contactIdSchema.describe('Numeric contact ID to add/remove.'), }); } function getTagCreateSchema() { return zod_1.z.object({ tag: zod_1.z.string().describe('Tag name (required).'), }); } function getTagUpdateSchema() { return zod_1.z.object({ id: idSchema, tag: zod_1.z.string().optional().describe('New tag name.'), }); } function getNoteCreateSchema() { return zod_1.z.object({ text: zod_1.z.string().describe('Note content text (required).'), lead: contactIdSchema.describe('Numeric contact ID the note belongs to (required).'), type: zod_1.z .enum(['general', 'email', 'call', 'meeting']) .optional() .describe("Note type: 'general' (default), 'email', 'call', or 'meeting'."), datetime: zod_1.z.string().optional().describe('Date/time for the note (ISO 8601 format).'), }); } function getNoteUpdateSchema() { return zod_1.z.object({ id: idSchema, text: zod_1.z.string().optional().describe('Note content text.'), type: zod_1.z .enum(['general', 'email', 'call', 'meeting']) .optional() .describe("Note type: 'general', 'email', 'call', or 'meeting'."), datetime: zod_1.z.string().optional().describe('Date/time for the note (ISO 8601 format).'), }); } function getCategoryCreateSchema() { return zod_1.z.object({ title: zod_1.z.string().describe('Category title (required).'), bundle: zod_1.z .enum(['asset', 'campaign', 'email', 'form', 'global', 'page', 'point', 'stage']) .describe('Category bundle type (required). Determines which Mautic module this category belongs to.'), description: zod_1.z.string().optional().describe('Category description.'), color: zod_1.z.string().optional().describe('Hex color code without # prefix (e.g., "b36262").'), }); } function getCategoryUpdateSchema() { return zod_1.z.object({ id: idSchema, title: zod_1.z.string().optional().describe('Category title.'), bundle: zod_1.z .enum(['asset', 'campaign', 'email', 'form', 'global', 'page', 'point', 'stage']) .optional() .describe('Category bundle type.'), description: zod_1.z.string().optional().describe('Category description.'), color: zod_1.z.string().optional().describe('Hex color code without # prefix.'), }); } function getFieldGetSchema() { return zod_1.z.object({ id: idSchema, fieldObject: zod_1.z.enum(['contact', 'company']).describe("Type of field: 'contact' or 'company'."), }); } function getCompanyContactSchema() { return zod_1.z.object({ companyId: companyIdSchema.describe('Numeric company ID.'), contactId: contactIdSchema.describe('Numeric contact ID.'), }); } function getCampaignContactSchema() { return zod_1.z.object({ campaignId: campaignIdSchema.describe('Numeric campaign ID.'), contactId: contactIdSchema.describe('Numeric contact ID.'), }); } function getContactSegmentSchema() { return zod_1.z.object({ segmentId: segmentIdSchema.describe('Numeric segment ID.'), contactId: contactIdSchema.describe('Numeric contact ID.'), }); } function getSegmentEmailSendSchema() { return zod_1.z.object({ emailId: emailIdSchema.describe("Numeric segment (list) email ID. If unknown, call mauticadvanced_email with operation 'getAll' and 'search' to find the email. Must be of type 'list'."), }); } // --------------------------------------------------------------------------- // Schema dispatchers // --------------------------------------------------------------------------- function getGetAllSchemaForResource(resource) { switch (resource) { case 'contact': return getContactGetAllSchema(); case 'company': return getCompanyGetAllSchema(); case 'campaign': return getCampaignGetAllSchema(); case 'email': return getEmailGetAllSchema(); case 'segment': return getSegmentGetAllSchema(); case 'tag': return getTagGetAllSchema(); case 'note': return getNoteGetAllSchema(); case 'category': return getCategoryGetAllSchema(); case 'field': return getFieldGetAllSchema(); case 'user': return getUserGetAllSchema(); default: return zod_1.z.object({ limit: limitSchema }); } } function getCreateSchemaForResource(resource) { switch (resource) { case 'contact': return getContactCreateSchema(); case 'company': return getCompanyCreateSchema(); case 'campaign': return getCampaignCreateSchema(); case 'email': return getEmailCreateSchema(); case 'segment': return getSegmentCreateSchema(); case 'tag': return getTagCreateSchema(); case 'note': return getNoteCreateSchema(); case 'category': return getCategoryCreateSchema(); default: return zod_1.z.object({}); } } function getUpdateSchemaForResource(resource) { switch (resource) { case 'contact': return getContactUpdateSchema(); case 'company': return getCompanyUpdateSchema(); case 'campaign': return getCampaignUpdateSchema(); case 'email': return getEmailUpdateSchema(); case 'segment': return getSegmentUpdateSchema(); case 'tag': return getTagUpdateSchema(); case 'note': return getNoteUpdateSchema(); case 'category': return getCategoryUpdateSchema(); default: return zod_1.z.object({ id: idSchema }); } } function getSchemaForOperation(resource, operation) { switch (operation) { case 'get': if (resource === 'field') return getFieldGetSchema(); return zod_1.z.object({ id: idSchema }); case 'getAll': return getGetAllSchemaForResource(resource); case 'create': return getCreateSchemaForResource(resource); case 'update': return getUpdateSchemaForResource(resource); case 'delete': return zod_1.z.object({ id: idSchema }); case 'sendEmail': return getContactSendEmailSchema(); case 'addToSegments': case 'removeFromSegments': return getContactSegmentBatchSchema(); case 'addToCampaigns': case 'removeFromCampaigns': return getContactCampaignBatchSchema(); case 'addContact': case 'removeContact': if (resource === 'segment') return getSegmentContactSchema(); return zod_1.z.object({}); case 'add': case 'remove': if (resource === 'companyContact') return getCompanyContactSchema(); if (resource === 'campaignContact') return getCampaignContactSchema(); if (resource === 'contactSegment') return getContactSegmentSchema(); return zod_1.z.object({}); case 'send': return getSegmentEmailSendSchema(); default: return zod_1.z.object({ id: idSchema }); } } // --------------------------------------------------------------------------- // buildUnifiedSchema() // --------------------------------------------------------------------------- function buildUnifiedSchema(resource, operations) { const enabledOps = Array.from(new Set(operations.filter(isValidOperation))); if (enabledOps.length === 0) { return zod_1.z.object({ operation: zod_1.z.string().describe('Operation to perform') }); } const operationEnum = zod_1.z .enum(enabledOps) .describe(`Operation to perform. Allowed values: ${enabledOps.join(', ')}.`); const fieldSources = new Map(); const fieldOps = new Map(); for (const operation of enabledOps) { const schema = getSchemaForOperation(resource, operation); for (const [field, fieldSchema] of Object.entries(schema.shape)) { if (!fieldSources.has(field)) fieldSources.set(field, fieldSchema); if (!fieldOps.has(field)) fieldOps.set(field, new Set()); fieldOps.get(field)?.add(operation); } } const mergedShape = { operation: operationEnum }; for (const [field, fieldSchema] of fieldSources.entries()) { const opsForField = Array.from(fieldOps.get(field) ?? []); const baseDescription = fieldSchema.description ?? ''; const opsDescription = `Used by operations: ${opsForField.map((op) => OPERATION_LABELS[op] ?? op).join(', ')}.`; const description = baseDescription ? `${baseDescription} ${opsDescription}` : opsDescription; mergedShape[field] = fieldSchema.optional().describe(description); } return zod_1.z.object(mergedShape); } exports.buildUnifiedSchema = buildUnifiedSchema; // --------------------------------------------------------------------------- // Runtime Zod conversion — converts compile-time Zod schemas to runtime Zod // --------------------------------------------------------------------------- function toRuntimeZodSchema(schema, runtimeZ) { const def = schema?._def; const typeName = def?.typeName; let converted; switch (typeName) { case 'ZodString': { let s = runtimeZ.string(); for (const check of def.checks ?? []) { switch (check.kind) { case 'min': s = s.min(check.value); break; case 'max': s = s.max(check.value); break; case 'email': s = s.email(); break; case 'url': s = s.url(); break; case 'uuid': s = s.uuid(); break; default: break; } } converted = s; break; } case 'ZodNumber': { let n = runtimeZ.number(); for (const check of def.checks ?? []) { switch (check.kind) { case 'int': n = n.int(); break; case 'min': n = check.inclusive === false ? n.gt(check.value) : n.min(check.value); break; case 'max': n = check.inclusive === false ? n.lt(check.value) : n.max(check.value); break; default: break; } } converted = n; break; } case 'ZodBoolean': converted = runtimeZ.boolean(); break; case 'ZodUnknown': converted = runtimeZ.unknown(); break; case 'ZodArray': converted = runtimeZ.array(toRuntimeZodSchema(def.type, runtimeZ)); break; case 'ZodEnum': converted = runtimeZ.enum(def.values); break; case 'ZodRecord': converted = runtimeZ.record(toRuntimeZodSchema(def.valueType, runtimeZ)); break; case 'ZodObject': { const shape = typeof def.shape === 'function' ? def.shape() : def.shape; const runtimeShape = {}; for (const [key, value] of Object.entries(shape ?? {})) { runtimeShape[key] = toRuntimeZodSchema(value, runtimeZ); } let obj = runtimeZ.object(runtimeShape); if (def.unknownKeys === 'passthrough') obj = obj.passthrough(); if (def.unknownKeys === 'strict') obj = obj.strict(); converted = obj; break; } case 'ZodOptional': converted = toRuntimeZodSchema(def.innerType, runtimeZ).optional(); break; case 'ZodNullable': converted = toRuntimeZodSchema(def.innerType, runtimeZ).nullable(); break; case 'ZodDefault': converted = toRuntimeZodSchema(def.innerType, runtimeZ).default(def.defaultValue()); break; case 'ZodLiteral': converted = runtimeZ.literal(def.value); break; case 'ZodUnion': converted = runtimeZ.union((def.options ?? []).map((o) => toRuntimeZodSchema(o, runtimeZ))); break; default: converted = runtimeZ.unknown(); break; } const description = typeof schema?.description === 'string' ? schema.description : undefined; if (description && typeof converted.describe === 'function') { return converted.describe(description); } return converted; } function withRuntimeZod(schemaBuilder, runtimeZ) { return toRuntimeZodSchema(schemaBuilder(), runtimeZ); } function getRuntimeSchemaBuilders(runtimeZ) { return { buildUnifiedSchema: (resource, operations) => withRuntimeZod(() => buildUnifiedSchema(resource, operations), runtimeZ), }; } exports.getRuntimeSchemaBuilders = getRuntimeSchemaBuilders;