payload-plugin-newsletter 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -1
- package/dist/index.cjs +32 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +32 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/access.ts","../src/collections/Subscribers.ts","../src/globals/NewsletterSettings.ts","../src/providers/resend.ts","../src/providers/types.ts","../src/providers/broadcast.ts","../src/providers/index.ts","../src/utils/validation.ts","../src/endpoints/subscribe.ts","../src/utils/jwt.ts","../src/endpoints/verify-magic-link.ts","../src/endpoints/preferences.ts","../src/endpoints/unsubscribe.ts","../src/endpoints/index.ts","../src/fields/newsletterScheduling.ts","../src/index.ts"],"sourcesContent":["import type { Access, AccessArgs } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\n\n/**\n * Check if a user is an admin based on the plugin configuration\n */\nexport const isAdmin = (user: any, config?: NewsletterPluginConfig): boolean => {\n if (!user || user.collection !== 'users') {\n return false\n }\n\n // If custom admin check is provided, use it\n if (config?.access?.isAdmin) {\n return config.access.isAdmin(user)\n }\n\n // Default checks for common admin patterns\n // 1. Check for admin role\n if (user.roles?.includes('admin')) {\n return true\n }\n\n // 2. Check for isAdmin boolean field\n if (user.isAdmin === true) {\n return true\n }\n\n // 3. Check for role field with admin value\n if (user.role === 'admin') {\n return true\n }\n\n // 4. Check for admin collection relationship\n if (user.admin === true) {\n return true\n }\n\n return false\n}\n\n/**\n * Create admin-only access control\n */\nexport const adminOnly = (config?: NewsletterPluginConfig): Access => \n ({ req }: AccessArgs) => {\n const user = req.user\n return isAdmin(user, config)\n }\n\n/**\n * Create admin or owner access control\n */\nexport const adminOrSelf = (config?: NewsletterPluginConfig): Access => \n ({ req, id }: AccessArgs) => {\n const user = req.user\n \n // No user = no access\n if (!user) {\n // For list operations without ID, return impossible condition\n if (!id) {\n return {\n id: {\n equals: 'unauthorized-no-access',\n },\n }\n }\n return false\n }\n \n // Admins can access everything\n if (isAdmin(user, config)) {\n return true\n }\n \n // Synthetic users (subscribers from magic link) can access their own data\n if (user.collection === 'subscribers') {\n // For list operations, scope to their own data\n if (!id) {\n return {\n id: {\n equals: user.id,\n },\n }\n }\n // For specific document access, check if it's their own\n return id === user.id\n }\n \n // Regular users cannot access subscriber data\n if (!id) {\n return {\n id: {\n equals: 'unauthorized-no-access',\n },\n }\n }\n return false\n }","import type { CollectionConfig, Field, CollectionAfterChangeHook, CollectionBeforeDeleteHook } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { adminOnly, adminOrSelf } from '../utils/access'\n\nexport const createSubscribersCollection = (\n pluginConfig: NewsletterPluginConfig\n): CollectionConfig => {\n const slug = pluginConfig.subscribersSlug || 'subscribers'\n \n // Default fields for the subscribers collection\n const defaultFields: Field[] = [\n // Core fields\n {\n name: 'email',\n type: 'email',\n required: true,\n unique: true,\n admin: {\n description: 'Subscriber email address',\n },\n },\n {\n name: 'name',\n type: 'text',\n admin: {\n description: 'Subscriber full name',\n },\n },\n {\n name: 'locale',\n type: 'select',\n options: pluginConfig.i18n?.locales?.map(locale => ({\n label: locale.toUpperCase(),\n value: locale,\n })) || [\n { label: 'EN', value: 'en' },\n ],\n defaultValue: pluginConfig.i18n?.defaultLocale || 'en',\n admin: {\n description: 'Preferred language for communications',\n },\n },\n \n // Authentication fields (hidden from admin UI)\n {\n name: 'magicLinkToken',\n type: 'text',\n hidden: true,\n },\n {\n name: 'magicLinkTokenExpiry',\n type: 'date',\n hidden: true,\n },\n \n // Subscription status\n {\n name: 'subscriptionStatus',\n type: 'select',\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Unsubscribed', value: 'unsubscribed' },\n { label: 'Pending', value: 'pending' },\n ],\n defaultValue: 'pending',\n required: true,\n admin: {\n description: 'Current subscription status',\n },\n },\n {\n name: 'unsubscribedAt',\n type: 'date',\n admin: {\n condition: (data) => data?.subscriptionStatus === 'unsubscribed',\n description: 'When the user unsubscribed',\n readOnly: true,\n },\n },\n \n // Email preferences\n {\n name: 'emailPreferences',\n type: 'group',\n fields: [\n {\n name: 'newsletter',\n type: 'checkbox',\n defaultValue: true,\n label: 'Newsletter',\n admin: {\n description: 'Receive regular newsletter updates',\n },\n },\n {\n name: 'announcements',\n type: 'checkbox',\n defaultValue: true,\n label: 'Announcements',\n admin: {\n description: 'Receive important announcements',\n },\n },\n ],\n admin: {\n description: 'Email communication preferences',\n },\n },\n \n // Source tracking\n {\n name: 'source',\n type: 'text',\n admin: {\n description: 'Where the subscriber signed up from',\n },\n },\n ]\n\n // Add UTM tracking fields if enabled\n if (pluginConfig.features?.utmTracking?.enabled) {\n const utmFields = pluginConfig.features.utmTracking.fields || [\n 'source',\n 'medium',\n 'campaign',\n 'content',\n 'term',\n ]\n \n defaultFields.push({\n name: 'utmParameters',\n type: 'group',\n fields: utmFields.map(field => ({\n name: field,\n type: 'text',\n admin: {\n description: `UTM ${field} parameter`,\n },\n })),\n admin: {\n description: 'UTM tracking parameters',\n },\n })\n }\n\n // Add signup metadata\n defaultFields.push({\n name: 'signupMetadata',\n type: 'group',\n fields: [\n {\n name: 'ipAddress',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'userAgent',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'referrer',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'signupPage',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n ],\n admin: {\n description: 'Technical information about signup',\n },\n })\n\n // Add lead magnet field if enabled\n if (pluginConfig.features?.leadMagnets?.enabled) {\n defaultFields.push({\n name: 'leadMagnet',\n type: 'relationship',\n relationTo: pluginConfig.features.leadMagnets.collection || 'media',\n admin: {\n description: 'Lead magnet downloaded at signup',\n },\n })\n }\n\n // Allow field customization\n let fields = defaultFields\n if (pluginConfig.fields?.overrides) {\n fields = pluginConfig.fields.overrides({ defaultFields })\n }\n if (pluginConfig.fields?.additional) {\n fields = [...fields, ...pluginConfig.fields.additional]\n }\n\n const subscribersCollection: CollectionConfig = {\n slug,\n labels: {\n singular: 'Subscriber',\n plural: 'Subscribers',\n },\n admin: {\n useAsTitle: 'email',\n defaultColumns: ['email', 'name', 'subscriptionStatus', 'createdAt'],\n group: 'Newsletter',\n },\n fields,\n hooks: {\n afterChange: [\n async ({ doc, req, operation, previousDoc }) => {\n // After create logic\n if (operation === 'create') {\n // Add to email service\n const emailService = (req.payload as any).newsletterEmailService\n if (emailService) {\n try {\n await emailService.addContact(doc)\n } catch {\n // Failed to add contact to email service\n }\n }\n\n // Send welcome email if active\n if (doc.subscriptionStatus === 'active' && emailService) {\n try {\n // TODO: Send welcome email\n } catch {\n // Failed to send welcome email\n }\n }\n\n // Custom after subscribe hook\n if (pluginConfig.hooks?.afterSubscribe) {\n await pluginConfig.hooks.afterSubscribe({ doc, req })\n }\n }\n \n // After update logic\n if (operation === 'update' && previousDoc) {\n // Update email service if status changed\n const emailService = (req.payload as any).newsletterEmailService\n if (\n doc.subscriptionStatus !== previousDoc.subscriptionStatus &&\n emailService\n ) {\n try {\n await emailService.updateContact(doc)\n } catch {\n // Failed to update contact in email service\n }\n }\n\n // Handle unsubscribe\n if (\n doc.subscriptionStatus === 'unsubscribed' &&\n previousDoc.subscriptionStatus !== 'unsubscribed'\n ) {\n // Set unsubscribed timestamp\n doc.unsubscribedAt = new Date().toISOString()\n \n // Custom after unsubscribe hook\n if (pluginConfig.hooks?.afterUnsubscribe) {\n await pluginConfig.hooks.afterUnsubscribe({ doc, req })\n }\n }\n }\n },\n ] as CollectionAfterChangeHook[],\n beforeDelete: [\n async ({ id, req }) => {\n // Remove from email service\n const emailService = (req.payload as any).newsletterEmailService\n if (emailService) {\n try {\n const doc = await req.payload.findByID({\n collection: slug,\n id,\n })\n await emailService.removeContact(doc.email)\n } catch {\n // Failed to remove contact from email service\n }\n }\n },\n ] as CollectionBeforeDeleteHook[],\n },\n access: {\n create: () => true, // Public can subscribe\n read: adminOrSelf(pluginConfig),\n update: adminOrSelf(pluginConfig),\n delete: adminOnly(pluginConfig),\n },\n timestamps: true,\n }\n\n return subscribersCollection\n}","import type { GlobalConfig } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { adminOnly } from '../utils/access'\n\nexport const createNewsletterSettingsGlobal = (\n pluginConfig: NewsletterPluginConfig\n): GlobalConfig => {\n const slug = pluginConfig.settingsSlug || 'newsletter-settings'\n \n return {\n slug,\n label: 'Newsletter Settings',\n admin: {\n group: 'Newsletter',\n description: 'Configure email provider settings and templates',\n },\n fields: [\n {\n type: 'tabs',\n tabs: [\n {\n label: 'Provider Settings',\n fields: [\n {\n name: 'provider',\n type: 'select',\n label: 'Email Provider',\n required: true,\n options: [\n { label: 'Resend', value: 'resend' },\n { label: 'Broadcast (Self-Hosted)', value: 'broadcast' },\n ],\n defaultValue: pluginConfig.providers.default,\n admin: {\n description: 'Choose which email service to use',\n },\n },\n {\n name: 'resendSettings',\n type: 'group',\n label: 'Resend Settings',\n admin: {\n condition: (data) => data?.provider === 'resend',\n },\n fields: [\n {\n name: 'apiKey',\n type: 'text',\n label: 'API Key',\n required: true,\n admin: {\n description: 'Your Resend API key',\n },\n },\n {\n name: 'audienceIds',\n type: 'array',\n label: 'Audience IDs by Locale',\n fields: [\n {\n name: 'locale',\n type: 'select',\n label: 'Locale',\n required: true,\n options: pluginConfig.i18n?.locales?.map(locale => ({\n label: locale.toUpperCase(),\n value: locale,\n })) || [\n { label: 'EN', value: 'en' },\n ],\n },\n {\n name: 'production',\n type: 'text',\n label: 'Production Audience ID',\n },\n {\n name: 'development',\n type: 'text',\n label: 'Development Audience ID',\n },\n ],\n },\n ],\n },\n {\n name: 'broadcastSettings',\n type: 'group',\n label: 'Broadcast Settings',\n admin: {\n condition: (data) => data?.provider === 'broadcast',\n },\n fields: [\n {\n name: 'apiUrl',\n type: 'text',\n label: 'API URL',\n required: true,\n admin: {\n description: 'Your Broadcast instance URL',\n },\n },\n {\n name: 'productionToken',\n type: 'text',\n label: 'Production Token',\n admin: {\n description: 'Token for production environment',\n },\n },\n {\n name: 'developmentToken',\n type: 'text',\n label: 'Development Token',\n admin: {\n description: 'Token for development environment',\n },\n },\n ],\n },\n {\n name: 'fromAddress',\n type: 'email',\n label: 'From Address',\n required: true,\n admin: {\n description: 'Default sender email address',\n },\n },\n {\n name: 'fromName',\n type: 'text',\n label: 'From Name',\n required: true,\n admin: {\n description: 'Default sender name',\n },\n },\n {\n name: 'replyTo',\n type: 'email',\n label: 'Reply-To Address',\n admin: {\n description: 'Optional reply-to email address',\n },\n },\n ],\n },\n {\n label: 'Email Templates',\n fields: [\n {\n name: 'emailTemplates',\n type: 'group',\n label: 'Email Templates',\n fields: [\n {\n name: 'welcome',\n type: 'group',\n label: 'Welcome Email',\n fields: [\n {\n name: 'enabled',\n type: 'checkbox',\n label: 'Send Welcome Email',\n defaultValue: true,\n },\n {\n name: 'subject',\n type: 'text',\n label: 'Subject Line',\n defaultValue: 'Welcome to {{fromName}}!',\n admin: {\n condition: (data) => data?.emailTemplates?.welcome?.enabled,\n },\n },\n {\n name: 'preheader',\n type: 'text',\n label: 'Preheader Text',\n admin: {\n condition: (data) => data?.emailTemplates?.welcome?.enabled,\n },\n },\n ],\n },\n {\n name: 'magicLink',\n type: 'group',\n label: 'Magic Link Email',\n fields: [\n {\n name: 'subject',\n type: 'text',\n label: 'Subject Line',\n defaultValue: 'Sign in to {{fromName}}',\n },\n {\n name: 'preheader',\n type: 'text',\n label: 'Preheader Text',\n defaultValue: 'Click the link to access your preferences',\n },\n {\n name: 'expirationTime',\n type: 'select',\n label: 'Link Expiration',\n defaultValue: '7d',\n options: [\n { label: '1 hour', value: '1h' },\n { label: '24 hours', value: '24h' },\n { label: '7 days', value: '7d' },\n { label: '30 days', value: '30d' },\n ],\n },\n ],\n },\n ],\n },\n ],\n },\n {\n label: 'Subscription Settings',\n fields: [\n {\n name: 'subscriptionSettings',\n type: 'group',\n label: 'Subscription Settings',\n fields: [\n {\n name: 'requireDoubleOptIn',\n type: 'checkbox',\n label: 'Require Double Opt-In',\n defaultValue: false,\n admin: {\n description: 'Require email confirmation before activating subscriptions',\n },\n },\n {\n name: 'allowedDomains',\n type: 'array',\n label: 'Allowed Email Domains',\n admin: {\n description: 'Leave empty to allow all domains',\n },\n fields: [\n {\n name: 'domain',\n type: 'text',\n label: 'Domain',\n required: true,\n admin: {\n placeholder: 'example.com',\n },\n },\n ],\n },\n {\n name: 'maxSubscribersPerIP',\n type: 'number',\n label: 'Max Subscribers per IP',\n defaultValue: 10,\n min: 1,\n admin: {\n description: 'Maximum number of subscriptions allowed from a single IP address',\n },\n },\n ],\n },\n ],\n },\n ],\n },\n ],\n hooks: {\n beforeChange: [\n async ({ data, req }) => {\n // Verify admin access for settings changes\n if (!req.user || req.user.collection !== 'users') {\n throw new Error('Only administrators can modify newsletter settings')\n }\n \n return data\n },\n ],\n afterChange: [\n async ({ doc, req }) => {\n // Reinitialize email service when settings change\n if ((req.payload as any).newsletterEmailService) {\n try {\n // TODO: Implement email service reinitialization\n console.warn('Newsletter settings updated, reinitializing service...')\n } catch {\n // Failed to reinitialize email service\n }\n }\n \n return doc\n },\n ],\n },\n access: {\n read: () => true, // Settings can be read publicly for validation\n update: adminOnly(pluginConfig),\n },\n }\n}","import { Resend } from 'resend'\nimport type { EmailProvider, SendEmailParams } from './types'\nimport { EmailProviderError } from './types'\nimport type { Subscriber, ResendProviderConfig } from '../types'\n\nexport class ResendProvider implements EmailProvider {\n private client: Resend\n private audienceIds: ResendProviderConfig['audienceIds']\n private fromAddress: string\n private fromName: string\n private isDevelopment: boolean\n\n constructor(config: ResendProviderConfig & { \n fromAddress: string\n fromName: string \n }) {\n this.client = new Resend(config.apiKey)\n this.audienceIds = config.audienceIds || {}\n this.fromAddress = config.fromAddress\n this.fromName = config.fromName\n this.isDevelopment = process.env.NODE_ENV !== 'production'\n }\n\n getProvider(): string {\n return 'resend'\n }\n\n async send(params: SendEmailParams): Promise<void> {\n try {\n const from = params.from || {\n email: this.fromAddress,\n name: this.fromName,\n }\n\n if (!params.html && !params.text) {\n throw new Error('Either html or text content is required')\n }\n\n await this.client.emails.send({\n from: `${from.name} <${from.email}>`,\n to: Array.isArray(params.to) ? params.to : [params.to],\n subject: params.subject,\n html: params.html || '',\n text: params.text,\n replyTo: params.replyTo,\n })\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to send email via Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n try {\n const audienceId = this.getAudienceId(contact.locale)\n if (!audienceId) {\n console.warn(`No audience ID configured for locale: ${contact.locale}`)\n return\n }\n\n await this.client.contacts.create({\n email: contact.email,\n firstName: contact.name?.split(' ')[0],\n lastName: contact.name?.split(' ').slice(1).join(' '),\n unsubscribed: contact.subscriptionStatus === 'unsubscribed',\n audienceId,\n })\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to add contact to Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n try {\n const audienceId = this.getAudienceId(contact.locale)\n if (!audienceId) {\n console.warn(`No audience ID configured for locale: ${contact.locale}`)\n return\n }\n\n // Resend requires finding the contact first\n const contacts = await this.client.contacts.list({ audienceId })\n const existingContact = contacts.data?.data?.find(c => c.email === contact.email)\n\n if (existingContact) {\n await this.client.contacts.update({\n id: existingContact.id,\n audienceId,\n firstName: contact.name?.split(' ')[0],\n lastName: contact.name?.split(' ').slice(1).join(' '),\n unsubscribed: contact.subscriptionStatus === 'unsubscribed',\n })\n } else {\n // If contact doesn't exist, add them\n await this.addContact(contact)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to update contact in Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async removeContact(email: string): Promise<void> {\n try {\n // Resend doesn't have a direct remove method, so we unsubscribe instead\n // First, we need to find the contact across all audiences\n for (const locale in this.audienceIds) {\n const audienceId = this.getAudienceId(locale)\n if (!audienceId) continue\n\n const contacts = await this.client.contacts.list({ audienceId })\n const contact = contacts.data?.data?.find(c => c.email === email)\n\n if (contact) {\n await this.client.contacts.update({\n id: contact.id,\n audienceId,\n unsubscribed: true,\n })\n break\n }\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to remove contact from Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n private getAudienceId(locale?: string): string | undefined {\n const localeKey = locale || 'en'\n if (!this.audienceIds) return undefined\n \n const localeConfig = this.audienceIds[localeKey]\n if (!localeConfig) return undefined\n\n const audienceId = this.isDevelopment \n ? (localeConfig.development || localeConfig.production)\n : (localeConfig.production || localeConfig.development)\n \n return audienceId\n }\n}","import type { Subscriber } from '../types'\n\nexport interface EmailProvider {\n send(params: SendEmailParams): Promise<void>\n addContact(contact: Subscriber): Promise<void>\n updateContact(contact: Subscriber): Promise<void>\n removeContact(email: string): Promise<void>\n getProvider(): string\n}\n\nexport interface SendEmailParams {\n to: string | string[]\n subject: string\n html?: string\n text?: string\n react?: React.ReactElement\n from?: {\n email: string\n name?: string\n }\n replyTo?: string\n}\n\nexport interface EmailServiceConfig {\n provider: 'resend' | 'broadcast' | string\n fromAddress: string\n fromName: string\n replyTo?: string\n resend?: {\n apiKey: string\n audienceIds?: Record<string, { production?: string; development?: string }>\n }\n broadcast?: {\n apiUrl: string\n tokens: {\n production?: string\n development?: string\n }\n }\n}\n\nexport class EmailProviderError extends Error {\n provider: string\n originalError?: any\n\n constructor(message: string, provider: string, originalError?: any) {\n super(message)\n this.name = 'EmailProviderError'\n this.provider = provider\n this.originalError = originalError\n }\n}","import type { EmailProvider, SendEmailParams } from './types'\nimport { EmailProviderError } from './types'\nimport type { Subscriber, BroadcastProviderConfig } from '../types'\n\nexport class BroadcastProvider implements EmailProvider {\n private apiUrl: string\n private token: string\n private fromAddress: string\n private fromName: string\n private isDevelopment: boolean\n\n constructor(config: BroadcastProviderConfig & { \n fromAddress: string\n fromName: string \n }) {\n this.apiUrl = config.apiUrl.replace(/\\/$/, '') // Remove trailing slash\n this.isDevelopment = process.env.NODE_ENV !== 'production'\n this.token = this.isDevelopment \n ? config.tokens.development || config.tokens.production || ''\n : config.tokens.production || config.tokens.development || ''\n this.fromAddress = config.fromAddress\n this.fromName = config.fromName\n }\n\n getProvider(): string {\n return 'broadcast'\n }\n\n async send(params: SendEmailParams): Promise<void> {\n try {\n const from = params.from || {\n email: this.fromAddress,\n name: this.fromName,\n }\n\n const recipients = Array.isArray(params.to) ? params.to : [params.to]\n \n // Broadcast expects a specific format\n const response = await fetch(`${this.apiUrl}/api/v1/emails`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n from_email: from.email,\n from_name: from.name,\n to: recipients,\n subject: params.subject,\n html_body: params.html,\n text_body: params.text,\n reply_to: params.replyTo,\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to send email via Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n try {\n const response = await fetch(`${this.apiUrl}/api/v1/contacts`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n email: contact.email,\n name: contact.name,\n status: contact.subscriptionStatus === 'active' ? 'subscribed' : 'unsubscribed',\n metadata: {\n locale: contact.locale,\n source: contact.source,\n ...contact.utmParameters,\n },\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to add contact to Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n try {\n // First, try to find the contact\n const searchResponse = await fetch(\n `${this.apiUrl}/api/v1/contacts?email=${encodeURIComponent(contact.email)}`,\n {\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n },\n }\n )\n\n if (!searchResponse.ok) {\n // If contact doesn't exist, create it\n await this.addContact(contact)\n return\n }\n\n const contacts = await searchResponse.json()\n const existingContact = contacts.data?.[0]\n\n if (!existingContact) {\n await this.addContact(contact)\n return\n }\n\n // Update existing contact\n const response = await fetch(`${this.apiUrl}/api/v1/contacts/${existingContact.id}`, {\n method: 'PUT',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n email: contact.email,\n name: contact.name,\n status: contact.subscriptionStatus === 'active' ? 'subscribed' : 'unsubscribed',\n metadata: {\n locale: contact.locale,\n source: contact.source,\n ...contact.utmParameters,\n },\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to update contact in Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async removeContact(email: string): Promise<void> {\n try {\n // First, find the contact\n const searchResponse = await fetch(\n `${this.apiUrl}/api/v1/contacts?email=${encodeURIComponent(email)}`,\n {\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n },\n }\n )\n\n if (!searchResponse.ok) {\n // Contact doesn't exist, nothing to remove\n return\n }\n\n const contacts = await searchResponse.json()\n const contact = contacts.data?.[0]\n\n if (!contact) {\n return\n }\n\n // Delete the contact\n const response = await fetch(`${this.apiUrl}/api/v1/contacts/${contact.id}`, {\n method: 'DELETE',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n },\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to remove contact from Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n}","import type { EmailProvider, EmailServiceConfig, SendEmailParams } from './types'\nimport type { Subscriber } from '../types'\nimport { ResendProvider } from './resend'\nimport { BroadcastProvider } from './broadcast'\n\nexport * from './types'\n\nexport class EmailService {\n private provider: EmailProvider\n\n constructor(config: EmailServiceConfig) {\n this.provider = this.createProvider(config)\n }\n\n private createProvider(config: EmailServiceConfig): EmailProvider {\n const baseConfig = {\n fromAddress: config.fromAddress,\n fromName: config.fromName,\n }\n\n switch (config.provider) {\n case 'resend':\n if (!config.resend) {\n throw new Error('Resend configuration is required when using Resend provider')\n }\n return new ResendProvider({\n ...config.resend,\n ...baseConfig,\n })\n\n case 'broadcast':\n if (!config.broadcast) {\n throw new Error('Broadcast configuration is required when using Broadcast provider')\n }\n return new BroadcastProvider({\n ...config.broadcast,\n ...baseConfig,\n })\n\n default:\n throw new Error(`Unknown email provider: ${config.provider}`)\n }\n }\n\n async send(params: SendEmailParams): Promise<void> {\n return this.provider.send(params)\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n return this.provider.addContact(contact)\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n return this.provider.updateContact(contact)\n }\n\n async removeContact(email: string): Promise<void> {\n return this.provider.removeContact(email)\n }\n\n getProvider(): string {\n return this.provider.getProvider()\n }\n\n /**\n * Update the provider configuration\n * Useful when settings are changed in the admin UI\n */\n updateConfig(config: EmailServiceConfig): void {\n this.provider = this.createProvider(config)\n }\n}\n\n/**\n * Create email service from plugin configuration\n */\nexport function createEmailService(config: EmailServiceConfig): EmailService {\n return new EmailService(config)\n}","import DOMPurify from 'isomorphic-dompurify'\n\n/**\n * Validate email address format\n */\nexport function isValidEmail(email: string): boolean {\n if (!email || typeof email !== 'string') return false\n \n // Trim whitespace\n const trimmed = email.trim()\n \n // Length limits\n if (trimmed.length > 255) return false\n \n // Check for dangerous patterns\n if (trimmed.includes('<') || trimmed.includes('>')) return false\n if (trimmed.includes('javascript:')) return false\n if (trimmed.includes('data:')) return false\n \n // Basic format validation with stricter regex\n const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/\n if (!emailRegex.test(trimmed)) return false\n \n // Additional validation rules\n const parts = trimmed.split('@')\n if (parts.length !== 2) return false\n \n const [localPart, domain] = parts\n \n // Check local part length\n if (localPart.length > 64 || localPart.length === 0) return false\n \n // Check for invalid patterns\n if (localPart.startsWith('.') || localPart.endsWith('.')) return false\n if (domain.startsWith('.') || domain.endsWith('.')) return false\n if (domain.includes('..')) return false\n if (localPart.includes('..')) return false\n \n return true\n}\n\n/**\n * Normalize email for rate limiting and deduplication\n */\nexport function normalizeEmail(email: string): string {\n if (!email || typeof email !== 'string') return ''\n \n const parts = email.toLowerCase().trim().split('@')\n if (parts.length !== 2) return email.toLowerCase().trim()\n \n let [localPart] = parts\n const [, domain] = parts\n \n // Remove dots from local part (Gmail-style)\n localPart = localPart.replace(/\\./g, '')\n \n // Remove everything after + (Gmail-style aliases)\n const plusIndex = localPart.indexOf('+')\n if (plusIndex > -1) {\n localPart = localPart.substring(0, plusIndex)\n }\n \n return `${localPart}@${domain}`\n}\n\n/**\n * Check if email domain is allowed\n */\nexport function isDomainAllowed(\n email: string,\n allowedDomains?: string[]\n): boolean {\n // Validate email format first\n if (!isValidEmail(email)) {\n return false\n }\n \n // If no domains specified, allow all valid emails\n if (!allowedDomains || allowedDomains.length === 0) {\n return true\n }\n\n const domain = email.split('@')[1]?.toLowerCase()\n if (!domain) return false\n\n return allowedDomains.some(\n allowedDomain => domain === allowedDomain.toLowerCase()\n )\n}\n\n/**\n * Sanitize user input to prevent XSS\n */\nexport function sanitizeInput(input: string): string {\n if (!input) return ''\n \n // First, remove all HTML tags and scripts\n let cleaned = DOMPurify.sanitize(input, { \n ALLOWED_TAGS: [],\n ALLOWED_ATTR: [],\n KEEP_CONTENT: true\n })\n \n // Additional security: remove dangerous patterns\n cleaned = cleaned\n .replace(/javascript:/gi, '')\n .replace(/data:/gi, '')\n .replace(/vbscript:/gi, '')\n .replace(/file:\\/\\//gi, '')\n .replace(/onload/gi, '')\n .replace(/onerror/gi, '')\n .replace(/onclick/gi, '')\n .replace(/onmouseover/gi, '')\n .replace(/alert\\(/gi, '')\n .replace(/prompt\\(/gi, '')\n .replace(/confirm\\(/gi, '')\n .replace(/\\|/g, '') // Remove pipe character (command injection)\n .replace(/;/g, '') // Remove semicolon (command chaining)\n .replace(/`/g, '') // Remove backticks (command substitution)\n .replace(/&&/g, '') // Remove command chaining\n .replace(/\\$\\(/g, '') // Remove command substitution pattern $()\n .replace(/\\.\\./g, '') // Remove directory traversal\n .replace(/\\/..\\//g, '') // Remove path traversal\n .replace(/\\0/g, '') // Remove null bytes\n \n return cleaned.trim()\n}\n\n/**\n * Extract UTM parameters from URL search params\n */\nexport function extractUTMParams(searchParams: URLSearchParams): Record<string, string> {\n const utmParams: Record<string, string> = {}\n const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']\n\n utmKeys.forEach(key => {\n const value = searchParams.get(key)\n if (value) {\n // Remove 'utm_' prefix for storage\n const shortKey = key.replace('utm_', '')\n utmParams[shortKey] = value\n }\n })\n\n return utmParams\n}\n\n/**\n * Validate source field - only allow predefined values\n */\nexport function isValidSource(source: string): boolean {\n if (!source || typeof source !== 'string') return false\n \n const allowedSources = [\n 'website',\n 'api',\n 'import',\n 'admin',\n 'signup-form',\n 'magic-link',\n 'preferences',\n 'external'\n ]\n \n return allowedSources.includes(source)\n}\n\n/**\n * Validate subscriber data before creation\n */\nexport interface ValidateSubscriberResult {\n valid: boolean\n errors: string[]\n}\n\nexport function validateSubscriberData(data: any): ValidateSubscriberResult {\n const errors: string[] = []\n\n // Email validation\n if (!data.email) {\n errors.push('Email is required')\n } else if (!isValidEmail(data.email)) {\n errors.push('Invalid email format')\n }\n\n // Name validation (optional but if provided, should be reasonable)\n if (data.name && data.name.length > 100) {\n errors.push('Name is too long (max 100 characters)')\n }\n\n // Source validation\n if (data.source !== undefined) {\n if (!data.source || data.source.length === 0) {\n errors.push('Source cannot be empty')\n } else if (data.source.length > 50) {\n errors.push('Source is too long (max 50 characters)')\n } else if (!isValidSource(data.source)) {\n errors.push('Invalid source value')\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { \n isDomainAllowed, \n sanitizeInput, \n validateSubscriberData,\n extractUTMParams \n} from '../utils/validation'\n\nexport const createSubscribeEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/subscribe',\n method: 'post',\n handler: (async (req: any, res: any) => {\n try {\n const { \n email, \n name, \n source,\n preferences,\n leadMagnet,\n surveyResponses,\n metadata = {}\n } = req.body\n\n // Trim email before validation\n const trimmedEmail = email?.trim()\n\n // Validate input\n const validation = validateSubscriberData({ email: trimmedEmail, name, source })\n if (!validation.valid) {\n return res.status(400).json({\n success: false,\n errors: validation.errors,\n })\n }\n\n // Check domain restrictions from global settings\n // Settings are public info needed for validation, but we can still respect access control\n const settings = await req.payload.findGlobal({\n slug: config.settingsSlug || 'newsletter-settings',\n overrideAccess: false,\n // No user context for public endpoint\n })\n\n const allowedDomains = settings?.subscriptionSettings?.allowedDomains?.map((d: any) => d.domain) || []\n if (!isDomainAllowed(trimmedEmail, allowedDomains)) {\n return res.status(400).json({\n success: false,\n error: 'Email domain not allowed',\n })\n }\n\n // Check if already subscribed\n // This needs admin access to check for existing email\n const existing = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n email: {\n equals: trimmedEmail.toLowerCase(),\n },\n },\n overrideAccess: true, // Need to check for duplicates in public endpoint\n })\n\n if (existing.docs.length > 0) {\n const subscriber = existing.docs[0]\n \n // If unsubscribed, don't allow resubscription via API\n if (subscriber.subscriptionStatus === 'unsubscribed') {\n return res.status(400).json({\n success: false,\n error: 'This email has been unsubscribed. Please contact support to resubscribe.',\n })\n }\n\n return res.status(400).json({\n success: false,\n error: 'Already subscribed',\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n })\n }\n\n // Check IP rate limiting\n const ipAddress = req.ip || req.connection.remoteAddress\n const maxPerIP = settings?.subscriptionSettings?.maxSubscribersPerIP || 10\n\n const ipSubscribers = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n 'signupMetadata.ipAddress': {\n equals: ipAddress,\n },\n },\n overrideAccess: true, // Need to check IP limits in public endpoint\n })\n\n if (ipSubscribers.docs.length >= maxPerIP) {\n return res.status(429).json({\n success: false,\n error: 'Too many subscriptions from this IP address',\n })\n }\n\n // Extract UTM parameters\n const referer = req.headers.referer || req.headers.referrer || ''\n let utmParams = {}\n if (referer) {\n try {\n utmParams = extractUTMParams(new URL(referer).searchParams)\n } catch {\n // Invalid URL, ignore UTM params\n }\n }\n\n // Prepare subscriber data\n const subscriberData: any = {\n email: trimmedEmail.toLowerCase(),\n name: name ? sanitizeInput(name) : undefined,\n locale: metadata.locale || config.i18n?.defaultLocale || 'en',\n subscriptionStatus: settings?.subscriptionSettings?.requireDoubleOptIn ? 'pending' : 'active',\n source: source || 'api',\n emailPreferences: {\n newsletter: true,\n announcements: true,\n ...(preferences || {}),\n },\n signupMetadata: {\n ipAddress,\n userAgent: req.headers['user-agent'],\n referrer: referer,\n signupPage: metadata.signupPage || referer,\n },\n }\n\n // Add UTM parameters if tracking is enabled\n if (config.features?.utmTracking?.enabled && Object.keys(utmParams).length > 0) {\n subscriberData.utmParameters = utmParams\n }\n\n // Add lead magnet if provided\n if (config.features?.leadMagnets?.enabled && leadMagnet) {\n subscriberData.leadMagnet = leadMagnet\n }\n\n // Create subscriber\n // Public endpoint needs to create subscribers\n const subscriber = await req.payload.create({\n collection: config.subscribersSlug || 'subscribers',\n data: subscriberData,\n overrideAccess: true, // Public endpoint needs to create subscribers\n })\n\n // Handle survey responses if provided\n if (config.features?.surveys?.enabled && surveyResponses) {\n // TODO: Store survey responses\n }\n\n // Send confirmation email if double opt-in\n if (settings?.subscriptionSettings?.requireDoubleOptIn) {\n // TODO: Send confirmation email with magic link\n }\n\n res.json({\n success: true,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n message: settings?.subscriptionSettings?.requireDoubleOptIn \n ? 'Please check your email to confirm your subscription'\n : 'Successfully subscribed',\n })\n } catch {\n res.status(500).json({\n success: false,\n error: 'Failed to subscribe. Please try again.',\n })\n }\n }) as PayloadHandler,\n }\n}","import jwt from 'jsonwebtoken'\nimport type { NewsletterPluginConfig } from '../types'\n\nexport interface MagicLinkTokenPayload {\n subscriberId: string\n email: string\n type: 'magic-link'\n}\n\nexport interface SessionTokenPayload {\n subscriberId: string\n email: string\n type: 'session'\n}\n\n/**\n * Get JWT secret from environment or generate a warning\n */\nfunction getJWTSecret(): string {\n const secret = process.env.JWT_SECRET || process.env.PAYLOAD_SECRET\n\n if (!secret) {\n console.warn(\n 'WARNING: No JWT_SECRET or PAYLOAD_SECRET found in environment variables. ' +\n 'Magic link authentication will not work properly. ' +\n 'Please set JWT_SECRET in your environment.'\n )\n // Return a placeholder to prevent crashes during development\n return 'INSECURE_DEVELOPMENT_SECRET_PLEASE_SET_JWT_SECRET'\n }\n\n return secret\n}\n\n/**\n * Generate a magic link token for email authentication\n */\nexport function generateMagicLinkToken(\n subscriberId: string,\n email: string,\n config: NewsletterPluginConfig\n): string {\n const payload: MagicLinkTokenPayload = {\n subscriberId,\n email,\n type: 'magic-link',\n }\n\n const expiresIn = config.auth?.tokenExpiration || '7d'\n\n return jwt.sign(payload, getJWTSecret(), {\n expiresIn: expiresIn,\n issuer: 'payload-newsletter-plugin',\n } as jwt.SignOptions)\n}\n\n/**\n * Verify a magic link token\n */\nexport function verifyMagicLinkToken(token: string): MagicLinkTokenPayload {\n try {\n const payload = jwt.verify(token, getJWTSecret(), {\n issuer: 'payload-newsletter-plugin',\n }) as any\n\n if (payload.type !== 'magic-link') {\n throw new Error('Invalid token type')\n }\n\n return payload as MagicLinkTokenPayload\n } catch (error: unknown) {\n if (error instanceof Error && error.name === 'TokenExpiredError') {\n throw new Error('Magic link has expired. Please request a new one.')\n }\n if (error instanceof Error && error.name === 'JsonWebTokenError') {\n throw new Error('Invalid magic link token')\n }\n throw error\n }\n}\n\n/**\n * Generate a session token after successful magic link verification\n */\nexport function generateSessionToken(\n subscriberId: string,\n email: string\n): string {\n const payload: SessionTokenPayload = {\n subscriberId,\n email,\n type: 'session',\n }\n\n return jwt.sign(payload, getJWTSecret(), {\n expiresIn: '30d',\n issuer: 'payload-newsletter-plugin',\n })\n}\n\n/**\n * Verify a session token\n */\nexport function verifySessionToken(token: string): SessionTokenPayload {\n try {\n const payload = jwt.verify(token, getJWTSecret(), {\n issuer: 'payload-newsletter-plugin',\n }) as any\n\n if (payload.type !== 'session') {\n throw new Error('Invalid token type')\n }\n\n return payload as SessionTokenPayload\n } catch (error: unknown) {\n if (error instanceof Error && error.name === 'TokenExpiredError') {\n throw new Error('Session has expired. Please sign in again.')\n }\n if (error instanceof Error && error.name === 'JsonWebTokenError') {\n throw new Error('Invalid session token')\n }\n throw error\n }\n}\n\n/**\n * Generate a magic link URL\n */\nexport function generateMagicLinkURL(\n token: string,\n baseURL: string,\n config: NewsletterPluginConfig\n): string {\n const path = config.auth?.magicLinkPath || '/newsletter/verify'\n const url = new URL(path, baseURL)\n url.searchParams.set('token', token)\n return url.toString()\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { \n verifyMagicLinkToken, \n generateSessionToken \n} from '../utils/jwt'\n\nexport const createVerifyMagicLinkEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/verify-magic-link',\n method: 'post',\n handler: (async (req: any, res: any) => {\n try {\n const { token } = req.body\n\n if (!token) {\n return res.status(400).json({\n success: false,\n error: 'Token is required',\n })\n }\n\n // Verify the magic link token\n let payload\n try {\n payload = verifyMagicLinkToken(token)\n } catch (error: unknown) {\n return res.status(401).json({\n success: false,\n error: error instanceof Error ? error.message : 'Invalid token',\n })\n }\n\n // Find the subscriber - token verified so we can use admin access for initial lookup\n const subscriber = await req.payload.findByID({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n // Keep overrideAccess: true for token verification\n })\n\n if (!subscriber) {\n return res.status(404).json({\n success: false,\n error: 'Subscriber not found',\n })\n }\n\n // Check if email matches\n if (subscriber.email !== payload.email) {\n return res.status(401).json({\n success: false,\n error: 'Invalid token',\n })\n }\n\n // Check if subscriber is active\n if (subscriber.subscriptionStatus === 'unsubscribed') {\n return res.status(403).json({\n success: false,\n error: 'This email has been unsubscribed',\n })\n }\n\n // Create synthetic user for subscriber operations\n const syntheticUser = {\n collection: 'subscribers',\n id: subscriber.id,\n email: subscriber.email,\n }\n\n // Update subscription status if pending\n if (subscriber.subscriptionStatus === 'pending') {\n await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: subscriber.id,\n data: {\n subscriptionStatus: 'active',\n },\n overrideAccess: false,\n user: syntheticUser,\n })\n }\n\n // Clear the magic link token\n await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: subscriber.id,\n data: {\n magicLinkToken: null,\n magicLinkTokenExpiry: null,\n },\n overrideAccess: false,\n user: syntheticUser,\n })\n\n // Generate session token\n const sessionToken = generateSessionToken(\n String(subscriber.id),\n subscriber.email\n )\n\n res.json({\n success: true,\n sessionToken,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n name: subscriber.name,\n locale: subscriber.locale,\n emailPreferences: subscriber.emailPreferences,\n },\n })\n } catch (error: unknown) {\n console.error('Verify magic link error:', error)\n res.status(500).json({\n success: false,\n error: 'Failed to verify magic link',\n })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { verifySessionToken } from '../utils/jwt'\n\nexport const createPreferencesEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/preferences',\n method: 'get',\n handler: (async (req: any, res: any) => {\n try {\n // Get token from Authorization header\n const authHeader = req.headers.authorization\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n return res.status(401).json({\n success: false,\n error: 'Authorization required',\n })\n }\n\n const token = authHeader.substring(7)\n\n // Verify session token\n let payload\n try {\n payload = verifySessionToken(token)\n } catch (error: unknown) {\n return res.status(401).json({\n success: false,\n error: error instanceof Error ? error.message : 'Invalid token',\n })\n }\n\n // Get subscriber - use synthetic user to ensure access control\n const subscriber = await req.payload.findByID({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n overrideAccess: false,\n user: {\n collection: 'subscribers',\n id: payload.subscriberId,\n email: payload.email,\n },\n })\n\n if (!subscriber) {\n return res.status(404).json({\n success: false,\n error: 'Subscriber not found',\n })\n }\n\n res.json({\n success: true,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n name: subscriber.name,\n locale: subscriber.locale,\n emailPreferences: subscriber.emailPreferences,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n })\n } catch (error: unknown) {\n console.error('Get preferences error:', error)\n res.status(500).json({\n success: false,\n error: 'Failed to get preferences',\n })\n }\n }) as PayloadHandler,\n }\n}\n\nexport const createUpdatePreferencesEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/preferences',\n method: 'post',\n handler: (async (req: any, res: any) => {\n try {\n // Get token from Authorization header\n const authHeader = req.headers.authorization\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n return res.status(401).json({\n success: false,\n error: 'Authorization required',\n })\n }\n\n const token = authHeader.substring(7)\n\n // Verify session token\n let payload\n try {\n payload = verifySessionToken(token)\n } catch (error: unknown) {\n return res.status(401).json({\n success: false,\n error: error instanceof Error ? error.message : 'Invalid token',\n })\n }\n\n const { name, locale, emailPreferences } = req.body\n\n // Prepare update data\n const updateData: any = {}\n \n if (name !== undefined) {\n updateData.name = name\n }\n \n if (locale !== undefined) {\n updateData.locale = locale\n }\n \n if (emailPreferences !== undefined) {\n updateData.emailPreferences = emailPreferences\n }\n\n // Update subscriber - use synthetic user to ensure only updating own data\n const subscriber = await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n data: updateData,\n overrideAccess: false,\n user: {\n collection: 'subscribers',\n id: payload.subscriberId,\n email: payload.email,\n },\n })\n\n res.json({\n success: true,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n name: subscriber.name,\n locale: subscriber.locale,\n emailPreferences: subscriber.emailPreferences,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n })\n } catch (error: unknown) {\n console.error('Update preferences error:', error)\n res.status(500).json({\n success: false,\n error: 'Failed to update preferences',\n })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { isValidEmail } from '../utils/validation'\n\nexport const createUnsubscribeEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/unsubscribe',\n method: 'post',\n handler: (async (req: any, res: any) => {\n try {\n const { email, token } = req.body\n\n // Two methods: email or token\n if (!email && !token) {\n return res.status(400).json({\n success: false,\n error: 'Email or token is required',\n })\n }\n\n let subscriber\n\n if (token) {\n // Token-based unsubscribe (from email link)\n try {\n const jwt = await import('jsonwebtoken')\n const payload = jwt.verify(\n token,\n process.env.JWT_SECRET || process.env.PAYLOAD_SECRET || ''\n ) as any\n\n if (payload.type !== 'unsubscribe') {\n throw new Error('Invalid token type')\n }\n\n // Token verified, so we can look up the subscriber\n // Using overrideAccess: true here is OK since we verified the token\n subscriber = await req.payload.findByID({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n })\n } catch {\n return res.status(401).json({\n success: false,\n error: 'Invalid or expired unsubscribe link',\n })\n }\n } else {\n // Email-based unsubscribe\n if (!isValidEmail(email)) {\n return res.status(400).json({\n success: false,\n error: 'Invalid email format',\n })\n }\n\n const result = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n email: {\n equals: email.toLowerCase(),\n },\n },\n })\n\n if (result.docs.length === 0) {\n // Don't reveal if email exists or not\n return res.json({\n success: true,\n message: 'If this email was subscribed, it has been unsubscribed.',\n })\n }\n\n subscriber = result.docs[0]\n }\n\n if (!subscriber) {\n return res.json({\n success: true,\n message: 'If this email was subscribed, it has been unsubscribed.',\n })\n }\n\n // Check if already unsubscribed\n if (subscriber.subscriptionStatus === 'unsubscribed') {\n return res.json({\n success: true,\n message: 'Already unsubscribed',\n })\n }\n\n // Update subscription status - use synthetic user to ensure proper access\n await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: subscriber.id,\n data: {\n subscriptionStatus: 'unsubscribed',\n unsubscribedAt: new Date().toISOString(),\n },\n overrideAccess: false,\n user: {\n collection: 'subscribers',\n id: subscriber.id,\n email: subscriber.email,\n },\n })\n\n res.json({\n success: true,\n message: 'Successfully unsubscribed',\n })\n } catch (error: unknown) {\n console.error('Unsubscribe error:', error)\n res.status(500).json({\n success: false,\n error: 'Failed to unsubscribe. Please try again.',\n })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { createSubscribeEndpoint } from './subscribe'\nimport { createVerifyMagicLinkEndpoint } from './verify-magic-link'\nimport { createPreferencesEndpoint, createUpdatePreferencesEndpoint } from './preferences'\nimport { createUnsubscribeEndpoint } from './unsubscribe'\n\nexport function createNewsletterEndpoints(\n config: NewsletterPluginConfig\n): Endpoint[] {\n const endpoints: Endpoint[] = [\n createSubscribeEndpoint(config),\n createUnsubscribeEndpoint(config),\n ]\n\n // Add auth endpoints if enabled\n if (config.auth?.enabled !== false) {\n endpoints.push(\n createVerifyMagicLinkEndpoint(config),\n createPreferencesEndpoint(config),\n createUpdatePreferencesEndpoint(config)\n )\n }\n\n return endpoints\n}","import type { Field } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\n\nexport function createNewsletterSchedulingFields(\n config: NewsletterPluginConfig\n): Field[] {\n const groupName = config.features?.newsletterScheduling?.fields?.groupName || 'newsletterScheduling'\n const contentField = config.features?.newsletterScheduling?.fields?.contentField || 'content'\n const createMarkdownField = config.features?.newsletterScheduling?.fields?.createMarkdownField !== false\n\n const fields: Field[] = [\n {\n name: groupName,\n type: 'group',\n label: 'Newsletter Scheduling',\n admin: {\n condition: (data, { user }) => user?.collection === 'users', // Only show for admin users\n },\n fields: [\n {\n name: 'scheduled',\n type: 'checkbox',\n label: 'Schedule for Newsletter',\n defaultValue: false,\n admin: {\n description: 'Schedule this content to be sent as a newsletter',\n },\n },\n {\n name: 'scheduledDate',\n type: 'date',\n label: 'Send Date',\n required: true,\n admin: {\n date: {\n pickerAppearance: 'dayAndTime',\n },\n condition: (data) => data?.[groupName]?.scheduled,\n description: 'When to send this newsletter',\n },\n },\n {\n name: 'sentDate',\n type: 'date',\n label: 'Sent Date',\n admin: {\n readOnly: true,\n condition: (data) => data?.[groupName]?.sendStatus === 'sent',\n description: 'When this newsletter was sent',\n },\n },\n {\n name: 'sendStatus',\n type: 'select',\n label: 'Status',\n options: [\n { label: 'Draft', value: 'draft' },\n { label: 'Scheduled', value: 'scheduled' },\n { label: 'Sending', value: 'sending' },\n { label: 'Sent', value: 'sent' },\n { label: 'Failed', value: 'failed' },\n ],\n defaultValue: 'draft',\n admin: {\n readOnly: true,\n description: 'Current send status',\n },\n },\n {\n name: 'emailSubject',\n type: 'text',\n label: 'Email Subject',\n required: true,\n admin: {\n condition: (data) => data?.[groupName]?.scheduled,\n description: 'Subject line for the newsletter email',\n },\n },\n {\n name: 'preheader',\n type: 'text',\n label: 'Email Preheader',\n admin: {\n condition: (data) => data?.[groupName]?.scheduled,\n description: 'Preview text that appears after the subject line',\n },\n },\n {\n name: 'segments',\n type: 'select',\n label: 'Target Segments',\n hasMany: true,\n options: [\n { label: 'All Subscribers', value: 'all' },\n ...(config.i18n?.locales?.map(locale => ({\n label: `${locale.toUpperCase()} Subscribers`,\n value: locale,\n })) || []),\n ],\n defaultValue: ['all'],\n admin: {\n condition: (data) => data?.[groupName]?.scheduled,\n description: 'Which subscriber segments to send to',\n },\n },\n {\n name: 'testEmails',\n type: 'array',\n label: 'Test Email Recipients',\n admin: {\n condition: (data) => data?.[groupName]?.scheduled && data?.[groupName]?.sendStatus === 'draft',\n description: 'Send test emails before scheduling',\n },\n fields: [\n {\n name: 'email',\n type: 'email',\n required: true,\n },\n ],\n },\n ],\n },\n ]\n\n // Add markdown companion field if requested\n if (createMarkdownField) {\n fields.push(createMarkdownFieldInternal({\n name: `${contentField}Markdown`,\n richTextField: contentField,\n label: 'Email Content (Markdown)',\n admin: {\n position: 'sidebar',\n condition: (data: any) => Boolean(data?.[contentField] && data?.[groupName]?.scheduled),\n description: 'Markdown version for email rendering',\n readOnly: true,\n },\n }))\n }\n\n return fields\n}\n\n/**\n * Create a markdown companion field for rich text\n * This creates a virtual field that converts rich text to markdown\n */\nfunction createMarkdownFieldInternal(config: {\n name: string\n richTextField: string\n label?: string\n admin?: any\n}): Field {\n return {\n name: config.name,\n type: 'textarea',\n label: config.label || 'Markdown',\n admin: {\n ...config.admin,\n description: config.admin?.description || 'Auto-generated from rich text content',\n },\n hooks: {\n afterRead: [\n async ({ data }) => {\n // Convert rich text to markdown on read\n if (data?.[config.richTextField]) {\n try {\n const { convertLexicalToMarkdown } = await import('@payloadcms/richtext-lexical')\n return convertLexicalToMarkdown({\n data: data[config.richTextField],\n } as any)\n } catch {\n return ''\n }\n }\n return ''\n },\n ],\n beforeChange: [\n () => {\n // Don't save markdown to database\n return null\n },\n ],\n },\n }\n}","import type { Config } from 'payload'\nimport type { NewsletterPluginConfig } from './types'\nimport { createSubscribersCollection } from './collections/Subscribers'\nimport { createNewsletterSettingsGlobal } from './globals/NewsletterSettings'\nimport { createEmailService } from './providers'\nimport { createNewsletterEndpoints } from './endpoints'\nimport { createNewsletterSchedulingFields } from './fields/newsletterScheduling'\n\n// Extend Payload type to include our email service\ndeclare module 'payload' {\n interface BasePayload {\n newsletterEmailService?: any\n }\n}\n\nexport const newsletterPlugin = (pluginConfig: NewsletterPluginConfig) => (incomingConfig: Config): Config => {\n // Validate and set defaults\n const config: NewsletterPluginConfig = {\n enabled: true,\n subscribersSlug: 'subscribers',\n settingsSlug: 'newsletter-settings',\n auth: {\n enabled: true,\n tokenExpiration: '7d',\n magicLinkPath: '/newsletter/verify',\n ...pluginConfig.auth,\n },\n ...pluginConfig,\n }\n\n // If plugin is disabled, return config unchanged\n if (!config.enabled) {\n return incomingConfig\n }\n\n // Create plugin collections and globals\n const subscribersCollection = createSubscribersCollection(config)\n const settingsGlobal = createNewsletterSettingsGlobal(config)\n\n // Build collections array\n let collections = [...(incomingConfig.collections || []), subscribersCollection]\n\n // Extend collections with newsletter scheduling fields if enabled\n if (config.features?.newsletterScheduling?.enabled) {\n const targetCollections = config.features.newsletterScheduling.collections || 'articles'\n const collectionsToExtend = Array.isArray(targetCollections) ? targetCollections : [targetCollections]\n const schedulingFields = createNewsletterSchedulingFields(config)\n \n collections = collections.map(collection => {\n if (collectionsToExtend.includes(collection.slug)) {\n return {\n ...collection,\n fields: [\n ...collection.fields,\n ...schedulingFields,\n ],\n }\n }\n return collection\n })\n }\n\n // Create API endpoints\n const endpoints = createNewsletterEndpoints(config)\n\n // Build the modified config\n const modifiedConfig: Config = {\n ...incomingConfig,\n collections,\n globals: [\n ...(incomingConfig.globals || []),\n settingsGlobal,\n ],\n endpoints: [\n ...(incomingConfig.endpoints || []),\n ...endpoints,\n ],\n onInit: async (payload) => {\n // Initialize email service\n try {\n // Get settings from global\n const settings = await payload.findGlobal({\n slug: config.settingsSlug || 'newsletter-settings',\n })\n\n let emailServiceConfig: any\n \n if (settings) {\n emailServiceConfig = {\n provider: settings.provider || config.providers.default,\n fromAddress: settings.fromAddress || config.providers.resend?.fromAddress || config.providers.broadcast?.fromAddress || 'noreply@example.com',\n fromName: settings.fromName || config.providers.resend?.fromName || config.providers.broadcast?.fromName || 'Newsletter',\n replyTo: settings.replyTo,\n resend: settings.provider === 'resend' ? {\n apiKey: settings.resendSettings?.apiKey || config.providers.resend?.apiKey || '',\n audienceIds: settings.resendSettings?.audienceIds?.reduce((acc: any, item: any) => {\n acc[item.locale] = {\n production: item.production,\n development: item.development,\n }\n return acc\n }, {}) || config.providers.resend?.audienceIds,\n } : config.providers.resend,\n broadcast: settings.provider === 'broadcast' ? {\n apiUrl: settings.broadcastSettings?.apiUrl || config.providers.broadcast?.apiUrl || '',\n tokens: {\n production: settings.broadcastSettings?.productionToken || config.providers.broadcast?.tokens.production,\n development: settings.broadcastSettings?.developmentToken || config.providers.broadcast?.tokens.development,\n },\n } : config.providers.broadcast,\n }\n } else {\n // Use config defaults\n emailServiceConfig = {\n provider: config.providers.default,\n fromAddress: config.providers.resend?.fromAddress || config.providers.broadcast?.fromAddress || 'noreply@example.com',\n fromName: config.providers.resend?.fromName || config.providers.broadcast?.fromName || 'Newsletter',\n resend: config.providers.resend,\n broadcast: config.providers.broadcast,\n }\n }\n\n (payload as any).newsletterEmailService = createEmailService(emailServiceConfig)\n\n console.warn('Newsletter plugin initialized with', (payload as any).newsletterEmailService.getProvider(), 'provider')\n } catch (error) {\n console.error('Failed to initialize newsletter email service:', error)\n }\n\n // Call original onInit if it exists\n if (incomingConfig.onInit) {\n await incomingConfig.onInit(payload)\n }\n },\n }\n\n return modifiedConfig\n}\n\nexport { newsletterPlugin as default }"],"mappings":"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","names":["subscriber","jwt"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/access.ts","../src/collections/Subscribers.ts","../src/globals/NewsletterSettings.ts","../src/providers/resend.ts","../src/providers/types.ts","../src/providers/broadcast.ts","../src/providers/index.ts","../src/utils/validation.ts","../src/endpoints/subscribe.ts","../src/utils/jwt.ts","../src/endpoints/verify-magic-link.ts","../src/endpoints/preferences.ts","../src/endpoints/unsubscribe.ts","../src/endpoints/index.ts","../src/fields/newsletterScheduling.ts","../src/index.ts"],"sourcesContent":["import type { Access, AccessArgs } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\n\n/**\n * Check if a user is an admin based on the plugin configuration\n */\nexport const isAdmin = (user: any, config?: NewsletterPluginConfig): boolean => {\n if (!user || user.collection !== 'users') {\n return false\n }\n\n // If custom admin check is provided, use it\n if (config?.access?.isAdmin) {\n return config.access.isAdmin(user)\n }\n\n // Default checks for common admin patterns\n // 1. Check for admin role\n if (user.roles?.includes('admin')) {\n return true\n }\n\n // 2. Check for isAdmin boolean field\n if (user.isAdmin === true) {\n return true\n }\n\n // 3. Check for role field with admin value\n if (user.role === 'admin') {\n return true\n }\n\n // 4. Check for admin collection relationship\n if (user.admin === true) {\n return true\n }\n\n return false\n}\n\n/**\n * Create admin-only access control\n */\nexport const adminOnly = (config?: NewsletterPluginConfig): Access => \n ({ req }: AccessArgs) => {\n const user = req.user\n return isAdmin(user, config)\n }\n\n/**\n * Create admin or owner access control\n */\nexport const adminOrSelf = (config?: NewsletterPluginConfig): Access => \n ({ req, id }: AccessArgs) => {\n const user = req.user\n \n // No user = no access\n if (!user) {\n // For list operations without ID, return impossible condition\n if (!id) {\n return {\n id: {\n equals: 'unauthorized-no-access',\n },\n }\n }\n return false\n }\n \n // Admins can access everything\n if (isAdmin(user, config)) {\n return true\n }\n \n // Synthetic users (subscribers from magic link) can access their own data\n if (user.collection === 'subscribers') {\n // For list operations, scope to their own data\n if (!id) {\n return {\n id: {\n equals: user.id,\n },\n }\n }\n // For specific document access, check if it's their own\n return id === user.id\n }\n \n // Regular users cannot access subscriber data\n if (!id) {\n return {\n id: {\n equals: 'unauthorized-no-access',\n },\n }\n }\n return false\n }","import type { CollectionConfig, Field, CollectionAfterChangeHook, CollectionBeforeDeleteHook } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { adminOnly, adminOrSelf } from '../utils/access'\n\nexport const createSubscribersCollection = (\n pluginConfig: NewsletterPluginConfig\n): CollectionConfig => {\n const slug = pluginConfig.subscribersSlug || 'subscribers'\n \n // Default fields for the subscribers collection\n const defaultFields: Field[] = [\n // Core fields\n {\n name: 'email',\n type: 'email',\n required: true,\n unique: true,\n admin: {\n description: 'Subscriber email address',\n },\n },\n {\n name: 'name',\n type: 'text',\n admin: {\n description: 'Subscriber full name',\n },\n },\n {\n name: 'locale',\n type: 'select',\n options: pluginConfig.i18n?.locales?.map(locale => ({\n label: locale.toUpperCase(),\n value: locale,\n })) || [\n { label: 'EN', value: 'en' },\n ],\n defaultValue: pluginConfig.i18n?.defaultLocale || 'en',\n admin: {\n description: 'Preferred language for communications',\n },\n },\n \n // Authentication fields (hidden from admin UI)\n {\n name: 'magicLinkToken',\n type: 'text',\n hidden: true,\n },\n {\n name: 'magicLinkTokenExpiry',\n type: 'date',\n hidden: true,\n },\n \n // Subscription status\n {\n name: 'subscriptionStatus',\n type: 'select',\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Unsubscribed', value: 'unsubscribed' },\n { label: 'Pending', value: 'pending' },\n ],\n defaultValue: 'pending',\n required: true,\n admin: {\n description: 'Current subscription status',\n },\n },\n {\n name: 'unsubscribedAt',\n type: 'date',\n admin: {\n condition: (data) => data?.subscriptionStatus === 'unsubscribed',\n description: 'When the user unsubscribed',\n readOnly: true,\n },\n },\n \n // Email preferences\n {\n name: 'emailPreferences',\n type: 'group',\n fields: [\n {\n name: 'newsletter',\n type: 'checkbox',\n defaultValue: true,\n label: 'Newsletter',\n admin: {\n description: 'Receive regular newsletter updates',\n },\n },\n {\n name: 'announcements',\n type: 'checkbox',\n defaultValue: true,\n label: 'Announcements',\n admin: {\n description: 'Receive important announcements',\n },\n },\n ],\n admin: {\n description: 'Email communication preferences',\n },\n },\n \n // Source tracking\n {\n name: 'source',\n type: 'text',\n admin: {\n description: 'Where the subscriber signed up from',\n },\n },\n ]\n\n // Add UTM tracking fields if enabled\n if (pluginConfig.features?.utmTracking?.enabled) {\n const utmFields = pluginConfig.features.utmTracking.fields || [\n 'source',\n 'medium',\n 'campaign',\n 'content',\n 'term',\n ]\n \n defaultFields.push({\n name: 'utmParameters',\n type: 'group',\n fields: utmFields.map(field => ({\n name: field,\n type: 'text',\n admin: {\n description: `UTM ${field} parameter`,\n },\n })),\n admin: {\n description: 'UTM tracking parameters',\n },\n })\n }\n\n // Add signup metadata\n defaultFields.push({\n name: 'signupMetadata',\n type: 'group',\n fields: [\n {\n name: 'ipAddress',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'userAgent',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'referrer',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'signupPage',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n ],\n admin: {\n description: 'Technical information about signup',\n },\n })\n\n // Add lead magnet field if enabled\n if (pluginConfig.features?.leadMagnets?.enabled) {\n defaultFields.push({\n name: 'leadMagnet',\n type: 'relationship',\n relationTo: pluginConfig.features.leadMagnets.collection || 'media',\n admin: {\n description: 'Lead magnet downloaded at signup',\n },\n })\n }\n\n // Allow field customization\n let fields = defaultFields\n if (pluginConfig.fields?.overrides) {\n fields = pluginConfig.fields.overrides({ defaultFields })\n }\n if (pluginConfig.fields?.additional) {\n fields = [...fields, ...pluginConfig.fields.additional]\n }\n\n const subscribersCollection: CollectionConfig = {\n slug,\n labels: {\n singular: 'Subscriber',\n plural: 'Subscribers',\n },\n admin: {\n useAsTitle: 'email',\n defaultColumns: ['email', 'name', 'subscriptionStatus', 'createdAt'],\n group: 'Newsletter',\n },\n fields,\n hooks: {\n afterChange: [\n async ({ doc, req, operation, previousDoc }) => {\n // After create logic\n if (operation === 'create') {\n // Add to email service\n const emailService = (req.payload as any).newsletterEmailService\n if (emailService) {\n try {\n await emailService.addContact(doc)\n } catch {\n // Failed to add contact to email service\n }\n }\n\n // Send welcome email if active\n if (doc.subscriptionStatus === 'active' && emailService) {\n try {\n // TODO: Send welcome email\n } catch {\n // Failed to send welcome email\n }\n }\n\n // Custom after subscribe hook\n if (pluginConfig.hooks?.afterSubscribe) {\n await pluginConfig.hooks.afterSubscribe({ doc, req })\n }\n }\n \n // After update logic\n if (operation === 'update' && previousDoc) {\n // Update email service if status changed\n const emailService = (req.payload as any).newsletterEmailService\n if (\n doc.subscriptionStatus !== previousDoc.subscriptionStatus &&\n emailService\n ) {\n try {\n await emailService.updateContact(doc)\n } catch {\n // Failed to update contact in email service\n }\n }\n\n // Handle unsubscribe\n if (\n doc.subscriptionStatus === 'unsubscribed' &&\n previousDoc.subscriptionStatus !== 'unsubscribed'\n ) {\n // Set unsubscribed timestamp\n doc.unsubscribedAt = new Date().toISOString()\n \n // Custom after unsubscribe hook\n if (pluginConfig.hooks?.afterUnsubscribe) {\n await pluginConfig.hooks.afterUnsubscribe({ doc, req })\n }\n }\n }\n },\n ] as CollectionAfterChangeHook[],\n beforeDelete: [\n async ({ id, req }) => {\n // Remove from email service\n const emailService = (req.payload as any).newsletterEmailService\n if (emailService) {\n try {\n const doc = await req.payload.findByID({\n collection: slug,\n id,\n })\n await emailService.removeContact(doc.email)\n } catch {\n // Failed to remove contact from email service\n }\n }\n },\n ] as CollectionBeforeDeleteHook[],\n },\n access: {\n create: () => true, // Public can subscribe\n read: adminOrSelf(pluginConfig),\n update: adminOrSelf(pluginConfig),\n delete: adminOnly(pluginConfig),\n },\n timestamps: true,\n }\n\n return subscribersCollection\n}","import type { GlobalConfig } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { adminOnly } from '../utils/access'\n\nexport const createNewsletterSettingsGlobal = (\n pluginConfig: NewsletterPluginConfig\n): GlobalConfig => {\n const slug = pluginConfig.settingsSlug || 'newsletter-settings'\n \n return {\n slug,\n label: 'Newsletter Settings',\n admin: {\n group: 'Newsletter',\n description: 'Configure email provider settings and templates',\n },\n fields: [\n {\n type: 'tabs',\n tabs: [\n {\n label: 'Provider Settings',\n fields: [\n {\n name: 'provider',\n type: 'select',\n label: 'Email Provider',\n required: true,\n options: [\n { label: 'Resend', value: 'resend' },\n { label: 'Broadcast (Self-Hosted)', value: 'broadcast' },\n ],\n defaultValue: pluginConfig.providers.default,\n admin: {\n description: 'Choose which email service to use',\n },\n },\n {\n name: 'resendSettings',\n type: 'group',\n label: 'Resend Settings',\n admin: {\n condition: (data) => data?.provider === 'resend',\n },\n fields: [\n {\n name: 'apiKey',\n type: 'text',\n label: 'API Key',\n required: true,\n admin: {\n description: 'Your Resend API key',\n },\n },\n {\n name: 'audienceIds',\n type: 'array',\n label: 'Audience IDs by Locale',\n fields: [\n {\n name: 'locale',\n type: 'select',\n label: 'Locale',\n required: true,\n options: pluginConfig.i18n?.locales?.map(locale => ({\n label: locale.toUpperCase(),\n value: locale,\n })) || [\n { label: 'EN', value: 'en' },\n ],\n },\n {\n name: 'production',\n type: 'text',\n label: 'Production Audience ID',\n },\n {\n name: 'development',\n type: 'text',\n label: 'Development Audience ID',\n },\n ],\n },\n ],\n },\n {\n name: 'broadcastSettings',\n type: 'group',\n label: 'Broadcast Settings',\n admin: {\n condition: (data) => data?.provider === 'broadcast',\n },\n fields: [\n {\n name: 'apiUrl',\n type: 'text',\n label: 'API URL',\n required: true,\n admin: {\n description: 'Your Broadcast instance URL',\n },\n },\n {\n name: 'productionToken',\n type: 'text',\n label: 'Production Token',\n admin: {\n description: 'Token for production environment',\n },\n },\n {\n name: 'developmentToken',\n type: 'text',\n label: 'Development Token',\n admin: {\n description: 'Token for development environment',\n },\n },\n ],\n },\n {\n name: 'fromAddress',\n type: 'email',\n label: 'From Address',\n required: true,\n admin: {\n description: 'Default sender email address',\n },\n },\n {\n name: 'fromName',\n type: 'text',\n label: 'From Name',\n required: true,\n admin: {\n description: 'Default sender name',\n },\n },\n {\n name: 'replyTo',\n type: 'email',\n label: 'Reply-To Address',\n admin: {\n description: 'Optional reply-to email address',\n },\n },\n ],\n },\n {\n label: 'Email Templates',\n fields: [\n {\n name: 'emailTemplates',\n type: 'group',\n label: 'Email Templates',\n fields: [\n {\n name: 'welcome',\n type: 'group',\n label: 'Welcome Email',\n fields: [\n {\n name: 'enabled',\n type: 'checkbox',\n label: 'Send Welcome Email',\n defaultValue: true,\n },\n {\n name: 'subject',\n type: 'text',\n label: 'Subject Line',\n defaultValue: 'Welcome to {{fromName}}!',\n admin: {\n condition: (data) => data?.emailTemplates?.welcome?.enabled,\n },\n },\n {\n name: 'preheader',\n type: 'text',\n label: 'Preheader Text',\n admin: {\n condition: (data) => data?.emailTemplates?.welcome?.enabled,\n },\n },\n ],\n },\n {\n name: 'magicLink',\n type: 'group',\n label: 'Magic Link Email',\n fields: [\n {\n name: 'subject',\n type: 'text',\n label: 'Subject Line',\n defaultValue: 'Sign in to {{fromName}}',\n },\n {\n name: 'preheader',\n type: 'text',\n label: 'Preheader Text',\n defaultValue: 'Click the link to access your preferences',\n },\n {\n name: 'expirationTime',\n type: 'select',\n label: 'Link Expiration',\n defaultValue: '7d',\n options: [\n { label: '1 hour', value: '1h' },\n { label: '24 hours', value: '24h' },\n { label: '7 days', value: '7d' },\n { label: '30 days', value: '30d' },\n ],\n },\n ],\n },\n ],\n },\n ],\n },\n {\n label: 'Subscription Settings',\n fields: [\n {\n name: 'subscriptionSettings',\n type: 'group',\n label: 'Subscription Settings',\n fields: [\n {\n name: 'requireDoubleOptIn',\n type: 'checkbox',\n label: 'Require Double Opt-In',\n defaultValue: false,\n admin: {\n description: 'Require email confirmation before activating subscriptions',\n },\n },\n {\n name: 'allowedDomains',\n type: 'array',\n label: 'Allowed Email Domains',\n admin: {\n description: 'Leave empty to allow all domains',\n },\n fields: [\n {\n name: 'domain',\n type: 'text',\n label: 'Domain',\n required: true,\n admin: {\n placeholder: 'example.com',\n },\n },\n ],\n },\n {\n name: 'maxSubscribersPerIP',\n type: 'number',\n label: 'Max Subscribers per IP',\n defaultValue: 10,\n min: 1,\n admin: {\n description: 'Maximum number of subscriptions allowed from a single IP address',\n },\n },\n ],\n },\n ],\n },\n ],\n },\n ],\n hooks: {\n beforeChange: [\n async ({ data, req }) => {\n // Verify admin access for settings changes\n if (!req.user || req.user.collection !== 'users') {\n throw new Error('Only administrators can modify newsletter settings')\n }\n \n return data\n },\n ],\n afterChange: [\n async ({ doc, req }) => {\n // Reinitialize email service when settings change\n if ((req.payload as any).newsletterEmailService) {\n try {\n // TODO: Implement email service reinitialization\n console.warn('Newsletter settings updated, reinitializing service...')\n } catch {\n // Failed to reinitialize email service\n }\n }\n \n return doc\n },\n ],\n },\n access: {\n read: () => true, // Settings can be read publicly for validation\n update: adminOnly(pluginConfig),\n },\n }\n}","import { Resend } from 'resend'\nimport type { EmailProvider, SendEmailParams } from './types'\nimport { EmailProviderError } from './types'\nimport type { Subscriber, ResendProviderConfig } from '../types'\n\nexport class ResendProvider implements EmailProvider {\n private client: Resend\n private audienceIds: ResendProviderConfig['audienceIds']\n private fromAddress: string\n private fromName: string\n private isDevelopment: boolean\n\n constructor(config: ResendProviderConfig & { \n fromAddress: string\n fromName: string \n }) {\n this.client = new Resend(config.apiKey)\n this.audienceIds = config.audienceIds || {}\n this.fromAddress = config.fromAddress\n this.fromName = config.fromName\n this.isDevelopment = process.env.NODE_ENV !== 'production'\n }\n\n getProvider(): string {\n return 'resend'\n }\n\n async send(params: SendEmailParams): Promise<void> {\n try {\n const from = params.from || {\n email: this.fromAddress,\n name: this.fromName,\n }\n\n if (!params.html && !params.text) {\n throw new Error('Either html or text content is required')\n }\n\n await this.client.emails.send({\n from: `${from.name} <${from.email}>`,\n to: Array.isArray(params.to) ? params.to : [params.to],\n subject: params.subject,\n html: params.html || '',\n text: params.text,\n replyTo: params.replyTo,\n })\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to send email via Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n try {\n const audienceId = this.getAudienceId(contact.locale)\n if (!audienceId) {\n console.warn(`No audience ID configured for locale: ${contact.locale}`)\n return\n }\n\n await this.client.contacts.create({\n email: contact.email,\n firstName: contact.name?.split(' ')[0],\n lastName: contact.name?.split(' ').slice(1).join(' '),\n unsubscribed: contact.subscriptionStatus === 'unsubscribed',\n audienceId,\n })\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to add contact to Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n try {\n const audienceId = this.getAudienceId(contact.locale)\n if (!audienceId) {\n console.warn(`No audience ID configured for locale: ${contact.locale}`)\n return\n }\n\n // Resend requires finding the contact first\n const contacts = await this.client.contacts.list({ audienceId })\n const existingContact = contacts.data?.data?.find(c => c.email === contact.email)\n\n if (existingContact) {\n await this.client.contacts.update({\n id: existingContact.id,\n audienceId,\n firstName: contact.name?.split(' ')[0],\n lastName: contact.name?.split(' ').slice(1).join(' '),\n unsubscribed: contact.subscriptionStatus === 'unsubscribed',\n })\n } else {\n // If contact doesn't exist, add them\n await this.addContact(contact)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to update contact in Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async removeContact(email: string): Promise<void> {\n try {\n // Resend doesn't have a direct remove method, so we unsubscribe instead\n // First, we need to find the contact across all audiences\n for (const locale in this.audienceIds) {\n const audienceId = this.getAudienceId(locale)\n if (!audienceId) continue\n\n const contacts = await this.client.contacts.list({ audienceId })\n const contact = contacts.data?.data?.find(c => c.email === email)\n\n if (contact) {\n await this.client.contacts.update({\n id: contact.id,\n audienceId,\n unsubscribed: true,\n })\n break\n }\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to remove contact from Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n private getAudienceId(locale?: string): string | undefined {\n const localeKey = locale || 'en'\n if (!this.audienceIds) return undefined\n \n const localeConfig = this.audienceIds[localeKey]\n if (!localeConfig) return undefined\n\n const audienceId = this.isDevelopment \n ? (localeConfig.development || localeConfig.production)\n : (localeConfig.production || localeConfig.development)\n \n return audienceId\n }\n}","import type { Subscriber } from '../types'\n\nexport interface EmailProvider {\n send(params: SendEmailParams): Promise<void>\n addContact(contact: Subscriber): Promise<void>\n updateContact(contact: Subscriber): Promise<void>\n removeContact(email: string): Promise<void>\n getProvider(): string\n}\n\nexport interface SendEmailParams {\n to: string | string[]\n subject: string\n html?: string\n text?: string\n react?: React.ReactElement\n from?: {\n email: string\n name?: string\n }\n replyTo?: string\n}\n\nexport interface EmailServiceConfig {\n provider: 'resend' | 'broadcast' | string\n fromAddress: string\n fromName: string\n replyTo?: string\n resend?: {\n apiKey: string\n audienceIds?: Record<string, { production?: string; development?: string }>\n }\n broadcast?: {\n apiUrl: string\n tokens: {\n production?: string\n development?: string\n }\n }\n}\n\nexport class EmailProviderError extends Error {\n provider: string\n originalError?: any\n\n constructor(message: string, provider: string, originalError?: any) {\n super(message)\n this.name = 'EmailProviderError'\n this.provider = provider\n this.originalError = originalError\n }\n}","import type { EmailProvider, SendEmailParams } from './types'\nimport { EmailProviderError } from './types'\nimport type { Subscriber, BroadcastProviderConfig } from '../types'\n\nexport class BroadcastProvider implements EmailProvider {\n private apiUrl: string\n private token: string\n private fromAddress: string\n private fromName: string\n private isDevelopment: boolean\n\n constructor(config: BroadcastProviderConfig & { \n fromAddress: string\n fromName: string \n }) {\n this.apiUrl = config.apiUrl.replace(/\\/$/, '') // Remove trailing slash\n this.isDevelopment = process.env.NODE_ENV !== 'production'\n this.token = this.isDevelopment \n ? config.tokens.development || config.tokens.production || ''\n : config.tokens.production || config.tokens.development || ''\n this.fromAddress = config.fromAddress\n this.fromName = config.fromName\n }\n\n getProvider(): string {\n return 'broadcast'\n }\n\n async send(params: SendEmailParams): Promise<void> {\n try {\n const from = params.from || {\n email: this.fromAddress,\n name: this.fromName,\n }\n\n const recipients = Array.isArray(params.to) ? params.to : [params.to]\n \n // Broadcast expects a specific format\n const response = await fetch(`${this.apiUrl}/api/v1/emails`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n from_email: from.email,\n from_name: from.name,\n to: recipients,\n subject: params.subject,\n html_body: params.html,\n text_body: params.text,\n reply_to: params.replyTo,\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to send email via Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n try {\n const [firstName, ...lastNameParts] = (contact.name || '').split(' ')\n const lastName = lastNameParts.join(' ')\n\n const response = await fetch(`${this.apiUrl}/api/v1/subscribers.json`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n subscriber: {\n email: contact.email,\n first_name: firstName || undefined,\n last_name: lastName || undefined,\n tags: [`lang:${contact.locale || 'en'}`],\n is_active: contact.subscriptionStatus === 'active',\n source: contact.source,\n },\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to add contact to Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n try {\n // First, try to find the contact\n const searchResponse = await fetch(\n `${this.apiUrl}/api/v1/subscribers/find.json?email=${encodeURIComponent(contact.email)}`,\n {\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n },\n }\n )\n\n if (!searchResponse.ok) {\n // If contact doesn't exist, create it\n await this.addContact(contact)\n return\n }\n\n const existingContact = await searchResponse.json()\n\n if (!existingContact || !existingContact.id) {\n await this.addContact(contact)\n return\n }\n\n const [firstName, ...lastNameParts] = (contact.name || '').split(' ')\n const lastName = lastNameParts.join(' ')\n\n // Update existing contact\n const response = await fetch(`${this.apiUrl}/api/v1/subscribers.json`, {\n method: 'PATCH',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n email: contact.email,\n subscriber: {\n first_name: firstName || undefined,\n last_name: lastName || undefined,\n tags: [`lang:${contact.locale || 'en'}`],\n is_active: contact.subscriptionStatus === 'active',\n source: contact.source,\n },\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to update contact in Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async removeContact(email: string): Promise<void> {\n try {\n // First, find the contact\n const searchResponse = await fetch(\n `${this.apiUrl}/api/v1/subscribers/find.json?email=${encodeURIComponent(email)}`,\n {\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n },\n }\n )\n\n if (!searchResponse.ok) {\n // Contact doesn't exist, nothing to remove\n return\n }\n\n const contact = await searchResponse.json()\n\n if (!contact || !contact.id) {\n return\n }\n\n // Deactivate the contact\n const response = await fetch(`${this.apiUrl}/api/v1/subscribers/deactivate.json`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ email }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to remove contact from Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n}","import type { EmailProvider, EmailServiceConfig, SendEmailParams } from './types'\nimport type { Subscriber } from '../types'\nimport { ResendProvider } from './resend'\nimport { BroadcastProvider } from './broadcast'\n\nexport * from './types'\n\nexport class EmailService {\n private provider: EmailProvider\n\n constructor(config: EmailServiceConfig) {\n this.provider = this.createProvider(config)\n }\n\n private createProvider(config: EmailServiceConfig): EmailProvider {\n const baseConfig = {\n fromAddress: config.fromAddress,\n fromName: config.fromName,\n }\n\n switch (config.provider) {\n case 'resend':\n if (!config.resend) {\n throw new Error('Resend configuration is required when using Resend provider')\n }\n return new ResendProvider({\n ...config.resend,\n ...baseConfig,\n })\n\n case 'broadcast':\n if (!config.broadcast) {\n throw new Error('Broadcast configuration is required when using Broadcast provider')\n }\n return new BroadcastProvider({\n ...config.broadcast,\n ...baseConfig,\n })\n\n default:\n throw new Error(`Unknown email provider: ${config.provider}`)\n }\n }\n\n async send(params: SendEmailParams): Promise<void> {\n return this.provider.send(params)\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n return this.provider.addContact(contact)\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n return this.provider.updateContact(contact)\n }\n\n async removeContact(email: string): Promise<void> {\n return this.provider.removeContact(email)\n }\n\n getProvider(): string {\n return this.provider.getProvider()\n }\n\n /**\n * Update the provider configuration\n * Useful when settings are changed in the admin UI\n */\n updateConfig(config: EmailServiceConfig): void {\n this.provider = this.createProvider(config)\n }\n}\n\n/**\n * Create email service from plugin configuration\n */\nexport function createEmailService(config: EmailServiceConfig): EmailService {\n return new EmailService(config)\n}","import DOMPurify from 'isomorphic-dompurify'\n\n/**\n * Validate email address format\n */\nexport function isValidEmail(email: string): boolean {\n if (!email || typeof email !== 'string') return false\n \n // Trim whitespace\n const trimmed = email.trim()\n \n // Length limits\n if (trimmed.length > 255) return false\n \n // Check for dangerous patterns\n if (trimmed.includes('<') || trimmed.includes('>')) return false\n if (trimmed.includes('javascript:')) return false\n if (trimmed.includes('data:')) return false\n \n // Basic format validation with stricter regex\n const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/\n if (!emailRegex.test(trimmed)) return false\n \n // Additional validation rules\n const parts = trimmed.split('@')\n if (parts.length !== 2) return false\n \n const [localPart, domain] = parts\n \n // Check local part length\n if (localPart.length > 64 || localPart.length === 0) return false\n \n // Check for invalid patterns\n if (localPart.startsWith('.') || localPart.endsWith('.')) return false\n if (domain.startsWith('.') || domain.endsWith('.')) return false\n if (domain.includes('..')) return false\n if (localPart.includes('..')) return false\n \n return true\n}\n\n/**\n * Normalize email for rate limiting and deduplication\n */\nexport function normalizeEmail(email: string): string {\n if (!email || typeof email !== 'string') return ''\n \n const parts = email.toLowerCase().trim().split('@')\n if (parts.length !== 2) return email.toLowerCase().trim()\n \n let [localPart] = parts\n const [, domain] = parts\n \n // Remove dots from local part (Gmail-style)\n localPart = localPart.replace(/\\./g, '')\n \n // Remove everything after + (Gmail-style aliases)\n const plusIndex = localPart.indexOf('+')\n if (plusIndex > -1) {\n localPart = localPart.substring(0, plusIndex)\n }\n \n return `${localPart}@${domain}`\n}\n\n/**\n * Check if email domain is allowed\n */\nexport function isDomainAllowed(\n email: string,\n allowedDomains?: string[]\n): boolean {\n // Validate email format first\n if (!isValidEmail(email)) {\n return false\n }\n \n // If no domains specified, allow all valid emails\n if (!allowedDomains || allowedDomains.length === 0) {\n return true\n }\n\n const domain = email.split('@')[1]?.toLowerCase()\n if (!domain) return false\n\n return allowedDomains.some(\n allowedDomain => domain === allowedDomain.toLowerCase()\n )\n}\n\n/**\n * Sanitize user input to prevent XSS\n */\nexport function sanitizeInput(input: string): string {\n if (!input) return ''\n \n // First, remove all HTML tags and scripts\n let cleaned = DOMPurify.sanitize(input, { \n ALLOWED_TAGS: [],\n ALLOWED_ATTR: [],\n KEEP_CONTENT: true\n })\n \n // Additional security: remove dangerous patterns\n cleaned = cleaned\n .replace(/javascript:/gi, '')\n .replace(/data:/gi, '')\n .replace(/vbscript:/gi, '')\n .replace(/file:\\/\\//gi, '')\n .replace(/onload/gi, '')\n .replace(/onerror/gi, '')\n .replace(/onclick/gi, '')\n .replace(/onmouseover/gi, '')\n .replace(/alert\\(/gi, '')\n .replace(/prompt\\(/gi, '')\n .replace(/confirm\\(/gi, '')\n .replace(/\\|/g, '') // Remove pipe character (command injection)\n .replace(/;/g, '') // Remove semicolon (command chaining)\n .replace(/`/g, '') // Remove backticks (command substitution)\n .replace(/&&/g, '') // Remove command chaining\n .replace(/\\$\\(/g, '') // Remove command substitution pattern $()\n .replace(/\\.\\./g, '') // Remove directory traversal\n .replace(/\\/..\\//g, '') // Remove path traversal\n .replace(/\\0/g, '') // Remove null bytes\n \n return cleaned.trim()\n}\n\n/**\n * Extract UTM parameters from URL search params\n */\nexport function extractUTMParams(searchParams: URLSearchParams): Record<string, string> {\n const utmParams: Record<string, string> = {}\n const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']\n\n utmKeys.forEach(key => {\n const value = searchParams.get(key)\n if (value) {\n // Remove 'utm_' prefix for storage\n const shortKey = key.replace('utm_', '')\n utmParams[shortKey] = value\n }\n })\n\n return utmParams\n}\n\n/**\n * Validate source field - only allow predefined values\n */\nexport function isValidSource(source: string): boolean {\n if (!source || typeof source !== 'string') return false\n \n const allowedSources = [\n 'website',\n 'api',\n 'import',\n 'admin',\n 'signup-form',\n 'magic-link',\n 'preferences',\n 'external'\n ]\n \n return allowedSources.includes(source)\n}\n\n/**\n * Validate subscriber data before creation\n */\nexport interface ValidateSubscriberResult {\n valid: boolean\n errors: string[]\n}\n\nexport function validateSubscriberData(data: any): ValidateSubscriberResult {\n const errors: string[] = []\n\n // Email validation\n if (!data.email) {\n errors.push('Email is required')\n } else if (!isValidEmail(data.email)) {\n errors.push('Invalid email format')\n }\n\n // Name validation (optional but if provided, should be reasonable)\n if (data.name && data.name.length > 100) {\n errors.push('Name is too long (max 100 characters)')\n }\n\n // Source validation\n if (data.source !== undefined) {\n if (!data.source || data.source.length === 0) {\n errors.push('Source cannot be empty')\n } else if (data.source.length > 50) {\n errors.push('Source is too long (max 50 characters)')\n } else if (!isValidSource(data.source)) {\n errors.push('Invalid source value')\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { \n isDomainAllowed, \n sanitizeInput, \n validateSubscriberData,\n extractUTMParams \n} from '../utils/validation'\n\nexport const createSubscribeEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/subscribe',\n method: 'post',\n handler: (async (req: any, res: any) => {\n try {\n const { \n email, \n name, \n source,\n preferences,\n leadMagnet,\n surveyResponses,\n metadata = {}\n } = req.body\n\n // Trim email before validation\n const trimmedEmail = email?.trim()\n\n // Validate input\n const validation = validateSubscriberData({ email: trimmedEmail, name, source })\n if (!validation.valid) {\n return res.status(400).json({\n success: false,\n errors: validation.errors,\n })\n }\n\n // Check domain restrictions from global settings\n // Settings are public info needed for validation, but we can still respect access control\n const settings = await req.payload.findGlobal({\n slug: config.settingsSlug || 'newsletter-settings',\n overrideAccess: false,\n // No user context for public endpoint\n })\n\n const allowedDomains = settings?.subscriptionSettings?.allowedDomains?.map((d: any) => d.domain) || []\n if (!isDomainAllowed(trimmedEmail, allowedDomains)) {\n return res.status(400).json({\n success: false,\n error: 'Email domain not allowed',\n })\n }\n\n // Check if already subscribed\n // This needs admin access to check for existing email\n const existing = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n email: {\n equals: trimmedEmail.toLowerCase(),\n },\n },\n overrideAccess: true, // Need to check for duplicates in public endpoint\n })\n\n if (existing.docs.length > 0) {\n const subscriber = existing.docs[0]\n \n // If unsubscribed, don't allow resubscription via API\n if (subscriber.subscriptionStatus === 'unsubscribed') {\n return res.status(400).json({\n success: false,\n error: 'This email has been unsubscribed. Please contact support to resubscribe.',\n })\n }\n\n return res.status(400).json({\n success: false,\n error: 'Already subscribed',\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n })\n }\n\n // Check IP rate limiting\n const ipAddress = req.ip || req.connection.remoteAddress\n const maxPerIP = settings?.subscriptionSettings?.maxSubscribersPerIP || 10\n\n const ipSubscribers = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n 'signupMetadata.ipAddress': {\n equals: ipAddress,\n },\n },\n overrideAccess: true, // Need to check IP limits in public endpoint\n })\n\n if (ipSubscribers.docs.length >= maxPerIP) {\n return res.status(429).json({\n success: false,\n error: 'Too many subscriptions from this IP address',\n })\n }\n\n // Extract UTM parameters\n const referer = req.headers.referer || req.headers.referrer || ''\n let utmParams = {}\n if (referer) {\n try {\n utmParams = extractUTMParams(new URL(referer).searchParams)\n } catch {\n // Invalid URL, ignore UTM params\n }\n }\n\n // Prepare subscriber data\n const subscriberData: any = {\n email: trimmedEmail.toLowerCase(),\n name: name ? sanitizeInput(name) : undefined,\n locale: metadata.locale || config.i18n?.defaultLocale || 'en',\n subscriptionStatus: settings?.subscriptionSettings?.requireDoubleOptIn ? 'pending' : 'active',\n source: source || 'api',\n emailPreferences: {\n newsletter: true,\n announcements: true,\n ...(preferences || {}),\n },\n signupMetadata: {\n ipAddress,\n userAgent: req.headers['user-agent'],\n referrer: referer,\n signupPage: metadata.signupPage || referer,\n },\n }\n\n // Add UTM parameters if tracking is enabled\n if (config.features?.utmTracking?.enabled && Object.keys(utmParams).length > 0) {\n subscriberData.utmParameters = utmParams\n }\n\n // Add lead magnet if provided\n if (config.features?.leadMagnets?.enabled && leadMagnet) {\n subscriberData.leadMagnet = leadMagnet\n }\n\n // Create subscriber\n // Public endpoint needs to create subscribers\n const subscriber = await req.payload.create({\n collection: config.subscribersSlug || 'subscribers',\n data: subscriberData,\n overrideAccess: true, // Public endpoint needs to create subscribers\n })\n\n // Handle survey responses if provided\n if (config.features?.surveys?.enabled && surveyResponses) {\n // TODO: Store survey responses\n }\n\n // Send confirmation email if double opt-in\n if (settings?.subscriptionSettings?.requireDoubleOptIn) {\n // TODO: Send confirmation email with magic link\n }\n\n res.json({\n success: true,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n message: settings?.subscriptionSettings?.requireDoubleOptIn \n ? 'Please check your email to confirm your subscription'\n : 'Successfully subscribed',\n })\n } catch {\n res.status(500).json({\n success: false,\n error: 'Failed to subscribe. Please try again.',\n })\n }\n }) as PayloadHandler,\n }\n}","import jwt from 'jsonwebtoken'\nimport type { NewsletterPluginConfig } from '../types'\n\nexport interface MagicLinkTokenPayload {\n subscriberId: string\n email: string\n type: 'magic-link'\n}\n\nexport interface SessionTokenPayload {\n subscriberId: string\n email: string\n type: 'session'\n}\n\n/**\n * Get JWT secret from environment or generate a warning\n */\nfunction getJWTSecret(): string {\n const secret = process.env.JWT_SECRET || process.env.PAYLOAD_SECRET\n\n if (!secret) {\n console.warn(\n 'WARNING: No JWT_SECRET or PAYLOAD_SECRET found in environment variables. ' +\n 'Magic link authentication will not work properly. ' +\n 'Please set JWT_SECRET in your environment.'\n )\n // Return a placeholder to prevent crashes during development\n return 'INSECURE_DEVELOPMENT_SECRET_PLEASE_SET_JWT_SECRET'\n }\n\n return secret\n}\n\n/**\n * Generate a magic link token for email authentication\n */\nexport function generateMagicLinkToken(\n subscriberId: string,\n email: string,\n config: NewsletterPluginConfig\n): string {\n const payload: MagicLinkTokenPayload = {\n subscriberId,\n email,\n type: 'magic-link',\n }\n\n const expiresIn = config.auth?.tokenExpiration || '7d'\n\n return jwt.sign(payload, getJWTSecret(), {\n expiresIn: expiresIn,\n issuer: 'payload-newsletter-plugin',\n } as jwt.SignOptions)\n}\n\n/**\n * Verify a magic link token\n */\nexport function verifyMagicLinkToken(token: string): MagicLinkTokenPayload {\n try {\n const payload = jwt.verify(token, getJWTSecret(), {\n issuer: 'payload-newsletter-plugin',\n }) as any\n\n if (payload.type !== 'magic-link') {\n throw new Error('Invalid token type')\n }\n\n return payload as MagicLinkTokenPayload\n } catch (error: unknown) {\n if (error instanceof Error && error.name === 'TokenExpiredError') {\n throw new Error('Magic link has expired. Please request a new one.')\n }\n if (error instanceof Error && error.name === 'JsonWebTokenError') {\n throw new Error('Invalid magic link token')\n }\n throw error\n }\n}\n\n/**\n * Generate a session token after successful magic link verification\n */\nexport function generateSessionToken(\n subscriberId: string,\n email: string\n): string {\n const payload: SessionTokenPayload = {\n subscriberId,\n email,\n type: 'session',\n }\n\n return jwt.sign(payload, getJWTSecret(), {\n expiresIn: '30d',\n issuer: 'payload-newsletter-plugin',\n })\n}\n\n/**\n * Verify a session token\n */\nexport function verifySessionToken(token: string): SessionTokenPayload {\n try {\n const payload = jwt.verify(token, getJWTSecret(), {\n issuer: 'payload-newsletter-plugin',\n }) as any\n\n if (payload.type !== 'session') {\n throw new Error('Invalid token type')\n }\n\n return payload as SessionTokenPayload\n } catch (error: unknown) {\n if (error instanceof Error && error.name === 'TokenExpiredError') {\n throw new Error('Session has expired. Please sign in again.')\n }\n if (error instanceof Error && error.name === 'JsonWebTokenError') {\n throw new Error('Invalid session token')\n }\n throw error\n }\n}\n\n/**\n * Generate a magic link URL\n */\nexport function generateMagicLinkURL(\n token: string,\n baseURL: string,\n config: NewsletterPluginConfig\n): string {\n const path = config.auth?.magicLinkPath || '/newsletter/verify'\n const url = new URL(path, baseURL)\n url.searchParams.set('token', token)\n return url.toString()\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { \n verifyMagicLinkToken, \n generateSessionToken \n} from '../utils/jwt'\n\nexport const createVerifyMagicLinkEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/verify-magic-link',\n method: 'post',\n handler: (async (req: any, res: any) => {\n try {\n const { token } = req.body\n\n if (!token) {\n return res.status(400).json({\n success: false,\n error: 'Token is required',\n })\n }\n\n // Verify the magic link token\n let payload\n try {\n payload = verifyMagicLinkToken(token)\n } catch (error: unknown) {\n return res.status(401).json({\n success: false,\n error: error instanceof Error ? error.message : 'Invalid token',\n })\n }\n\n // Find the subscriber - token verified so we can use admin access for initial lookup\n const subscriber = await req.payload.findByID({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n // Keep overrideAccess: true for token verification\n })\n\n if (!subscriber) {\n return res.status(404).json({\n success: false,\n error: 'Subscriber not found',\n })\n }\n\n // Check if email matches\n if (subscriber.email !== payload.email) {\n return res.status(401).json({\n success: false,\n error: 'Invalid token',\n })\n }\n\n // Check if subscriber is active\n if (subscriber.subscriptionStatus === 'unsubscribed') {\n return res.status(403).json({\n success: false,\n error: 'This email has been unsubscribed',\n })\n }\n\n // Create synthetic user for subscriber operations\n const syntheticUser = {\n collection: 'subscribers',\n id: subscriber.id,\n email: subscriber.email,\n }\n\n // Update subscription status if pending\n if (subscriber.subscriptionStatus === 'pending') {\n await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: subscriber.id,\n data: {\n subscriptionStatus: 'active',\n },\n overrideAccess: false,\n user: syntheticUser,\n })\n }\n\n // Clear the magic link token\n await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: subscriber.id,\n data: {\n magicLinkToken: null,\n magicLinkTokenExpiry: null,\n },\n overrideAccess: false,\n user: syntheticUser,\n })\n\n // Generate session token\n const sessionToken = generateSessionToken(\n String(subscriber.id),\n subscriber.email\n )\n\n res.json({\n success: true,\n sessionToken,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n name: subscriber.name,\n locale: subscriber.locale,\n emailPreferences: subscriber.emailPreferences,\n },\n })\n } catch (error: unknown) {\n console.error('Verify magic link error:', error)\n res.status(500).json({\n success: false,\n error: 'Failed to verify magic link',\n })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { verifySessionToken } from '../utils/jwt'\n\nexport const createPreferencesEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/preferences',\n method: 'get',\n handler: (async (req: any, res: any) => {\n try {\n // Get token from Authorization header\n const authHeader = req.headers.authorization\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n return res.status(401).json({\n success: false,\n error: 'Authorization required',\n })\n }\n\n const token = authHeader.substring(7)\n\n // Verify session token\n let payload\n try {\n payload = verifySessionToken(token)\n } catch (error: unknown) {\n return res.status(401).json({\n success: false,\n error: error instanceof Error ? error.message : 'Invalid token',\n })\n }\n\n // Get subscriber - use synthetic user to ensure access control\n const subscriber = await req.payload.findByID({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n overrideAccess: false,\n user: {\n collection: 'subscribers',\n id: payload.subscriberId,\n email: payload.email,\n },\n })\n\n if (!subscriber) {\n return res.status(404).json({\n success: false,\n error: 'Subscriber not found',\n })\n }\n\n res.json({\n success: true,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n name: subscriber.name,\n locale: subscriber.locale,\n emailPreferences: subscriber.emailPreferences,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n })\n } catch (error: unknown) {\n console.error('Get preferences error:', error)\n res.status(500).json({\n success: false,\n error: 'Failed to get preferences',\n })\n }\n }) as PayloadHandler,\n }\n}\n\nexport const createUpdatePreferencesEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/preferences',\n method: 'post',\n handler: (async (req: any, res: any) => {\n try {\n // Get token from Authorization header\n const authHeader = req.headers.authorization\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n return res.status(401).json({\n success: false,\n error: 'Authorization required',\n })\n }\n\n const token = authHeader.substring(7)\n\n // Verify session token\n let payload\n try {\n payload = verifySessionToken(token)\n } catch (error: unknown) {\n return res.status(401).json({\n success: false,\n error: error instanceof Error ? error.message : 'Invalid token',\n })\n }\n\n const { name, locale, emailPreferences } = req.body\n\n // Prepare update data\n const updateData: any = {}\n \n if (name !== undefined) {\n updateData.name = name\n }\n \n if (locale !== undefined) {\n updateData.locale = locale\n }\n \n if (emailPreferences !== undefined) {\n updateData.emailPreferences = emailPreferences\n }\n\n // Update subscriber - use synthetic user to ensure only updating own data\n const subscriber = await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n data: updateData,\n overrideAccess: false,\n user: {\n collection: 'subscribers',\n id: payload.subscriberId,\n email: payload.email,\n },\n })\n\n res.json({\n success: true,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n name: subscriber.name,\n locale: subscriber.locale,\n emailPreferences: subscriber.emailPreferences,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n })\n } catch (error: unknown) {\n console.error('Update preferences error:', error)\n res.status(500).json({\n success: false,\n error: 'Failed to update preferences',\n })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { isValidEmail } from '../utils/validation'\n\nexport const createUnsubscribeEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/unsubscribe',\n method: 'post',\n handler: (async (req: any, res: any) => {\n try {\n const { email, token } = req.body\n\n // Two methods: email or token\n if (!email && !token) {\n return res.status(400).json({\n success: false,\n error: 'Email or token is required',\n })\n }\n\n let subscriber\n\n if (token) {\n // Token-based unsubscribe (from email link)\n try {\n const jwt = await import('jsonwebtoken')\n const payload = jwt.verify(\n token,\n process.env.JWT_SECRET || process.env.PAYLOAD_SECRET || ''\n ) as any\n\n if (payload.type !== 'unsubscribe') {\n throw new Error('Invalid token type')\n }\n\n // Token verified, so we can look up the subscriber\n // Using overrideAccess: true here is OK since we verified the token\n subscriber = await req.payload.findByID({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n })\n } catch {\n return res.status(401).json({\n success: false,\n error: 'Invalid or expired unsubscribe link',\n })\n }\n } else {\n // Email-based unsubscribe\n if (!isValidEmail(email)) {\n return res.status(400).json({\n success: false,\n error: 'Invalid email format',\n })\n }\n\n const result = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n email: {\n equals: email.toLowerCase(),\n },\n },\n })\n\n if (result.docs.length === 0) {\n // Don't reveal if email exists or not\n return res.json({\n success: true,\n message: 'If this email was subscribed, it has been unsubscribed.',\n })\n }\n\n subscriber = result.docs[0]\n }\n\n if (!subscriber) {\n return res.json({\n success: true,\n message: 'If this email was subscribed, it has been unsubscribed.',\n })\n }\n\n // Check if already unsubscribed\n if (subscriber.subscriptionStatus === 'unsubscribed') {\n return res.json({\n success: true,\n message: 'Already unsubscribed',\n })\n }\n\n // Update subscription status - use synthetic user to ensure proper access\n await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: subscriber.id,\n data: {\n subscriptionStatus: 'unsubscribed',\n unsubscribedAt: new Date().toISOString(),\n },\n overrideAccess: false,\n user: {\n collection: 'subscribers',\n id: subscriber.id,\n email: subscriber.email,\n },\n })\n\n res.json({\n success: true,\n message: 'Successfully unsubscribed',\n })\n } catch (error: unknown) {\n console.error('Unsubscribe error:', error)\n res.status(500).json({\n success: false,\n error: 'Failed to unsubscribe. Please try again.',\n })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { createSubscribeEndpoint } from './subscribe'\nimport { createVerifyMagicLinkEndpoint } from './verify-magic-link'\nimport { createPreferencesEndpoint, createUpdatePreferencesEndpoint } from './preferences'\nimport { createUnsubscribeEndpoint } from './unsubscribe'\n\nexport function createNewsletterEndpoints(\n config: NewsletterPluginConfig\n): Endpoint[] {\n const endpoints: Endpoint[] = [\n createSubscribeEndpoint(config),\n createUnsubscribeEndpoint(config),\n ]\n\n // Add auth endpoints if enabled\n if (config.auth?.enabled !== false) {\n endpoints.push(\n createVerifyMagicLinkEndpoint(config),\n createPreferencesEndpoint(config),\n createUpdatePreferencesEndpoint(config)\n )\n }\n\n return endpoints\n}","import type { Field } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\n\nexport function createNewsletterSchedulingFields(\n config: NewsletterPluginConfig\n): Field[] {\n const groupName = config.features?.newsletterScheduling?.fields?.groupName || 'newsletterScheduling'\n const contentField = config.features?.newsletterScheduling?.fields?.contentField || 'content'\n const createMarkdownField = config.features?.newsletterScheduling?.fields?.createMarkdownField !== false\n\n const fields: Field[] = [\n {\n name: groupName,\n type: 'group',\n label: 'Newsletter Scheduling',\n admin: {\n condition: (data, { user }) => user?.collection === 'users', // Only show for admin users\n },\n fields: [\n {\n name: 'scheduled',\n type: 'checkbox',\n label: 'Schedule for Newsletter',\n defaultValue: false,\n admin: {\n description: 'Schedule this content to be sent as a newsletter',\n },\n },\n {\n name: 'scheduledDate',\n type: 'date',\n label: 'Send Date',\n required: true,\n admin: {\n date: {\n pickerAppearance: 'dayAndTime',\n },\n condition: (data) => data?.[groupName]?.scheduled,\n description: 'When to send this newsletter',\n },\n },\n {\n name: 'sentDate',\n type: 'date',\n label: 'Sent Date',\n admin: {\n readOnly: true,\n condition: (data) => data?.[groupName]?.sendStatus === 'sent',\n description: 'When this newsletter was sent',\n },\n },\n {\n name: 'sendStatus',\n type: 'select',\n label: 'Status',\n options: [\n { label: 'Draft', value: 'draft' },\n { label: 'Scheduled', value: 'scheduled' },\n { label: 'Sending', value: 'sending' },\n { label: 'Sent', value: 'sent' },\n { label: 'Failed', value: 'failed' },\n ],\n defaultValue: 'draft',\n admin: {\n readOnly: true,\n description: 'Current send status',\n },\n },\n {\n name: 'emailSubject',\n type: 'text',\n label: 'Email Subject',\n required: true,\n admin: {\n condition: (data) => data?.[groupName]?.scheduled,\n description: 'Subject line for the newsletter email',\n },\n },\n {\n name: 'preheader',\n type: 'text',\n label: 'Email Preheader',\n admin: {\n condition: (data) => data?.[groupName]?.scheduled,\n description: 'Preview text that appears after the subject line',\n },\n },\n {\n name: 'segments',\n type: 'select',\n label: 'Target Segments',\n hasMany: true,\n options: [\n { label: 'All Subscribers', value: 'all' },\n ...(config.i18n?.locales?.map(locale => ({\n label: `${locale.toUpperCase()} Subscribers`,\n value: locale,\n })) || []),\n ],\n defaultValue: ['all'],\n admin: {\n condition: (data) => data?.[groupName]?.scheduled,\n description: 'Which subscriber segments to send to',\n },\n },\n {\n name: 'testEmails',\n type: 'array',\n label: 'Test Email Recipients',\n admin: {\n condition: (data) => data?.[groupName]?.scheduled && data?.[groupName]?.sendStatus === 'draft',\n description: 'Send test emails before scheduling',\n },\n fields: [\n {\n name: 'email',\n type: 'email',\n required: true,\n },\n ],\n },\n ],\n },\n ]\n\n // Add markdown companion field if requested\n if (createMarkdownField) {\n fields.push(createMarkdownFieldInternal({\n name: `${contentField}Markdown`,\n richTextField: contentField,\n label: 'Email Content (Markdown)',\n admin: {\n position: 'sidebar',\n condition: (data: any) => Boolean(data?.[contentField] && data?.[groupName]?.scheduled),\n description: 'Markdown version for email rendering',\n readOnly: true,\n },\n }))\n }\n\n return fields\n}\n\n/**\n * Create a markdown companion field for rich text\n * This creates a virtual field that converts rich text to markdown\n */\nfunction createMarkdownFieldInternal(config: {\n name: string\n richTextField: string\n label?: string\n admin?: any\n}): Field {\n return {\n name: config.name,\n type: 'textarea',\n label: config.label || 'Markdown',\n admin: {\n ...config.admin,\n description: config.admin?.description || 'Auto-generated from rich text content',\n },\n hooks: {\n afterRead: [\n async ({ data }) => {\n // Convert rich text to markdown on read\n if (data?.[config.richTextField]) {\n try {\n const { convertLexicalToMarkdown } = await import('@payloadcms/richtext-lexical')\n return convertLexicalToMarkdown({\n data: data[config.richTextField],\n } as any)\n } catch {\n return ''\n }\n }\n return ''\n },\n ],\n beforeChange: [\n () => {\n // Don't save markdown to database\n return null\n },\n ],\n },\n }\n}","import type { Config } from 'payload'\nimport type { NewsletterPluginConfig } from './types'\nimport { createSubscribersCollection } from './collections/Subscribers'\nimport { createNewsletterSettingsGlobal } from './globals/NewsletterSettings'\nimport { createEmailService } from './providers'\nimport { createNewsletterEndpoints } from './endpoints'\nimport { createNewsletterSchedulingFields } from './fields/newsletterScheduling'\n\n// Extend Payload type to include our email service\ndeclare module 'payload' {\n interface BasePayload {\n newsletterEmailService?: any\n }\n}\n\nexport const newsletterPlugin = (pluginConfig: NewsletterPluginConfig) => (incomingConfig: Config): Config => {\n // Validate and set defaults\n const config: NewsletterPluginConfig = {\n enabled: true,\n subscribersSlug: 'subscribers',\n settingsSlug: 'newsletter-settings',\n auth: {\n enabled: true,\n tokenExpiration: '7d',\n magicLinkPath: '/newsletter/verify',\n ...pluginConfig.auth,\n },\n ...pluginConfig,\n }\n\n // If plugin is disabled, return config unchanged\n if (!config.enabled) {\n return incomingConfig\n }\n\n // Create plugin collections and globals\n const subscribersCollection = createSubscribersCollection(config)\n const settingsGlobal = createNewsletterSettingsGlobal(config)\n\n // Build collections array\n let collections = [...(incomingConfig.collections || []), subscribersCollection]\n\n // Extend collections with newsletter scheduling fields if enabled\n if (config.features?.newsletterScheduling?.enabled) {\n const targetCollections = config.features.newsletterScheduling.collections || 'articles'\n const collectionsToExtend = Array.isArray(targetCollections) ? targetCollections : [targetCollections]\n const schedulingFields = createNewsletterSchedulingFields(config)\n \n collections = collections.map(collection => {\n if (collectionsToExtend.includes(collection.slug)) {\n return {\n ...collection,\n fields: [\n ...collection.fields,\n ...schedulingFields,\n ],\n }\n }\n return collection\n })\n }\n\n // Create API endpoints\n const endpoints = createNewsletterEndpoints(config)\n\n // Build the modified config\n const modifiedConfig: Config = {\n ...incomingConfig,\n collections,\n globals: [\n ...(incomingConfig.globals || []),\n settingsGlobal,\n ],\n endpoints: [\n ...(incomingConfig.endpoints || []),\n ...endpoints,\n ],\n onInit: async (payload) => {\n // Initialize email service\n try {\n // Get settings from global\n const settings = await payload.findGlobal({\n slug: config.settingsSlug || 'newsletter-settings',\n })\n\n let emailServiceConfig: any\n \n if (settings) {\n emailServiceConfig = {\n provider: settings.provider || config.providers.default,\n fromAddress: settings.fromAddress || config.providers.resend?.fromAddress || config.providers.broadcast?.fromAddress || 'noreply@example.com',\n fromName: settings.fromName || config.providers.resend?.fromName || config.providers.broadcast?.fromName || 'Newsletter',\n replyTo: settings.replyTo,\n resend: settings.provider === 'resend' ? {\n apiKey: settings.resendSettings?.apiKey || config.providers.resend?.apiKey || '',\n audienceIds: settings.resendSettings?.audienceIds?.reduce((acc: any, item: any) => {\n acc[item.locale] = {\n production: item.production,\n development: item.development,\n }\n return acc\n }, {}) || config.providers.resend?.audienceIds,\n } : config.providers.resend,\n broadcast: settings.provider === 'broadcast' ? {\n apiUrl: settings.broadcastSettings?.apiUrl || config.providers.broadcast?.apiUrl || '',\n tokens: {\n production: settings.broadcastSettings?.productionToken || config.providers.broadcast?.tokens.production,\n development: settings.broadcastSettings?.developmentToken || config.providers.broadcast?.tokens.development,\n },\n } : config.providers.broadcast,\n }\n } else {\n // Use config defaults\n emailServiceConfig = {\n provider: config.providers.default,\n fromAddress: config.providers.resend?.fromAddress || config.providers.broadcast?.fromAddress || 'noreply@example.com',\n fromName: config.providers.resend?.fromName || config.providers.broadcast?.fromName || 'Newsletter',\n resend: config.providers.resend,\n broadcast: config.providers.broadcast,\n }\n }\n\n (payload as any).newsletterEmailService = createEmailService(emailServiceConfig)\n\n console.warn('Newsletter plugin initialized with', (payload as any).newsletterEmailService.getProvider(), 'provider')\n } catch (error) {\n console.error('Failed to initialize newsletter email service:', error)\n }\n\n // Call original onInit if it exists\n if (incomingConfig.onInit) {\n await incomingConfig.onInit(payload)\n }\n },\n }\n\n return modifiedConfig\n}\n\nexport { newsletterPlugin as default }"],"mappings":"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","names":["subscriber","jwt"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payload-plugin-newsletter",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Complete newsletter management plugin for Payload CMS with subscriber management, magic link authentication, and email service integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|