payload-plugin-newsletter 0.25.13 → 0.27.0
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/dist/collections.cjs +43 -0
- package/dist/collections.cjs.map +1 -1
- package/dist/collections.js +43 -0
- package/dist/collections.js.map +1 -1
- package/dist/server.js +71 -18
- package/package.json +1 -1
package/dist/collections.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types/newsletter.ts","../src/types/broadcast.ts","../src/types/providers.ts","../src/types/index.ts","../src/providers/broadcast/broadcast.ts","../src/exports/collections.ts","../src/collections/Broadcasts.ts","../src/fields/emailContent.ts","../src/utils/blockValidation.ts","../src/fields/broadcastInlinePreview.ts","../src/utils/emailSafeHtml.ts","../src/utils/getBroadcastConfig.ts","../src/endpoints/broadcasts/send.ts","../src/utils/access.ts","../src/utils/auth.ts","../src/endpoints/broadcasts/schedule.ts","../src/endpoints/broadcasts/test.ts","../src/utils/mediaPopulation.ts","../src/endpoints/broadcasts/preview.ts","../src/emails/render.tsx","../src/emails/MagicLink.tsx","../src/emails/styles.ts","../src/emails/Welcome.tsx","../src/emails/SignIn.tsx","../src/collections/Subscribers.ts"],"sourcesContent":["/**\n * Core types for newsletter management functionality\n */\n\n/**\n * Represents a newsletter/broadcast in the system\n */\nexport interface Newsletter {\n id: string;\n name: string;\n subject: string;\n preheader?: string;\n content: string; // HTML content\n status: NewsletterStatus;\n trackOpens: boolean;\n trackClicks: boolean;\n replyTo?: string;\n recipientCount?: number;\n sentAt?: Date;\n scheduledAt?: Date;\n createdAt: Date;\n updatedAt: Date;\n // Provider-specific data stored here\n providerData?: Record<string, any>;\n // Provider information\n providerId?: string;\n providerType?: 'broadcast' | 'resend';\n}\n\n/**\n * Possible statuses for a newsletter\n */\nexport enum NewsletterStatus {\n DRAFT = 'draft',\n SCHEDULED = 'scheduled',\n SENDING = 'sending',\n SENT = 'sent',\n FAILED = 'failed',\n PAUSED = 'paused',\n CANCELED = 'canceled'\n}\n\n/**\n * Options for listing newsletters\n */\nexport interface ListNewsletterOptions {\n limit?: number;\n offset?: number;\n status?: NewsletterStatus;\n sortBy?: 'createdAt' | 'updatedAt' | 'sentAt' | 'name';\n sortOrder?: 'asc' | 'desc';\n}\n\n/**\n * Response from listing newsletters\n */\nexport interface ListNewsletterResponse<T = Newsletter> {\n items: T[];\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n}\n\n/**\n * Input for creating a new newsletter\n */\nexport interface CreateNewsletterInput {\n name: string;\n subject: string;\n preheader?: string;\n content: string;\n trackOpens?: boolean;\n trackClicks?: boolean;\n replyTo?: string;\n audienceIds?: string[]; // Maps to segments/audiences\n}\n\n/**\n * Input for updating an existing newsletter\n */\nexport interface UpdateNewsletterInput {\n name?: string;\n subject?: string;\n preheader?: string;\n content?: string;\n trackOpens?: boolean;\n trackClicks?: boolean;\n replyTo?: string;\n audienceIds?: string[];\n}\n\n/**\n * Options for sending a newsletter\n */\nexport interface SendNewsletterOptions {\n audienceIds?: string[]; // Target specific audiences\n testMode?: boolean; // Send test email\n testRecipients?: string[]; // Email addresses for test send\n}\n\n/**\n * Analytics data for a newsletter\n */\nexport interface NewsletterAnalytics {\n sent: number;\n delivered: number;\n opened: number;\n clicked: number;\n bounced: number;\n complained: number;\n unsubscribed: number;\n deliveryRate?: number;\n openRate?: number;\n clickRate?: number;\n bounceRate?: number;\n}\n\n/**\n * Capabilities that a newsletter provider supports\n */\nexport interface NewsletterProviderCapabilities {\n supportsScheduling: boolean;\n supportsSegmentation: boolean;\n supportsAnalytics: boolean;\n supportsABTesting: boolean;\n supportsTemplates: boolean;\n supportsPersonalization: boolean;\n maxRecipientsPerSend?: number;\n editableStatuses: NewsletterStatus[];\n supportedContentTypes: ('html' | 'text' | 'react')[];\n}\n\n/**\n * Error types specific to newsletter operations\n */\nexport class NewsletterProviderError extends Error {\n constructor(\n message: string,\n public code: NewsletterErrorCode,\n public provider: string,\n public details?: any\n ) {\n super(message);\n this.name = 'NewsletterProviderError';\n }\n}\n\nexport enum NewsletterErrorCode {\n NOT_SUPPORTED = 'NOT_SUPPORTED',\n INVALID_STATUS = 'INVALID_STATUS',\n PROVIDER_ERROR = 'PROVIDER_ERROR',\n VALIDATION_ERROR = 'VALIDATION_ERROR',\n NOT_FOUND = 'NOT_FOUND',\n PERMISSION_DENIED = 'PERMISSION_DENIED',\n RATE_LIMITED = 'RATE_LIMITED',\n CONFIGURATION_ERROR = 'CONFIGURATION_ERROR'\n}\n\n/**\n * Newsletter template for reusable content\n */\nexport interface NewsletterTemplate {\n id: string;\n name: string;\n description?: string;\n content: string;\n variables?: NewsletterTemplateVariable[];\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface NewsletterTemplateVariable {\n name: string;\n type: 'text' | 'html' | 'image' | 'url';\n defaultValue?: string;\n required?: boolean;\n}","/**\n * Core types for broadcast management functionality\n */\n\n/**\n * Represents a broadcast (individual email campaign) in the system\n */\nexport interface Broadcast {\n id: string;\n name: string;\n subject: string;\n preheader?: string;\n content: string; // HTML content\n sendStatus: BroadcastStatus;\n trackOpens: boolean;\n trackClicks: boolean;\n replyTo?: string;\n recipientCount?: number;\n sentAt?: Date;\n scheduledAt?: Date;\n createdAt: Date;\n updatedAt: Date;\n // Provider-specific data stored here\n providerData?: Record<string, any>;\n // Provider information\n providerId?: string;\n providerType?: 'broadcast' | 'resend';\n}\n\n/**\n * Possible statuses for a broadcast\n */\nexport enum BroadcastStatus {\n DRAFT = 'draft',\n SCHEDULED = 'scheduled',\n SENDING = 'sending',\n SENT = 'sent',\n FAILED = 'failed',\n PAUSED = 'paused',\n CANCELED = 'canceled'\n}\n\n/**\n * Options for listing broadcasts\n */\nexport interface ListBroadcastOptions {\n limit?: number;\n offset?: number;\n status?: BroadcastStatus;\n sortBy?: 'createdAt' | 'updatedAt' | 'sentAt' | 'name';\n sortOrder?: 'asc' | 'desc';\n}\n\n/**\n * Response from listing broadcasts\n */\nexport interface ListBroadcastResponse<T = Broadcast> {\n items: T[];\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n}\n\n/**\n * Input for creating a new broadcast\n */\nexport interface CreateBroadcastInput {\n name: string;\n subject: string;\n preheader?: string;\n content: string;\n trackOpens?: boolean;\n trackClicks?: boolean;\n replyTo?: string;\n audienceIds?: string[]; // Maps to segments/audiences\n}\n\n/**\n * Input for updating an existing broadcast\n */\nexport interface UpdateBroadcastInput {\n name?: string;\n subject?: string;\n preheader?: string;\n content?: string;\n trackOpens?: boolean;\n trackClicks?: boolean;\n replyTo?: string;\n audienceIds?: string[];\n}\n\n/**\n * Options for sending a broadcast\n */\nexport interface SendBroadcastOptions {\n audienceIds?: string[]; // Target specific audiences\n testMode?: boolean; // Send test email\n testRecipients?: string[]; // Email addresses for test send\n}\n\n/**\n * Analytics data for a broadcast\n */\nexport interface BroadcastAnalytics {\n sent: number;\n delivered: number;\n opened: number;\n clicked: number;\n bounced: number;\n complained: number;\n unsubscribed: number;\n deliveryRate?: number;\n openRate?: number;\n clickRate?: number;\n bounceRate?: number;\n}\n\n/**\n * Capabilities that a broadcast provider supports\n */\nexport interface BroadcastProviderCapabilities {\n supportsScheduling: boolean;\n supportsSegmentation: boolean;\n supportsAnalytics: boolean;\n supportsABTesting: boolean;\n supportsTemplates: boolean;\n supportsPersonalization: boolean;\n maxRecipientsPerSend?: number;\n editableStatuses: BroadcastStatus[];\n supportedContentTypes: ('html' | 'text' | 'react')[];\n supportsMultipleChannels: boolean;\n supportsChannelSegmentation: boolean;\n}\n\n/**\n * Error types specific to broadcast operations\n */\nexport class BroadcastProviderError extends Error {\n constructor(\n message: string,\n public code: BroadcastErrorCode,\n public provider: string,\n public details?: any\n ) {\n super(message);\n this.name = 'BroadcastProviderError';\n }\n}\n\nexport enum BroadcastErrorCode {\n NOT_SUPPORTED = 'NOT_SUPPORTED',\n INVALID_STATUS = 'INVALID_STATUS',\n PROVIDER_ERROR = 'PROVIDER_ERROR',\n VALIDATION_ERROR = 'VALIDATION_ERROR',\n NOT_FOUND = 'NOT_FOUND',\n PERMISSION_DENIED = 'PERMISSION_DENIED',\n RATE_LIMITED = 'RATE_LIMITED',\n CONFIGURATION_ERROR = 'CONFIGURATION_ERROR'\n}\n\n/**\n * Broadcast template for reusable content\n */\nexport interface BroadcastTemplate {\n id: string;\n name: string;\n description?: string;\n content: string;\n variables?: BroadcastTemplateVariable[];\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface BroadcastTemplateVariable {\n name: string;\n type: 'text' | 'html' | 'image' | 'url';\n defaultValue?: string;\n required?: boolean;\n}\n\n// Re-export newsletter types with deprecation notice for backwards compatibility\nexport {\n NewsletterStatus,\n type ListNewsletterOptions,\n type ListNewsletterResponse,\n type CreateNewsletterInput,\n type UpdateNewsletterInput,\n type SendNewsletterOptions,\n type NewsletterAnalytics,\n type NewsletterProviderCapabilities,\n NewsletterProviderError,\n NewsletterErrorCode,\n type NewsletterTemplate,\n type NewsletterTemplateVariable\n} from './newsletter';","/**\n * Provider interfaces for broadcast management\n */\n\n// Import broadcast types\nimport type {\n Broadcast,\n BroadcastStatus,\n ListBroadcastOptions,\n ListBroadcastResponse,\n CreateBroadcastInput,\n UpdateBroadcastInput,\n SendBroadcastOptions,\n BroadcastAnalytics,\n BroadcastProviderCapabilities\n} from './broadcast'\n\nimport {\n BroadcastProviderError,\n BroadcastErrorCode\n} from './broadcast'\n\n\n// Import legacy newsletter types for backwards compatibility\nimport type {\n Newsletter,\n NewsletterStatus,\n ListNewsletterOptions,\n ListNewsletterResponse,\n CreateNewsletterInput,\n UpdateNewsletterInput,\n SendNewsletterOptions,\n NewsletterAnalytics,\n NewsletterProviderCapabilities\n} from './newsletter'\n\nimport {\n NewsletterProviderError,\n NewsletterErrorCode\n} from './newsletter'\n\n/**\n * Main interface for broadcast providers\n */\nexport interface BroadcastProvider {\n /**\n * Get the provider name\n */\n readonly name: string;\n\n // Broadcast management methods\n /**\n * List broadcasts with pagination\n */\n list(options?: ListBroadcastOptions): Promise<ListBroadcastResponse<Broadcast>>;\n \n /**\n * Get a specific broadcast by ID\n */\n get(id: string): Promise<Broadcast>;\n \n /**\n * Create a new broadcast\n */\n create(data: CreateBroadcastInput): Promise<Broadcast>;\n \n /**\n * Update an existing broadcast\n */\n update(id: string, data: UpdateBroadcastInput): Promise<Broadcast>;\n \n /**\n * Delete a broadcast\n */\n delete(id: string): Promise<void>;\n \n /**\n * Send a broadcast immediately or to test recipients\n */\n send(id: string, options?: SendBroadcastOptions): Promise<Broadcast>;\n \n /**\n * Schedule a broadcast for future sending\n */\n schedule(id: string, scheduledAt: Date): Promise<Broadcast>;\n \n /**\n * Cancel a scheduled broadcast\n */\n cancelSchedule(id: string): Promise<Broadcast>;\n \n /**\n * Get analytics for a broadcast\n */\n getAnalytics(id: string): Promise<BroadcastAnalytics>;\n \n /**\n * Get provider capabilities\n */\n getCapabilities(): BroadcastProviderCapabilities;\n \n /**\n * Validate that the provider is properly configured\n */\n validateConfiguration(): Promise<boolean>;\n}\n\n/**\n * Legacy newsletter provider interface for backwards compatibility\n * @deprecated Use BroadcastProvider instead\n */\nexport interface NewsletterProvider {\n /**\n * Get the provider name\n */\n readonly name: string;\n\n /**\n * List newsletters with pagination\n */\n list(options?: ListNewsletterOptions): Promise<ListNewsletterResponse<Newsletter>>;\n \n /**\n * Get a specific newsletter by ID\n */\n get(id: string): Promise<Newsletter>;\n \n /**\n * Create a new newsletter\n */\n create(data: CreateNewsletterInput): Promise<Newsletter>;\n \n /**\n * Update an existing newsletter\n */\n update(id: string, data: UpdateNewsletterInput): Promise<Newsletter>;\n \n /**\n * Delete a newsletter\n */\n delete(id: string): Promise<void>;\n \n /**\n * Send a newsletter immediately or to test recipients\n */\n send(id: string, options?: SendNewsletterOptions): Promise<Newsletter>;\n \n /**\n * Schedule a newsletter for future sending\n */\n schedule(id: string, scheduledAt: Date): Promise<Newsletter>;\n \n /**\n * Cancel a scheduled newsletter\n */\n cancelSchedule(id: string): Promise<Newsletter>;\n \n /**\n * Get analytics for a newsletter\n */\n getAnalytics(id: string): Promise<NewsletterAnalytics>;\n \n /**\n * Get provider capabilities\n */\n getCapabilities(): NewsletterProviderCapabilities;\n \n /**\n * Validate that the provider is properly configured\n */\n validateConfiguration(): Promise<boolean>;\n}\n\n/**\n * Base abstract class for broadcast providers\n */\nexport abstract class BaseBroadcastProvider implements BroadcastProvider {\n abstract readonly name: string;\n \n constructor(protected config: any) {}\n \n // Broadcast management - abstract methods\n abstract list(options?: ListBroadcastOptions): Promise<ListBroadcastResponse<Broadcast>>;\n abstract get(id: string): Promise<Broadcast>;\n abstract create(data: CreateBroadcastInput): Promise<Broadcast>;\n abstract update(id: string, data: UpdateBroadcastInput): Promise<Broadcast>;\n abstract delete(id: string): Promise<void>;\n abstract send(id: string, options?: SendBroadcastOptions): Promise<Broadcast>;\n abstract getCapabilities(): BroadcastProviderCapabilities;\n abstract validateConfiguration(): Promise<boolean>;\n \n /**\n * Schedule a broadcast - default implementation throws not supported\n */\n async schedule(_id: string, _scheduledAt: Date): Promise<Broadcast> {\n const capabilities = this.getCapabilities();\n if (!capabilities.supportsScheduling) {\n throw new BroadcastProviderError(\n 'Scheduling is not supported by this provider',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n );\n }\n throw new Error('Method not implemented');\n }\n \n /**\n * Cancel scheduled broadcast - default implementation throws not supported\n */\n async cancelSchedule(_id: string): Promise<Broadcast> {\n const capabilities = this.getCapabilities();\n if (!capabilities.supportsScheduling) {\n throw new BroadcastProviderError(\n 'Scheduling is not supported by this provider',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n );\n }\n throw new Error('Method not implemented');\n }\n \n /**\n * Get analytics - default implementation returns zeros\n */\n async getAnalytics(_id: string): Promise<BroadcastAnalytics> {\n const capabilities = this.getCapabilities();\n if (!capabilities.supportsAnalytics) {\n throw new BroadcastProviderError(\n 'Analytics are not supported by this provider',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n );\n }\n \n return {\n sent: 0,\n delivered: 0,\n opened: 0,\n clicked: 0,\n bounced: 0,\n complained: 0,\n unsubscribed: 0\n };\n }\n \n /**\n * Helper method to validate required fields\n */\n protected validateRequiredFields(data: any, fields: string[]): void {\n const missing = fields.filter(field => !data[field]);\n if (missing.length > 0) {\n throw new BroadcastProviderError(\n `Missing required fields: ${missing.join(', ')}`,\n BroadcastErrorCode.VALIDATION_ERROR,\n this.name\n );\n }\n }\n \n /**\n * Helper method to check if a status transition is allowed\n */\n protected canEditInStatus(status: BroadcastStatus): boolean {\n const capabilities = this.getCapabilities();\n return capabilities.editableStatuses.includes(status);\n }\n \n /**\n * Helper to build pagination response\n */\n protected buildListResponse<T>(\n items: T[],\n total: number,\n options: ListBroadcastOptions = {}\n ): ListBroadcastResponse<T> {\n const limit = options.limit || 20;\n const offset = options.offset || 0;\n \n return {\n items,\n total,\n limit,\n offset,\n hasMore: offset + items.length < total\n };\n }\n}\n\n/**\n * Base abstract class for newsletter providers\n * @deprecated Use BaseBroadcastProvider instead\n */\nexport abstract class BaseNewsletterProvider implements NewsletterProvider {\n abstract readonly name: string;\n \n constructor(protected config: any) {}\n \n abstract list(options?: ListNewsletterOptions): Promise<ListNewsletterResponse<Newsletter>>;\n abstract get(id: string): Promise<Newsletter>;\n abstract create(data: CreateNewsletterInput): Promise<Newsletter>;\n abstract update(id: string, data: UpdateNewsletterInput): Promise<Newsletter>;\n abstract delete(id: string): Promise<void>;\n abstract send(id: string, options?: SendNewsletterOptions): Promise<Newsletter>;\n abstract getCapabilities(): NewsletterProviderCapabilities;\n abstract validateConfiguration(): Promise<boolean>;\n \n /**\n * Schedule a newsletter - default implementation throws not supported\n */\n async schedule(_id: string, _scheduledAt: Date): Promise<Newsletter> {\n const capabilities = this.getCapabilities();\n if (!capabilities.supportsScheduling) {\n throw new NewsletterProviderError(\n 'Scheduling is not supported by this provider',\n NewsletterErrorCode.NOT_SUPPORTED,\n this.name\n );\n }\n throw new Error('Method not implemented');\n }\n \n /**\n * Cancel scheduled newsletter - default implementation throws not supported\n */\n async cancelSchedule(_id: string): Promise<Newsletter> {\n const capabilities = this.getCapabilities();\n if (!capabilities.supportsScheduling) {\n throw new NewsletterProviderError(\n 'Scheduling is not supported by this provider',\n NewsletterErrorCode.NOT_SUPPORTED,\n this.name\n );\n }\n throw new Error('Method not implemented');\n }\n \n /**\n * Get analytics - default implementation returns zeros\n */\n async getAnalytics(_id: string): Promise<NewsletterAnalytics> {\n const capabilities = this.getCapabilities();\n if (!capabilities.supportsAnalytics) {\n throw new NewsletterProviderError(\n 'Analytics are not supported by this provider',\n NewsletterErrorCode.NOT_SUPPORTED,\n this.name\n );\n }\n \n return {\n sent: 0,\n delivered: 0,\n opened: 0,\n clicked: 0,\n bounced: 0,\n complained: 0,\n unsubscribed: 0\n };\n }\n \n /**\n * Helper method to validate required fields\n */\n protected validateRequiredFields(data: any, fields: string[]): void {\n const missing = fields.filter(field => !data[field]);\n if (missing.length > 0) {\n throw new NewsletterProviderError(\n `Missing required fields: ${missing.join(', ')}`,\n NewsletterErrorCode.VALIDATION_ERROR,\n this.name\n );\n }\n }\n \n /**\n * Helper method to check if a status transition is allowed\n */\n protected canEditInStatus(status: NewsletterStatus): boolean {\n const capabilities = this.getCapabilities();\n return capabilities.editableStatuses.includes(status);\n }\n \n /**\n * Helper to build pagination response\n */\n protected buildListResponse<T>(\n items: T[],\n total: number,\n options: ListNewsletterOptions = {}\n ): ListNewsletterResponse<T> {\n const limit = options.limit || 20;\n const offset = options.offset || 0;\n \n return {\n items,\n total,\n limit,\n offset,\n hasMore: offset + items.length < total\n };\n }\n}","import type { Field, Block, RichTextField } from 'payload'\nimport type { BroadcastProvider } from './providers'\n\n// Export broadcast types\nexport * from './broadcast'\nexport * from './providers'\n// Export legacy newsletter types for backwards compatibility\nexport * from './newsletter'\n\n// Email wrapper options interface\nexport interface EmailWrapperOptions {\n preheader?: string\n subject?: string\n documentData?: Record<string, any> // Generic document data\n}\n\n// Re-export for convenience\nexport type CustomEmailWrapper = (\n content: string, \n options?: EmailWrapperOptions\n) => string | Promise<string>\n\n// Add new interface for broadcast customizations\nexport interface BroadcastCustomizations {\n additionalFields?: Field[]\n customBlocks?: Block[]\n fieldOverrides?: {\n content?: (defaultField: RichTextField) => RichTextField\n }\n /**\n * Custom block email converter\n * @param node - The block node from Lexical editor state\n * @param mediaUrl - Base URL for media files\n * @returns Promise<string> - The email-safe HTML for the block\n */\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n \n /**\n * Fields to populate in custom blocks before email conversion\n * Can be an array of field names or a function that returns field names based on block type\n * This is useful for upload fields that need to be populated with full media objects\n * \n * @example\n * // Array of field names to always populate\n * populateFields: ['bannerImage', 'sponsorLogo']\n * \n * @example\n * // Function to return fields based on block type\n * populateFields: (blockType) => {\n * if (blockType === 'newsletter-hero') return ['bannerImage', 'sponsorLogo']\n * if (blockType === 'content-section') return ['featuredImage']\n * return []\n * }\n */\n populateFields?: string[] | ((blockType: string) => string[])\n \n /**\n * Email preview customization options\n */\n emailPreview?: {\n /**\n * Whether to wrap preview content in default email template\n * @default true\n */\n wrapInTemplate?: boolean\n \n /**\n * Custom wrapper function for preview content\n * Receives the converted HTML and should return wrapped HTML\n */\n customWrapper?: (content: string, options?: EmailWrapperOptions) => string | Promise<string>\n \n /**\n * Custom preview component to replace the default one entirely\n * If provided, this component will be used instead of the default EmailPreview\n */\n customPreviewComponent?: string // Path to custom component for import map\n }\n}\n\nexport interface NewsletterPluginConfig {\n /**\n * Enable or disable the plugin\n * @default true\n */\n enabled?: boolean\n\n /**\n * Slug for the subscribers collection\n * @default 'subscribers'\n */\n subscribersSlug?: string\n \n /**\n * Slug for the newsletter settings global\n * @default 'newsletter-settings'\n */\n settingsSlug?: string\n\n /**\n * Authentication configuration for magic links\n */\n auth?: {\n /**\n * Enable magic link authentication\n * @default true\n */\n enabled?: boolean\n \n /**\n * Token expiration time\n * @default '7d'\n */\n tokenExpiration?: string\n \n /**\n * Path where magic link redirects\n * @default '/newsletter/verify'\n */\n magicLinkPath?: string\n \n /**\n * Allow unsubscribed users to sign in\n * @default false\n */\n allowUnsubscribedSignin?: boolean\n \n /**\n * Allow unsubscribed users to resubscribe\n * @default false\n */\n allowResubscribe?: boolean\n }\n\n /**\n * Access control configuration\n */\n access?: {\n /**\n * Custom function to determine if a user is an admin\n * @param user - The authenticated user object\n * @returns true if the user should have admin access\n */\n isAdmin?: (user: any) => boolean\n }\n\n /**\n * Email provider configuration\n */\n providers: {\n /**\n * Default provider to use\n */\n default: 'resend' | 'broadcast' | string\n \n /**\n * Resend provider configuration\n */\n resend?: ResendProviderConfig\n \n /**\n * Broadcast provider configuration\n */\n broadcast?: BroadcastProviderConfig\n }\n\n /**\n * Field customization options\n */\n fields?: {\n /**\n * Override default fields\n */\n overrides?: (args: { defaultFields: Field[] }) => Field[]\n \n /**\n * Additional custom fields\n */\n additional?: Field[]\n }\n\n /**\n * Email template components\n */\n templates?: {\n /**\n * Welcome email template\n */\n welcome?: React.ComponentType<WelcomeEmailProps>\n \n /**\n * Magic link email template\n */\n magicLink?: React.ComponentType<MagicLinkEmailProps>\n }\n\n /**\n * Plugin hooks\n */\n hooks?: {\n beforeSubscribe?: (args: BeforeSubscribeArgs) => void | Promise<void>\n afterSubscribe?: (args: AfterSubscribeArgs) => void | Promise<void>\n beforeUnsubscribe?: (args: BeforeUnsubscribeArgs) => void | Promise<void>\n afterUnsubscribe?: (args: AfterUnsubscribeArgs) => void | Promise<void>\n }\n\n /**\n * UI component overrides\n */\n components?: {\n signupForm?: React.ComponentType<SignupFormProps>\n preferencesForm?: React.ComponentType<PreferencesFormProps>\n }\n\n /**\n * Feature flags\n */\n features?: {\n /**\n * Lead magnet configuration\n */\n leadMagnets?: {\n enabled?: boolean\n collection?: string\n }\n \n /**\n * Post-signup survey configuration\n */\n surveys?: {\n enabled?: boolean\n questions?: SurveyQuestion[]\n }\n \n /**\n * UTM tracking configuration\n */\n utmTracking?: {\n enabled?: boolean\n fields?: string[]\n }\n \n /**\n * Newsletter scheduling configuration\n */\n newsletterScheduling?: {\n enabled?: boolean\n /**\n * Collections to add newsletter fields to\n * Can be a string for single collection or array for multiple\n * @example 'articles' or ['articles', 'posts', 'updates']\n */\n collections?: string | string[]\n /**\n * Field configuration\n */\n fields?: {\n /**\n * Group name for newsletter fields\n * @default 'newsletterScheduling'\n */\n groupName?: string\n /**\n * Rich text field name to use for content\n * @default 'content'\n */\n contentField?: string\n /**\n * Whether to create a markdown companion field\n * @default true\n */\n createMarkdownField?: boolean\n }\n }\n \n \n /**\n * Newsletter management configuration\n */\n newsletterManagement?: {\n /**\n * Enable newsletter management features\n * @default false\n */\n enabled?: boolean\n /**\n * Collection names for broadcast management\n */\n collections?: {\n /**\n * Broadcasts collection slug\n * @default 'broadcasts'\n */\n broadcasts?: string\n }\n /**\n * Optional: Custom broadcast provider implementation\n * If not provided, will use the default email provider\n */\n provider?: BroadcastProvider\n }\n }\n\n /**\n * Internationalization configuration\n */\n i18n?: {\n defaultLocale?: string\n locales?: string[]\n }\n\n /**\n * Custom email templates\n */\n customTemplates?: {\n [key: string]: React.ComponentType<any>\n }\n\n /**\n * Customization options for plugin collections\n */\n customizations?: {\n broadcasts?: BroadcastCustomizations\n }\n}\n\nexport interface ResendProviderConfig {\n apiKey: string\n fromEmail?: string\n fromAddress?: string // Alias for fromEmail\n fromName?: string\n replyTo?: string\n audienceIds?: {\n [locale: string]: {\n production?: string\n development?: string\n }\n }\n}\n\nexport interface BroadcastProviderConfig {\n apiUrl: string\n token: string\n fromEmail?: string\n fromAddress?: string // Alias for fromEmail\n fromName?: string\n replyTo?: string\n}\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}\n\nexport interface SendEmailParams {\n to: string | string[]\n subject: string\n html?: string\n text?: string\n react?: React.ReactElement\n}\n\nexport interface Subscriber {\n id: string\n email: string\n name?: string\n locale?: string\n subscriptionStatus: 'active' | 'unsubscribed' | 'pending'\n emailPreferences?: {\n newsletter?: boolean\n announcements?: boolean\n [key: string]: boolean | undefined\n }\n source?: string\n importedFromProvider?: boolean\n utmParameters?: {\n source?: string\n medium?: string\n campaign?: string\n content?: string\n term?: string\n }\n // Additional fields that may exist in the database\n signupMetadata?: {\n ipAddress?: string\n userAgent?: string\n referrer?: string\n signupPage?: string\n }\n leadMagnet?: string\n unsubscribedAt?: string\n magicLinkToken?: string\n magicLinkTokenExpiry?: string\n createdAt: string\n updatedAt: string\n}\n\nexport interface WelcomeEmailProps {\n subscriber: Subscriber\n unsubscribeUrl: string\n preferencesUrl: string\n}\n\nexport interface MagicLinkEmailProps {\n magicLinkUrl: string\n subscriber: Subscriber\n}\n\nexport interface SignupFormProps {\n onSuccess?: (subscriber: Subscriber) => void\n onError?: (error: Error) => void\n showName?: boolean\n showPreferences?: boolean\n leadMagnet?: {\n id: string\n title: string\n description?: string\n }\n className?: string\n styles?: {\n form?: React.CSSProperties\n inputGroup?: React.CSSProperties\n label?: React.CSSProperties\n input?: React.CSSProperties\n button?: React.CSSProperties\n buttonDisabled?: React.CSSProperties\n error?: React.CSSProperties\n success?: React.CSSProperties\n checkbox?: React.CSSProperties\n checkboxInput?: React.CSSProperties\n checkboxLabel?: React.CSSProperties\n }\n apiEndpoint?: string\n buttonText?: string\n loadingText?: string\n successMessage?: string\n placeholders?: {\n email?: string\n name?: string\n }\n labels?: {\n email?: string\n name?: string\n newsletter?: string\n announcements?: string\n }\n}\n\nexport interface PreferencesFormProps {\n subscriber?: Subscriber\n onSuccess?: (subscriber: Subscriber) => void\n onError?: (error: Error) => void\n className?: string\n styles?: {\n container?: React.CSSProperties\n heading?: React.CSSProperties\n form?: React.CSSProperties\n section?: React.CSSProperties\n sectionTitle?: React.CSSProperties\n inputGroup?: React.CSSProperties\n label?: React.CSSProperties\n input?: React.CSSProperties\n select?: React.CSSProperties\n checkbox?: React.CSSProperties\n checkboxInput?: React.CSSProperties\n checkboxLabel?: React.CSSProperties\n buttonGroup?: React.CSSProperties\n button?: React.CSSProperties\n primaryButton?: React.CSSProperties\n secondaryButton?: React.CSSProperties\n dangerButton?: React.CSSProperties\n error?: React.CSSProperties\n success?: React.CSSProperties\n info?: React.CSSProperties\n }\n sessionToken?: string\n apiEndpoint?: string\n showUnsubscribe?: boolean\n locales?: string[]\n labels?: {\n title?: string\n personalInfo?: string\n emailPreferences?: string\n name?: string\n language?: string\n newsletter?: string\n announcements?: string\n saveButton?: string\n unsubscribeButton?: string\n saving?: string\n saved?: string\n unsubscribeConfirm?: string\n }\n}\n\nexport interface BeforeSubscribeArgs {\n data: Partial<Subscriber>\n req: any\n}\n\nexport interface AfterSubscribeArgs {\n doc: Subscriber\n req: any\n}\n\nexport interface BeforeUnsubscribeArgs {\n email: string\n req: any\n}\n\nexport interface AfterUnsubscribeArgs {\n doc: Subscriber\n req: any\n}\n\n\nexport interface SurveyQuestion {\n id: string\n question: string\n type: 'text' | 'select' | 'multiselect' | 'radio'\n options?: string[]\n required?: boolean\n}\n\n// Request data interfaces for endpoints\nexport interface SubscribeRequestData {\n email: string\n name?: string\n source?: string\n preferences?: { [key: string]: boolean }\n leadMagnet?: string\n surveyResponses?: { [key: string]: string | string[] }\n metadata?: {\n locale?: string\n signupPage?: string\n [key: string]: unknown\n }\n}\n\nexport interface UnsubscribeRequestData {\n email?: string\n token?: string\n}\n\nexport interface VerifyMagicLinkRequestData {\n token: string\n}\n\nexport interface SigninRequestData {\n email: string\n}\n\nexport interface UpdatePreferencesRequestData {\n name?: string\n locale?: string\n emailPreferences?: { [key: string]: boolean }\n}\n\n// Extended request types with proper data typing\nexport interface ExtendedPayloadRequest extends Request {\n payload: any // TODO: Add proper payload type\n data?: unknown\n ip?: string\n connection?: {\n remoteAddress?: string\n }\n cookies?: {\n [key: string]: string\n }\n // Headers are inherited from Request, but we document common ones for reference\n // Access via: req.headers.get('authorization'), req.headers.get('referer'), etc.\n}","import type { \n Broadcast,\n ListBroadcastOptions,\n ListBroadcastResponse,\n CreateBroadcastInput,\n UpdateBroadcastInput,\n SendBroadcastOptions,\n BroadcastAnalytics,\n BroadcastProviderCapabilities\n} from '../../types'\nimport { \n BroadcastProviderError, \n BroadcastErrorCode,\n BroadcastStatus,\n BaseBroadcastProvider\n} from '../../types'\nimport type { BroadcastProviderConfig } from '../../types'\n\ninterface BroadcastApiResponse {\n id: number\n name: string\n subject: string\n preheader?: string\n body: string\n status: string\n track_opens: boolean\n track_clicks: boolean\n html_body: boolean\n reply_to?: string\n total_recipients: number\n sent_at?: string\n scheduled_send_at?: string\n created_at: string\n updated_at: string\n}\n\ninterface BroadcastListResponse {\n data: BroadcastApiResponse[]\n total: number\n}\n\n\nexport class BroadcastApiProvider extends BaseBroadcastProvider {\n readonly name = 'broadcast'\n private apiUrl: string\n private token: string\n\n constructor(config: BroadcastProviderConfig) {\n super(config)\n this.apiUrl = config.apiUrl.replace(/\\/$/, '') // Remove trailing slash\n this.token = config.token\n \n if (!this.token) {\n throw new BroadcastProviderError(\n 'Broadcast API token is required',\n BroadcastErrorCode.CONFIGURATION_ERROR,\n this.name\n )\n }\n }\n\n // Broadcast Management Methods\n async list(options?: ListBroadcastOptions): Promise<ListBroadcastResponse<Broadcast>> {\n try {\n const params = new URLSearchParams()\n if (options?.limit) params.append('limit', options.limit.toString())\n if (options?.offset) params.append('offset', options.offset.toString())\n\n const response = await fetch(`${this.apiUrl}/api/v1/broadcasts?${params}`, {\n method: 'GET',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\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\n const data: BroadcastListResponse = await response.json()\n \n const broadcasts = data.data.map(broadcast => this.transformBroadcastFromApi(broadcast))\n \n return this.buildListResponse(broadcasts, data.total, options)\n } catch (error: unknown) {\n throw new BroadcastProviderError(\n `Failed to list broadcasts: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async get(id: string): Promise<Broadcast> {\n try {\n console.log('[BroadcastApiProvider] Getting broadcast with ID:', id)\n \n const response = await fetch(`${this.apiUrl}/api/v1/broadcasts/${id}`, {\n method: 'GET',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new BroadcastProviderError(\n `Broadcast not found: ${id}`,\n BroadcastErrorCode.NOT_FOUND,\n this.name\n )\n }\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n\n const broadcast: BroadcastApiResponse = await response.json()\n console.log('[BroadcastApiProvider] GET response:', broadcast)\n return this.transformBroadcastFromApi(broadcast)\n } catch (error: unknown) {\n if (error instanceof BroadcastProviderError) throw error\n \n throw new BroadcastProviderError(\n `Failed to get broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async create(data: CreateBroadcastInput): Promise<Broadcast> {\n try {\n this.validateRequiredFields(data, ['name', 'subject', 'content'])\n\n const requestBody = {\n broadcast: {\n name: data.name,\n subject: data.subject,\n preheader: data.preheader,\n body: data.content,\n html_body: true,\n track_opens: data.trackOpens ?? true,\n track_clicks: data.trackClicks ?? true,\n reply_to: data.replyTo,\n segment_ids: data.audienceIds,\n }\n }\n\n // Log the request details (without exposing the token)\n console.log('[BroadcastApiProvider] Creating broadcast:', {\n url: `${this.apiUrl}/api/v1/broadcasts`,\n method: 'POST',\n hasToken: !!this.token,\n tokenLength: this.token?.length,\n body: JSON.stringify(requestBody, null, 2),\n })\n\n const response = await fetch(`${this.apiUrl}/api/v1/broadcasts`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n })\n\n console.log('[BroadcastApiProvider] Response status:', response.status)\n console.log('[BroadcastApiProvider] Response headers:', Object.fromEntries(response.headers.entries()))\n\n if (!response.ok) {\n const errorText = await response.text()\n console.error('[BroadcastApiProvider] Error response body:', errorText)\n \n // Try to parse as JSON if possible\n let errorDetails\n try {\n errorDetails = JSON.parse(errorText)\n console.error('[BroadcastApiProvider] Parsed error:', errorDetails)\n } catch {\n // Not JSON, use as is\n }\n \n throw new Error(`Broadcast API error: ${response.status} - ${errorText}`)\n }\n\n const responseText = await response.text()\n console.log('[BroadcastApiProvider] Success response body:', responseText)\n \n let result\n try {\n result = JSON.parse(responseText)\n } catch {\n throw new Error(`Failed to parse response as JSON: ${responseText}`)\n }\n \n console.log('[BroadcastApiProvider] Parsed result:', result)\n \n if (!result.id) {\n throw new Error(`Response missing expected 'id' field: ${JSON.stringify(result)}`)\n }\n \n // Broadcast API returns just {id: 123}, so we need to fetch the full object\n return this.get(result.id.toString())\n } catch (error: unknown) {\n if (error instanceof BroadcastProviderError) throw error\n \n throw new BroadcastProviderError(\n `Failed to create broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async update(id: string, data: UpdateBroadcastInput): Promise<Broadcast> {\n try {\n // First check if the broadcast can be edited\n const existing = await this.get(id)\n if (!this.canEditInStatus(existing.sendStatus)) {\n throw new BroadcastProviderError(\n `Cannot update broadcast in status: ${existing.sendStatus}`,\n BroadcastErrorCode.INVALID_STATUS,\n this.name\n )\n }\n\n const response = await fetch(`${this.apiUrl}/api/v1/broadcasts/${id}`, {\n method: 'PATCH',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n broadcast: {\n name: data.name,\n subject: data.subject,\n preheader: data.preheader,\n body: data.content,\n track_opens: data.trackOpens,\n track_clicks: data.trackClicks,\n reply_to: data.replyTo,\n segment_ids: data.audienceIds,\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\n const broadcast: BroadcastApiResponse = await response.json()\n return this.transformBroadcastFromApi(broadcast)\n } catch (error: unknown) {\n if (error instanceof BroadcastProviderError) throw error\n \n throw new BroadcastProviderError(\n `Failed to update broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async delete(id: string): Promise<void> {\n try {\n // First check if the broadcast can be deleted\n const existing = await this.get(id)\n if (!this.canEditInStatus(existing.sendStatus)) {\n throw new BroadcastProviderError(\n `Cannot delete broadcast in status: ${existing.sendStatus}`,\n BroadcastErrorCode.INVALID_STATUS,\n this.name\n )\n }\n\n const response = await fetch(`${this.apiUrl}/api/v1/broadcasts/${id}`, {\n method: 'DELETE',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\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 if (error instanceof BroadcastProviderError) throw error\n \n throw new BroadcastProviderError(\n `Failed to delete broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async send(id: string, options?: SendBroadcastOptions): Promise<Broadcast> {\n try {\n // Check if we're in test mode\n if (options?.testMode && options.testRecipients?.length) {\n // TODO: Broadcast doesn't have a documented test send API\n // For now, we'll throw an error\n throw new BroadcastProviderError(\n 'Test send is not yet implemented for Broadcast provider',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\n }\n\n const response = await fetch(`${this.apiUrl}/api/v1/broadcasts/${id}/send_broadcast`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n segment_ids: options?.audienceIds\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\n // Response includes updated status\n const result = await response.json()\n return this.get(result.id.toString())\n } catch (error: unknown) {\n if (error instanceof BroadcastProviderError) throw error\n \n throw new BroadcastProviderError(\n `Failed to send broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async schedule(id: string, scheduledAt: Date): Promise<Broadcast> {\n try {\n // Update the newsletter with scheduled time\n const response = await fetch(`${this.apiUrl}/api/v1/broadcasts/${id}`, {\n method: 'PATCH',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n broadcast: {\n scheduled_send_at: scheduledAt.toISOString(),\n // TODO: Handle timezone properly\n scheduled_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone\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\n const broadcast: BroadcastApiResponse = await response.json()\n return this.transformBroadcastFromApi(broadcast)\n } catch (error: unknown) {\n throw new BroadcastProviderError(\n `Failed to schedule broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async cancelSchedule(id: string): Promise<Broadcast> {\n try {\n // Clear the scheduled time\n const response = await fetch(`${this.apiUrl}/api/v1/broadcasts/${id}`, {\n method: 'PATCH',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n broadcast: {\n scheduled_send_at: null,\n scheduled_timezone: null\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\n const broadcast: BroadcastApiResponse = await response.json()\n return this.transformBroadcastFromApi(broadcast)\n } catch (error: unknown) {\n throw new BroadcastProviderError(\n `Failed to cancel scheduled broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async getAnalytics(_id: string): Promise<BroadcastAnalytics> {\n // TODO: Broadcast analytics API is not documented in the CRUD API\n // This would need additional API documentation\n throw new BroadcastProviderError(\n 'Analytics API not yet implemented for Broadcast provider',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\n }\n\n getCapabilities(): BroadcastProviderCapabilities {\n return {\n supportsScheduling: true,\n supportsSegmentation: true,\n supportsAnalytics: false, // Not documented yet\n supportsABTesting: false,\n supportsTemplates: false,\n supportsPersonalization: true,\n supportsMultipleChannels: false,\n supportsChannelSegmentation: false,\n editableStatuses: [BroadcastStatus.DRAFT, BroadcastStatus.SCHEDULED],\n supportedContentTypes: ['html', 'text']\n }\n }\n\n async validateConfiguration(): Promise<boolean> {\n try {\n // Try to list broadcasts with limit 1 to validate API access\n await this.list({ limit: 1 })\n return true\n } catch {\n return false\n }\n }\n\n private transformBroadcastFromApi(broadcast: BroadcastApiResponse): Broadcast {\n return {\n id: broadcast.id.toString(),\n name: broadcast.name,\n subject: broadcast.subject,\n preheader: broadcast.preheader,\n content: broadcast.body,\n sendStatus: this.mapBroadcastStatus(broadcast.status),\n trackOpens: broadcast.track_opens,\n trackClicks: broadcast.track_clicks,\n replyTo: broadcast.reply_to,\n recipientCount: broadcast.total_recipients,\n sentAt: broadcast.sent_at ? new Date(broadcast.sent_at) : undefined,\n scheduledAt: broadcast.scheduled_send_at ? new Date(broadcast.scheduled_send_at) : undefined,\n createdAt: new Date(broadcast.created_at),\n updatedAt: new Date(broadcast.updated_at),\n providerData: { broadcast },\n providerId: broadcast.id.toString(),\n providerType: 'broadcast'\n }\n }\n\n private mapBroadcastStatus(status: string): BroadcastStatus {\n const statusMap: Record<string, BroadcastStatus> = {\n 'draft': BroadcastStatus.DRAFT,\n 'scheduled': BroadcastStatus.SCHEDULED,\n 'queueing': BroadcastStatus.SENDING,\n 'sending': BroadcastStatus.SENDING,\n 'sent': BroadcastStatus.SENT,\n 'failed': BroadcastStatus.FAILED,\n 'partial_failure': BroadcastStatus.FAILED,\n 'paused': BroadcastStatus.PAUSED,\n 'aborted': BroadcastStatus.CANCELED\n }\n return statusMap[status] || BroadcastStatus.DRAFT\n }\n}","// Collection factories\nexport { createBroadcastsCollection } from '../collections/Broadcasts'\nexport { createSubscribersCollection } from '../collections/Subscribers'","import type { CollectionConfig } from 'payload'\nimport type { SerializedEditorState } from 'lexical'\nimport type { NewsletterPluginConfig } from '../types'\nimport { BroadcastStatus } from '../types'\nimport { createEmailContentField, createEmailLexicalEditor } from '../fields/emailContent'\nimport { createBroadcastInlinePreviewField } from '../fields/broadcastInlinePreview'\nimport { convertToEmailSafeHtml } from '../utils/emailSafeHtml'\nimport { getBroadcastConfig } from '../utils/getBroadcastConfig'\nimport { createSendBroadcastEndpoint } from '../endpoints/broadcasts/send'\nimport { createScheduleBroadcastEndpoint } from '../endpoints/broadcasts/schedule'\nimport { createTestBroadcastEndpoint } from '../endpoints/broadcasts/test'\nimport { createBroadcastPreviewEndpoint, populateMediaFields } from '../endpoints/broadcasts/preview'\n\nexport const createBroadcastsCollection = (pluginConfig: NewsletterPluginConfig): CollectionConfig => {\n const hasProviders = !!(pluginConfig.providers?.broadcast || pluginConfig.providers?.resend)\n const customizations = pluginConfig.customizations?.broadcasts\n\n const collectionSlug = 'broadcasts'\n\n return {\n slug: collectionSlug,\n access: {\n read: () => true, // Public read access\n create: ({ req: { user } }) => {\n // Allow authenticated users to create\n return Boolean(user)\n },\n update: ({ req: { user } }) => {\n // Allow authenticated users to update\n return Boolean(user)\n },\n delete: ({ req: { user } }) => {\n // Allow authenticated users to delete\n return Boolean(user)\n },\n },\n versions: {\n drafts: {\n autosave: true,\n schedulePublish: true,\n }\n },\n labels: {\n singular: 'Broadcast',\n plural: 'Broadcasts',\n },\n admin: {\n useAsTitle: 'subject',\n description: 'Individual email campaigns sent to subscribers',\n defaultColumns: ['subject', '_status', 'sendStatus', 'sentAt', 'recipientCount'],\n },\n endpoints: [\n createSendBroadcastEndpoint(pluginConfig, collectionSlug),\n createScheduleBroadcastEndpoint(pluginConfig, collectionSlug),\n createTestBroadcastEndpoint(pluginConfig, collectionSlug),\n createBroadcastPreviewEndpoint(pluginConfig, collectionSlug),\n ],\n fields: [\n {\n name: 'subject',\n type: 'text',\n required: true,\n admin: {\n description: 'Email subject line'\n },\n },\n // Add any additional fields from customizations after subject\n ...(customizations?.additionalFields || []),\n {\n type: 'row',\n fields: [\n {\n name: 'contentSection',\n type: 'group',\n label: false,\n admin: {\n width: '50%',\n style: {\n paddingRight: '1rem',\n },\n },\n fields: [\n {\n name: 'preheader',\n type: 'text',\n admin: {\n description: 'Preview text shown in email clients'\n },\n },\n // Apply content field customization if provided\n // Process blocks server-side to avoid client serialization issues\n (() => {\n // Create email editor with custom blocks processed server-side\n const emailEditor = createEmailLexicalEditor(customizations?.customBlocks)\n \n // Create base field with pre-processed editor\n const baseField = createEmailContentField({\n admin: { description: 'Email content' },\n editor: emailEditor\n })\n \n // Apply field overrides if provided\n return customizations?.fieldOverrides?.content\n ? customizations.fieldOverrides.content(baseField)\n : baseField\n })(),\n ],\n },\n {\n name: 'previewSection',\n type: 'group',\n label: false,\n admin: {\n width: '50%',\n },\n fields: [\n createBroadcastInlinePreviewField(),\n ],\n },\n ],\n },\n {\n name: 'sendStatus',\n type: 'select',\n label: 'Send Status',\n required: true,\n defaultValue: BroadcastStatus.DRAFT,\n options: [\n { label: 'Draft', value: BroadcastStatus.DRAFT },\n { label: 'Scheduled', value: BroadcastStatus.SCHEDULED },\n { label: 'Sending', value: BroadcastStatus.SENDING },\n { label: 'Sent', value: BroadcastStatus.SENT },\n { label: 'Failed', value: BroadcastStatus.FAILED },\n { label: 'Paused', value: BroadcastStatus.PAUSED },\n { label: 'Canceled', value: BroadcastStatus.CANCELED },\n ],\n admin: {\n readOnly: true,\n description: 'The status of the email send operation',\n components: {\n Cell: 'payload-plugin-newsletter/components#StatusBadge',\n },\n },\n },\n {\n name: 'settings',\n type: 'group',\n fields: [\n {\n name: 'trackOpens',\n type: 'checkbox',\n defaultValue: true,\n admin: {\n description: 'Track when recipients open this email'\n },\n },\n {\n name: 'trackClicks',\n type: 'checkbox',\n defaultValue: true,\n admin: {\n description: 'Track when recipients click links'\n },\n },\n {\n name: 'replyTo',\n type: 'email',\n admin: {\n description: 'Override the channel reply-to address for this broadcast'\n },\n },\n ],\n },\n {\n name: 'audienceIds',\n type: 'array',\n fields: [\n {\n name: 'audienceId',\n type: 'text',\n required: true,\n },\n ],\n admin: {\n description: 'Target specific audience segments',\n condition: () => {\n // Only show if the provider supports segmentation\n return hasProviders\n },\n },\n },\n {\n name: 'analytics',\n type: 'group',\n admin: {\n readOnly: true,\n condition: (data) => data?.sendStatus === BroadcastStatus.SENT,\n },\n fields: [\n {\n name: 'recipientCount',\n type: 'number',\n defaultValue: 0,\n },\n {\n name: 'sent',\n type: 'number',\n defaultValue: 0,\n },\n {\n name: 'delivered',\n type: 'number',\n defaultValue: 0,\n },\n {\n name: 'opened',\n type: 'number',\n defaultValue: 0,\n },\n {\n name: 'clicked',\n type: 'number',\n defaultValue: 0,\n },\n {\n name: 'bounced',\n type: 'number',\n defaultValue: 0,\n },\n {\n name: 'complained',\n type: 'number',\n defaultValue: 0,\n },\n {\n name: 'unsubscribed',\n type: 'number',\n defaultValue: 0,\n },\n ],\n },\n {\n name: 'sentAt',\n type: 'date',\n admin: {\n readOnly: true,\n date: {\n displayFormat: 'MMM d, yyyy h:mm a',\n },\n },\n },\n {\n name: 'scheduledAt',\n type: 'date',\n admin: {\n condition: (data) => data?.sendStatus === BroadcastStatus.SCHEDULED,\n date: {\n displayFormat: 'MMM d, yyyy h:mm a',\n },\n },\n },\n {\n name: 'providerId',\n type: 'text',\n admin: {\n readOnly: true,\n description: 'ID from the email provider',\n condition: (data) => hasProviders && data?.providerId,\n },\n },\n {\n name: 'externalId',\n type: 'text',\n admin: {\n readOnly: true,\n description: 'External ID for webhook integration',\n },\n },\n {\n name: 'providerData',\n type: 'json',\n admin: {\n readOnly: true,\n condition: () => false, // Hidden by default\n },\n },\n // Webhook tracking fields\n {\n name: 'webhookData',\n type: 'group',\n label: 'Webhook Data',\n admin: {\n condition: () => false, // Hidden by default, used for webhook tracking\n },\n fields: [\n {\n name: 'lastWebhookEvent',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'lastWebhookEventAt',\n type: 'date',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'hasWarnings',\n type: 'checkbox',\n defaultValue: false,\n },\n {\n name: 'failureReason',\n type: 'text',\n },\n {\n name: 'sentCount',\n type: 'number',\n },\n {\n name: 'totalCount',\n type: 'number',\n },\n {\n name: 'failedCount',\n type: 'number',\n },\n {\n name: 'remainingCount',\n type: 'number',\n },\n {\n name: 'sendingStartedAt',\n type: 'date',\n },\n {\n name: 'failedAt',\n type: 'date',\n },\n {\n name: 'abortedAt',\n type: 'date',\n },\n {\n name: 'abortReason',\n type: 'text',\n },\n {\n name: 'pausedAt',\n type: 'date',\n },\n ],\n },\n ],\n hooks: {\n // Sync with provider on create and update\n afterChange: [\n async ({ doc, operation, req, previousDoc }) => {\n if (!hasProviders) return doc\n\n // Skip create operation - we'll handle provider creation on first update\n if (operation === 'create') {\n req.payload.logger.info('Broadcast created in Payload, provider sync will happen on first update with content')\n return doc\n }\n \n // Handle update operation\n if (operation === 'update') {\n req.payload.logger.info({\n operation,\n hasProviderId: !!doc.providerId,\n hasExternalId: !!doc.externalId,\n sendStatus: doc.sendStatus,\n publishStatus: doc._status,\n hasSubject: !!doc.subject,\n hasContent: !!doc.contentSection?.content\n }, 'Broadcast afterChange update hook triggered')\n\n try {\n // Get provider config from settings first, then fall back to env vars\n const providerConfig = await getBroadcastConfig(req, pluginConfig)\n if (!providerConfig || !providerConfig.token) {\n req.payload.logger.error('Broadcast provider not configured in Newsletter Settings or environment variables')\n return doc\n }\n\n const { BroadcastApiProvider } = await import('../providers/broadcast/broadcast')\n const provider = new BroadcastApiProvider(providerConfig)\n\n // If no providerId/externalId and has enough content, create in provider\n if (!doc.providerId && !doc.externalId && doc.subject && doc.contentSection?.content) {\n req.payload.logger.info('Creating broadcast in provider on first update with content')\n \n const htmlContent = await convertToEmailSafeHtml(\n await populateMediaFields(doc.contentSection.content, req.payload, pluginConfig) as SerializedEditorState | null,\n {\n wrapInTemplate: pluginConfig.customizations?.broadcasts?.emailPreview?.wrapInTemplate ?? true,\n customWrapper: pluginConfig.customizations?.broadcasts?.emailPreview?.customWrapper,\n preheader: doc.contentSection?.preheader,\n subject: doc.subject,\n documentData: doc,\n customBlockConverter: pluginConfig.customizations?.broadcasts?.customBlockConverter\n }\n )\n\n const createData = {\n name: doc.subject,\n subject: doc.subject,\n preheader: doc.contentSection?.preheader || '',\n content: htmlContent,\n trackOpens: doc.settings?.trackOpens ?? true,\n trackClicks: doc.settings?.trackClicks ?? true,\n replyTo: doc.settings?.replyTo || providerConfig.replyTo,\n audienceIds: doc.audienceIds?.map((a: any) => a.audienceId) || [],\n }\n\n const providerBroadcast = await provider.create(createData)\n \n req.payload.logger.info(`Broadcast ${doc.id} created in provider with ID ${providerBroadcast.id}`)\n \n // Return the document with provider IDs\n return {\n ...doc,\n providerId: providerBroadcast.id,\n externalId: providerBroadcast.id,\n providerData: providerBroadcast.providerData,\n }\n }\n\n // If no providerId, skip sync\n if (!doc.providerId) {\n req.payload.logger.info(`Broadcast ${doc.id} has no providerId and insufficient content for creation - skipping sync`)\n return doc\n }\n\n // Handle normal updates to existing broadcasts (only if providerId exists)\n if (doc.providerId) {\n // Only sync if broadcast is still editable\n const capabilities = provider.getCapabilities()\n const sendStatus = doc.sendStatus || BroadcastStatus.DRAFT\n if (!capabilities.editableStatuses.includes(sendStatus)) {\n req.payload.logger.info(`Skipping sync for broadcast in status: ${sendStatus}`)\n return doc\n }\n\n // Check what has changed\n const contentChanged = \n doc.subject !== previousDoc?.subject ||\n doc.contentSection?.preheader !== previousDoc?.contentSection?.preheader ||\n JSON.stringify(doc.contentSection?.content) !== JSON.stringify(previousDoc?.contentSection?.content) ||\n doc.settings?.trackOpens !== previousDoc?.settings?.trackOpens ||\n doc.settings?.trackClicks !== previousDoc?.settings?.trackClicks ||\n doc.settings?.replyTo !== previousDoc?.settings?.replyTo ||\n JSON.stringify(doc.audienceIds) !== JSON.stringify(previousDoc?.audienceIds)\n\n if (contentChanged) {\n // Build update data\n const updates: any = {}\n if (doc.subject !== previousDoc?.subject) {\n updates.name = doc.subject // Use subject as name in the provider\n updates.subject = doc.subject\n }\n if (doc.contentSection?.preheader !== previousDoc?.contentSection?.preheader) {\n updates.preheader = doc.contentSection?.preheader\n }\n if (JSON.stringify(doc.contentSection?.content) !== JSON.stringify(previousDoc?.contentSection?.content)) {\n const populatedContent = await populateMediaFields(doc.contentSection?.content, req.payload, pluginConfig) as SerializedEditorState | null\n\n // Get email preview customization options\n const emailPreviewConfig = pluginConfig.customizations?.broadcasts?.emailPreview\n\n updates.content = await convertToEmailSafeHtml(populatedContent, {\n wrapInTemplate: emailPreviewConfig?.wrapInTemplate ?? true,\n customWrapper: emailPreviewConfig?.customWrapper,\n preheader: doc.contentSection?.preheader,\n subject: doc.subject,\n documentData: doc, // Pass entire document\n customBlockConverter: pluginConfig.customizations?.broadcasts?.customBlockConverter\n })\n }\n if (doc.settings?.trackOpens !== previousDoc?.settings?.trackOpens) {\n updates.trackOpens = doc.settings.trackOpens\n }\n if (doc.settings?.trackClicks !== previousDoc?.settings?.trackClicks) {\n updates.trackClicks = doc.settings.trackClicks\n }\n if (doc.settings?.replyTo !== previousDoc?.settings?.replyTo) {\n updates.replyTo = doc.settings.replyTo || providerConfig.replyTo\n }\n if (JSON.stringify(doc.audienceIds) !== JSON.stringify(previousDoc?.audienceIds)) {\n updates.audienceIds = doc.audienceIds?.map((a: any) => a.audienceId)\n }\n\n req.payload.logger.info({\n providerId: doc.providerId,\n updates\n }, 'Syncing broadcast updates to provider')\n \n await provider.update(doc.providerId, updates)\n req.payload.logger.info(`Broadcast ${doc.id} synced to provider successfully`)\n } else {\n req.payload.logger.info('No content changes to sync to provider')\n }\n }\n } catch (error) {\n // Enhanced error logging for debugging\n req.payload.logger.error('Raw error from broadcast update operation:')\n req.payload.logger.error(error)\n \n if (error instanceof Error) {\n req.payload.logger.error('Error is instance of Error:', {\n message: error.message,\n stack: error.stack,\n name: error.name,\n ...(error as any).details,\n ...(error as any).response,\n ...(error as any).data,\n ...(error as any).status,\n ...(error as any).statusText,\n })\n } else if (typeof error === 'string') {\n req.payload.logger.error({ errorValue: error }, 'Error is a string')\n } else if (error && typeof error === 'object') {\n req.payload.logger.error({ errorValue: JSON.stringify(error, null, 2) }, 'Error is an object')\n } else {\n req.payload.logger.error({ errorType: typeof error }, 'Unknown error type')\n }\n\n req.payload.logger.error({\n id: doc.id,\n subject: doc.subject,\n hasContent: !!doc.contentSection?.content,\n contentType: doc.contentSection?.content ? typeof doc.contentSection.content : 'none',\n }, 'Failed broadcast document (update operation)')\n \n // Don't throw - allow Payload update to succeed even if provider sync fails\n }\n }\n\n return doc\n },\n // Hook to send when published\n async ({ doc, operation, previousDoc, req }) => {\n // Only run on updates when transitioning to published\n if (operation !== 'update') return doc\n \n const wasUnpublished = !previousDoc?._status || previousDoc._status === 'draft'\n const isNowPublished = doc._status === 'published'\n \n if (wasUnpublished && isNowPublished && doc.providerId) {\n // Check if already sent\n if (doc.sendStatus === BroadcastStatus.SENT || doc.sendStatus === BroadcastStatus.SENDING) {\n return doc\n }\n \n try {\n // Get provider config from settings first, then fall back to env vars\n const broadcastConfig = await getBroadcastConfig(req, pluginConfig)\n const resendConfig = pluginConfig.providers?.resend // TODO: Add getResendConfig utility\n \n if (!broadcastConfig && !resendConfig) {\n req.payload.logger.error('No provider configured for sending in Newsletter Settings or environment variables')\n return doc\n }\n \n // Send via provider\n if (broadcastConfig && broadcastConfig.token) {\n const { BroadcastApiProvider } = await import('../providers/broadcast/broadcast')\n const provider = new BroadcastApiProvider(broadcastConfig)\n await provider.send(doc.providerId)\n }\n // Add resend provider support here when needed\n \n // Update status\n await req.payload.update({\n collection: 'broadcasts',\n id: doc.id,\n data: {\n sendStatus: BroadcastStatus.SENDING,\n sentAt: new Date().toISOString(),\n },\n req,\n })\n \n req.payload.logger.info(`Broadcast ${doc.id} sent successfully`)\n \n } catch (error) {\n // Log full error details for debugging\n if (error instanceof Error) {\n req.payload.logger.error(`Failed to send broadcast ${doc.id}:`, {\n message: error.message,\n stack: error.stack,\n name: error.name,\n // If it's a BroadcastProviderError, it might have additional details\n ...(error as any).details\n })\n } else {\n req.payload.logger.error({ error: String(error) }, `Failed to send broadcast ${doc.id}`)\n }\n \n // Update status to failed\n await req.payload.update({\n collection: 'broadcasts',\n id: doc.id,\n data: {\n sendStatus: BroadcastStatus.FAILED,\n },\n req,\n })\n }\n }\n \n return doc\n },\n ],\n // beforeChange hooks can be added here if needed\n beforeChange: [],\n // Handle deletion\n afterDelete: [\n async ({ doc, req }) => {\n if (!hasProviders || !doc?.providerId) return doc\n\n try {\n // Get provider config from settings first, then fall back to env vars\n const providerConfig = await getBroadcastConfig(req, pluginConfig)\n if (!providerConfig || !providerConfig.token) {\n req.payload.logger.error('Broadcast provider not configured in Newsletter Settings or environment variables')\n return doc\n }\n\n const { BroadcastApiProvider } = await import('../providers/broadcast/broadcast')\n const provider = new BroadcastApiProvider(providerConfig)\n\n // Only delete if broadcast is still editable\n const capabilities = provider.getCapabilities()\n if (capabilities.editableStatuses.includes(doc.sendStatus)) {\n await provider.delete(doc.providerId)\n }\n } catch (error) {\n // Log full error details for debugging\n if (error instanceof Error) {\n req.payload.logger.error('Failed to delete broadcast from provider:', {\n message: error.message,\n stack: error.stack,\n name: error.name,\n // If it's a BroadcastProviderError, it might have additional details\n ...(error as any).details\n })\n } else {\n req.payload.logger.error({ error: String(error) }, 'Failed to delete broadcast from provider')\n }\n }\n\n return doc\n },\n ],\n },\n }\n}\n\n\n","import { \n BoldFeature,\n ItalicFeature,\n UnderlineFeature,\n StrikethroughFeature,\n LinkFeature,\n OrderedListFeature,\n UnorderedListFeature,\n HeadingFeature,\n ParagraphFeature,\n AlignFeature,\n BlockquoteFeature,\n BlocksFeature,\n UploadFeature,\n FixedToolbarFeature,\n InlineToolbarFeature,\n lexicalEditor,\n} from '@payloadcms/richtext-lexical'\nimport type { RichTextField, Block } from 'payload'\nimport { createEmailSafeBlocks } from '../utils/blockValidation'\n\n/**\n * Creates email-safe features for Lexical editor with optional additional blocks\n * Only includes features that render consistently across email clients\n */\n// Using any[] here because Payload's FeatureProviderServer type is complex\n// and varies between versions. The features are properly typed by Payload internally.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const createEmailSafeFeatures = (additionalBlocks?: Block[]): any[] => {\n // Base email-safe blocks\n const baseBlocks = [\n {\n slug: 'button',\n fields: [\n {\n name: 'text',\n type: 'text',\n label: 'Button Text',\n required: true,\n },\n {\n name: 'url',\n type: 'text',\n label: 'Button URL',\n required: true,\n admin: {\n description: 'Enter the full URL (including https://)',\n },\n },\n {\n name: 'style',\n type: 'select',\n label: 'Button Style',\n defaultValue: 'primary',\n options: [\n { label: 'Primary', value: 'primary' },\n { label: 'Secondary', value: 'secondary' },\n { label: 'Outline', value: 'outline' },\n ],\n },\n ],\n interfaceName: 'EmailButton',\n labels: {\n singular: 'Button',\n plural: 'Buttons',\n },\n },\n {\n slug: 'divider',\n fields: [\n {\n name: 'style',\n type: 'select',\n label: 'Divider Style',\n defaultValue: 'solid',\n options: [\n { label: 'Solid', value: 'solid' },\n { label: 'Dashed', value: 'dashed' },\n { label: 'Dotted', value: 'dotted' },\n ],\n },\n ],\n interfaceName: 'EmailDivider',\n labels: {\n singular: 'Divider',\n plural: 'Dividers',\n },\n },\n ] as Block[]\n\n // Merge additional blocks if provided\n const allBlocks = [\n ...baseBlocks,\n ...(additionalBlocks || [])\n ]\n\n return [\n // Toolbars\n FixedToolbarFeature(), // Fixed toolbar at the top\n InlineToolbarFeature(), // Floating toolbar when text is selected\n \n // Basic text formatting\n BoldFeature(),\n ItalicFeature(),\n UnderlineFeature(),\n StrikethroughFeature(),\n \n // Links - use default fields to ensure drawer UI works correctly\n LinkFeature(),\n \n // Lists\n OrderedListFeature(),\n UnorderedListFeature(),\n \n // Headings - limited to h1, h2, h3 for email compatibility\n HeadingFeature({\n enabledHeadingSizes: ['h1', 'h2', 'h3'],\n }),\n \n // Basic paragraph and alignment\n ParagraphFeature(),\n AlignFeature(),\n \n // Blockquotes\n BlockquoteFeature(),\n \n // Upload feature for images\n UploadFeature({\n collections: {\n media: {\n fields: [\n {\n name: 'caption',\n type: 'text',\n admin: {\n description: 'Optional caption for the image',\n },\n },\n {\n name: 'altText',\n type: 'text',\n label: 'Alt Text',\n required: true,\n admin: {\n description: 'Alternative text for accessibility and when image cannot be displayed',\n },\n },\n ],\n },\n },\n }),\n \n // Custom blocks for email-specific content\n BlocksFeature({\n blocks: allBlocks,\n }),\n ]\n}\n\n/**\n * Creates a Lexical editor configured specifically for email content\n * Processes blocks server-side to avoid client serialization issues\n */\nexport const createEmailLexicalEditor = (customBlocks: Block[] = []): any => {\n const emailSafeBlocks = createEmailSafeBlocks(customBlocks)\n \n return lexicalEditor({\n features: [\n // Toolbars\n FixedToolbarFeature(),\n InlineToolbarFeature(),\n \n // Basic text formatting\n BoldFeature(),\n ItalicFeature(),\n UnderlineFeature(),\n StrikethroughFeature(),\n \n // Links - use default fields to ensure drawer UI works correctly\n LinkFeature(),\n \n // Lists\n OrderedListFeature(),\n UnorderedListFeature(),\n \n // Headings - limited to h1, h2, h3 for email compatibility\n HeadingFeature({\n enabledHeadingSizes: ['h1', 'h2', 'h3'],\n }),\n \n // Basic paragraph and alignment\n ParagraphFeature(),\n AlignFeature(),\n \n // Blockquotes\n BlockquoteFeature(),\n \n // Upload feature for images\n UploadFeature({\n collections: {\n media: {\n fields: [\n {\n name: 'caption',\n type: 'text',\n admin: {\n description: 'Optional caption for the image',\n },\n },\n {\n name: 'altText',\n type: 'text',\n label: 'Alt Text',\n required: true,\n admin: {\n description: 'Alternative text for accessibility and when image cannot be displayed',\n },\n },\n ],\n },\n },\n }),\n \n // Email-safe blocks (processed server-side)\n BlocksFeature({\n blocks: emailSafeBlocks,\n }),\n ],\n })\n}\n\n/**\n * Legacy export for backward compatibility\n */\nexport const emailSafeFeatures = createEmailSafeFeatures()\n\n/**\n * Creates an email-safe rich text field configuration\n */\nexport const createEmailContentField = (\n overrides?: Partial<RichTextField> & {\n additionalBlocks?: Block[]\n editor?: any // Lexical editor instance\n }\n): RichTextField => {\n // Use provided editor or create one with blocks\n const editor = overrides?.editor || createEmailLexicalEditor(overrides?.additionalBlocks)\n\n return {\n name: 'content',\n type: 'richText',\n required: true,\n editor,\n admin: {\n description: 'Email content with limited formatting for compatibility',\n ...overrides?.admin,\n },\n ...overrides,\n }\n}","import type { Block } from 'payload'\n\n/**\n * Email-incompatible block types that should be warned about\n */\nconst EMAIL_INCOMPATIBLE_TYPES = [\n 'chart',\n 'dataTable', \n 'interactive',\n 'streamable',\n 'video',\n 'iframe',\n 'form',\n 'carousel',\n 'tabs',\n 'accordion',\n 'map'\n]\n\n/**\n * Validates that blocks are email-compatible and warns about potential issues\n */\nexport const validateEmailBlocks = (blocks: Block[]): void => {\n blocks.forEach(block => {\n if (EMAIL_INCOMPATIBLE_TYPES.includes(block.slug)) {\n console.warn(`⚠️ Block \"${block.slug}\" may not be email-compatible. Consider creating an email-specific version.`)\n }\n \n // Check for complex field types that might not work in emails\n const hasComplexFields = block.fields?.some(field => {\n const complexTypes = ['code', 'json', 'richText', 'blocks', 'array']\n return complexTypes.includes(field.type)\n })\n \n if (hasComplexFields) {\n console.warn(`⚠️ Block \"${block.slug}\" contains complex field types that may not render consistently in email clients.`)\n }\n })\n}\n\n/**\n * Creates email-safe block configurations by filtering and validating blocks\n */\nexport const createEmailSafeBlocks = (customBlocks: Block[] = []): Block[] => {\n // Validate blocks\n validateEmailBlocks(customBlocks)\n \n // Base email-safe blocks that come with the plugin\n const baseBlocks: Block[] = [\n {\n slug: 'button',\n fields: [\n {\n name: 'text',\n type: 'text',\n label: 'Button Text',\n required: true,\n },\n {\n name: 'url',\n type: 'text',\n label: 'Button URL',\n required: true,\n admin: {\n description: 'Enter the full URL (including https://)',\n },\n },\n {\n name: 'style',\n type: 'select',\n label: 'Button Style',\n defaultValue: 'primary',\n options: [\n { label: 'Primary', value: 'primary' },\n { label: 'Secondary', value: 'secondary' },\n { label: 'Outline', value: 'outline' },\n ],\n },\n ],\n interfaceName: 'EmailButton',\n labels: {\n singular: 'Button',\n plural: 'Buttons',\n },\n },\n {\n slug: 'divider',\n fields: [\n {\n name: 'style',\n type: 'select',\n label: 'Divider Style',\n defaultValue: 'solid',\n options: [\n { label: 'Solid', value: 'solid' },\n { label: 'Dashed', value: 'dashed' },\n { label: 'Dotted', value: 'dotted' },\n ],\n },\n ],\n interfaceName: 'EmailDivider',\n labels: {\n singular: 'Divider',\n plural: 'Dividers',\n },\n },\n ]\n \n // Combine base blocks with custom blocks\n return [\n ...baseBlocks,\n ...customBlocks\n ]\n}","import type { Field } from 'payload'\n\nexport const createBroadcastInlinePreviewField = (): Field => {\n return {\n name: 'broadcastInlinePreview',\n type: 'ui',\n admin: {\n components: {\n Field: 'payload-plugin-newsletter/components#BroadcastInlinePreview',\n },\n },\n }\n}","import DOMPurify from 'isomorphic-dompurify'\nimport type { SerializedEditorState } from 'lexical'\n\n/**\n * DOMPurify configuration for email-safe HTML\n */\nexport const EMAIL_SAFE_CONFIG = {\n ALLOWED_TAGS: [\n 'p', 'br', 'strong', 'b', 'em', 'i', 'u', 'strike', 's', 'span',\n 'a', 'h1', 'h2', 'h3', 'ul', 'ol', 'li', 'blockquote', 'hr',\n 'img', 'div', 'table', 'tr', 'td', 'th', 'tbody', 'thead'\n ],\n ALLOWED_ATTR: ['href', 'style', 'target', 'rel', 'align', 'src', 'alt', 'width', 'height', 'border', 'cellpadding', 'cellspacing'],\n ALLOWED_STYLES: {\n '*': [\n 'color', 'background-color', 'font-size', 'font-weight',\n 'font-style', 'text-decoration', 'text-align', 'margin',\n 'margin-top', 'margin-right', 'margin-bottom', 'margin-left',\n 'padding', 'padding-top', 'padding-right', 'padding-bottom', \n 'padding-left', 'line-height', 'border-left', 'border-left-width',\n 'border-left-style', 'border-left-color'\n ],\n },\n FORBID_TAGS: ['script', 'style', 'iframe', 'object', 'embed', 'form', 'input'],\n FORBID_ATTR: ['class', 'id', 'onclick', 'onload', 'onerror'],\n}\n\n/**\n * Converts Lexical editor state to email-safe HTML\n */\nexport async function convertToEmailSafeHtml(\n editorState: SerializedEditorState | undefined | null,\n options?: {\n wrapInTemplate?: boolean\n preheader?: string\n mediaUrl?: string // Base URL for media files\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n payload?: any // Payload instance for populating relationships\n populateFields?: string[] | ((blockType: string) => string[]) // Fields to populate\n customWrapper?: (content: string, options?: { preheader?: string; subject?: string; documentData?: Record<string, any> }) => string | Promise<string>\n subject?: string // Email subject for custom wrapper\n documentData?: Record<string, any> // Generic document data for custom wrapper\n }\n): Promise<string> {\n // Handle empty content\n if (!editorState) {\n return ''\n }\n \n // First, convert Lexical state to HTML using custom converters\n const rawHtml = await lexicalToEmailHtml(editorState, options?.mediaUrl, options?.customBlockConverter)\n \n // Sanitize the HTML\n const sanitizedHtml = DOMPurify.sanitize(rawHtml, EMAIL_SAFE_CONFIG)\n \n // Optionally wrap in email template\n if (options?.wrapInTemplate) {\n if (options.customWrapper) {\n return await Promise.resolve(options.customWrapper(sanitizedHtml, { \n preheader: options.preheader,\n subject: options.subject,\n documentData: options.documentData\n }))\n }\n return wrapInEmailTemplate(sanitizedHtml, options.preheader)\n }\n \n return sanitizedHtml\n}\n\n/**\n * Custom Lexical to HTML converter for email\n */\nasync function lexicalToEmailHtml(\n editorState: SerializedEditorState, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n const { root } = editorState\n \n if (!root || !root.children) {\n return ''\n }\n \n // Convert nodes asynchronously to support custom converters\n const htmlParts = await Promise.all(\n root.children.map((node: any) => convertNode(node, mediaUrl, customBlockConverter))\n )\n \n return htmlParts.join('')\n}\n\n/**\n * Convert individual Lexical nodes to email-safe HTML\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function convertNode(\n node: any, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n switch (node.type) {\n case 'paragraph':\n return convertParagraph(node, mediaUrl, customBlockConverter)\n case 'heading':\n return convertHeading(node, mediaUrl, customBlockConverter)\n case 'list':\n return convertList(node, mediaUrl, customBlockConverter)\n case 'listitem':\n return convertListItem(node, mediaUrl, customBlockConverter)\n case 'blockquote':\n return convertBlockquote(node, mediaUrl, customBlockConverter)\n case 'text':\n return convertText(node)\n case 'link':\n return convertLink(node, mediaUrl, customBlockConverter)\n case 'linebreak':\n return '<br>'\n case 'upload':\n return convertUpload(node, mediaUrl)\n case 'block':\n return await convertBlock(node, mediaUrl, customBlockConverter)\n default:\n // Unknown node type - convert children if any\n if (node.children) {\n const childParts = await Promise.all(\n node.children.map((child: any) => convertNode(child, mediaUrl, customBlockConverter))\n )\n return childParts.join('')\n }\n return ''\n }\n}\n\n/**\n * Convert paragraph node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function convertParagraph(\n node: any, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n const align = getAlignment(node.format)\n const childParts = await Promise.all(\n (node.children || []).map((child: any) => convertNode(child, mediaUrl, customBlockConverter))\n )\n const children = childParts.join('')\n \n if (!children.trim()) {\n return '<p class=\"mobile-margin-bottom-16\" style=\"margin: 0 0 16px 0; min-height: 1em;\"> </p>'\n }\n \n return `<p class=\"mobile-margin-bottom-16\" style=\"margin: 0 0 16px 0; text-align: ${align}; font-size: 16px; line-height: 1.5;\">${children}</p>`\n}\n\n/**\n * Convert heading node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function convertHeading(\n node: any, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n const tag = node.tag || 'h1'\n const align = getAlignment(node.format)\n const childParts = await Promise.all(\n (node.children || []).map((child: any) => convertNode(child, mediaUrl, customBlockConverter))\n )\n const children = childParts.join('')\n \n const styles: Record<string, string> = {\n h1: 'font-size: 32px; font-weight: 700; margin: 0 0 24px 0; line-height: 1.2;',\n h2: 'font-size: 24px; font-weight: 600; margin: 0 0 16px 0; line-height: 1.3;',\n h3: 'font-size: 20px; font-weight: 600; margin: 0 0 12px 0; line-height: 1.4;',\n }\n \n const mobileClasses: Record<string, string> = {\n h1: 'mobile-font-size-24',\n h2: 'mobile-font-size-20',\n h3: 'mobile-font-size-16',\n }\n \n const style = `${styles[tag] || styles.h3} text-align: ${align};`\n const mobileClass = mobileClasses[tag] || mobileClasses.h3\n \n return `<${tag} class=\"${mobileClass}\" style=\"${style}\">${children}</${tag}>`\n}\n\n/**\n * Convert list node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function convertList(\n node: any, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n const tag = node.listType === 'number' ? 'ol' : 'ul'\n const childParts = await Promise.all(\n (node.children || []).map((child: any) => convertNode(child, mediaUrl, customBlockConverter))\n )\n const children = childParts.join('')\n \n const style = tag === 'ul' \n ? 'margin: 0 0 16px 0; padding-left: 24px; list-style-type: disc; font-size: 16px; line-height: 1.5;'\n : 'margin: 0 0 16px 0; padding-left: 24px; list-style-type: decimal; font-size: 16px; line-height: 1.5;'\n \n return `<${tag} class=\"mobile-margin-bottom-16\" style=\"${style}\">${children}</${tag}>`\n}\n\n/**\n * Convert list item node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function convertListItem(\n node: any, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n const childParts = await Promise.all(\n (node.children || []).map((child: any) => convertNode(child, mediaUrl, customBlockConverter))\n )\n const children = childParts.join('')\n return `<li style=\"margin: 0 0 8px 0;\">${children}</li>`\n}\n\n/**\n * Convert blockquote node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function convertBlockquote(\n node: any, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n const childParts = await Promise.all(\n (node.children || []).map((child: any) => convertNode(child, mediaUrl, customBlockConverter))\n )\n const children = childParts.join('')\n const style = 'margin: 0 0 16px 0; padding-left: 16px; border-left: 4px solid #e5e7eb; color: #6b7280;'\n \n return `<blockquote style=\"${style}\">${children}</blockquote>`\n}\n\n/**\n * Convert text node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction convertText(node: any): string {\n let text = escapeHtml(node.text || '')\n \n // Apply formatting\n if (node.format & 1) { // Bold\n text = `<strong>${text}</strong>`\n }\n if (node.format & 2) { // Italic\n text = `<em>${text}</em>`\n }\n if (node.format & 8) { // Underline\n text = `<u>${text}</u>`\n }\n if (node.format & 4) { // Strikethrough\n text = `<strike>${text}</strike>`\n }\n \n return text\n}\n\n/**\n * Convert link node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function convertLink(\n node: any, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n const childParts = await Promise.all(\n (node.children || []).map((child: any) => convertNode(child, mediaUrl, customBlockConverter))\n )\n const children = childParts.join('')\n const url = node.fields?.url || '#'\n const newTab = node.fields?.newTab ?? false\n \n // Add target and rel attributes based on newTab setting\n const targetAttr = newTab ? ' target=\"_blank\"' : ''\n const relAttr = newTab ? ' rel=\"noopener noreferrer\"' : ''\n \n return `<a href=\"${escapeHtml(url)}\"${targetAttr}${relAttr} style=\"color: #2563eb; text-decoration: underline;\">${children}</a>`\n}\n\n/**\n * Convert upload (image) node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction convertUpload(node: any, mediaUrl?: string): string {\n const upload = node.value\n if (!upload) return ''\n \n // Get image URL - handle both direct URL and media object\n let src = ''\n if (typeof upload === 'string') {\n src = upload\n } else if (upload.url) {\n src = upload.url\n } else if (upload.filename && mediaUrl) {\n // Construct URL from media URL and filename\n src = `${mediaUrl}/${upload.filename}`\n }\n \n const alt = node.fields?.altText || upload.alt || ''\n const caption = node.fields?.caption || ''\n \n // Responsive email-safe image\n const imgHtml = `<img src=\"${escapeHtml(src)}\" alt=\"${escapeHtml(alt)}\" class=\"mobile-width-100\" style=\"max-width: 100%; height: auto; display: block; margin: 0 auto; border-radius: 6px;\" />`\n \n if (caption) {\n return `\n <div style=\"margin: 0 0 16px 0; text-align: center;\" class=\"mobile-margin-bottom-16\">\n ${imgHtml}\n <p style=\"margin: 8px 0 0 0; font-size: 14px; color: #6b7280; font-style: italic; text-align: center;\" class=\"mobile-font-size-14\">${escapeHtml(caption)}</p>\n </div>\n `\n }\n \n return `<div style=\"margin: 0 0 16px 0; text-align: center;\" class=\"mobile-margin-bottom-16\">${imgHtml}</div>`\n}\n\n/**\n * Convert custom block node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function convertBlock(\n node: any, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n const blockType = node.fields?.blockName || node.blockName\n \n // First, check if there's a custom converter for this block\n if (customBlockConverter) {\n try {\n const customHtml = await customBlockConverter(node, mediaUrl)\n if (customHtml) {\n return customHtml\n }\n } catch (error) {\n console.error(`Custom block converter error for ${blockType}:`, error)\n // Fall through to default handling\n }\n }\n \n // Default handling for built-in blocks\n switch (blockType) {\n case 'button':\n return convertButtonBlock(node.fields)\n case 'divider':\n return convertDividerBlock(node.fields)\n default:\n // Unknown block type - try to convert children\n if (node.children) {\n const childParts = await Promise.all(\n node.children.map((child: any) => convertNode(child, mediaUrl, customBlockConverter))\n )\n return childParts.join('')\n }\n return ''\n }\n}\n\n/**\n * Convert button block\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction convertButtonBlock(fields: any): string {\n const text = fields?.text || 'Click here'\n const url = fields?.url || '#'\n const style = fields?.style || 'primary'\n \n const styles: Record<string, string> = {\n primary: 'background-color: #2563eb; color: #ffffff; border: 2px solid #2563eb;',\n secondary: 'background-color: #6b7280; color: #ffffff; border: 2px solid #6b7280;',\n outline: 'background-color: transparent; color: #2563eb; border: 2px solid #2563eb;',\n }\n \n const buttonStyle = `${styles[style] || styles.primary} display: inline-block; padding: 12px 24px; font-size: 16px; font-weight: 600; text-decoration: none; border-radius: 6px; text-align: center;`\n \n return `\n <div style=\"margin: 0 0 16px 0; text-align: center;\">\n <a href=\"${escapeHtml(url)}\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"${buttonStyle}\">${escapeHtml(text)}</a>\n </div>\n `\n}\n\n/**\n * Convert divider block\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction convertDividerBlock(fields: any): string {\n const style = fields?.style || 'solid'\n \n const styles: Record<string, string> = {\n solid: 'border-top: 1px solid #e5e7eb;',\n dashed: 'border-top: 1px dashed #e5e7eb;',\n dotted: 'border-top: 1px dotted #e5e7eb;',\n }\n \n return `<hr style=\"${styles[style] || styles.solid} margin: 24px 0; border-bottom: none; border-left: none; border-right: none;\" />`\n}\n\n/**\n * Get text alignment from format number\n */\nfunction getAlignment(format?: number): string {\n if (!format) return 'left'\n \n // Lexical alignment format values\n if (format & 2) return 'center'\n if (format & 3) return 'right'\n if (format & 4) return 'justify'\n \n return 'left'\n}\n\n/**\n * Escape HTML special characters\n */\nfunction escapeHtml(text: string): string {\n const map: Record<string, string> = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": '''\n }\n \n return text.replace(/[&<>\"']/g, m => map[m])\n}\n\n/**\n * Wrap content in a responsive email template\n */\nfunction wrapInEmailTemplate(content: string, preheader?: string): string {\n return `<!DOCTYPE html>\n<html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:o=\"urn:schemas-microsoft-com:office:office\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n <meta name=\"x-apple-disable-message-reformatting\">\n <title>Newsletter</title>\n \n <!--[if mso]>\n <noscript>\n <xml>\n <o:OfficeDocumentSettings>\n <o:PixelsPerInch>96</o:PixelsPerInch>\n </o:OfficeDocumentSettings>\n </xml>\n </noscript>\n <![endif]-->\n \n <style>\n /* Reset and base styles */\n * {\n -webkit-text-size-adjust: 100%;\n -ms-text-size-adjust: 100%;\n }\n \n body {\n margin: 0 !important;\n padding: 0 !important;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;\n font-size: 16px;\n line-height: 1.5;\n color: #1A1A1A;\n background-color: #f8f9fa;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n \n table {\n border-spacing: 0 !important;\n border-collapse: collapse !important;\n table-layout: fixed !important;\n margin: 0 auto !important;\n }\n \n table table table {\n table-layout: auto;\n }\n \n img {\n -ms-interpolation-mode: bicubic;\n max-width: 100%;\n height: auto;\n border: 0;\n outline: none;\n text-decoration: none;\n }\n \n /* Responsive styles */\n @media only screen and (max-width: 640px) {\n .mobile-hide {\n display: none !important;\n }\n \n .mobile-center {\n text-align: center !important;\n }\n \n .mobile-width-100 {\n width: 100% !important;\n max-width: 100% !important;\n }\n \n .mobile-padding {\n padding: 20px !important;\n }\n \n .mobile-padding-sm {\n padding: 16px !important;\n }\n \n .mobile-font-size-14 {\n font-size: 14px !important;\n }\n \n .mobile-font-size-16 {\n font-size: 16px !important;\n }\n \n .mobile-font-size-20 {\n font-size: 20px !important;\n line-height: 1.3 !important;\n }\n \n .mobile-font-size-24 {\n font-size: 24px !important;\n line-height: 1.2 !important;\n }\n \n /* Stack sections on mobile */\n .mobile-stack {\n display: block !important;\n width: 100% !important;\n }\n \n /* Mobile-specific spacing */\n .mobile-margin-bottom-16 {\n margin-bottom: 16px !important;\n }\n \n .mobile-margin-bottom-20 {\n margin-bottom: 20px !important;\n }\n }\n \n /* Dark mode support */\n @media (prefers-color-scheme: dark) {\n .dark-mode-bg {\n background-color: #1a1a1a !important;\n }\n \n .dark-mode-text {\n color: #ffffff !important;\n }\n \n .dark-mode-border {\n border-color: #333333 !important;\n }\n }\n \n /* Outlook-specific fixes */\n <!--[if mso]>\n <style>\n table {\n border-collapse: collapse;\n border-spacing: 0;\n border: none;\n margin: 0;\n }\n \n div, p {\n margin: 0;\n }\n </style>\n <![endif]-->\n </style>\n</head>\n<body style=\"margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif; font-size: 16px; line-height: 1.5; color: #1A1A1A; background-color: #f8f9fa;\">\n ${preheader ? `\n <!-- Preheader text -->\n <div style=\"display: none; max-height: 0; overflow: hidden; font-size: 1px; line-height: 1px; color: transparent;\">\n ${escapeHtml(preheader)}\n </div>\n ` : ''}\n \n <!-- Main container -->\n <table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" style=\"margin: 0; padding: 0; background-color: #f8f9fa;\">\n <tr>\n <td align=\"center\" style=\"padding: 20px 10px;\">\n <!-- Email wrapper -->\n <table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" width=\"600\" class=\"mobile-width-100\" style=\"margin: 0 auto; max-width: 600px;\">\n <tr>\n <td class=\"mobile-padding\" style=\"padding: 0;\">\n <!-- Content area with light background -->\n <div style=\"background-color: #ffffff; padding: 40px 30px; border-radius: 8px;\" class=\"mobile-padding\">\n ${content}\n </div>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n</body>\n</html>`\n}\n\n/**\n * Extract personalization tags from content\n */\nexport function extractPersonalizationTags(html: string): string[] {\n const regex = /\\{\\{([^}]+)\\}\\}/g\n const tags: string[] = []\n let match\n \n while ((match = regex.exec(html)) !== null) {\n tags.push(match[1].trim())\n }\n \n return [...new Set(tags)]\n}\n\n/**\n * Replace personalization tags with sample data\n */\nexport function replacePersonalizationTags(\n html: string, \n sampleData: Record<string, string>\n): string {\n return html.replace(/\\{\\{([^}]+)\\}\\}/g, (match, tag) => {\n const trimmedTag = tag.trim()\n return sampleData[trimmedTag] || match\n })\n}","import type { PayloadRequest } from 'payload'\nimport type { NewsletterPluginConfig, BroadcastProviderConfig } from '../types'\n\nexport async function getBroadcastConfig(\n req: PayloadRequest,\n pluginConfig: NewsletterPluginConfig\n): Promise<BroadcastProviderConfig | null> {\n try {\n // Get settings from Newsletter Settings collection\n const settings = await req.payload.findGlobal({\n slug: pluginConfig.settingsSlug || 'newsletter-settings',\n req,\n })\n\n // Build provider config from settings, falling back to env vars\n if (settings?.provider === 'broadcast' && settings?.broadcastSettings) {\n return {\n apiUrl: settings.broadcastSettings.apiUrl || pluginConfig.providers?.broadcast?.apiUrl || '',\n token: settings.broadcastSettings.token || pluginConfig.providers?.broadcast?.token || '',\n fromAddress: settings.fromAddress || pluginConfig.providers?.broadcast?.fromAddress || '',\n fromName: settings.fromName || pluginConfig.providers?.broadcast?.fromName || '',\n replyTo: settings.replyTo || pluginConfig.providers?.broadcast?.replyTo,\n }\n }\n\n // Fall back to env var config\n return pluginConfig.providers?.broadcast || null\n } catch (error) {\n req.payload.logger.error({ error: String(error) }, 'Failed to get broadcast config from settings')\n // Fall back to env var config on error\n return pluginConfig.providers?.broadcast || null\n }\n}","import type { Endpoint, PayloadHandler, PayloadRequest } from 'payload'\nimport type { NewsletterPluginConfig, SendBroadcastOptions } from '../../types'\nimport { NewsletterProviderError, NewsletterStatus } from '../../types'\nimport { requireAdmin } from '../../utils/auth'\nimport { getBroadcastConfig } from '../../utils/getBroadcastConfig'\n\nexport const createSendBroadcastEndpoint = (\n config: NewsletterPluginConfig,\n collectionSlug: string\n): Endpoint => {\n return {\n path: '/:id/send',\n method: 'post',\n handler: (async (req: PayloadRequest) => {\n try {\n // Check authentication\n const auth = await requireAdmin(req, config)\n if (!auth.authorized) {\n return Response.json({\n success: false,\n error: auth.error,\n }, { status: 401 })\n }\n\n // Check if broadcast management is enabled\n if (!config.features?.newsletterManagement?.enabled) {\n return Response.json({\n success: false,\n error: 'Broadcast management is not enabled',\n }, { status: 400 })\n }\n\n // Get ID from URL\n const url = new URL(req.url || '', `http://localhost`)\n const pathParts = url.pathname.split('/')\n const id = pathParts[pathParts.length - 2] // -2 because last part is 'send'\n\n if (!id) {\n return Response.json({\n success: false,\n error: 'Broadcast ID is required',\n }, { status: 400 })\n }\n\n // Parse request body\n const data = await (req.json?.() || Promise.resolve({})) as SendBroadcastOptions\n\n // Get the broadcast document\n const broadcastDoc = await req.payload.findByID({\n collection: collectionSlug,\n id,\n user: auth.user,\n })\n\n if (!broadcastDoc || !broadcastDoc.providerId) {\n return Response.json({\n success: false,\n error: 'Broadcast not found or not synced with provider',\n }, { status: 404 })\n }\n\n // Get provider config from settings first, then fall back to env vars\n const providerConfig = await getBroadcastConfig(req, config)\n if (!providerConfig || !providerConfig.token) {\n return Response.json({\n success: false,\n error: 'Broadcast provider not configured in Newsletter Settings or environment variables',\n }, { status: 500 })\n }\n\n const { BroadcastApiProvider } = await import('../../providers/broadcast/broadcast')\n const provider = new BroadcastApiProvider(providerConfig)\n\n // Send broadcast using provider ID\n const broadcast = await provider.send(broadcastDoc.providerId, data)\n\n // Update status in Payload collection\n await req.payload.update({\n collection: collectionSlug,\n id,\n data: {\n sendStatus: NewsletterStatus.SENDING,\n sentAt: new Date().toISOString(),\n },\n user: auth.user,\n })\n\n return Response.json({\n success: true,\n message: 'Broadcast sent successfully',\n broadcast,\n })\n } catch (error) {\n console.error('Failed to send broadcast:', error)\n \n if (error instanceof NewsletterProviderError) {\n return Response.json({\n success: false,\n error: error.message,\n code: error.code,\n }, { status: error.code === 'NOT_SUPPORTED' ? 501 : 500 })\n }\n\n return Response.json({\n success: false,\n error: 'Failed to send broadcast',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","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 { PayloadRequest } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { isAdmin } from './access'\n\n/**\n * Get authenticated user from request\n * In Payload v3, authentication is handled differently than v2\n */\nexport async function getAuthenticatedUser(req: PayloadRequest): Promise<any | null> {\n try {\n // Try to get the current user using Payload's auth\n // This requires the request to have proper authentication headers/cookies\n const me = await req.payload.find({\n collection: 'users',\n where: {\n id: {\n equals: 'me', // Special value in Payload to get current user\n },\n },\n limit: 1,\n depth: 0,\n })\n \n return me.docs[0] || null\n } catch {\n return null\n }\n}\n\n/**\n * Check if request has admin access\n */\nexport async function requireAdmin(\n req: PayloadRequest,\n config: NewsletterPluginConfig\n): Promise<{ authorized: true; user: any } | { authorized: false; error: string }> {\n const user = await getAuthenticatedUser(req)\n \n if (!user) {\n return {\n authorized: false,\n error: 'Authentication required',\n }\n }\n \n if (!isAdmin(user, config)) {\n return {\n authorized: false,\n error: 'Admin access required',\n }\n }\n \n return {\n authorized: true,\n user,\n }\n}","import type { Endpoint, PayloadHandler, PayloadRequest } from 'payload'\nimport type { NewsletterPluginConfig } from '../../types'\nimport { NewsletterProviderError, NewsletterStatus } from '../../types'\nimport { requireAdmin } from '../../utils/auth'\n\nexport const createScheduleBroadcastEndpoint = (\n config: NewsletterPluginConfig,\n collectionSlug: string\n): Endpoint => {\n return {\n path: '/:id/schedule',\n method: 'post',\n handler: (async (req: PayloadRequest) => {\n try {\n // Check authentication\n const auth = await requireAdmin(req, config)\n if (!auth.authorized) {\n return Response.json({\n success: false,\n error: auth.error,\n }, { status: 401 })\n }\n\n // Check if broadcast management is enabled\n if (!config.features?.newsletterManagement?.enabled) {\n return Response.json({\n success: false,\n error: 'Broadcast management is not enabled',\n }, { status: 400 })\n }\n\n // Get ID from URL\n const url = new URL(req.url || '', `http://localhost`)\n const pathParts = url.pathname.split('/')\n const id = pathParts[pathParts.length - 2] // -2 because last part is 'schedule'\n\n if (!id) {\n return Response.json({\n success: false,\n error: 'Broadcast ID is required',\n }, { status: 400 })\n }\n\n // Parse request body\n const data = await (req.json?.() || Promise.resolve({}))\n const { scheduledAt } = data\n\n if (!scheduledAt) {\n return Response.json({\n success: false,\n error: 'scheduledAt is required',\n }, { status: 400 })\n }\n\n // Parse and validate date\n const scheduledDate = new Date(scheduledAt)\n if (isNaN(scheduledDate.getTime())) {\n return Response.json({\n success: false,\n error: 'Invalid scheduledAt date',\n }, { status: 400 })\n }\n\n // Ensure scheduled date is in the future\n if (scheduledDate <= new Date()) {\n return Response.json({\n success: false,\n error: 'scheduledAt must be in the future',\n }, { status: 400 })\n }\n\n // Get the broadcast document\n const broadcastDoc = await req.payload.findByID({\n collection: collectionSlug,\n id,\n user: auth.user,\n })\n\n if (!broadcastDoc || !broadcastDoc.providerId) {\n return Response.json({\n success: false,\n error: 'Broadcast not found or not synced with provider',\n }, { status: 404 })\n }\n\n // Get provider from config\n const providerConfig = config.providers?.broadcast\n if (!providerConfig) {\n return Response.json({\n success: false,\n error: 'Broadcast provider not configured',\n }, { status: 500 })\n }\n\n const { BroadcastApiProvider } = await import('../../providers/broadcast/broadcast')\n const provider = new BroadcastApiProvider(providerConfig)\n\n // Schedule broadcast using provider ID\n const broadcast = await provider.schedule(broadcastDoc.providerId, scheduledDate)\n\n // Update status in Payload collection\n await req.payload.update({\n collection: collectionSlug,\n id,\n data: {\n sendStatus: NewsletterStatus.SCHEDULED,\n scheduledAt: scheduledDate.toISOString(),\n },\n user: auth.user,\n })\n\n return Response.json({\n success: true,\n message: `Broadcast scheduled for ${scheduledDate.toISOString()}`,\n broadcast,\n })\n } catch (error) {\n console.error('Failed to schedule broadcast:', error)\n \n if (error instanceof NewsletterProviderError) {\n return Response.json({\n success: false,\n error: error.message,\n code: error.code,\n }, { status: error.code === 'NOT_SUPPORTED' ? 501 : 500 })\n }\n\n return Response.json({\n success: false,\n error: 'Failed to schedule broadcast',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint, PayloadHandler, PayloadRequest } from 'payload'\nimport type { NewsletterPluginConfig } from '../../types'\nimport { requireAdmin } from '../../utils/auth'\nimport { convertToEmailSafeHtml } from '../../utils/emailSafeHtml'\n\nexport const createTestBroadcastEndpoint = (\n config: NewsletterPluginConfig,\n collectionSlug: string\n): Endpoint => {\n return {\n path: '/:id/test',\n method: 'post',\n handler: (async (req: PayloadRequest) => {\n try {\n // Check authentication\n const auth = await requireAdmin(req, config)\n if (!auth.authorized) {\n return Response.json({\n success: false,\n error: auth.error,\n }, { status: 401 })\n }\n\n // Get ID from URL\n const url = new URL(req.url || '', `http://localhost`)\n const pathParts = url.pathname.split('/')\n const id = pathParts[pathParts.length - 2] // -2 because last part is 'test'\n\n if (!id) {\n return Response.json({\n success: false,\n error: 'Broadcast ID is required',\n }, { status: 400 })\n }\n\n // Parse request body for optional test email\n const data = await (req.json?.() || Promise.resolve({}))\n const testEmail = data.email || auth.user.email\n\n if (!testEmail) {\n return Response.json({\n success: false,\n error: 'No email address available for test send',\n }, { status: 400 })\n }\n\n // Get the broadcast document\n const broadcast = await req.payload.findByID({\n collection: collectionSlug,\n id,\n user: auth.user,\n })\n\n if (!broadcast) {\n return Response.json({\n success: false,\n error: 'Broadcast not found',\n }, { status: 404 })\n }\n\n // Convert content to email-safe HTML\n const htmlContent = await convertToEmailSafeHtml(broadcast.content, {\n wrapInTemplate: true,\n preheader: broadcast.preheader,\n customBlockConverter: config.customizations?.broadcasts?.customBlockConverter,\n })\n\n // Get email service\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const emailService = (req.payload as any).newsletterEmailService\n if (!emailService) {\n return Response.json({\n success: false,\n error: 'Email service is not configured',\n }, { status: 500 })\n }\n\n // Get sender info from provider config\n const providerConfig = config.providers.default === 'resend' \n ? config.providers.resend \n : config.providers.broadcast\n const fromEmail = providerConfig?.fromAddress || providerConfig?.fromEmail || 'noreply@example.com'\n const fromName = providerConfig?.fromName || 'Newsletter'\n const replyTo = broadcast.settings?.replyTo || providerConfig?.replyTo\n\n // Send test email\n await emailService.send({\n to: testEmail,\n from: fromEmail,\n fromName: fromName,\n replyTo: replyTo,\n subject: `[TEST] ${broadcast.subject}`,\n html: htmlContent,\n trackOpens: false,\n trackClicks: false,\n })\n\n return Response.json({\n success: true,\n message: `Test email sent to ${testEmail}`,\n })\n } catch (error) {\n console.error('Failed to send test broadcast:', error)\n \n return Response.json({\n success: false,\n error: 'Failed to send test email',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import type { Payload } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\n\n/**\n * Recursively populates media fields in Lexical content.\n * Resolves Media IDs to full media objects with URLs.\n *\n * @param content - Lexical editor state content\n * @param payload - Payload instance for database queries\n * @param config - Newsletter plugin configuration\n * @returns Populated content with resolved media objects\n */\nexport async function populateMediaFields(\n content: unknown,\n payload: Payload,\n config: NewsletterPluginConfig\n): Promise<unknown> {\n if (!content || typeof content !== 'object') return content\n\n const typedContent = content as { root?: { children?: unknown[] } }\n\n // Handle Lexical editor state\n if (typedContent.root?.children) {\n for (const child of typedContent.root.children) {\n await populateBlockMediaFields(child, payload, config)\n }\n }\n\n return content\n}\n\n/**\n * Populates media fields in individual block nodes.\n * Handles upload fields, arrays of uploads, and rich text fields.\n */\nasync function populateBlockMediaFields(\n node: unknown,\n payload: Payload,\n config: NewsletterPluginConfig\n): Promise<void> {\n if (!node || typeof node !== 'object') return\n\n const typedNode = node as {\n type?: string\n fields?: Record<string, unknown>\n children?: unknown[]\n }\n\n // Check if this is a block node\n if (typedNode.type === 'block' && typedNode.fields) {\n const blockType = (typedNode.fields.blockType || typedNode.fields.blockName) as string | undefined\n\n // Get custom blocks configuration\n const customBlocks = config.customizations?.broadcasts?.customBlocks || []\n const blockConfig = customBlocks.find((b: { slug: string }) => b.slug === blockType)\n\n if (blockConfig && blockConfig.fields) {\n // Find all upload fields in the block\n for (const field of blockConfig.fields) {\n if (field.type === 'upload' && field.relationTo && typedNode.fields[field.name]) {\n const fieldValue = typedNode.fields[field.name]\n const collectionName = Array.isArray(field.relationTo) ? field.relationTo[0] : field.relationTo\n\n // If it's just an ID string, populate it\n if (typeof fieldValue === 'string' && fieldValue.match(/^[a-f0-9]{24}$/i)) {\n try {\n const media = await payload.findByID({\n collection: collectionName,\n id: fieldValue,\n depth: 0,\n })\n\n if (media) {\n typedNode.fields[field.name] = media\n payload.logger?.info(\n {\n mediaId: fieldValue,\n mediaUrl: (media as { url?: string }).url,\n filename: (media as { filename?: string }).filename,\n },\n `Populated ${field.name} for block ${blockType}`\n )\n }\n } catch (error) {\n payload.logger?.error(\n { error: String(error) },\n `Failed to populate ${field.name} for block ${blockType}`\n )\n }\n }\n }\n\n // Also handle arrays of uploads\n if (field.type === 'array' && field.fields) {\n const arrayValue = typedNode.fields[field.name]\n if (Array.isArray(arrayValue)) {\n for (const arrayItem of arrayValue) {\n if (arrayItem && typeof arrayItem === 'object') {\n const typedArrayItem = arrayItem as Record<string, unknown>\n // Recursively process array items for upload fields\n for (const arrayField of field.fields) {\n if (\n arrayField.type === 'upload' &&\n arrayField.relationTo &&\n typedArrayItem[arrayField.name]\n ) {\n const arrayFieldValue = typedArrayItem[arrayField.name]\n const arrayCollectionName = Array.isArray(arrayField.relationTo)\n ? arrayField.relationTo[0]\n : arrayField.relationTo\n\n if (\n typeof arrayFieldValue === 'string' &&\n arrayFieldValue.match(/^[a-f0-9]{24}$/i)\n ) {\n try {\n const media = await payload.findByID({\n collection: arrayCollectionName,\n id: arrayFieldValue,\n depth: 0,\n })\n\n if (media) {\n typedArrayItem[arrayField.name] = media\n payload.logger?.info(\n {\n mediaId: arrayFieldValue,\n mediaUrl: (media as { url?: string }).url,\n filename: (media as { filename?: string }).filename,\n },\n `Populated array ${arrayField.name} for block ${blockType}`\n )\n }\n } catch (error) {\n payload.logger?.error(\n { error: String(error) },\n `Failed to populate array ${arrayField.name} for block ${blockType}`\n )\n }\n }\n }\n }\n }\n }\n }\n }\n\n // Also handle rich text fields\n if (field.type === 'richText' && typedNode.fields[field.name]) {\n await populateRichTextUploads(typedNode.fields[field.name], payload)\n payload.logger?.info(`Processed rich text field ${field.name} for upload nodes`)\n }\n }\n }\n }\n\n // Recursively process children\n if (typedNode.children) {\n for (const child of typedNode.children) {\n await populateBlockMediaFields(child, payload, config)\n }\n }\n}\n\n/**\n * Populates upload nodes within rich text content.\n * Resolves media IDs to full media objects.\n */\nasync function populateRichTextUploads(content: unknown, payload: Payload): Promise<void> {\n if (!content || typeof content !== 'object') return\n\n const typedContent = content as {\n root?: { children?: unknown[] }\n }\n\n // Handle Lexical root structure\n if (typedContent.root?.children) {\n await processNodeArray(typedContent.root.children)\n }\n\n // Handle direct children array\n if (Array.isArray(content)) {\n await processNodeArray(content)\n }\n\n async function processNodeArray(nodes: unknown[]): Promise<void> {\n await Promise.all(nodes.map(processNode))\n }\n\n async function processNode(node: unknown): Promise<void> {\n if (!node || typeof node !== 'object') return\n\n const typedNode = node as {\n type?: string\n relationTo?: string\n value?: unknown\n children?: unknown[]\n root?: { children?: unknown[] }\n }\n\n // Check if this is an upload node with unpopulated value\n if (\n typedNode.type === 'upload' &&\n typedNode.relationTo === 'media' &&\n typeof typedNode.value === 'string' &&\n typedNode.value.match(/^[a-f0-9]{24}$/i)\n ) {\n try {\n const media = await payload.findByID({\n collection: 'media',\n id: typedNode.value,\n depth: 0,\n })\n\n if (media) {\n typedNode.value = media\n payload.logger?.info(\n {\n mediaId: typedNode.value,\n mediaUrl: (media as { url?: string }).url,\n filename: (media as { filename?: string }).filename,\n },\n 'Populated rich text upload node'\n )\n }\n } catch (error) {\n payload.logger?.error(\n { error: String(error) },\n `Failed to populate rich text upload ${typedNode.value}`\n )\n }\n }\n\n // Recursively process children\n if (typedNode.children && Array.isArray(typedNode.children)) {\n await processNodeArray(typedNode.children)\n }\n\n // Also check for root property (some Lexical structures)\n if (typedNode.root?.children && Array.isArray(typedNode.root.children)) {\n await processNodeArray(typedNode.root.children)\n }\n }\n}\n","import type { Endpoint, PayloadHandler, PayloadRequest } from 'payload'\nimport type { SerializedEditorState } from 'lexical'\nimport type { NewsletterPluginConfig } from '../../types'\nimport { convertToEmailSafeHtml } from '../../utils/emailSafeHtml'\nimport { populateMediaFields } from '../../utils/mediaPopulation'\n\n// Re-export for backwards compatibility\nexport { populateMediaFields } from '../../utils/mediaPopulation'\n\nexport const createBroadcastPreviewEndpoint = (\n config: NewsletterPluginConfig,\n _collectionSlug: string\n): Endpoint => {\n return {\n path: '/preview',\n method: 'post',\n handler: (async (req: PayloadRequest) => {\n try {\n // Parse request body\n const data = await (req.json?.() || Promise.resolve({}))\n const { content, preheader, subject, documentData } = data\n\n if (!content) {\n return Response.json({\n success: false,\n error: 'Content is required for preview',\n }, { status: 400 })\n }\n\n // Get media URL from payload config or use default\n const mediaUrl = req.payload.config.serverURL \n ? `${req.payload.config.serverURL}/api/media`\n : '/api/media'\n\n // Populate media fields in custom blocks before conversion\n req.payload.logger?.info('Populating media fields for email preview...')\n const populatedContent = await populateMediaFields(content, req.payload, config)\n\n // Get email preview customization options\n const emailPreviewConfig = config.customizations?.broadcasts?.emailPreview\n \n // Convert content to email-safe HTML with customization options\n const htmlContent = await convertToEmailSafeHtml(populatedContent as SerializedEditorState | null, {\n wrapInTemplate: emailPreviewConfig?.wrapInTemplate ?? true,\n preheader: preheader,\n subject: subject,\n mediaUrl: mediaUrl,\n documentData, // Pass all document data\n customBlockConverter: config.customizations?.broadcasts?.customBlockConverter,\n customWrapper: emailPreviewConfig?.customWrapper,\n })\n\n return Response.json({\n success: true,\n html: htmlContent,\n preview: {\n subject: subject || 'Preview',\n preheader: preheader || '',\n html: htmlContent,\n },\n })\n } catch (error) {\n console.error('Failed to generate email preview:', error)\n \n return Response.json({\n success: false,\n error: 'Failed to generate email preview',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import { render } from '@react-email/render'\nimport { MagicLinkEmail } from './MagicLink'\nimport { WelcomeEmail } from './Welcome'\nimport { SignInEmail } from './SignIn'\nimport type { NewsletterPluginConfig } from '../types'\n\nexport type EmailTemplate = 'magic-link' | 'welcome' | 'signin'\n\nexport interface BaseEmailData {\n email?: string\n siteName?: string\n [key: string]: any\n}\n\nexport interface MagicLinkData extends BaseEmailData {\n magicLink?: string\n verificationUrl?: string\n magicLinkUrl?: string\n expiresIn?: string\n}\n\nexport interface WelcomeData extends BaseEmailData {\n preferencesUrl?: string\n}\n\nexport async function renderEmail(\n template: EmailTemplate, \n data: MagicLinkData | WelcomeData,\n config?: NewsletterPluginConfig\n): Promise<string> {\n try {\n // Check for custom templates if config provided\n if (config?.customTemplates) {\n const customTemplate = config.customTemplates[template]\n if (customTemplate) {\n const CustomComponent = customTemplate\n return render(<CustomComponent {...data} />)\n }\n }\n \n // Fall back to built-in templates\n switch (template) {\n case 'magic-link': {\n const magicLinkData = data as MagicLinkData\n return render(\n <MagicLinkEmail\n magicLink={\n magicLinkData.magicLink || \n magicLinkData.verificationUrl || \n magicLinkData.magicLinkUrl || \n ''\n }\n email={magicLinkData.email || ''}\n siteName={magicLinkData.siteName}\n expiresIn={magicLinkData.expiresIn}\n />\n )\n }\n \n case 'signin': {\n const signinData = data as MagicLinkData\n return render(\n <SignInEmail\n magicLink={\n signinData.magicLink || \n signinData.verificationUrl || \n signinData.magicLinkUrl || \n ''\n }\n email={signinData.email || ''}\n siteName={signinData.siteName}\n expiresIn={signinData.expiresIn}\n />\n )\n }\n \n case 'welcome': {\n const welcomeData = data as WelcomeData\n return render(\n <WelcomeEmail\n email={welcomeData.email || ''}\n siteName={welcomeData.siteName}\n preferencesUrl={welcomeData.preferencesUrl}\n />\n )\n }\n \n default:\n throw new Error(`Unknown email template: ${template}`)\n }\n } catch (error) {\n console.error(`Failed to render email template ${template}:`, error)\n throw error\n }\n}\n\n// Export for custom template rendering\nexport { MagicLinkEmail, WelcomeEmail, SignInEmail }","import React from 'react'\nimport {\n Body,\n Button,\n Container,\n Head,\n Hr,\n Html,\n Preview,\n Text,\n} from '@react-email/components'\nimport { styles } from './styles'\n\nexport interface MagicLinkEmailProps {\n magicLink: string\n email: string\n siteName?: string\n expiresIn?: string\n}\n\nexport const MagicLinkEmail: React.FC<MagicLinkEmailProps> = ({\n magicLink,\n email,\n siteName = 'Newsletter',\n expiresIn = '24 hours',\n}) => {\n const previewText = `Sign in to ${siteName}`\n \n return (\n <Html>\n <Head />\n <Preview>{previewText}</Preview>\n <Body style={styles.main}>\n <Container style={styles.container}>\n <Text style={styles.heading}>Sign in to {siteName}</Text>\n \n <Text style={styles.text}>\n Hi {email.split('@')[0]},\n </Text>\n \n <Text style={styles.text}>\n We received a request to sign in to your {siteName} account. \n Click the button below to complete your sign in:\n </Text>\n \n <Button href={magicLink} style={styles.button}>\n Sign in to {siteName}\n </Button>\n \n <Text style={styles.text}>\n Or copy and paste this URL into your browser:\n </Text>\n \n <code style={styles.code}>{magicLink}</code>\n \n <Hr style={styles.hr} />\n \n <Text style={styles.footer}>\n This link will expire in {expiresIn}. If you didn't request this email, \n you can safely ignore it.\n </Text>\n </Container>\n </Body>\n </Html>\n )\n}\n\nexport default MagicLinkEmail","export const styles = {\n main: {\n backgroundColor: '#f6f9fc',\n fontFamily:\n '-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,\"Helvetica Neue\",Ubuntu,sans-serif',\n },\n container: {\n backgroundColor: '#ffffff',\n border: '1px solid #f0f0f0',\n borderRadius: '5px',\n margin: '0 auto',\n padding: '45px',\n marginBottom: '64px',\n maxWidth: '500px',\n },\n heading: {\n fontSize: '24px',\n letterSpacing: '-0.5px',\n lineHeight: '1.3',\n fontWeight: '600',\n color: '#484848',\n margin: '0 0 20px',\n padding: '0',\n },\n text: {\n fontSize: '16px',\n lineHeight: '26px',\n fontWeight: '400',\n color: '#484848',\n margin: '16px 0',\n },\n button: {\n backgroundColor: '#000000',\n borderRadius: '5px',\n color: '#fff',\n fontSize: '16px',\n fontWeight: 'bold',\n textDecoration: 'none',\n textAlign: 'center' as const,\n display: 'block',\n width: '100%',\n padding: '14px 20px',\n margin: '30px 0',\n },\n link: {\n color: '#2754C5',\n fontSize: '14px',\n textDecoration: 'underline',\n wordBreak: 'break-all' as const,\n },\n hr: {\n borderColor: '#e6ebf1',\n margin: '30px 0',\n },\n footer: {\n fontSize: '14px',\n lineHeight: '24px',\n color: '#9ca2ac',\n textAlign: 'center' as const,\n margin: '0',\n },\n code: {\n display: 'inline-block',\n padding: '16px',\n width: '100%',\n backgroundColor: '#f4f4f4',\n borderRadius: '5px',\n border: '1px solid #eee',\n fontSize: '14px',\n fontFamily: 'monospace',\n textAlign: 'center' as const,\n margin: '24px 0',\n },\n}","import React from 'react'\nimport {\n Body,\n Button,\n Container,\n Head,\n Hr,\n Html,\n Preview,\n Text,\n} from '@react-email/components'\nimport { styles } from './styles'\n\nexport interface WelcomeEmailProps {\n email: string\n siteName?: string\n preferencesUrl?: string\n}\n\nexport const WelcomeEmail: React.FC<WelcomeEmailProps> = ({\n email,\n siteName = 'Newsletter',\n preferencesUrl,\n}) => {\n const previewText = `Welcome to ${siteName}!`\n const firstName = email.split('@')[0]\n \n return (\n <Html>\n <Head />\n <Preview>{previewText}</Preview>\n <Body style={styles.main}>\n <Container style={styles.container}>\n <Text style={styles.heading}>Welcome to {siteName}! 🎉</Text>\n \n <Text style={styles.text}>\n Hi {firstName},\n </Text>\n \n <Text style={styles.text}>\n Thanks for subscribing to {siteName}! We're excited to have you as part \n of our community.\n </Text>\n \n <Text style={styles.text}>\n You'll receive our newsletter based on your preferences. Speaking of which, \n you can update your preferences anytime:\n </Text>\n \n {preferencesUrl && (\n <Button href={preferencesUrl} style={styles.button}>\n Manage Preferences\n </Button>\n )}\n \n <Text style={styles.text}>\n Here's what you can expect from us:\n </Text>\n \n <Text style={styles.text}>\n • Regular updates based on your chosen frequency<br />\n • Content tailored to your interests<br />\n • Easy unsubscribe options in every email<br />\n • Your privacy respected always\n </Text>\n \n <Hr style={styles.hr} />\n \n <Text style={styles.footer}>\n If you have any questions, feel free to reply to this email. \n We're here to help!\n </Text>\n </Container>\n </Body>\n </Html>\n )\n}\n\nexport default WelcomeEmail","// SignIn is just an alias for MagicLink with slightly different defaults\nimport React from 'react'\nimport { MagicLinkEmail, MagicLinkEmailProps } from './MagicLink'\n\nexport const SignInEmail: React.FC<MagicLinkEmailProps> = (props) => {\n return <MagicLinkEmail {...props} />\n}\n\nexport default SignInEmail","import type { CollectionConfig, Field, CollectionAfterChangeHook, CollectionBeforeDeleteHook } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { adminOnly, adminOrSelf } from '../utils/access'\nimport { renderEmail } from '../emails/render'\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 // External ID for webhook integration\n {\n name: 'externalId',\n type: 'text',\n admin: {\n description: 'ID from email service provider',\n readOnly: true,\n },\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: 'subscribedAt',\n type: 'date',\n admin: {\n description: 'When the user subscribed',\n readOnly: true,\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 name: 'unsubscribeReason',\n type: 'text',\n admin: {\n condition: (data) => data?.subscriptionStatus === 'unsubscribed',\n description: 'Reason for unsubscribing',\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 // Import tracking\n {\n name: 'importedFromProvider',\n type: 'checkbox',\n defaultValue: false,\n admin: {\n description: 'Indicates this subscriber was imported from an external provider via webhook',\n position: 'sidebar',\n readOnly: true,\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 // TODO: Add proper type for newsletter email service\n console.log('[Newsletter Plugin] Creating subscriber:', {\n email: doc.email,\n hasEmailService: !!emailService\n })\n \n if (emailService) {\n try {\n await emailService.addContact(doc)\n console.log('[Newsletter Plugin] Successfully added contact to email service')\n } catch (error) {\n console.error('[Newsletter Plugin] Failed to add contact to email service:', error)\n }\n } else {\n console.warn('[Newsletter Plugin] No email service configured for subscriber creation')\n }\n\n // Send welcome email if active and not imported from provider\n if (doc.subscriptionStatus === 'active' && emailService && !doc.importedFromProvider) {\n try {\n // Get settings for site name\n const settings = await req.payload.findGlobal({\n slug: pluginConfig.settingsSlug || 'newsletter-settings',\n })\n \n // Render welcome email\n const serverURL = req.payload.config.serverURL || process.env.PAYLOAD_PUBLIC_SERVER_URL || ''\n const html = await renderEmail('welcome', {\n email: doc.email,\n siteName: settings?.brandSettings?.siteName || 'Newsletter',\n preferencesUrl: `${serverURL}/account/preferences`, // This could be customized\n }, pluginConfig)\n \n // Send email\n await emailService.send({\n to: doc.email,\n subject: settings?.brandSettings?.siteName ? `Welcome to ${settings.brandSettings.siteName}!` : 'Welcome!',\n html,\n })\n \n console.warn(`Welcome email sent to: ${doc.email}`)\n } catch (error) {\n console.error('Failed to send welcome email:', error)\n // Don't fail the subscription if welcome email fails\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 // TODO: Add proper type for newsletter email service\n \n if (doc.subscriptionStatus !== previousDoc.subscriptionStatus) {\n console.log('[Newsletter Plugin] Subscription status changed:', {\n email: doc.email,\n from: previousDoc.subscriptionStatus,\n to: doc.subscriptionStatus,\n hasEmailService: !!emailService\n })\n \n if (emailService) {\n try {\n await emailService.updateContact(doc)\n console.log('[Newsletter Plugin] Successfully updated contact in email service')\n } catch (error) {\n console.error('[Newsletter Plugin] Failed to update contact in email service:', error)\n }\n } else {\n console.warn('[Newsletter Plugin] No email service configured')\n }\n }\n\n // Handle resubscribe - send welcome email for user-initiated resubscriptions\n if (\n doc.subscriptionStatus === 'active' &&\n previousDoc.subscriptionStatus === 'unsubscribed' &&\n !doc.importedFromProvider &&\n emailService\n ) {\n try {\n // Get settings for site name\n const settings = await req.payload.findGlobal({\n slug: pluginConfig.settingsSlug || 'newsletter-settings',\n })\n \n // Render welcome email\n const serverURL = req.payload.config.serverURL || process.env.PAYLOAD_PUBLIC_SERVER_URL || ''\n const html = await renderEmail('welcome', {\n email: doc.email,\n siteName: settings?.brandSettings?.siteName || 'Newsletter',\n preferencesUrl: `${serverURL}/account/preferences`,\n }, pluginConfig)\n \n // Send email\n await emailService.send({\n to: doc.email,\n subject: settings?.brandSettings?.siteName ? `Welcome back to ${settings.brandSettings.siteName}!` : 'Welcome back!',\n html,\n })\n \n console.warn(`Welcome email sent to resubscribed user: ${doc.email}`)\n } catch (error) {\n console.error('Failed to send resubscription welcome email:', error)\n // Don't fail the resubscription if welcome email fails\n }\n \n // Call custom after subscribe hook for resubscriptions\n if (pluginConfig.hooks?.afterSubscribe) {\n await pluginConfig.hooks.afterSubscribe({ doc, req })\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 // TODO: Add proper type for newsletter email service\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}"],"mappings":"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","names":["init_broadcast","DOMPurify","styles","BroadcastApiProvider","BroadcastApiProvider","BroadcastApiProvider","import_components","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/types/newsletter.ts","../src/types/broadcast.ts","../src/types/providers.ts","../src/types/index.ts","../src/providers/broadcast/broadcast.ts","../src/exports/collections.ts","../src/collections/Broadcasts.ts","../src/fields/emailContent.ts","../src/utils/blockValidation.ts","../src/fields/broadcastInlinePreview.ts","../src/fields/broadcastSchedule.ts","../src/utils/emailSafeHtml.ts","../src/utils/getBroadcastConfig.ts","../src/endpoints/broadcasts/send.ts","../src/utils/access.ts","../src/utils/auth.ts","../src/endpoints/broadcasts/schedule.ts","../src/endpoints/broadcasts/test.ts","../src/utils/mediaPopulation.ts","../src/endpoints/broadcasts/preview.ts","../src/emails/render.tsx","../src/emails/MagicLink.tsx","../src/emails/styles.ts","../src/emails/Welcome.tsx","../src/emails/SignIn.tsx","../src/collections/Subscribers.ts"],"sourcesContent":["/**\n * Core types for newsletter management functionality\n */\n\n/**\n * Represents a newsletter/broadcast in the system\n */\nexport interface Newsletter {\n id: string;\n name: string;\n subject: string;\n preheader?: string;\n content: string; // HTML content\n status: NewsletterStatus;\n trackOpens: boolean;\n trackClicks: boolean;\n replyTo?: string;\n recipientCount?: number;\n sentAt?: Date;\n scheduledAt?: Date;\n createdAt: Date;\n updatedAt: Date;\n // Provider-specific data stored here\n providerData?: Record<string, any>;\n // Provider information\n providerId?: string;\n providerType?: 'broadcast' | 'resend';\n}\n\n/**\n * Possible statuses for a newsletter\n */\nexport enum NewsletterStatus {\n DRAFT = 'draft',\n SCHEDULED = 'scheduled',\n SENDING = 'sending',\n SENT = 'sent',\n FAILED = 'failed',\n PAUSED = 'paused',\n CANCELED = 'canceled'\n}\n\n/**\n * Options for listing newsletters\n */\nexport interface ListNewsletterOptions {\n limit?: number;\n offset?: number;\n status?: NewsletterStatus;\n sortBy?: 'createdAt' | 'updatedAt' | 'sentAt' | 'name';\n sortOrder?: 'asc' | 'desc';\n}\n\n/**\n * Response from listing newsletters\n */\nexport interface ListNewsletterResponse<T = Newsletter> {\n items: T[];\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n}\n\n/**\n * Input for creating a new newsletter\n */\nexport interface CreateNewsletterInput {\n name: string;\n subject: string;\n preheader?: string;\n content: string;\n trackOpens?: boolean;\n trackClicks?: boolean;\n replyTo?: string;\n audienceIds?: string[]; // Maps to segments/audiences\n}\n\n/**\n * Input for updating an existing newsletter\n */\nexport interface UpdateNewsletterInput {\n name?: string;\n subject?: string;\n preheader?: string;\n content?: string;\n trackOpens?: boolean;\n trackClicks?: boolean;\n replyTo?: string;\n audienceIds?: string[];\n}\n\n/**\n * Options for sending a newsletter\n */\nexport interface SendNewsletterOptions {\n audienceIds?: string[]; // Target specific audiences\n testMode?: boolean; // Send test email\n testRecipients?: string[]; // Email addresses for test send\n}\n\n/**\n * Analytics data for a newsletter\n */\nexport interface NewsletterAnalytics {\n sent: number;\n delivered: number;\n opened: number;\n clicked: number;\n bounced: number;\n complained: number;\n unsubscribed: number;\n deliveryRate?: number;\n openRate?: number;\n clickRate?: number;\n bounceRate?: number;\n}\n\n/**\n * Capabilities that a newsletter provider supports\n */\nexport interface NewsletterProviderCapabilities {\n supportsScheduling: boolean;\n supportsSegmentation: boolean;\n supportsAnalytics: boolean;\n supportsABTesting: boolean;\n supportsTemplates: boolean;\n supportsPersonalization: boolean;\n maxRecipientsPerSend?: number;\n editableStatuses: NewsletterStatus[];\n supportedContentTypes: ('html' | 'text' | 'react')[];\n}\n\n/**\n * Error types specific to newsletter operations\n */\nexport class NewsletterProviderError extends Error {\n constructor(\n message: string,\n public code: NewsletterErrorCode,\n public provider: string,\n public details?: any\n ) {\n super(message);\n this.name = 'NewsletterProviderError';\n }\n}\n\nexport enum NewsletterErrorCode {\n NOT_SUPPORTED = 'NOT_SUPPORTED',\n INVALID_STATUS = 'INVALID_STATUS',\n PROVIDER_ERROR = 'PROVIDER_ERROR',\n VALIDATION_ERROR = 'VALIDATION_ERROR',\n NOT_FOUND = 'NOT_FOUND',\n PERMISSION_DENIED = 'PERMISSION_DENIED',\n RATE_LIMITED = 'RATE_LIMITED',\n CONFIGURATION_ERROR = 'CONFIGURATION_ERROR'\n}\n\n/**\n * Newsletter template for reusable content\n */\nexport interface NewsletterTemplate {\n id: string;\n name: string;\n description?: string;\n content: string;\n variables?: NewsletterTemplateVariable[];\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface NewsletterTemplateVariable {\n name: string;\n type: 'text' | 'html' | 'image' | 'url';\n defaultValue?: string;\n required?: boolean;\n}","/**\n * Core types for broadcast management functionality\n */\n\n/**\n * Represents a broadcast (individual email campaign) in the system\n */\nexport interface Broadcast {\n id: string;\n name: string;\n subject: string;\n preheader?: string;\n content: string; // HTML content\n sendStatus: BroadcastStatus;\n trackOpens: boolean;\n trackClicks: boolean;\n replyTo?: string;\n recipientCount?: number;\n sentAt?: Date;\n scheduledAt?: Date;\n createdAt: Date;\n updatedAt: Date;\n // Provider-specific data stored here\n providerData?: Record<string, any>;\n // Provider information\n providerId?: string;\n providerType?: 'broadcast' | 'resend';\n}\n\n/**\n * Possible statuses for a broadcast\n */\nexport enum BroadcastStatus {\n DRAFT = 'draft',\n SCHEDULED = 'scheduled',\n SENDING = 'sending',\n SENT = 'sent',\n FAILED = 'failed',\n PAUSED = 'paused',\n CANCELED = 'canceled'\n}\n\n/**\n * Options for listing broadcasts\n */\nexport interface ListBroadcastOptions {\n limit?: number;\n offset?: number;\n status?: BroadcastStatus;\n sortBy?: 'createdAt' | 'updatedAt' | 'sentAt' | 'name';\n sortOrder?: 'asc' | 'desc';\n}\n\n/**\n * Response from listing broadcasts\n */\nexport interface ListBroadcastResponse<T = Broadcast> {\n items: T[];\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n}\n\n/**\n * Input for creating a new broadcast\n */\nexport interface CreateBroadcastInput {\n name: string;\n subject: string;\n preheader?: string;\n content: string;\n trackOpens?: boolean;\n trackClicks?: boolean;\n replyTo?: string;\n audienceIds?: string[]; // Maps to segments/audiences\n}\n\n/**\n * Input for updating an existing broadcast\n */\nexport interface UpdateBroadcastInput {\n name?: string;\n subject?: string;\n preheader?: string;\n content?: string;\n trackOpens?: boolean;\n trackClicks?: boolean;\n replyTo?: string;\n audienceIds?: string[];\n}\n\n/**\n * Options for sending a broadcast\n */\nexport interface SendBroadcastOptions {\n audienceIds?: string[]; // Target specific audiences\n testMode?: boolean; // Send test email\n testRecipients?: string[]; // Email addresses for test send\n}\n\n/**\n * Analytics data for a broadcast\n */\nexport interface BroadcastAnalytics {\n sent: number;\n delivered: number;\n opened: number;\n clicked: number;\n bounced: number;\n complained: number;\n unsubscribed: number;\n deliveryRate?: number;\n openRate?: number;\n clickRate?: number;\n bounceRate?: number;\n}\n\n/**\n * Capabilities that a broadcast provider supports\n */\nexport interface BroadcastProviderCapabilities {\n supportsScheduling: boolean;\n supportsSegmentation: boolean;\n supportsAnalytics: boolean;\n supportsABTesting: boolean;\n supportsTemplates: boolean;\n supportsPersonalization: boolean;\n maxRecipientsPerSend?: number;\n editableStatuses: BroadcastStatus[];\n supportedContentTypes: ('html' | 'text' | 'react')[];\n supportsMultipleChannels: boolean;\n supportsChannelSegmentation: boolean;\n}\n\n/**\n * Error types specific to broadcast operations\n */\nexport class BroadcastProviderError extends Error {\n constructor(\n message: string,\n public code: BroadcastErrorCode,\n public provider: string,\n public details?: any\n ) {\n super(message);\n this.name = 'BroadcastProviderError';\n }\n}\n\nexport enum BroadcastErrorCode {\n NOT_SUPPORTED = 'NOT_SUPPORTED',\n INVALID_STATUS = 'INVALID_STATUS',\n PROVIDER_ERROR = 'PROVIDER_ERROR',\n VALIDATION_ERROR = 'VALIDATION_ERROR',\n NOT_FOUND = 'NOT_FOUND',\n PERMISSION_DENIED = 'PERMISSION_DENIED',\n RATE_LIMITED = 'RATE_LIMITED',\n CONFIGURATION_ERROR = 'CONFIGURATION_ERROR'\n}\n\n/**\n * Broadcast template for reusable content\n */\nexport interface BroadcastTemplate {\n id: string;\n name: string;\n description?: string;\n content: string;\n variables?: BroadcastTemplateVariable[];\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface BroadcastTemplateVariable {\n name: string;\n type: 'text' | 'html' | 'image' | 'url';\n defaultValue?: string;\n required?: boolean;\n}\n\n// Re-export newsletter types with deprecation notice for backwards compatibility\nexport {\n NewsletterStatus,\n type ListNewsletterOptions,\n type ListNewsletterResponse,\n type CreateNewsletterInput,\n type UpdateNewsletterInput,\n type SendNewsletterOptions,\n type NewsletterAnalytics,\n type NewsletterProviderCapabilities,\n NewsletterProviderError,\n NewsletterErrorCode,\n type NewsletterTemplate,\n type NewsletterTemplateVariable\n} from './newsletter';","/**\n * Provider interfaces for broadcast management\n */\n\n// Import broadcast types\nimport type {\n Broadcast,\n BroadcastStatus,\n ListBroadcastOptions,\n ListBroadcastResponse,\n CreateBroadcastInput,\n UpdateBroadcastInput,\n SendBroadcastOptions,\n BroadcastAnalytics,\n BroadcastProviderCapabilities\n} from './broadcast'\n\nimport {\n BroadcastProviderError,\n BroadcastErrorCode\n} from './broadcast'\n\n\n// Import legacy newsletter types for backwards compatibility\nimport type {\n Newsletter,\n NewsletterStatus,\n ListNewsletterOptions,\n ListNewsletterResponse,\n CreateNewsletterInput,\n UpdateNewsletterInput,\n SendNewsletterOptions,\n NewsletterAnalytics,\n NewsletterProviderCapabilities\n} from './newsletter'\n\nimport {\n NewsletterProviderError,\n NewsletterErrorCode\n} from './newsletter'\n\n/**\n * Main interface for broadcast providers\n */\nexport interface BroadcastProvider {\n /**\n * Get the provider name\n */\n readonly name: string;\n\n // Broadcast management methods\n /**\n * List broadcasts with pagination\n */\n list(options?: ListBroadcastOptions): Promise<ListBroadcastResponse<Broadcast>>;\n \n /**\n * Get a specific broadcast by ID\n */\n get(id: string): Promise<Broadcast>;\n \n /**\n * Create a new broadcast\n */\n create(data: CreateBroadcastInput): Promise<Broadcast>;\n \n /**\n * Update an existing broadcast\n */\n update(id: string, data: UpdateBroadcastInput): Promise<Broadcast>;\n \n /**\n * Delete a broadcast\n */\n delete(id: string): Promise<void>;\n \n /**\n * Send a broadcast immediately or to test recipients\n */\n send(id: string, options?: SendBroadcastOptions): Promise<Broadcast>;\n \n /**\n * Schedule a broadcast for future sending\n */\n schedule(id: string, scheduledAt: Date): Promise<Broadcast>;\n \n /**\n * Cancel a scheduled broadcast\n */\n cancelSchedule(id: string): Promise<Broadcast>;\n \n /**\n * Get analytics for a broadcast\n */\n getAnalytics(id: string): Promise<BroadcastAnalytics>;\n \n /**\n * Get provider capabilities\n */\n getCapabilities(): BroadcastProviderCapabilities;\n \n /**\n * Validate that the provider is properly configured\n */\n validateConfiguration(): Promise<boolean>;\n}\n\n/**\n * Legacy newsletter provider interface for backwards compatibility\n * @deprecated Use BroadcastProvider instead\n */\nexport interface NewsletterProvider {\n /**\n * Get the provider name\n */\n readonly name: string;\n\n /**\n * List newsletters with pagination\n */\n list(options?: ListNewsletterOptions): Promise<ListNewsletterResponse<Newsletter>>;\n \n /**\n * Get a specific newsletter by ID\n */\n get(id: string): Promise<Newsletter>;\n \n /**\n * Create a new newsletter\n */\n create(data: CreateNewsletterInput): Promise<Newsletter>;\n \n /**\n * Update an existing newsletter\n */\n update(id: string, data: UpdateNewsletterInput): Promise<Newsletter>;\n \n /**\n * Delete a newsletter\n */\n delete(id: string): Promise<void>;\n \n /**\n * Send a newsletter immediately or to test recipients\n */\n send(id: string, options?: SendNewsletterOptions): Promise<Newsletter>;\n \n /**\n * Schedule a newsletter for future sending\n */\n schedule(id: string, scheduledAt: Date): Promise<Newsletter>;\n \n /**\n * Cancel a scheduled newsletter\n */\n cancelSchedule(id: string): Promise<Newsletter>;\n \n /**\n * Get analytics for a newsletter\n */\n getAnalytics(id: string): Promise<NewsletterAnalytics>;\n \n /**\n * Get provider capabilities\n */\n getCapabilities(): NewsletterProviderCapabilities;\n \n /**\n * Validate that the provider is properly configured\n */\n validateConfiguration(): Promise<boolean>;\n}\n\n/**\n * Base abstract class for broadcast providers\n */\nexport abstract class BaseBroadcastProvider implements BroadcastProvider {\n abstract readonly name: string;\n \n constructor(protected config: any) {}\n \n // Broadcast management - abstract methods\n abstract list(options?: ListBroadcastOptions): Promise<ListBroadcastResponse<Broadcast>>;\n abstract get(id: string): Promise<Broadcast>;\n abstract create(data: CreateBroadcastInput): Promise<Broadcast>;\n abstract update(id: string, data: UpdateBroadcastInput): Promise<Broadcast>;\n abstract delete(id: string): Promise<void>;\n abstract send(id: string, options?: SendBroadcastOptions): Promise<Broadcast>;\n abstract getCapabilities(): BroadcastProviderCapabilities;\n abstract validateConfiguration(): Promise<boolean>;\n \n /**\n * Schedule a broadcast - default implementation throws not supported\n */\n async schedule(_id: string, _scheduledAt: Date): Promise<Broadcast> {\n const capabilities = this.getCapabilities();\n if (!capabilities.supportsScheduling) {\n throw new BroadcastProviderError(\n 'Scheduling is not supported by this provider',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n );\n }\n throw new Error('Method not implemented');\n }\n \n /**\n * Cancel scheduled broadcast - default implementation throws not supported\n */\n async cancelSchedule(_id: string): Promise<Broadcast> {\n const capabilities = this.getCapabilities();\n if (!capabilities.supportsScheduling) {\n throw new BroadcastProviderError(\n 'Scheduling is not supported by this provider',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n );\n }\n throw new Error('Method not implemented');\n }\n \n /**\n * Get analytics - default implementation returns zeros\n */\n async getAnalytics(_id: string): Promise<BroadcastAnalytics> {\n const capabilities = this.getCapabilities();\n if (!capabilities.supportsAnalytics) {\n throw new BroadcastProviderError(\n 'Analytics are not supported by this provider',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n );\n }\n \n return {\n sent: 0,\n delivered: 0,\n opened: 0,\n clicked: 0,\n bounced: 0,\n complained: 0,\n unsubscribed: 0\n };\n }\n \n /**\n * Helper method to validate required fields\n */\n protected validateRequiredFields(data: any, fields: string[]): void {\n const missing = fields.filter(field => !data[field]);\n if (missing.length > 0) {\n throw new BroadcastProviderError(\n `Missing required fields: ${missing.join(', ')}`,\n BroadcastErrorCode.VALIDATION_ERROR,\n this.name\n );\n }\n }\n \n /**\n * Helper method to check if a status transition is allowed\n */\n protected canEditInStatus(status: BroadcastStatus): boolean {\n const capabilities = this.getCapabilities();\n return capabilities.editableStatuses.includes(status);\n }\n \n /**\n * Helper to build pagination response\n */\n protected buildListResponse<T>(\n items: T[],\n total: number,\n options: ListBroadcastOptions = {}\n ): ListBroadcastResponse<T> {\n const limit = options.limit || 20;\n const offset = options.offset || 0;\n \n return {\n items,\n total,\n limit,\n offset,\n hasMore: offset + items.length < total\n };\n }\n}\n\n/**\n * Base abstract class for newsletter providers\n * @deprecated Use BaseBroadcastProvider instead\n */\nexport abstract class BaseNewsletterProvider implements NewsletterProvider {\n abstract readonly name: string;\n \n constructor(protected config: any) {}\n \n abstract list(options?: ListNewsletterOptions): Promise<ListNewsletterResponse<Newsletter>>;\n abstract get(id: string): Promise<Newsletter>;\n abstract create(data: CreateNewsletterInput): Promise<Newsletter>;\n abstract update(id: string, data: UpdateNewsletterInput): Promise<Newsletter>;\n abstract delete(id: string): Promise<void>;\n abstract send(id: string, options?: SendNewsletterOptions): Promise<Newsletter>;\n abstract getCapabilities(): NewsletterProviderCapabilities;\n abstract validateConfiguration(): Promise<boolean>;\n \n /**\n * Schedule a newsletter - default implementation throws not supported\n */\n async schedule(_id: string, _scheduledAt: Date): Promise<Newsletter> {\n const capabilities = this.getCapabilities();\n if (!capabilities.supportsScheduling) {\n throw new NewsletterProviderError(\n 'Scheduling is not supported by this provider',\n NewsletterErrorCode.NOT_SUPPORTED,\n this.name\n );\n }\n throw new Error('Method not implemented');\n }\n \n /**\n * Cancel scheduled newsletter - default implementation throws not supported\n */\n async cancelSchedule(_id: string): Promise<Newsletter> {\n const capabilities = this.getCapabilities();\n if (!capabilities.supportsScheduling) {\n throw new NewsletterProviderError(\n 'Scheduling is not supported by this provider',\n NewsletterErrorCode.NOT_SUPPORTED,\n this.name\n );\n }\n throw new Error('Method not implemented');\n }\n \n /**\n * Get analytics - default implementation returns zeros\n */\n async getAnalytics(_id: string): Promise<NewsletterAnalytics> {\n const capabilities = this.getCapabilities();\n if (!capabilities.supportsAnalytics) {\n throw new NewsletterProviderError(\n 'Analytics are not supported by this provider',\n NewsletterErrorCode.NOT_SUPPORTED,\n this.name\n );\n }\n \n return {\n sent: 0,\n delivered: 0,\n opened: 0,\n clicked: 0,\n bounced: 0,\n complained: 0,\n unsubscribed: 0\n };\n }\n \n /**\n * Helper method to validate required fields\n */\n protected validateRequiredFields(data: any, fields: string[]): void {\n const missing = fields.filter(field => !data[field]);\n if (missing.length > 0) {\n throw new NewsletterProviderError(\n `Missing required fields: ${missing.join(', ')}`,\n NewsletterErrorCode.VALIDATION_ERROR,\n this.name\n );\n }\n }\n \n /**\n * Helper method to check if a status transition is allowed\n */\n protected canEditInStatus(status: NewsletterStatus): boolean {\n const capabilities = this.getCapabilities();\n return capabilities.editableStatuses.includes(status);\n }\n \n /**\n * Helper to build pagination response\n */\n protected buildListResponse<T>(\n items: T[],\n total: number,\n options: ListNewsletterOptions = {}\n ): ListNewsletterResponse<T> {\n const limit = options.limit || 20;\n const offset = options.offset || 0;\n \n return {\n items,\n total,\n limit,\n offset,\n hasMore: offset + items.length < total\n };\n }\n}","import type { Field, Block, RichTextField } from 'payload'\nimport type { BroadcastProvider } from './providers'\n\n// Export broadcast types\nexport * from './broadcast'\nexport * from './providers'\n// Export legacy newsletter types for backwards compatibility\nexport * from './newsletter'\n\n// Email wrapper options interface\nexport interface EmailWrapperOptions {\n preheader?: string\n subject?: string\n documentData?: Record<string, any> // Generic document data\n}\n\n// Re-export for convenience\nexport type CustomEmailWrapper = (\n content: string, \n options?: EmailWrapperOptions\n) => string | Promise<string>\n\n// Add new interface for broadcast customizations\nexport interface BroadcastCustomizations {\n additionalFields?: Field[]\n customBlocks?: Block[]\n fieldOverrides?: {\n content?: (defaultField: RichTextField) => RichTextField\n }\n /**\n * Custom block email converter\n * @param node - The block node from Lexical editor state\n * @param mediaUrl - Base URL for media files\n * @returns Promise<string> - The email-safe HTML for the block\n */\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n \n /**\n * Fields to populate in custom blocks before email conversion\n * Can be an array of field names or a function that returns field names based on block type\n * This is useful for upload fields that need to be populated with full media objects\n * \n * @example\n * // Array of field names to always populate\n * populateFields: ['bannerImage', 'sponsorLogo']\n * \n * @example\n * // Function to return fields based on block type\n * populateFields: (blockType) => {\n * if (blockType === 'newsletter-hero') return ['bannerImage', 'sponsorLogo']\n * if (blockType === 'content-section') return ['featuredImage']\n * return []\n * }\n */\n populateFields?: string[] | ((blockType: string) => string[])\n \n /**\n * Email preview customization options\n */\n emailPreview?: {\n /**\n * Whether to wrap preview content in default email template\n * @default true\n */\n wrapInTemplate?: boolean\n \n /**\n * Custom wrapper function for preview content\n * Receives the converted HTML and should return wrapped HTML\n */\n customWrapper?: (content: string, options?: EmailWrapperOptions) => string | Promise<string>\n \n /**\n * Custom preview component to replace the default one entirely\n * If provided, this component will be used instead of the default EmailPreview\n */\n customPreviewComponent?: string // Path to custom component for import map\n }\n}\n\nexport interface NewsletterPluginConfig {\n /**\n * Enable or disable the plugin\n * @default true\n */\n enabled?: boolean\n\n /**\n * Slug for the subscribers collection\n * @default 'subscribers'\n */\n subscribersSlug?: string\n \n /**\n * Slug for the newsletter settings global\n * @default 'newsletter-settings'\n */\n settingsSlug?: string\n\n /**\n * Authentication configuration for magic links\n */\n auth?: {\n /**\n * Enable magic link authentication\n * @default true\n */\n enabled?: boolean\n \n /**\n * Token expiration time\n * @default '7d'\n */\n tokenExpiration?: string\n \n /**\n * Path where magic link redirects\n * @default '/newsletter/verify'\n */\n magicLinkPath?: string\n \n /**\n * Allow unsubscribed users to sign in\n * @default false\n */\n allowUnsubscribedSignin?: boolean\n \n /**\n * Allow unsubscribed users to resubscribe\n * @default false\n */\n allowResubscribe?: boolean\n }\n\n /**\n * Access control configuration\n */\n access?: {\n /**\n * Custom function to determine if a user is an admin\n * @param user - The authenticated user object\n * @returns true if the user should have admin access\n */\n isAdmin?: (user: any) => boolean\n }\n\n /**\n * Email provider configuration\n */\n providers: {\n /**\n * Default provider to use\n */\n default: 'resend' | 'broadcast' | string\n \n /**\n * Resend provider configuration\n */\n resend?: ResendProviderConfig\n \n /**\n * Broadcast provider configuration\n */\n broadcast?: BroadcastProviderConfig\n }\n\n /**\n * Field customization options\n */\n fields?: {\n /**\n * Override default fields\n */\n overrides?: (args: { defaultFields: Field[] }) => Field[]\n \n /**\n * Additional custom fields\n */\n additional?: Field[]\n }\n\n /**\n * Email template components\n */\n templates?: {\n /**\n * Welcome email template\n */\n welcome?: React.ComponentType<WelcomeEmailProps>\n \n /**\n * Magic link email template\n */\n magicLink?: React.ComponentType<MagicLinkEmailProps>\n }\n\n /**\n * Plugin hooks\n */\n hooks?: {\n beforeSubscribe?: (args: BeforeSubscribeArgs) => void | Promise<void>\n afterSubscribe?: (args: AfterSubscribeArgs) => void | Promise<void>\n beforeUnsubscribe?: (args: BeforeUnsubscribeArgs) => void | Promise<void>\n afterUnsubscribe?: (args: AfterUnsubscribeArgs) => void | Promise<void>\n }\n\n /**\n * UI component overrides\n */\n components?: {\n signupForm?: React.ComponentType<SignupFormProps>\n preferencesForm?: React.ComponentType<PreferencesFormProps>\n }\n\n /**\n * Feature flags\n */\n features?: {\n /**\n * Lead magnet configuration\n */\n leadMagnets?: {\n enabled?: boolean\n collection?: string\n }\n \n /**\n * Post-signup survey configuration\n */\n surveys?: {\n enabled?: boolean\n questions?: SurveyQuestion[]\n }\n \n /**\n * UTM tracking configuration\n */\n utmTracking?: {\n enabled?: boolean\n fields?: string[]\n }\n \n /**\n * Newsletter scheduling configuration\n */\n newsletterScheduling?: {\n enabled?: boolean\n /**\n * Collections to add newsletter fields to\n * Can be a string for single collection or array for multiple\n * @example 'articles' or ['articles', 'posts', 'updates']\n */\n collections?: string | string[]\n /**\n * Field configuration\n */\n fields?: {\n /**\n * Group name for newsletter fields\n * @default 'newsletterScheduling'\n */\n groupName?: string\n /**\n * Rich text field name to use for content\n * @default 'content'\n */\n contentField?: string\n /**\n * Whether to create a markdown companion field\n * @default true\n */\n createMarkdownField?: boolean\n }\n }\n \n \n /**\n * Newsletter management configuration\n */\n newsletterManagement?: {\n /**\n * Enable newsletter management features\n * @default false\n */\n enabled?: boolean\n /**\n * Collection names for broadcast management\n */\n collections?: {\n /**\n * Broadcasts collection slug\n * @default 'broadcasts'\n */\n broadcasts?: string\n }\n /**\n * Optional: Custom broadcast provider implementation\n * If not provided, will use the default email provider\n */\n provider?: BroadcastProvider\n }\n }\n\n /**\n * Internationalization configuration\n */\n i18n?: {\n defaultLocale?: string\n locales?: string[]\n }\n\n /**\n * Custom email templates\n */\n customTemplates?: {\n [key: string]: React.ComponentType<any>\n }\n\n /**\n * Customization options for plugin collections\n */\n customizations?: {\n broadcasts?: BroadcastCustomizations\n }\n}\n\nexport interface ResendProviderConfig {\n apiKey: string\n fromEmail?: string\n fromAddress?: string // Alias for fromEmail\n fromName?: string\n replyTo?: string\n audienceIds?: {\n [locale: string]: {\n production?: string\n development?: string\n }\n }\n}\n\nexport interface BroadcastProviderConfig {\n apiUrl: string\n token: string\n fromEmail?: string\n fromAddress?: string // Alias for fromEmail\n fromName?: string\n replyTo?: string\n}\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}\n\nexport interface SendEmailParams {\n to: string | string[]\n subject: string\n html?: string\n text?: string\n react?: React.ReactElement\n}\n\nexport interface Subscriber {\n id: string\n email: string\n name?: string\n locale?: string\n subscriptionStatus: 'active' | 'unsubscribed' | 'pending'\n emailPreferences?: {\n newsletter?: boolean\n announcements?: boolean\n [key: string]: boolean | undefined\n }\n source?: string\n importedFromProvider?: boolean\n utmParameters?: {\n source?: string\n medium?: string\n campaign?: string\n content?: string\n term?: string\n }\n // Additional fields that may exist in the database\n signupMetadata?: {\n ipAddress?: string\n userAgent?: string\n referrer?: string\n signupPage?: string\n }\n leadMagnet?: string\n unsubscribedAt?: string\n magicLinkToken?: string\n magicLinkTokenExpiry?: string\n createdAt: string\n updatedAt: string\n}\n\nexport interface WelcomeEmailProps {\n subscriber: Subscriber\n unsubscribeUrl: string\n preferencesUrl: string\n}\n\nexport interface MagicLinkEmailProps {\n magicLinkUrl: string\n subscriber: Subscriber\n}\n\nexport interface SignupFormProps {\n onSuccess?: (subscriber: Subscriber) => void\n onError?: (error: Error) => void\n showName?: boolean\n showPreferences?: boolean\n leadMagnet?: {\n id: string\n title: string\n description?: string\n }\n className?: string\n styles?: {\n form?: React.CSSProperties\n inputGroup?: React.CSSProperties\n label?: React.CSSProperties\n input?: React.CSSProperties\n button?: React.CSSProperties\n buttonDisabled?: React.CSSProperties\n error?: React.CSSProperties\n success?: React.CSSProperties\n checkbox?: React.CSSProperties\n checkboxInput?: React.CSSProperties\n checkboxLabel?: React.CSSProperties\n }\n apiEndpoint?: string\n buttonText?: string\n loadingText?: string\n successMessage?: string\n placeholders?: {\n email?: string\n name?: string\n }\n labels?: {\n email?: string\n name?: string\n newsletter?: string\n announcements?: string\n }\n}\n\nexport interface PreferencesFormProps {\n subscriber?: Subscriber\n onSuccess?: (subscriber: Subscriber) => void\n onError?: (error: Error) => void\n className?: string\n styles?: {\n container?: React.CSSProperties\n heading?: React.CSSProperties\n form?: React.CSSProperties\n section?: React.CSSProperties\n sectionTitle?: React.CSSProperties\n inputGroup?: React.CSSProperties\n label?: React.CSSProperties\n input?: React.CSSProperties\n select?: React.CSSProperties\n checkbox?: React.CSSProperties\n checkboxInput?: React.CSSProperties\n checkboxLabel?: React.CSSProperties\n buttonGroup?: React.CSSProperties\n button?: React.CSSProperties\n primaryButton?: React.CSSProperties\n secondaryButton?: React.CSSProperties\n dangerButton?: React.CSSProperties\n error?: React.CSSProperties\n success?: React.CSSProperties\n info?: React.CSSProperties\n }\n sessionToken?: string\n apiEndpoint?: string\n showUnsubscribe?: boolean\n locales?: string[]\n labels?: {\n title?: string\n personalInfo?: string\n emailPreferences?: string\n name?: string\n language?: string\n newsletter?: string\n announcements?: string\n saveButton?: string\n unsubscribeButton?: string\n saving?: string\n saved?: string\n unsubscribeConfirm?: string\n }\n}\n\nexport interface BeforeSubscribeArgs {\n data: Partial<Subscriber>\n req: any\n}\n\nexport interface AfterSubscribeArgs {\n doc: Subscriber\n req: any\n}\n\nexport interface BeforeUnsubscribeArgs {\n email: string\n req: any\n}\n\nexport interface AfterUnsubscribeArgs {\n doc: Subscriber\n req: any\n}\n\n\nexport interface SurveyQuestion {\n id: string\n question: string\n type: 'text' | 'select' | 'multiselect' | 'radio'\n options?: string[]\n required?: boolean\n}\n\n// Request data interfaces for endpoints\nexport interface SubscribeRequestData {\n email: string\n name?: string\n source?: string\n preferences?: { [key: string]: boolean }\n leadMagnet?: string\n surveyResponses?: { [key: string]: string | string[] }\n metadata?: {\n locale?: string\n signupPage?: string\n [key: string]: unknown\n }\n}\n\nexport interface UnsubscribeRequestData {\n email?: string\n token?: string\n}\n\nexport interface VerifyMagicLinkRequestData {\n token: string\n}\n\nexport interface SigninRequestData {\n email: string\n}\n\nexport interface UpdatePreferencesRequestData {\n name?: string\n locale?: string\n emailPreferences?: { [key: string]: boolean }\n}\n\n// Extended request types with proper data typing\nexport interface ExtendedPayloadRequest extends Request {\n payload: any // TODO: Add proper payload type\n data?: unknown\n ip?: string\n connection?: {\n remoteAddress?: string\n }\n cookies?: {\n [key: string]: string\n }\n // Headers are inherited from Request, but we document common ones for reference\n // Access via: req.headers.get('authorization'), req.headers.get('referer'), etc.\n}","import type { \n Broadcast,\n ListBroadcastOptions,\n ListBroadcastResponse,\n CreateBroadcastInput,\n UpdateBroadcastInput,\n SendBroadcastOptions,\n BroadcastAnalytics,\n BroadcastProviderCapabilities\n} from '../../types'\nimport { \n BroadcastProviderError, \n BroadcastErrorCode,\n BroadcastStatus,\n BaseBroadcastProvider\n} from '../../types'\nimport type { BroadcastProviderConfig } from '../../types'\n\ninterface BroadcastApiResponse {\n id: number\n name: string\n subject: string\n preheader?: string\n body: string\n status: string\n track_opens: boolean\n track_clicks: boolean\n html_body: boolean\n reply_to?: string\n total_recipients: number\n sent_at?: string\n scheduled_send_at?: string\n created_at: string\n updated_at: string\n}\n\ninterface BroadcastListResponse {\n data: BroadcastApiResponse[]\n total: number\n}\n\n\nexport class BroadcastApiProvider extends BaseBroadcastProvider {\n readonly name = 'broadcast'\n private apiUrl: string\n private token: string\n\n constructor(config: BroadcastProviderConfig) {\n super(config)\n this.apiUrl = config.apiUrl.replace(/\\/$/, '') // Remove trailing slash\n this.token = config.token\n \n if (!this.token) {\n throw new BroadcastProviderError(\n 'Broadcast API token is required',\n BroadcastErrorCode.CONFIGURATION_ERROR,\n this.name\n )\n }\n }\n\n // Broadcast Management Methods\n async list(options?: ListBroadcastOptions): Promise<ListBroadcastResponse<Broadcast>> {\n try {\n const params = new URLSearchParams()\n if (options?.limit) params.append('limit', options.limit.toString())\n if (options?.offset) params.append('offset', options.offset.toString())\n\n const response = await fetch(`${this.apiUrl}/api/v1/broadcasts?${params}`, {\n method: 'GET',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\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\n const data: BroadcastListResponse = await response.json()\n \n const broadcasts = data.data.map(broadcast => this.transformBroadcastFromApi(broadcast))\n \n return this.buildListResponse(broadcasts, data.total, options)\n } catch (error: unknown) {\n throw new BroadcastProviderError(\n `Failed to list broadcasts: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async get(id: string): Promise<Broadcast> {\n try {\n console.log('[BroadcastApiProvider] Getting broadcast with ID:', id)\n \n const response = await fetch(`${this.apiUrl}/api/v1/broadcasts/${id}`, {\n method: 'GET',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new BroadcastProviderError(\n `Broadcast not found: ${id}`,\n BroadcastErrorCode.NOT_FOUND,\n this.name\n )\n }\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n\n const broadcast: BroadcastApiResponse = await response.json()\n console.log('[BroadcastApiProvider] GET response:', broadcast)\n return this.transformBroadcastFromApi(broadcast)\n } catch (error: unknown) {\n if (error instanceof BroadcastProviderError) throw error\n \n throw new BroadcastProviderError(\n `Failed to get broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async create(data: CreateBroadcastInput): Promise<Broadcast> {\n try {\n this.validateRequiredFields(data, ['name', 'subject', 'content'])\n\n const requestBody = {\n broadcast: {\n name: data.name,\n subject: data.subject,\n preheader: data.preheader,\n body: data.content,\n html_body: true,\n track_opens: data.trackOpens ?? true,\n track_clicks: data.trackClicks ?? true,\n reply_to: data.replyTo,\n segment_ids: data.audienceIds,\n }\n }\n\n // Log the request details (without exposing the token)\n console.log('[BroadcastApiProvider] Creating broadcast:', {\n url: `${this.apiUrl}/api/v1/broadcasts`,\n method: 'POST',\n hasToken: !!this.token,\n tokenLength: this.token?.length,\n body: JSON.stringify(requestBody, null, 2),\n })\n\n const response = await fetch(`${this.apiUrl}/api/v1/broadcasts`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n })\n\n console.log('[BroadcastApiProvider] Response status:', response.status)\n console.log('[BroadcastApiProvider] Response headers:', Object.fromEntries(response.headers.entries()))\n\n if (!response.ok) {\n const errorText = await response.text()\n console.error('[BroadcastApiProvider] Error response body:', errorText)\n \n // Try to parse as JSON if possible\n let errorDetails\n try {\n errorDetails = JSON.parse(errorText)\n console.error('[BroadcastApiProvider] Parsed error:', errorDetails)\n } catch {\n // Not JSON, use as is\n }\n \n throw new Error(`Broadcast API error: ${response.status} - ${errorText}`)\n }\n\n const responseText = await response.text()\n console.log('[BroadcastApiProvider] Success response body:', responseText)\n \n let result\n try {\n result = JSON.parse(responseText)\n } catch {\n throw new Error(`Failed to parse response as JSON: ${responseText}`)\n }\n \n console.log('[BroadcastApiProvider] Parsed result:', result)\n \n if (!result.id) {\n throw new Error(`Response missing expected 'id' field: ${JSON.stringify(result)}`)\n }\n \n // Broadcast API returns just {id: 123}, so we need to fetch the full object\n return this.get(result.id.toString())\n } catch (error: unknown) {\n if (error instanceof BroadcastProviderError) throw error\n \n throw new BroadcastProviderError(\n `Failed to create broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async update(id: string, data: UpdateBroadcastInput): Promise<Broadcast> {\n try {\n // First check if the broadcast can be edited\n const existing = await this.get(id)\n if (!this.canEditInStatus(existing.sendStatus)) {\n throw new BroadcastProviderError(\n `Cannot update broadcast in status: ${existing.sendStatus}`,\n BroadcastErrorCode.INVALID_STATUS,\n this.name\n )\n }\n\n const response = await fetch(`${this.apiUrl}/api/v1/broadcasts/${id}`, {\n method: 'PATCH',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n broadcast: {\n name: data.name,\n subject: data.subject,\n preheader: data.preheader,\n body: data.content,\n track_opens: data.trackOpens,\n track_clicks: data.trackClicks,\n reply_to: data.replyTo,\n segment_ids: data.audienceIds,\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\n const broadcast: BroadcastApiResponse = await response.json()\n return this.transformBroadcastFromApi(broadcast)\n } catch (error: unknown) {\n if (error instanceof BroadcastProviderError) throw error\n \n throw new BroadcastProviderError(\n `Failed to update broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async delete(id: string): Promise<void> {\n try {\n // First check if the broadcast can be deleted\n const existing = await this.get(id)\n if (!this.canEditInStatus(existing.sendStatus)) {\n throw new BroadcastProviderError(\n `Cannot delete broadcast in status: ${existing.sendStatus}`,\n BroadcastErrorCode.INVALID_STATUS,\n this.name\n )\n }\n\n const response = await fetch(`${this.apiUrl}/api/v1/broadcasts/${id}`, {\n method: 'DELETE',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\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 if (error instanceof BroadcastProviderError) throw error\n \n throw new BroadcastProviderError(\n `Failed to delete broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async send(id: string, options?: SendBroadcastOptions): Promise<Broadcast> {\n try {\n // Check if we're in test mode\n if (options?.testMode && options.testRecipients?.length) {\n // TODO: Broadcast doesn't have a documented test send API\n // For now, we'll throw an error\n throw new BroadcastProviderError(\n 'Test send is not yet implemented for Broadcast provider',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\n }\n\n const response = await fetch(`${this.apiUrl}/api/v1/broadcasts/${id}/send_broadcast`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n segment_ids: options?.audienceIds\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\n // Response includes updated status\n const result = await response.json()\n return this.get(result.id.toString())\n } catch (error: unknown) {\n if (error instanceof BroadcastProviderError) throw error\n \n throw new BroadcastProviderError(\n `Failed to send broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async schedule(id: string, scheduledAt: Date): Promise<Broadcast> {\n try {\n // Update the newsletter with scheduled time\n const response = await fetch(`${this.apiUrl}/api/v1/broadcasts/${id}`, {\n method: 'PATCH',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n broadcast: {\n scheduled_send_at: scheduledAt.toISOString(),\n // TODO: Handle timezone properly\n scheduled_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone\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\n const broadcast: BroadcastApiResponse = await response.json()\n return this.transformBroadcastFromApi(broadcast)\n } catch (error: unknown) {\n throw new BroadcastProviderError(\n `Failed to schedule broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async cancelSchedule(id: string): Promise<Broadcast> {\n try {\n // Clear the scheduled time\n const response = await fetch(`${this.apiUrl}/api/v1/broadcasts/${id}`, {\n method: 'PATCH',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n broadcast: {\n scheduled_send_at: null,\n scheduled_timezone: null\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\n const broadcast: BroadcastApiResponse = await response.json()\n return this.transformBroadcastFromApi(broadcast)\n } catch (error: unknown) {\n throw new BroadcastProviderError(\n `Failed to cancel scheduled broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async getAnalytics(_id: string): Promise<BroadcastAnalytics> {\n // TODO: Broadcast analytics API is not documented in the CRUD API\n // This would need additional API documentation\n throw new BroadcastProviderError(\n 'Analytics API not yet implemented for Broadcast provider',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\n }\n\n getCapabilities(): BroadcastProviderCapabilities {\n return {\n supportsScheduling: true,\n supportsSegmentation: true,\n supportsAnalytics: false, // Not documented yet\n supportsABTesting: false,\n supportsTemplates: false,\n supportsPersonalization: true,\n supportsMultipleChannels: false,\n supportsChannelSegmentation: false,\n editableStatuses: [BroadcastStatus.DRAFT, BroadcastStatus.SCHEDULED],\n supportedContentTypes: ['html', 'text']\n }\n }\n\n async validateConfiguration(): Promise<boolean> {\n try {\n // Try to list broadcasts with limit 1 to validate API access\n await this.list({ limit: 1 })\n return true\n } catch {\n return false\n }\n }\n\n private transformBroadcastFromApi(broadcast: BroadcastApiResponse): Broadcast {\n return {\n id: broadcast.id.toString(),\n name: broadcast.name,\n subject: broadcast.subject,\n preheader: broadcast.preheader,\n content: broadcast.body,\n sendStatus: this.mapBroadcastStatus(broadcast.status),\n trackOpens: broadcast.track_opens,\n trackClicks: broadcast.track_clicks,\n replyTo: broadcast.reply_to,\n recipientCount: broadcast.total_recipients,\n sentAt: broadcast.sent_at ? new Date(broadcast.sent_at) : undefined,\n scheduledAt: broadcast.scheduled_send_at ? new Date(broadcast.scheduled_send_at) : undefined,\n createdAt: new Date(broadcast.created_at),\n updatedAt: new Date(broadcast.updated_at),\n providerData: { broadcast },\n providerId: broadcast.id.toString(),\n providerType: 'broadcast'\n }\n }\n\n private mapBroadcastStatus(status: string): BroadcastStatus {\n const statusMap: Record<string, BroadcastStatus> = {\n 'draft': BroadcastStatus.DRAFT,\n 'scheduled': BroadcastStatus.SCHEDULED,\n 'queueing': BroadcastStatus.SENDING,\n 'sending': BroadcastStatus.SENDING,\n 'sent': BroadcastStatus.SENT,\n 'failed': BroadcastStatus.FAILED,\n 'partial_failure': BroadcastStatus.FAILED,\n 'paused': BroadcastStatus.PAUSED,\n 'aborted': BroadcastStatus.CANCELED\n }\n return statusMap[status] || BroadcastStatus.DRAFT\n }\n}","// Collection factories\nexport { createBroadcastsCollection } from '../collections/Broadcasts'\nexport { createSubscribersCollection } from '../collections/Subscribers'","import type { CollectionConfig } from 'payload'\nimport type { SerializedEditorState } from 'lexical'\nimport type { NewsletterPluginConfig } from '../types'\nimport { BroadcastStatus } from '../types'\nimport { createEmailContentField, createEmailLexicalEditor } from '../fields/emailContent'\nimport { createBroadcastInlinePreviewField } from '../fields/broadcastInlinePreview'\nimport { createBroadcastScheduleField } from '../fields/broadcastSchedule'\nimport { convertToEmailSafeHtml } from '../utils/emailSafeHtml'\nimport { getBroadcastConfig } from '../utils/getBroadcastConfig'\nimport { createSendBroadcastEndpoint } from '../endpoints/broadcasts/send'\nimport { createScheduleBroadcastEndpoint } from '../endpoints/broadcasts/schedule'\nimport { createTestBroadcastEndpoint } from '../endpoints/broadcasts/test'\nimport { createBroadcastPreviewEndpoint, populateMediaFields } from '../endpoints/broadcasts/preview'\n\nexport const createBroadcastsCollection = (pluginConfig: NewsletterPluginConfig): CollectionConfig => {\n const hasProviders = !!(pluginConfig.providers?.broadcast || pluginConfig.providers?.resend)\n const customizations = pluginConfig.customizations?.broadcasts\n\n const collectionSlug = 'broadcasts'\n\n return {\n slug: collectionSlug,\n access: {\n read: () => true, // Public read access\n create: ({ req: { user } }) => {\n // Allow authenticated users to create\n return Boolean(user)\n },\n update: ({ req: { user } }) => {\n // Allow authenticated users to update\n return Boolean(user)\n },\n delete: ({ req: { user } }) => {\n // Allow authenticated users to delete\n return Boolean(user)\n },\n },\n versions: {\n drafts: {\n autosave: true,\n schedulePublish: true,\n }\n },\n labels: {\n singular: 'Broadcast',\n plural: 'Broadcasts',\n },\n admin: {\n useAsTitle: 'subject',\n description: 'Individual email campaigns sent to subscribers',\n defaultColumns: ['subject', '_status', 'sendStatus', 'sentAt', 'recipientCount'],\n },\n endpoints: [\n createSendBroadcastEndpoint(pluginConfig, collectionSlug),\n createScheduleBroadcastEndpoint(pluginConfig, collectionSlug),\n createTestBroadcastEndpoint(pluginConfig, collectionSlug),\n createBroadcastPreviewEndpoint(pluginConfig, collectionSlug),\n ],\n fields: [\n {\n name: 'subject',\n type: 'text',\n required: true,\n admin: {\n description: 'Email subject line'\n },\n },\n // Add any additional fields from customizations after subject\n ...(customizations?.additionalFields || []),\n {\n type: 'row',\n fields: [\n {\n name: 'contentSection',\n type: 'group',\n label: false,\n admin: {\n width: '50%',\n style: {\n paddingRight: '1rem',\n },\n },\n fields: [\n {\n name: 'preheader',\n type: 'text',\n admin: {\n description: 'Preview text shown in email clients'\n },\n },\n // Apply content field customization if provided\n // Process blocks server-side to avoid client serialization issues\n (() => {\n // Create email editor with custom blocks processed server-side\n const emailEditor = createEmailLexicalEditor(customizations?.customBlocks)\n \n // Create base field with pre-processed editor\n const baseField = createEmailContentField({\n admin: { description: 'Email content' },\n editor: emailEditor\n })\n \n // Apply field overrides if provided\n return customizations?.fieldOverrides?.content\n ? customizations.fieldOverrides.content(baseField)\n : baseField\n })(),\n ],\n },\n {\n name: 'previewSection',\n type: 'group',\n label: false,\n admin: {\n width: '50%',\n },\n fields: [\n createBroadcastInlinePreviewField(),\n ],\n },\n ],\n },\n {\n name: 'sendStatus',\n type: 'select',\n label: 'Send Status',\n required: true,\n defaultValue: BroadcastStatus.DRAFT,\n options: [\n { label: 'Draft', value: BroadcastStatus.DRAFT },\n { label: 'Scheduled', value: BroadcastStatus.SCHEDULED },\n { label: 'Sending', value: BroadcastStatus.SENDING },\n { label: 'Sent', value: BroadcastStatus.SENT },\n { label: 'Failed', value: BroadcastStatus.FAILED },\n { label: 'Paused', value: BroadcastStatus.PAUSED },\n { label: 'Canceled', value: BroadcastStatus.CANCELED },\n ],\n admin: {\n readOnly: true,\n description: 'The status of the email send operation',\n components: {\n Cell: 'payload-plugin-newsletter/components#StatusBadge',\n },\n },\n },\n // Scheduling controls - shows schedule/cancel buttons based on status\n createBroadcastScheduleField(),\n {\n name: 'settings',\n type: 'group',\n fields: [\n {\n name: 'trackOpens',\n type: 'checkbox',\n defaultValue: true,\n admin: {\n description: 'Track when recipients open this email'\n },\n },\n {\n name: 'trackClicks',\n type: 'checkbox',\n defaultValue: true,\n admin: {\n description: 'Track when recipients click links'\n },\n },\n {\n name: 'replyTo',\n type: 'email',\n admin: {\n description: 'Override the channel reply-to address for this broadcast'\n },\n },\n ],\n },\n {\n name: 'audienceIds',\n type: 'array',\n fields: [\n {\n name: 'audienceId',\n type: 'text',\n required: true,\n },\n ],\n admin: {\n description: 'Target specific audience segments',\n condition: () => {\n // Only show if the provider supports segmentation\n return hasProviders\n },\n },\n },\n {\n name: 'analytics',\n type: 'group',\n admin: {\n readOnly: true,\n condition: (data) => data?.sendStatus === BroadcastStatus.SENT,\n },\n fields: [\n {\n name: 'recipientCount',\n type: 'number',\n defaultValue: 0,\n },\n {\n name: 'sent',\n type: 'number',\n defaultValue: 0,\n },\n {\n name: 'delivered',\n type: 'number',\n defaultValue: 0,\n },\n {\n name: 'opened',\n type: 'number',\n defaultValue: 0,\n },\n {\n name: 'clicked',\n type: 'number',\n defaultValue: 0,\n },\n {\n name: 'bounced',\n type: 'number',\n defaultValue: 0,\n },\n {\n name: 'complained',\n type: 'number',\n defaultValue: 0,\n },\n {\n name: 'unsubscribed',\n type: 'number',\n defaultValue: 0,\n },\n ],\n },\n {\n name: 'sentAt',\n type: 'date',\n admin: {\n readOnly: true,\n date: {\n displayFormat: 'MMM d, yyyy h:mm a',\n },\n },\n },\n {\n name: 'scheduledAt',\n type: 'date',\n admin: {\n condition: (data) => data?.sendStatus === BroadcastStatus.SCHEDULED,\n date: {\n displayFormat: 'MMM d, yyyy h:mm a',\n },\n },\n },\n {\n name: 'providerId',\n type: 'text',\n admin: {\n readOnly: true,\n description: 'ID from the email provider',\n condition: (data) => hasProviders && data?.providerId,\n },\n },\n {\n name: 'externalId',\n type: 'text',\n admin: {\n readOnly: true,\n description: 'External ID for webhook integration',\n },\n },\n {\n name: 'providerData',\n type: 'json',\n admin: {\n readOnly: true,\n condition: () => false, // Hidden by default\n },\n },\n // Webhook tracking fields\n {\n name: 'webhookData',\n type: 'group',\n label: 'Webhook Data',\n admin: {\n condition: () => false, // Hidden by default, used for webhook tracking\n },\n fields: [\n {\n name: 'lastWebhookEvent',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'lastWebhookEventAt',\n type: 'date',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'hasWarnings',\n type: 'checkbox',\n defaultValue: false,\n },\n {\n name: 'failureReason',\n type: 'text',\n },\n {\n name: 'sentCount',\n type: 'number',\n },\n {\n name: 'totalCount',\n type: 'number',\n },\n {\n name: 'failedCount',\n type: 'number',\n },\n {\n name: 'remainingCount',\n type: 'number',\n },\n {\n name: 'sendingStartedAt',\n type: 'date',\n },\n {\n name: 'failedAt',\n type: 'date',\n },\n {\n name: 'abortedAt',\n type: 'date',\n },\n {\n name: 'abortReason',\n type: 'text',\n },\n {\n name: 'pausedAt',\n type: 'date',\n },\n {\n name: 'webhookEvents',\n type: 'array',\n label: 'Webhook Event Log',\n maxRows: 10,\n admin: {\n readOnly: true,\n description: 'Recent webhook events for debugging',\n },\n fields: [\n {\n name: 'eventType',\n type: 'text',\n admin: { readOnly: true },\n },\n {\n name: 'receivedAt',\n type: 'date',\n admin: { readOnly: true },\n },\n {\n name: 'eventPayload',\n type: 'json',\n admin: { readOnly: true },\n },\n ],\n },\n ],\n },\n ],\n hooks: {\n // Sync with provider on create and update\n afterChange: [\n async ({ doc, operation, req, previousDoc }) => {\n if (!hasProviders) return doc\n\n // Skip create operation - we'll handle provider creation on first update\n if (operation === 'create') {\n req.payload.logger.info('Broadcast created in Payload, provider sync will happen on first update with content')\n return doc\n }\n \n // Handle update operation\n if (operation === 'update') {\n req.payload.logger.info({\n operation,\n hasProviderId: !!doc.providerId,\n hasExternalId: !!doc.externalId,\n sendStatus: doc.sendStatus,\n publishStatus: doc._status,\n hasSubject: !!doc.subject,\n hasContent: !!doc.contentSection?.content\n }, 'Broadcast afterChange update hook triggered')\n\n try {\n // Get provider config from settings first, then fall back to env vars\n const providerConfig = await getBroadcastConfig(req, pluginConfig)\n if (!providerConfig || !providerConfig.token) {\n req.payload.logger.error('Broadcast provider not configured in Newsletter Settings or environment variables')\n return doc\n }\n\n const { BroadcastApiProvider } = await import('../providers/broadcast/broadcast')\n const provider = new BroadcastApiProvider(providerConfig)\n\n // If no providerId/externalId and has enough content, create in provider\n if (!doc.providerId && !doc.externalId && doc.subject && doc.contentSection?.content) {\n req.payload.logger.info('Creating broadcast in provider on first update with content')\n \n const htmlContent = await convertToEmailSafeHtml(\n await populateMediaFields(doc.contentSection.content, req.payload, pluginConfig) as SerializedEditorState | null,\n {\n wrapInTemplate: pluginConfig.customizations?.broadcasts?.emailPreview?.wrapInTemplate ?? true,\n customWrapper: pluginConfig.customizations?.broadcasts?.emailPreview?.customWrapper,\n preheader: doc.contentSection?.preheader,\n subject: doc.subject,\n documentData: doc,\n customBlockConverter: pluginConfig.customizations?.broadcasts?.customBlockConverter\n }\n )\n\n const createData = {\n name: doc.subject,\n subject: doc.subject,\n preheader: doc.contentSection?.preheader || '',\n content: htmlContent,\n trackOpens: doc.settings?.trackOpens ?? true,\n trackClicks: doc.settings?.trackClicks ?? true,\n replyTo: doc.settings?.replyTo || providerConfig.replyTo,\n audienceIds: doc.audienceIds?.map((a: any) => a.audienceId) || [],\n }\n\n const providerBroadcast = await provider.create(createData)\n \n req.payload.logger.info(`Broadcast ${doc.id} created in provider with ID ${providerBroadcast.id}`)\n \n // Return the document with provider IDs\n return {\n ...doc,\n providerId: providerBroadcast.id,\n externalId: providerBroadcast.id,\n providerData: providerBroadcast.providerData,\n }\n }\n\n // If no providerId, skip sync\n if (!doc.providerId) {\n req.payload.logger.info(`Broadcast ${doc.id} has no providerId and insufficient content for creation - skipping sync`)\n return doc\n }\n\n // Handle normal updates to existing broadcasts (only if providerId exists)\n if (doc.providerId) {\n // Only sync if broadcast is still editable\n const capabilities = provider.getCapabilities()\n const sendStatus = doc.sendStatus || BroadcastStatus.DRAFT\n if (!capabilities.editableStatuses.includes(sendStatus)) {\n req.payload.logger.info(`Skipping sync for broadcast in status: ${sendStatus}`)\n return doc\n }\n\n // Check what has changed\n const contentChanged = \n doc.subject !== previousDoc?.subject ||\n doc.contentSection?.preheader !== previousDoc?.contentSection?.preheader ||\n JSON.stringify(doc.contentSection?.content) !== JSON.stringify(previousDoc?.contentSection?.content) ||\n doc.settings?.trackOpens !== previousDoc?.settings?.trackOpens ||\n doc.settings?.trackClicks !== previousDoc?.settings?.trackClicks ||\n doc.settings?.replyTo !== previousDoc?.settings?.replyTo ||\n JSON.stringify(doc.audienceIds) !== JSON.stringify(previousDoc?.audienceIds)\n\n if (contentChanged) {\n // Build update data\n const updates: any = {}\n if (doc.subject !== previousDoc?.subject) {\n updates.name = doc.subject // Use subject as name in the provider\n updates.subject = doc.subject\n }\n if (doc.contentSection?.preheader !== previousDoc?.contentSection?.preheader) {\n updates.preheader = doc.contentSection?.preheader\n }\n if (JSON.stringify(doc.contentSection?.content) !== JSON.stringify(previousDoc?.contentSection?.content)) {\n const populatedContent = await populateMediaFields(doc.contentSection?.content, req.payload, pluginConfig) as SerializedEditorState | null\n\n // Get email preview customization options\n const emailPreviewConfig = pluginConfig.customizations?.broadcasts?.emailPreview\n\n updates.content = await convertToEmailSafeHtml(populatedContent, {\n wrapInTemplate: emailPreviewConfig?.wrapInTemplate ?? true,\n customWrapper: emailPreviewConfig?.customWrapper,\n preheader: doc.contentSection?.preheader,\n subject: doc.subject,\n documentData: doc, // Pass entire document\n customBlockConverter: pluginConfig.customizations?.broadcasts?.customBlockConverter\n })\n }\n if (doc.settings?.trackOpens !== previousDoc?.settings?.trackOpens) {\n updates.trackOpens = doc.settings.trackOpens\n }\n if (doc.settings?.trackClicks !== previousDoc?.settings?.trackClicks) {\n updates.trackClicks = doc.settings.trackClicks\n }\n if (doc.settings?.replyTo !== previousDoc?.settings?.replyTo) {\n updates.replyTo = doc.settings.replyTo || providerConfig.replyTo\n }\n if (JSON.stringify(doc.audienceIds) !== JSON.stringify(previousDoc?.audienceIds)) {\n updates.audienceIds = doc.audienceIds?.map((a: any) => a.audienceId)\n }\n\n req.payload.logger.info({\n providerId: doc.providerId,\n updates\n }, 'Syncing broadcast updates to provider')\n \n await provider.update(doc.providerId, updates)\n req.payload.logger.info(`Broadcast ${doc.id} synced to provider successfully`)\n } else {\n req.payload.logger.info('No content changes to sync to provider')\n }\n }\n } catch (error) {\n // Enhanced error logging for debugging\n req.payload.logger.error('Raw error from broadcast update operation:')\n req.payload.logger.error(error)\n \n if (error instanceof Error) {\n req.payload.logger.error('Error is instance of Error:', {\n message: error.message,\n stack: error.stack,\n name: error.name,\n ...(error as any).details,\n ...(error as any).response,\n ...(error as any).data,\n ...(error as any).status,\n ...(error as any).statusText,\n })\n } else if (typeof error === 'string') {\n req.payload.logger.error({ errorValue: error }, 'Error is a string')\n } else if (error && typeof error === 'object') {\n req.payload.logger.error({ errorValue: JSON.stringify(error, null, 2) }, 'Error is an object')\n } else {\n req.payload.logger.error({ errorType: typeof error }, 'Unknown error type')\n }\n\n req.payload.logger.error({\n id: doc.id,\n subject: doc.subject,\n hasContent: !!doc.contentSection?.content,\n contentType: doc.contentSection?.content ? typeof doc.contentSection.content : 'none',\n }, 'Failed broadcast document (update operation)')\n \n // Don't throw - allow Payload update to succeed even if provider sync fails\n }\n }\n\n return doc\n },\n // Hook to send when published\n async ({ doc, operation, previousDoc, req }) => {\n // Only run on updates when transitioning to published\n if (operation !== 'update') return doc\n \n const wasUnpublished = !previousDoc?._status || previousDoc._status === 'draft'\n const isNowPublished = doc._status === 'published'\n \n if (wasUnpublished && isNowPublished && doc.providerId) {\n // Check if already sent\n if (doc.sendStatus === BroadcastStatus.SENT || doc.sendStatus === BroadcastStatus.SENDING) {\n return doc\n }\n \n try {\n // Get provider config from settings first, then fall back to env vars\n const broadcastConfig = await getBroadcastConfig(req, pluginConfig)\n const resendConfig = pluginConfig.providers?.resend // TODO: Add getResendConfig utility\n \n if (!broadcastConfig && !resendConfig) {\n req.payload.logger.error('No provider configured for sending in Newsletter Settings or environment variables')\n return doc\n }\n \n // Send via provider\n if (broadcastConfig && broadcastConfig.token) {\n const { BroadcastApiProvider } = await import('../providers/broadcast/broadcast')\n const provider = new BroadcastApiProvider(broadcastConfig)\n await provider.send(doc.providerId)\n }\n // Add resend provider support here when needed\n \n // Update status\n await req.payload.update({\n collection: 'broadcasts',\n id: doc.id,\n data: {\n sendStatus: BroadcastStatus.SENDING,\n sentAt: new Date().toISOString(),\n },\n req,\n })\n \n req.payload.logger.info(`Broadcast ${doc.id} sent successfully`)\n \n } catch (error) {\n // Log full error details for debugging\n if (error instanceof Error) {\n req.payload.logger.error(`Failed to send broadcast ${doc.id}:`, {\n message: error.message,\n stack: error.stack,\n name: error.name,\n // If it's a BroadcastProviderError, it might have additional details\n ...(error as any).details\n })\n } else {\n req.payload.logger.error({ error: String(error) }, `Failed to send broadcast ${doc.id}`)\n }\n \n // Update status to failed\n await req.payload.update({\n collection: 'broadcasts',\n id: doc.id,\n data: {\n sendStatus: BroadcastStatus.FAILED,\n },\n req,\n })\n }\n }\n \n return doc\n },\n ],\n // beforeChange hooks can be added here if needed\n beforeChange: [],\n // Handle deletion\n afterDelete: [\n async ({ doc, req }) => {\n if (!hasProviders || !doc?.providerId) return doc\n\n try {\n // Get provider config from settings first, then fall back to env vars\n const providerConfig = await getBroadcastConfig(req, pluginConfig)\n if (!providerConfig || !providerConfig.token) {\n req.payload.logger.error('Broadcast provider not configured in Newsletter Settings or environment variables')\n return doc\n }\n\n const { BroadcastApiProvider } = await import('../providers/broadcast/broadcast')\n const provider = new BroadcastApiProvider(providerConfig)\n\n // Only delete if broadcast is still editable\n const capabilities = provider.getCapabilities()\n if (capabilities.editableStatuses.includes(doc.sendStatus)) {\n await provider.delete(doc.providerId)\n }\n } catch (error) {\n // Log full error details for debugging\n if (error instanceof Error) {\n req.payload.logger.error('Failed to delete broadcast from provider:', {\n message: error.message,\n stack: error.stack,\n name: error.name,\n // If it's a BroadcastProviderError, it might have additional details\n ...(error as any).details\n })\n } else {\n req.payload.logger.error({ error: String(error) }, 'Failed to delete broadcast from provider')\n }\n }\n\n return doc\n },\n ],\n },\n }\n}\n\n\n","import { \n BoldFeature,\n ItalicFeature,\n UnderlineFeature,\n StrikethroughFeature,\n LinkFeature,\n OrderedListFeature,\n UnorderedListFeature,\n HeadingFeature,\n ParagraphFeature,\n AlignFeature,\n BlockquoteFeature,\n BlocksFeature,\n UploadFeature,\n FixedToolbarFeature,\n InlineToolbarFeature,\n lexicalEditor,\n} from '@payloadcms/richtext-lexical'\nimport type { RichTextField, Block } from 'payload'\nimport { createEmailSafeBlocks } from '../utils/blockValidation'\n\n/**\n * Creates email-safe features for Lexical editor with optional additional blocks\n * Only includes features that render consistently across email clients\n */\n// Using any[] here because Payload's FeatureProviderServer type is complex\n// and varies between versions. The features are properly typed by Payload internally.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const createEmailSafeFeatures = (additionalBlocks?: Block[]): any[] => {\n // Base email-safe blocks\n const baseBlocks = [\n {\n slug: 'button',\n fields: [\n {\n name: 'text',\n type: 'text',\n label: 'Button Text',\n required: true,\n },\n {\n name: 'url',\n type: 'text',\n label: 'Button URL',\n required: true,\n admin: {\n description: 'Enter the full URL (including https://)',\n },\n },\n {\n name: 'style',\n type: 'select',\n label: 'Button Style',\n defaultValue: 'primary',\n options: [\n { label: 'Primary', value: 'primary' },\n { label: 'Secondary', value: 'secondary' },\n { label: 'Outline', value: 'outline' },\n ],\n },\n ],\n interfaceName: 'EmailButton',\n labels: {\n singular: 'Button',\n plural: 'Buttons',\n },\n },\n {\n slug: 'divider',\n fields: [\n {\n name: 'style',\n type: 'select',\n label: 'Divider Style',\n defaultValue: 'solid',\n options: [\n { label: 'Solid', value: 'solid' },\n { label: 'Dashed', value: 'dashed' },\n { label: 'Dotted', value: 'dotted' },\n ],\n },\n ],\n interfaceName: 'EmailDivider',\n labels: {\n singular: 'Divider',\n plural: 'Dividers',\n },\n },\n ] as Block[]\n\n // Merge additional blocks if provided\n const allBlocks = [\n ...baseBlocks,\n ...(additionalBlocks || [])\n ]\n\n return [\n // Toolbars\n FixedToolbarFeature(), // Fixed toolbar at the top\n InlineToolbarFeature(), // Floating toolbar when text is selected\n \n // Basic text formatting\n BoldFeature(),\n ItalicFeature(),\n UnderlineFeature(),\n StrikethroughFeature(),\n \n // Links - use default fields to ensure drawer UI works correctly\n LinkFeature(),\n \n // Lists\n OrderedListFeature(),\n UnorderedListFeature(),\n \n // Headings - limited to h1, h2, h3 for email compatibility\n HeadingFeature({\n enabledHeadingSizes: ['h1', 'h2', 'h3'],\n }),\n \n // Basic paragraph and alignment\n ParagraphFeature(),\n AlignFeature(),\n \n // Blockquotes\n BlockquoteFeature(),\n \n // Upload feature for images\n UploadFeature({\n collections: {\n media: {\n fields: [\n {\n name: 'caption',\n type: 'text',\n admin: {\n description: 'Optional caption for the image',\n },\n },\n {\n name: 'altText',\n type: 'text',\n label: 'Alt Text',\n required: true,\n admin: {\n description: 'Alternative text for accessibility and when image cannot be displayed',\n },\n },\n ],\n },\n },\n }),\n \n // Custom blocks for email-specific content\n BlocksFeature({\n blocks: allBlocks,\n }),\n ]\n}\n\n/**\n * Creates a Lexical editor configured specifically for email content\n * Processes blocks server-side to avoid client serialization issues\n */\nexport const createEmailLexicalEditor = (customBlocks: Block[] = []): any => {\n const emailSafeBlocks = createEmailSafeBlocks(customBlocks)\n \n return lexicalEditor({\n features: [\n // Toolbars\n FixedToolbarFeature(),\n InlineToolbarFeature(),\n \n // Basic text formatting\n BoldFeature(),\n ItalicFeature(),\n UnderlineFeature(),\n StrikethroughFeature(),\n \n // Links - use default fields to ensure drawer UI works correctly\n LinkFeature(),\n \n // Lists\n OrderedListFeature(),\n UnorderedListFeature(),\n \n // Headings - limited to h1, h2, h3 for email compatibility\n HeadingFeature({\n enabledHeadingSizes: ['h1', 'h2', 'h3'],\n }),\n \n // Basic paragraph and alignment\n ParagraphFeature(),\n AlignFeature(),\n \n // Blockquotes\n BlockquoteFeature(),\n \n // Upload feature for images\n UploadFeature({\n collections: {\n media: {\n fields: [\n {\n name: 'caption',\n type: 'text',\n admin: {\n description: 'Optional caption for the image',\n },\n },\n {\n name: 'altText',\n type: 'text',\n label: 'Alt Text',\n required: true,\n admin: {\n description: 'Alternative text for accessibility and when image cannot be displayed',\n },\n },\n ],\n },\n },\n }),\n \n // Email-safe blocks (processed server-side)\n BlocksFeature({\n blocks: emailSafeBlocks,\n }),\n ],\n })\n}\n\n/**\n * Legacy export for backward compatibility\n */\nexport const emailSafeFeatures = createEmailSafeFeatures()\n\n/**\n * Creates an email-safe rich text field configuration\n */\nexport const createEmailContentField = (\n overrides?: Partial<RichTextField> & {\n additionalBlocks?: Block[]\n editor?: any // Lexical editor instance\n }\n): RichTextField => {\n // Use provided editor or create one with blocks\n const editor = overrides?.editor || createEmailLexicalEditor(overrides?.additionalBlocks)\n\n return {\n name: 'content',\n type: 'richText',\n required: true,\n editor,\n admin: {\n description: 'Email content with limited formatting for compatibility',\n ...overrides?.admin,\n },\n ...overrides,\n }\n}","import type { Block } from 'payload'\n\n/**\n * Email-incompatible block types that should be warned about\n */\nconst EMAIL_INCOMPATIBLE_TYPES = [\n 'chart',\n 'dataTable', \n 'interactive',\n 'streamable',\n 'video',\n 'iframe',\n 'form',\n 'carousel',\n 'tabs',\n 'accordion',\n 'map'\n]\n\n/**\n * Validates that blocks are email-compatible and warns about potential issues\n */\nexport const validateEmailBlocks = (blocks: Block[]): void => {\n blocks.forEach(block => {\n if (EMAIL_INCOMPATIBLE_TYPES.includes(block.slug)) {\n console.warn(`⚠️ Block \"${block.slug}\" may not be email-compatible. Consider creating an email-specific version.`)\n }\n \n // Check for complex field types that might not work in emails\n const hasComplexFields = block.fields?.some(field => {\n const complexTypes = ['code', 'json', 'richText', 'blocks', 'array']\n return complexTypes.includes(field.type)\n })\n \n if (hasComplexFields) {\n console.warn(`⚠️ Block \"${block.slug}\" contains complex field types that may not render consistently in email clients.`)\n }\n })\n}\n\n/**\n * Creates email-safe block configurations by filtering and validating blocks\n */\nexport const createEmailSafeBlocks = (customBlocks: Block[] = []): Block[] => {\n // Validate blocks\n validateEmailBlocks(customBlocks)\n \n // Base email-safe blocks that come with the plugin\n const baseBlocks: Block[] = [\n {\n slug: 'button',\n fields: [\n {\n name: 'text',\n type: 'text',\n label: 'Button Text',\n required: true,\n },\n {\n name: 'url',\n type: 'text',\n label: 'Button URL',\n required: true,\n admin: {\n description: 'Enter the full URL (including https://)',\n },\n },\n {\n name: 'style',\n type: 'select',\n label: 'Button Style',\n defaultValue: 'primary',\n options: [\n { label: 'Primary', value: 'primary' },\n { label: 'Secondary', value: 'secondary' },\n { label: 'Outline', value: 'outline' },\n ],\n },\n ],\n interfaceName: 'EmailButton',\n labels: {\n singular: 'Button',\n plural: 'Buttons',\n },\n },\n {\n slug: 'divider',\n fields: [\n {\n name: 'style',\n type: 'select',\n label: 'Divider Style',\n defaultValue: 'solid',\n options: [\n { label: 'Solid', value: 'solid' },\n { label: 'Dashed', value: 'dashed' },\n { label: 'Dotted', value: 'dotted' },\n ],\n },\n ],\n interfaceName: 'EmailDivider',\n labels: {\n singular: 'Divider',\n plural: 'Dividers',\n },\n },\n ]\n \n // Combine base blocks with custom blocks\n return [\n ...baseBlocks,\n ...customBlocks\n ]\n}","import type { Field } from 'payload'\n\nexport const createBroadcastInlinePreviewField = (): Field => {\n return {\n name: 'broadcastInlinePreview',\n type: 'ui',\n admin: {\n components: {\n Field: 'payload-plugin-newsletter/components#BroadcastInlinePreview',\n },\n },\n }\n}","import type { Field } from 'payload'\n\n/**\n * Creates a UI field that displays scheduling controls for broadcasts\n * Shows Schedule button for drafts, Cancel button for scheduled broadcasts\n */\nexport const createBroadcastScheduleField = (): Field => {\n return {\n name: 'scheduleControls',\n type: 'ui',\n label: 'Scheduling',\n admin: {\n components: {\n Field: 'payload-plugin-newsletter/components#BroadcastScheduleField',\n },\n },\n }\n}\n","import DOMPurify from 'isomorphic-dompurify'\nimport type { SerializedEditorState } from 'lexical'\n\n/**\n * DOMPurify configuration for email-safe HTML\n */\nexport const EMAIL_SAFE_CONFIG = {\n ALLOWED_TAGS: [\n 'p', 'br', 'strong', 'b', 'em', 'i', 'u', 'strike', 's', 'span',\n 'a', 'h1', 'h2', 'h3', 'ul', 'ol', 'li', 'blockquote', 'hr',\n 'img', 'div', 'table', 'tr', 'td', 'th', 'tbody', 'thead'\n ],\n ALLOWED_ATTR: ['href', 'style', 'target', 'rel', 'align', 'src', 'alt', 'width', 'height', 'border', 'cellpadding', 'cellspacing'],\n ALLOWED_STYLES: {\n '*': [\n 'color', 'background-color', 'font-size', 'font-weight',\n 'font-style', 'text-decoration', 'text-align', 'margin',\n 'margin-top', 'margin-right', 'margin-bottom', 'margin-left',\n 'padding', 'padding-top', 'padding-right', 'padding-bottom', \n 'padding-left', 'line-height', 'border-left', 'border-left-width',\n 'border-left-style', 'border-left-color'\n ],\n },\n FORBID_TAGS: ['script', 'style', 'iframe', 'object', 'embed', 'form', 'input'],\n FORBID_ATTR: ['class', 'id', 'onclick', 'onload', 'onerror'],\n}\n\n/**\n * Converts Lexical editor state to email-safe HTML\n */\nexport async function convertToEmailSafeHtml(\n editorState: SerializedEditorState | undefined | null,\n options?: {\n wrapInTemplate?: boolean\n preheader?: string\n mediaUrl?: string // Base URL for media files\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n payload?: any // Payload instance for populating relationships\n populateFields?: string[] | ((blockType: string) => string[]) // Fields to populate\n customWrapper?: (content: string, options?: { preheader?: string; subject?: string; documentData?: Record<string, any> }) => string | Promise<string>\n subject?: string // Email subject for custom wrapper\n documentData?: Record<string, any> // Generic document data for custom wrapper\n }\n): Promise<string> {\n // Handle empty content\n if (!editorState) {\n return ''\n }\n \n // First, convert Lexical state to HTML using custom converters\n const rawHtml = await lexicalToEmailHtml(editorState, options?.mediaUrl, options?.customBlockConverter)\n \n // Sanitize the HTML\n const sanitizedHtml = DOMPurify.sanitize(rawHtml, EMAIL_SAFE_CONFIG)\n \n // Optionally wrap in email template\n if (options?.wrapInTemplate) {\n if (options.customWrapper) {\n return await Promise.resolve(options.customWrapper(sanitizedHtml, { \n preheader: options.preheader,\n subject: options.subject,\n documentData: options.documentData\n }))\n }\n return wrapInEmailTemplate(sanitizedHtml, options.preheader)\n }\n \n return sanitizedHtml\n}\n\n/**\n * Custom Lexical to HTML converter for email\n */\nasync function lexicalToEmailHtml(\n editorState: SerializedEditorState, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n const { root } = editorState\n \n if (!root || !root.children) {\n return ''\n }\n \n // Convert nodes asynchronously to support custom converters\n const htmlParts = await Promise.all(\n root.children.map((node: any) => convertNode(node, mediaUrl, customBlockConverter))\n )\n \n return htmlParts.join('')\n}\n\n/**\n * Convert individual Lexical nodes to email-safe HTML\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function convertNode(\n node: any, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n switch (node.type) {\n case 'paragraph':\n return convertParagraph(node, mediaUrl, customBlockConverter)\n case 'heading':\n return convertHeading(node, mediaUrl, customBlockConverter)\n case 'list':\n return convertList(node, mediaUrl, customBlockConverter)\n case 'listitem':\n return convertListItem(node, mediaUrl, customBlockConverter)\n case 'blockquote':\n return convertBlockquote(node, mediaUrl, customBlockConverter)\n case 'text':\n return convertText(node)\n case 'link':\n return convertLink(node, mediaUrl, customBlockConverter)\n case 'linebreak':\n return '<br>'\n case 'upload':\n return convertUpload(node, mediaUrl)\n case 'block':\n return await convertBlock(node, mediaUrl, customBlockConverter)\n default:\n // Unknown node type - convert children if any\n if (node.children) {\n const childParts = await Promise.all(\n node.children.map((child: any) => convertNode(child, mediaUrl, customBlockConverter))\n )\n return childParts.join('')\n }\n return ''\n }\n}\n\n/**\n * Convert paragraph node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function convertParagraph(\n node: any, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n const align = getAlignment(node.format)\n const childParts = await Promise.all(\n (node.children || []).map((child: any) => convertNode(child, mediaUrl, customBlockConverter))\n )\n const children = childParts.join('')\n \n if (!children.trim()) {\n return '<p class=\"mobile-margin-bottom-16\" style=\"margin: 0 0 16px 0; min-height: 1em;\"> </p>'\n }\n \n return `<p class=\"mobile-margin-bottom-16\" style=\"margin: 0 0 16px 0; text-align: ${align}; font-size: 16px; line-height: 1.5;\">${children}</p>`\n}\n\n/**\n * Convert heading node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function convertHeading(\n node: any, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n const tag = node.tag || 'h1'\n const align = getAlignment(node.format)\n const childParts = await Promise.all(\n (node.children || []).map((child: any) => convertNode(child, mediaUrl, customBlockConverter))\n )\n const children = childParts.join('')\n \n const styles: Record<string, string> = {\n h1: 'font-size: 32px; font-weight: 700; margin: 0 0 24px 0; line-height: 1.2;',\n h2: 'font-size: 24px; font-weight: 600; margin: 0 0 16px 0; line-height: 1.3;',\n h3: 'font-size: 20px; font-weight: 600; margin: 0 0 12px 0; line-height: 1.4;',\n }\n \n const mobileClasses: Record<string, string> = {\n h1: 'mobile-font-size-24',\n h2: 'mobile-font-size-20',\n h3: 'mobile-font-size-16',\n }\n \n const style = `${styles[tag] || styles.h3} text-align: ${align};`\n const mobileClass = mobileClasses[tag] || mobileClasses.h3\n \n return `<${tag} class=\"${mobileClass}\" style=\"${style}\">${children}</${tag}>`\n}\n\n/**\n * Convert list node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function convertList(\n node: any, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n const tag = node.listType === 'number' ? 'ol' : 'ul'\n const childParts = await Promise.all(\n (node.children || []).map((child: any) => convertNode(child, mediaUrl, customBlockConverter))\n )\n const children = childParts.join('')\n \n const style = tag === 'ul' \n ? 'margin: 0 0 16px 0; padding-left: 24px; list-style-type: disc; font-size: 16px; line-height: 1.5;'\n : 'margin: 0 0 16px 0; padding-left: 24px; list-style-type: decimal; font-size: 16px; line-height: 1.5;'\n \n return `<${tag} class=\"mobile-margin-bottom-16\" style=\"${style}\">${children}</${tag}>`\n}\n\n/**\n * Convert list item node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function convertListItem(\n node: any, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n const childParts = await Promise.all(\n (node.children || []).map((child: any) => convertNode(child, mediaUrl, customBlockConverter))\n )\n const children = childParts.join('')\n return `<li style=\"margin: 0 0 8px 0;\">${children}</li>`\n}\n\n/**\n * Convert blockquote node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function convertBlockquote(\n node: any, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n const childParts = await Promise.all(\n (node.children || []).map((child: any) => convertNode(child, mediaUrl, customBlockConverter))\n )\n const children = childParts.join('')\n const style = 'margin: 0 0 16px 0; padding-left: 16px; border-left: 4px solid #e5e7eb; color: #6b7280;'\n \n return `<blockquote style=\"${style}\">${children}</blockquote>`\n}\n\n/**\n * Convert text node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction convertText(node: any): string {\n let text = escapeHtml(node.text || '')\n \n // Apply formatting\n if (node.format & 1) { // Bold\n text = `<strong>${text}</strong>`\n }\n if (node.format & 2) { // Italic\n text = `<em>${text}</em>`\n }\n if (node.format & 8) { // Underline\n text = `<u>${text}</u>`\n }\n if (node.format & 4) { // Strikethrough\n text = `<strike>${text}</strike>`\n }\n \n return text\n}\n\n/**\n * Convert link node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function convertLink(\n node: any, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n const childParts = await Promise.all(\n (node.children || []).map((child: any) => convertNode(child, mediaUrl, customBlockConverter))\n )\n const children = childParts.join('')\n const url = node.fields?.url || '#'\n const newTab = node.fields?.newTab ?? false\n \n // Add target and rel attributes based on newTab setting\n const targetAttr = newTab ? ' target=\"_blank\"' : ''\n const relAttr = newTab ? ' rel=\"noopener noreferrer\"' : ''\n \n return `<a href=\"${escapeHtml(url)}\"${targetAttr}${relAttr} style=\"color: #2563eb; text-decoration: underline;\">${children}</a>`\n}\n\n/**\n * Convert upload (image) node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction convertUpload(node: any, mediaUrl?: string): string {\n const upload = node.value\n if (!upload) return ''\n \n // Get image URL - handle both direct URL and media object\n let src = ''\n if (typeof upload === 'string') {\n src = upload\n } else if (upload.url) {\n src = upload.url\n } else if (upload.filename && mediaUrl) {\n // Construct URL from media URL and filename\n src = `${mediaUrl}/${upload.filename}`\n }\n \n const alt = node.fields?.altText || upload.alt || ''\n const caption = node.fields?.caption || ''\n \n // Responsive email-safe image\n const imgHtml = `<img src=\"${escapeHtml(src)}\" alt=\"${escapeHtml(alt)}\" class=\"mobile-width-100\" style=\"max-width: 100%; height: auto; display: block; margin: 0 auto; border-radius: 6px;\" />`\n \n if (caption) {\n return `\n <div style=\"margin: 0 0 16px 0; text-align: center;\" class=\"mobile-margin-bottom-16\">\n ${imgHtml}\n <p style=\"margin: 8px 0 0 0; font-size: 14px; color: #6b7280; font-style: italic; text-align: center;\" class=\"mobile-font-size-14\">${escapeHtml(caption)}</p>\n </div>\n `\n }\n \n return `<div style=\"margin: 0 0 16px 0; text-align: center;\" class=\"mobile-margin-bottom-16\">${imgHtml}</div>`\n}\n\n/**\n * Convert custom block node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function convertBlock(\n node: any, \n mediaUrl?: string,\n customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>\n): Promise<string> {\n const blockType = node.fields?.blockName || node.blockName\n \n // First, check if there's a custom converter for this block\n if (customBlockConverter) {\n try {\n const customHtml = await customBlockConverter(node, mediaUrl)\n if (customHtml) {\n return customHtml\n }\n } catch (error) {\n console.error(`Custom block converter error for ${blockType}:`, error)\n // Fall through to default handling\n }\n }\n \n // Default handling for built-in blocks\n switch (blockType) {\n case 'button':\n return convertButtonBlock(node.fields)\n case 'divider':\n return convertDividerBlock(node.fields)\n default:\n // Unknown block type - try to convert children\n if (node.children) {\n const childParts = await Promise.all(\n node.children.map((child: any) => convertNode(child, mediaUrl, customBlockConverter))\n )\n return childParts.join('')\n }\n return ''\n }\n}\n\n/**\n * Convert button block\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction convertButtonBlock(fields: any): string {\n const text = fields?.text || 'Click here'\n const url = fields?.url || '#'\n const style = fields?.style || 'primary'\n \n const styles: Record<string, string> = {\n primary: 'background-color: #2563eb; color: #ffffff; border: 2px solid #2563eb;',\n secondary: 'background-color: #6b7280; color: #ffffff; border: 2px solid #6b7280;',\n outline: 'background-color: transparent; color: #2563eb; border: 2px solid #2563eb;',\n }\n \n const buttonStyle = `${styles[style] || styles.primary} display: inline-block; padding: 12px 24px; font-size: 16px; font-weight: 600; text-decoration: none; border-radius: 6px; text-align: center;`\n \n return `\n <div style=\"margin: 0 0 16px 0; text-align: center;\">\n <a href=\"${escapeHtml(url)}\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"${buttonStyle}\">${escapeHtml(text)}</a>\n </div>\n `\n}\n\n/**\n * Convert divider block\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction convertDividerBlock(fields: any): string {\n const style = fields?.style || 'solid'\n \n const styles: Record<string, string> = {\n solid: 'border-top: 1px solid #e5e7eb;',\n dashed: 'border-top: 1px dashed #e5e7eb;',\n dotted: 'border-top: 1px dotted #e5e7eb;',\n }\n \n return `<hr style=\"${styles[style] || styles.solid} margin: 24px 0; border-bottom: none; border-left: none; border-right: none;\" />`\n}\n\n/**\n * Get text alignment from format number\n */\nfunction getAlignment(format?: number): string {\n if (!format) return 'left'\n \n // Lexical alignment format values\n if (format & 2) return 'center'\n if (format & 3) return 'right'\n if (format & 4) return 'justify'\n \n return 'left'\n}\n\n/**\n * Escape HTML special characters\n */\nfunction escapeHtml(text: string): string {\n const map: Record<string, string> = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": '''\n }\n \n return text.replace(/[&<>\"']/g, m => map[m])\n}\n\n/**\n * Wrap content in a responsive email template\n */\nfunction wrapInEmailTemplate(content: string, preheader?: string): string {\n return `<!DOCTYPE html>\n<html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:o=\"urn:schemas-microsoft-com:office:office\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n <meta name=\"x-apple-disable-message-reformatting\">\n <title>Newsletter</title>\n \n <!--[if mso]>\n <noscript>\n <xml>\n <o:OfficeDocumentSettings>\n <o:PixelsPerInch>96</o:PixelsPerInch>\n </o:OfficeDocumentSettings>\n </xml>\n </noscript>\n <![endif]-->\n \n <style>\n /* Reset and base styles */\n * {\n -webkit-text-size-adjust: 100%;\n -ms-text-size-adjust: 100%;\n }\n \n body {\n margin: 0 !important;\n padding: 0 !important;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;\n font-size: 16px;\n line-height: 1.5;\n color: #1A1A1A;\n background-color: #f8f9fa;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n \n table {\n border-spacing: 0 !important;\n border-collapse: collapse !important;\n table-layout: fixed !important;\n margin: 0 auto !important;\n }\n \n table table table {\n table-layout: auto;\n }\n \n img {\n -ms-interpolation-mode: bicubic;\n max-width: 100%;\n height: auto;\n border: 0;\n outline: none;\n text-decoration: none;\n }\n \n /* Responsive styles */\n @media only screen and (max-width: 640px) {\n .mobile-hide {\n display: none !important;\n }\n \n .mobile-center {\n text-align: center !important;\n }\n \n .mobile-width-100 {\n width: 100% !important;\n max-width: 100% !important;\n }\n \n .mobile-padding {\n padding: 20px !important;\n }\n \n .mobile-padding-sm {\n padding: 16px !important;\n }\n \n .mobile-font-size-14 {\n font-size: 14px !important;\n }\n \n .mobile-font-size-16 {\n font-size: 16px !important;\n }\n \n .mobile-font-size-20 {\n font-size: 20px !important;\n line-height: 1.3 !important;\n }\n \n .mobile-font-size-24 {\n font-size: 24px !important;\n line-height: 1.2 !important;\n }\n \n /* Stack sections on mobile */\n .mobile-stack {\n display: block !important;\n width: 100% !important;\n }\n \n /* Mobile-specific spacing */\n .mobile-margin-bottom-16 {\n margin-bottom: 16px !important;\n }\n \n .mobile-margin-bottom-20 {\n margin-bottom: 20px !important;\n }\n }\n \n /* Dark mode support */\n @media (prefers-color-scheme: dark) {\n .dark-mode-bg {\n background-color: #1a1a1a !important;\n }\n \n .dark-mode-text {\n color: #ffffff !important;\n }\n \n .dark-mode-border {\n border-color: #333333 !important;\n }\n }\n \n /* Outlook-specific fixes */\n <!--[if mso]>\n <style>\n table {\n border-collapse: collapse;\n border-spacing: 0;\n border: none;\n margin: 0;\n }\n \n div, p {\n margin: 0;\n }\n </style>\n <![endif]-->\n </style>\n</head>\n<body style=\"margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif; font-size: 16px; line-height: 1.5; color: #1A1A1A; background-color: #f8f9fa;\">\n ${preheader ? `\n <!-- Preheader text -->\n <div style=\"display: none; max-height: 0; overflow: hidden; font-size: 1px; line-height: 1px; color: transparent;\">\n ${escapeHtml(preheader)}\n </div>\n ` : ''}\n \n <!-- Main container -->\n <table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" style=\"margin: 0; padding: 0; background-color: #f8f9fa;\">\n <tr>\n <td align=\"center\" style=\"padding: 20px 10px;\">\n <!-- Email wrapper -->\n <table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" width=\"600\" class=\"mobile-width-100\" style=\"margin: 0 auto; max-width: 600px;\">\n <tr>\n <td class=\"mobile-padding\" style=\"padding: 0;\">\n <!-- Content area with light background -->\n <div style=\"background-color: #ffffff; padding: 40px 30px; border-radius: 8px;\" class=\"mobile-padding\">\n ${content}\n </div>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n</body>\n</html>`\n}\n\n/**\n * Extract personalization tags from content\n */\nexport function extractPersonalizationTags(html: string): string[] {\n const regex = /\\{\\{([^}]+)\\}\\}/g\n const tags: string[] = []\n let match\n \n while ((match = regex.exec(html)) !== null) {\n tags.push(match[1].trim())\n }\n \n return [...new Set(tags)]\n}\n\n/**\n * Replace personalization tags with sample data\n */\nexport function replacePersonalizationTags(\n html: string, \n sampleData: Record<string, string>\n): string {\n return html.replace(/\\{\\{([^}]+)\\}\\}/g, (match, tag) => {\n const trimmedTag = tag.trim()\n return sampleData[trimmedTag] || match\n })\n}","import type { PayloadRequest } from 'payload'\nimport type { NewsletterPluginConfig, BroadcastProviderConfig } from '../types'\n\nexport async function getBroadcastConfig(\n req: PayloadRequest,\n pluginConfig: NewsletterPluginConfig\n): Promise<BroadcastProviderConfig | null> {\n try {\n // Get settings from Newsletter Settings collection\n const settings = await req.payload.findGlobal({\n slug: pluginConfig.settingsSlug || 'newsletter-settings',\n req,\n })\n\n // Build provider config from settings, falling back to env vars\n if (settings?.provider === 'broadcast' && settings?.broadcastSettings) {\n return {\n apiUrl: settings.broadcastSettings.apiUrl || pluginConfig.providers?.broadcast?.apiUrl || '',\n token: settings.broadcastSettings.token || pluginConfig.providers?.broadcast?.token || '',\n fromAddress: settings.fromAddress || pluginConfig.providers?.broadcast?.fromAddress || '',\n fromName: settings.fromName || pluginConfig.providers?.broadcast?.fromName || '',\n replyTo: settings.replyTo || pluginConfig.providers?.broadcast?.replyTo,\n }\n }\n\n // Fall back to env var config\n return pluginConfig.providers?.broadcast || null\n } catch (error) {\n req.payload.logger.error({ error: String(error) }, 'Failed to get broadcast config from settings')\n // Fall back to env var config on error\n return pluginConfig.providers?.broadcast || null\n }\n}","import type { Endpoint, PayloadHandler, PayloadRequest } from 'payload'\nimport type { NewsletterPluginConfig, SendBroadcastOptions } from '../../types'\nimport { NewsletterProviderError, NewsletterStatus } from '../../types'\nimport { requireAdmin } from '../../utils/auth'\nimport { getBroadcastConfig } from '../../utils/getBroadcastConfig'\n\nexport const createSendBroadcastEndpoint = (\n config: NewsletterPluginConfig,\n collectionSlug: string\n): Endpoint => {\n return {\n path: '/:id/send',\n method: 'post',\n handler: (async (req: PayloadRequest) => {\n try {\n // Check authentication\n const auth = await requireAdmin(req, config)\n if (!auth.authorized) {\n return Response.json({\n success: false,\n error: auth.error,\n }, { status: 401 })\n }\n\n // Check if broadcast management is enabled\n if (!config.features?.newsletterManagement?.enabled) {\n return Response.json({\n success: false,\n error: 'Broadcast management is not enabled',\n }, { status: 400 })\n }\n\n // Get ID from URL\n const url = new URL(req.url || '', `http://localhost`)\n const pathParts = url.pathname.split('/')\n const id = pathParts[pathParts.length - 2] // -2 because last part is 'send'\n\n if (!id) {\n return Response.json({\n success: false,\n error: 'Broadcast ID is required',\n }, { status: 400 })\n }\n\n // Parse request body\n const data = await (req.json?.() || Promise.resolve({})) as SendBroadcastOptions\n\n // Get the broadcast document\n const broadcastDoc = await req.payload.findByID({\n collection: collectionSlug,\n id,\n user: auth.user,\n })\n\n if (!broadcastDoc || !broadcastDoc.providerId) {\n return Response.json({\n success: false,\n error: 'Broadcast not found or not synced with provider',\n }, { status: 404 })\n }\n\n // Get provider config from settings first, then fall back to env vars\n const providerConfig = await getBroadcastConfig(req, config)\n if (!providerConfig || !providerConfig.token) {\n return Response.json({\n success: false,\n error: 'Broadcast provider not configured in Newsletter Settings or environment variables',\n }, { status: 500 })\n }\n\n const { BroadcastApiProvider } = await import('../../providers/broadcast/broadcast')\n const provider = new BroadcastApiProvider(providerConfig)\n\n // Send broadcast using provider ID\n const broadcast = await provider.send(broadcastDoc.providerId, data)\n\n // Update status in Payload collection\n await req.payload.update({\n collection: collectionSlug,\n id,\n data: {\n sendStatus: NewsletterStatus.SENDING,\n sentAt: new Date().toISOString(),\n },\n user: auth.user,\n })\n\n return Response.json({\n success: true,\n message: 'Broadcast sent successfully',\n broadcast,\n })\n } catch (error) {\n console.error('Failed to send broadcast:', error)\n \n if (error instanceof NewsletterProviderError) {\n return Response.json({\n success: false,\n error: error.message,\n code: error.code,\n }, { status: error.code === 'NOT_SUPPORTED' ? 501 : 500 })\n }\n\n return Response.json({\n success: false,\n error: 'Failed to send broadcast',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","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 { PayloadRequest } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { isAdmin } from './access'\n\n/**\n * Get authenticated user from request\n * In Payload v3, authentication is handled differently than v2\n */\nexport async function getAuthenticatedUser(req: PayloadRequest): Promise<any | null> {\n try {\n // Try to get the current user using Payload's auth\n // This requires the request to have proper authentication headers/cookies\n const me = await req.payload.find({\n collection: 'users',\n where: {\n id: {\n equals: 'me', // Special value in Payload to get current user\n },\n },\n limit: 1,\n depth: 0,\n })\n \n return me.docs[0] || null\n } catch {\n return null\n }\n}\n\n/**\n * Check if request has admin access\n */\nexport async function requireAdmin(\n req: PayloadRequest,\n config: NewsletterPluginConfig\n): Promise<{ authorized: true; user: any } | { authorized: false; error: string }> {\n const user = await getAuthenticatedUser(req)\n \n if (!user) {\n return {\n authorized: false,\n error: 'Authentication required',\n }\n }\n \n if (!isAdmin(user, config)) {\n return {\n authorized: false,\n error: 'Admin access required',\n }\n }\n \n return {\n authorized: true,\n user,\n }\n}","import type { Endpoint, PayloadHandler, PayloadRequest } from 'payload'\nimport type { NewsletterPluginConfig } from '../../types'\nimport { NewsletterProviderError, NewsletterStatus } from '../../types'\nimport { requireAdmin } from '../../utils/auth'\n\nexport const createScheduleBroadcastEndpoint = (\n config: NewsletterPluginConfig,\n collectionSlug: string\n): Endpoint => {\n return {\n path: '/:id/schedule',\n method: 'post',\n handler: (async (req: PayloadRequest) => {\n try {\n // Check authentication\n const auth = await requireAdmin(req, config)\n if (!auth.authorized) {\n return Response.json({\n success: false,\n error: auth.error,\n }, { status: 401 })\n }\n\n // Check if broadcast management is enabled\n if (!config.features?.newsletterManagement?.enabled) {\n return Response.json({\n success: false,\n error: 'Broadcast management is not enabled',\n }, { status: 400 })\n }\n\n // Get ID from URL\n const url = new URL(req.url || '', `http://localhost`)\n const pathParts = url.pathname.split('/')\n const id = pathParts[pathParts.length - 2] // -2 because last part is 'schedule'\n\n if (!id) {\n return Response.json({\n success: false,\n error: 'Broadcast ID is required',\n }, { status: 400 })\n }\n\n // Parse request body\n const data = await (req.json?.() || Promise.resolve({}))\n const { scheduledAt } = data\n\n if (!scheduledAt) {\n return Response.json({\n success: false,\n error: 'scheduledAt is required',\n }, { status: 400 })\n }\n\n // Parse and validate date\n const scheduledDate = new Date(scheduledAt)\n if (isNaN(scheduledDate.getTime())) {\n return Response.json({\n success: false,\n error: 'Invalid scheduledAt date',\n }, { status: 400 })\n }\n\n // Ensure scheduled date is in the future\n if (scheduledDate <= new Date()) {\n return Response.json({\n success: false,\n error: 'scheduledAt must be in the future',\n }, { status: 400 })\n }\n\n // Get the broadcast document\n const broadcastDoc = await req.payload.findByID({\n collection: collectionSlug,\n id,\n user: auth.user,\n })\n\n if (!broadcastDoc || !broadcastDoc.providerId) {\n return Response.json({\n success: false,\n error: 'Broadcast not found or not synced with provider',\n }, { status: 404 })\n }\n\n // Get provider from config\n const providerConfig = config.providers?.broadcast\n if (!providerConfig) {\n return Response.json({\n success: false,\n error: 'Broadcast provider not configured',\n }, { status: 500 })\n }\n\n const { BroadcastApiProvider } = await import('../../providers/broadcast/broadcast')\n const provider = new BroadcastApiProvider(providerConfig)\n\n // Schedule broadcast using provider ID\n const broadcast = await provider.schedule(broadcastDoc.providerId, scheduledDate)\n\n // Update status in Payload collection\n await req.payload.update({\n collection: collectionSlug,\n id,\n data: {\n sendStatus: NewsletterStatus.SCHEDULED,\n scheduledAt: scheduledDate.toISOString(),\n },\n user: auth.user,\n })\n\n return Response.json({\n success: true,\n message: `Broadcast scheduled for ${scheduledDate.toISOString()}`,\n broadcast,\n })\n } catch (error) {\n console.error('Failed to schedule broadcast:', error)\n \n if (error instanceof NewsletterProviderError) {\n return Response.json({\n success: false,\n error: error.message,\n code: error.code,\n }, { status: error.code === 'NOT_SUPPORTED' ? 501 : 500 })\n }\n\n return Response.json({\n success: false,\n error: 'Failed to schedule broadcast',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint, PayloadHandler, PayloadRequest } from 'payload'\nimport type { NewsletterPluginConfig } from '../../types'\nimport { requireAdmin } from '../../utils/auth'\nimport { convertToEmailSafeHtml } from '../../utils/emailSafeHtml'\n\nexport const createTestBroadcastEndpoint = (\n config: NewsletterPluginConfig,\n collectionSlug: string\n): Endpoint => {\n return {\n path: '/:id/test',\n method: 'post',\n handler: (async (req: PayloadRequest) => {\n try {\n // Check authentication\n const auth = await requireAdmin(req, config)\n if (!auth.authorized) {\n return Response.json({\n success: false,\n error: auth.error,\n }, { status: 401 })\n }\n\n // Get ID from URL\n const url = new URL(req.url || '', `http://localhost`)\n const pathParts = url.pathname.split('/')\n const id = pathParts[pathParts.length - 2] // -2 because last part is 'test'\n\n if (!id) {\n return Response.json({\n success: false,\n error: 'Broadcast ID is required',\n }, { status: 400 })\n }\n\n // Parse request body for optional test email\n const data = await (req.json?.() || Promise.resolve({}))\n const testEmail = data.email || auth.user.email\n\n if (!testEmail) {\n return Response.json({\n success: false,\n error: 'No email address available for test send',\n }, { status: 400 })\n }\n\n // Get the broadcast document\n const broadcast = await req.payload.findByID({\n collection: collectionSlug,\n id,\n user: auth.user,\n })\n\n if (!broadcast) {\n return Response.json({\n success: false,\n error: 'Broadcast not found',\n }, { status: 404 })\n }\n\n // Convert content to email-safe HTML\n const htmlContent = await convertToEmailSafeHtml(broadcast.content, {\n wrapInTemplate: true,\n preheader: broadcast.preheader,\n customBlockConverter: config.customizations?.broadcasts?.customBlockConverter,\n })\n\n // Get email service\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const emailService = (req.payload as any).newsletterEmailService\n if (!emailService) {\n return Response.json({\n success: false,\n error: 'Email service is not configured',\n }, { status: 500 })\n }\n\n // Get sender info from provider config\n const providerConfig = config.providers.default === 'resend' \n ? config.providers.resend \n : config.providers.broadcast\n const fromEmail = providerConfig?.fromAddress || providerConfig?.fromEmail || 'noreply@example.com'\n const fromName = providerConfig?.fromName || 'Newsletter'\n const replyTo = broadcast.settings?.replyTo || providerConfig?.replyTo\n\n // Send test email\n await emailService.send({\n to: testEmail,\n from: fromEmail,\n fromName: fromName,\n replyTo: replyTo,\n subject: `[TEST] ${broadcast.subject}`,\n html: htmlContent,\n trackOpens: false,\n trackClicks: false,\n })\n\n return Response.json({\n success: true,\n message: `Test email sent to ${testEmail}`,\n })\n } catch (error) {\n console.error('Failed to send test broadcast:', error)\n \n return Response.json({\n success: false,\n error: 'Failed to send test email',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import type { Payload } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\n\n/**\n * Recursively populates media fields in Lexical content.\n * Resolves Media IDs to full media objects with URLs.\n *\n * @param content - Lexical editor state content\n * @param payload - Payload instance for database queries\n * @param config - Newsletter plugin configuration\n * @returns Populated content with resolved media objects\n */\nexport async function populateMediaFields(\n content: unknown,\n payload: Payload,\n config: NewsletterPluginConfig\n): Promise<unknown> {\n if (!content || typeof content !== 'object') return content\n\n const typedContent = content as { root?: { children?: unknown[] } }\n\n // Handle Lexical editor state\n if (typedContent.root?.children) {\n for (const child of typedContent.root.children) {\n await populateBlockMediaFields(child, payload, config)\n }\n }\n\n return content\n}\n\n/**\n * Populates media fields in individual block nodes.\n * Handles upload fields, arrays of uploads, and rich text fields.\n */\nasync function populateBlockMediaFields(\n node: unknown,\n payload: Payload,\n config: NewsletterPluginConfig\n): Promise<void> {\n if (!node || typeof node !== 'object') return\n\n const typedNode = node as {\n type?: string\n fields?: Record<string, unknown>\n children?: unknown[]\n }\n\n // Check if this is a block node\n if (typedNode.type === 'block' && typedNode.fields) {\n const blockType = (typedNode.fields.blockType || typedNode.fields.blockName) as string | undefined\n\n // Get custom blocks configuration\n const customBlocks = config.customizations?.broadcasts?.customBlocks || []\n const blockConfig = customBlocks.find((b: { slug: string }) => b.slug === blockType)\n\n if (blockConfig && blockConfig.fields) {\n // Find all upload fields in the block\n for (const field of blockConfig.fields) {\n if (field.type === 'upload' && field.relationTo && typedNode.fields[field.name]) {\n const fieldValue = typedNode.fields[field.name]\n const collectionName = Array.isArray(field.relationTo) ? field.relationTo[0] : field.relationTo\n\n // If it's just an ID string, populate it\n if (typeof fieldValue === 'string' && fieldValue.match(/^[a-f0-9]{24}$/i)) {\n try {\n const media = await payload.findByID({\n collection: collectionName,\n id: fieldValue,\n depth: 0,\n })\n\n if (media) {\n typedNode.fields[field.name] = media\n payload.logger?.info(\n {\n mediaId: fieldValue,\n mediaUrl: (media as { url?: string }).url,\n filename: (media as { filename?: string }).filename,\n },\n `Populated ${field.name} for block ${blockType}`\n )\n }\n } catch (error) {\n payload.logger?.error(\n { error: String(error) },\n `Failed to populate ${field.name} for block ${blockType}`\n )\n }\n }\n }\n\n // Also handle arrays of uploads\n if (field.type === 'array' && field.fields) {\n const arrayValue = typedNode.fields[field.name]\n if (Array.isArray(arrayValue)) {\n for (const arrayItem of arrayValue) {\n if (arrayItem && typeof arrayItem === 'object') {\n const typedArrayItem = arrayItem as Record<string, unknown>\n // Recursively process array items for upload fields\n for (const arrayField of field.fields) {\n if (\n arrayField.type === 'upload' &&\n arrayField.relationTo &&\n typedArrayItem[arrayField.name]\n ) {\n const arrayFieldValue = typedArrayItem[arrayField.name]\n const arrayCollectionName = Array.isArray(arrayField.relationTo)\n ? arrayField.relationTo[0]\n : arrayField.relationTo\n\n if (\n typeof arrayFieldValue === 'string' &&\n arrayFieldValue.match(/^[a-f0-9]{24}$/i)\n ) {\n try {\n const media = await payload.findByID({\n collection: arrayCollectionName,\n id: arrayFieldValue,\n depth: 0,\n })\n\n if (media) {\n typedArrayItem[arrayField.name] = media\n payload.logger?.info(\n {\n mediaId: arrayFieldValue,\n mediaUrl: (media as { url?: string }).url,\n filename: (media as { filename?: string }).filename,\n },\n `Populated array ${arrayField.name} for block ${blockType}`\n )\n }\n } catch (error) {\n payload.logger?.error(\n { error: String(error) },\n `Failed to populate array ${arrayField.name} for block ${blockType}`\n )\n }\n }\n }\n }\n }\n }\n }\n }\n\n // Also handle rich text fields\n if (field.type === 'richText' && typedNode.fields[field.name]) {\n await populateRichTextUploads(typedNode.fields[field.name], payload)\n payload.logger?.info(`Processed rich text field ${field.name} for upload nodes`)\n }\n }\n }\n }\n\n // Recursively process children\n if (typedNode.children) {\n for (const child of typedNode.children) {\n await populateBlockMediaFields(child, payload, config)\n }\n }\n}\n\n/**\n * Populates upload nodes within rich text content.\n * Resolves media IDs to full media objects.\n */\nasync function populateRichTextUploads(content: unknown, payload: Payload): Promise<void> {\n if (!content || typeof content !== 'object') return\n\n const typedContent = content as {\n root?: { children?: unknown[] }\n }\n\n // Handle Lexical root structure\n if (typedContent.root?.children) {\n await processNodeArray(typedContent.root.children)\n }\n\n // Handle direct children array\n if (Array.isArray(content)) {\n await processNodeArray(content)\n }\n\n async function processNodeArray(nodes: unknown[]): Promise<void> {\n await Promise.all(nodes.map(processNode))\n }\n\n async function processNode(node: unknown): Promise<void> {\n if (!node || typeof node !== 'object') return\n\n const typedNode = node as {\n type?: string\n relationTo?: string\n value?: unknown\n children?: unknown[]\n root?: { children?: unknown[] }\n }\n\n // Check if this is an upload node with unpopulated value\n if (\n typedNode.type === 'upload' &&\n typedNode.relationTo === 'media' &&\n typeof typedNode.value === 'string' &&\n typedNode.value.match(/^[a-f0-9]{24}$/i)\n ) {\n try {\n const media = await payload.findByID({\n collection: 'media',\n id: typedNode.value,\n depth: 0,\n })\n\n if (media) {\n typedNode.value = media\n payload.logger?.info(\n {\n mediaId: typedNode.value,\n mediaUrl: (media as { url?: string }).url,\n filename: (media as { filename?: string }).filename,\n },\n 'Populated rich text upload node'\n )\n }\n } catch (error) {\n payload.logger?.error(\n { error: String(error) },\n `Failed to populate rich text upload ${typedNode.value}`\n )\n }\n }\n\n // Recursively process children\n if (typedNode.children && Array.isArray(typedNode.children)) {\n await processNodeArray(typedNode.children)\n }\n\n // Also check for root property (some Lexical structures)\n if (typedNode.root?.children && Array.isArray(typedNode.root.children)) {\n await processNodeArray(typedNode.root.children)\n }\n }\n}\n","import type { Endpoint, PayloadHandler, PayloadRequest } from 'payload'\nimport type { SerializedEditorState } from 'lexical'\nimport type { NewsletterPluginConfig } from '../../types'\nimport { convertToEmailSafeHtml } from '../../utils/emailSafeHtml'\nimport { populateMediaFields } from '../../utils/mediaPopulation'\n\n// Re-export for backwards compatibility\nexport { populateMediaFields } from '../../utils/mediaPopulation'\n\nexport const createBroadcastPreviewEndpoint = (\n config: NewsletterPluginConfig,\n _collectionSlug: string\n): Endpoint => {\n return {\n path: '/preview',\n method: 'post',\n handler: (async (req: PayloadRequest) => {\n try {\n // Parse request body\n const data = await (req.json?.() || Promise.resolve({}))\n const { content, preheader, subject, documentData } = data\n\n if (!content) {\n return Response.json({\n success: false,\n error: 'Content is required for preview',\n }, { status: 400 })\n }\n\n // Get media URL from payload config or use default\n const mediaUrl = req.payload.config.serverURL \n ? `${req.payload.config.serverURL}/api/media`\n : '/api/media'\n\n // Populate media fields in custom blocks before conversion\n req.payload.logger?.info('Populating media fields for email preview...')\n const populatedContent = await populateMediaFields(content, req.payload, config)\n\n // Get email preview customization options\n const emailPreviewConfig = config.customizations?.broadcasts?.emailPreview\n \n // Convert content to email-safe HTML with customization options\n const htmlContent = await convertToEmailSafeHtml(populatedContent as SerializedEditorState | null, {\n wrapInTemplate: emailPreviewConfig?.wrapInTemplate ?? true,\n preheader: preheader,\n subject: subject,\n mediaUrl: mediaUrl,\n documentData, // Pass all document data\n customBlockConverter: config.customizations?.broadcasts?.customBlockConverter,\n customWrapper: emailPreviewConfig?.customWrapper,\n })\n\n return Response.json({\n success: true,\n html: htmlContent,\n preview: {\n subject: subject || 'Preview',\n preheader: preheader || '',\n html: htmlContent,\n },\n })\n } catch (error) {\n console.error('Failed to generate email preview:', error)\n \n return Response.json({\n success: false,\n error: 'Failed to generate email preview',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import { render } from '@react-email/render'\nimport { MagicLinkEmail } from './MagicLink'\nimport { WelcomeEmail } from './Welcome'\nimport { SignInEmail } from './SignIn'\nimport type { NewsletterPluginConfig } from '../types'\n\nexport type EmailTemplate = 'magic-link' | 'welcome' | 'signin'\n\nexport interface BaseEmailData {\n email?: string\n siteName?: string\n [key: string]: any\n}\n\nexport interface MagicLinkData extends BaseEmailData {\n magicLink?: string\n verificationUrl?: string\n magicLinkUrl?: string\n expiresIn?: string\n}\n\nexport interface WelcomeData extends BaseEmailData {\n preferencesUrl?: string\n}\n\nexport async function renderEmail(\n template: EmailTemplate, \n data: MagicLinkData | WelcomeData,\n config?: NewsletterPluginConfig\n): Promise<string> {\n try {\n // Check for custom templates if config provided\n if (config?.customTemplates) {\n const customTemplate = config.customTemplates[template]\n if (customTemplate) {\n const CustomComponent = customTemplate\n return render(<CustomComponent {...data} />)\n }\n }\n \n // Fall back to built-in templates\n switch (template) {\n case 'magic-link': {\n const magicLinkData = data as MagicLinkData\n return render(\n <MagicLinkEmail\n magicLink={\n magicLinkData.magicLink || \n magicLinkData.verificationUrl || \n magicLinkData.magicLinkUrl || \n ''\n }\n email={magicLinkData.email || ''}\n siteName={magicLinkData.siteName}\n expiresIn={magicLinkData.expiresIn}\n />\n )\n }\n \n case 'signin': {\n const signinData = data as MagicLinkData\n return render(\n <SignInEmail\n magicLink={\n signinData.magicLink || \n signinData.verificationUrl || \n signinData.magicLinkUrl || \n ''\n }\n email={signinData.email || ''}\n siteName={signinData.siteName}\n expiresIn={signinData.expiresIn}\n />\n )\n }\n \n case 'welcome': {\n const welcomeData = data as WelcomeData\n return render(\n <WelcomeEmail\n email={welcomeData.email || ''}\n siteName={welcomeData.siteName}\n preferencesUrl={welcomeData.preferencesUrl}\n />\n )\n }\n \n default:\n throw new Error(`Unknown email template: ${template}`)\n }\n } catch (error) {\n console.error(`Failed to render email template ${template}:`, error)\n throw error\n }\n}\n\n// Export for custom template rendering\nexport { MagicLinkEmail, WelcomeEmail, SignInEmail }","import React from 'react'\nimport {\n Body,\n Button,\n Container,\n Head,\n Hr,\n Html,\n Preview,\n Text,\n} from '@react-email/components'\nimport { styles } from './styles'\n\nexport interface MagicLinkEmailProps {\n magicLink: string\n email: string\n siteName?: string\n expiresIn?: string\n}\n\nexport const MagicLinkEmail: React.FC<MagicLinkEmailProps> = ({\n magicLink,\n email,\n siteName = 'Newsletter',\n expiresIn = '24 hours',\n}) => {\n const previewText = `Sign in to ${siteName}`\n \n return (\n <Html>\n <Head />\n <Preview>{previewText}</Preview>\n <Body style={styles.main}>\n <Container style={styles.container}>\n <Text style={styles.heading}>Sign in to {siteName}</Text>\n \n <Text style={styles.text}>\n Hi {email.split('@')[0]},\n </Text>\n \n <Text style={styles.text}>\n We received a request to sign in to your {siteName} account. \n Click the button below to complete your sign in:\n </Text>\n \n <Button href={magicLink} style={styles.button}>\n Sign in to {siteName}\n </Button>\n \n <Text style={styles.text}>\n Or copy and paste this URL into your browser:\n </Text>\n \n <code style={styles.code}>{magicLink}</code>\n \n <Hr style={styles.hr} />\n \n <Text style={styles.footer}>\n This link will expire in {expiresIn}. If you didn't request this email, \n you can safely ignore it.\n </Text>\n </Container>\n </Body>\n </Html>\n )\n}\n\nexport default MagicLinkEmail","export const styles = {\n main: {\n backgroundColor: '#f6f9fc',\n fontFamily:\n '-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,\"Helvetica Neue\",Ubuntu,sans-serif',\n },\n container: {\n backgroundColor: '#ffffff',\n border: '1px solid #f0f0f0',\n borderRadius: '5px',\n margin: '0 auto',\n padding: '45px',\n marginBottom: '64px',\n maxWidth: '500px',\n },\n heading: {\n fontSize: '24px',\n letterSpacing: '-0.5px',\n lineHeight: '1.3',\n fontWeight: '600',\n color: '#484848',\n margin: '0 0 20px',\n padding: '0',\n },\n text: {\n fontSize: '16px',\n lineHeight: '26px',\n fontWeight: '400',\n color: '#484848',\n margin: '16px 0',\n },\n button: {\n backgroundColor: '#000000',\n borderRadius: '5px',\n color: '#fff',\n fontSize: '16px',\n fontWeight: 'bold',\n textDecoration: 'none',\n textAlign: 'center' as const,\n display: 'block',\n width: '100%',\n padding: '14px 20px',\n margin: '30px 0',\n },\n link: {\n color: '#2754C5',\n fontSize: '14px',\n textDecoration: 'underline',\n wordBreak: 'break-all' as const,\n },\n hr: {\n borderColor: '#e6ebf1',\n margin: '30px 0',\n },\n footer: {\n fontSize: '14px',\n lineHeight: '24px',\n color: '#9ca2ac',\n textAlign: 'center' as const,\n margin: '0',\n },\n code: {\n display: 'inline-block',\n padding: '16px',\n width: '100%',\n backgroundColor: '#f4f4f4',\n borderRadius: '5px',\n border: '1px solid #eee',\n fontSize: '14px',\n fontFamily: 'monospace',\n textAlign: 'center' as const,\n margin: '24px 0',\n },\n}","import React from 'react'\nimport {\n Body,\n Button,\n Container,\n Head,\n Hr,\n Html,\n Preview,\n Text,\n} from '@react-email/components'\nimport { styles } from './styles'\n\nexport interface WelcomeEmailProps {\n email: string\n siteName?: string\n preferencesUrl?: string\n}\n\nexport const WelcomeEmail: React.FC<WelcomeEmailProps> = ({\n email,\n siteName = 'Newsletter',\n preferencesUrl,\n}) => {\n const previewText = `Welcome to ${siteName}!`\n const firstName = email.split('@')[0]\n \n return (\n <Html>\n <Head />\n <Preview>{previewText}</Preview>\n <Body style={styles.main}>\n <Container style={styles.container}>\n <Text style={styles.heading}>Welcome to {siteName}! 🎉</Text>\n \n <Text style={styles.text}>\n Hi {firstName},\n </Text>\n \n <Text style={styles.text}>\n Thanks for subscribing to {siteName}! We're excited to have you as part \n of our community.\n </Text>\n \n <Text style={styles.text}>\n You'll receive our newsletter based on your preferences. Speaking of which, \n you can update your preferences anytime:\n </Text>\n \n {preferencesUrl && (\n <Button href={preferencesUrl} style={styles.button}>\n Manage Preferences\n </Button>\n )}\n \n <Text style={styles.text}>\n Here's what you can expect from us:\n </Text>\n \n <Text style={styles.text}>\n • Regular updates based on your chosen frequency<br />\n • Content tailored to your interests<br />\n • Easy unsubscribe options in every email<br />\n • Your privacy respected always\n </Text>\n \n <Hr style={styles.hr} />\n \n <Text style={styles.footer}>\n If you have any questions, feel free to reply to this email. \n We're here to help!\n </Text>\n </Container>\n </Body>\n </Html>\n )\n}\n\nexport default WelcomeEmail","// SignIn is just an alias for MagicLink with slightly different defaults\nimport React from 'react'\nimport { MagicLinkEmail, MagicLinkEmailProps } from './MagicLink'\n\nexport const SignInEmail: React.FC<MagicLinkEmailProps> = (props) => {\n return <MagicLinkEmail {...props} />\n}\n\nexport default SignInEmail","import type { CollectionConfig, Field, CollectionAfterChangeHook, CollectionBeforeDeleteHook } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { adminOnly, adminOrSelf } from '../utils/access'\nimport { renderEmail } from '../emails/render'\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 // External ID for webhook integration\n {\n name: 'externalId',\n type: 'text',\n admin: {\n description: 'ID from email service provider',\n readOnly: true,\n },\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: 'subscribedAt',\n type: 'date',\n admin: {\n description: 'When the user subscribed',\n readOnly: true,\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 name: 'unsubscribeReason',\n type: 'text',\n admin: {\n condition: (data) => data?.subscriptionStatus === 'unsubscribed',\n description: 'Reason for unsubscribing',\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 // Import tracking\n {\n name: 'importedFromProvider',\n type: 'checkbox',\n defaultValue: false,\n admin: {\n description: 'Indicates this subscriber was imported from an external provider via webhook',\n position: 'sidebar',\n readOnly: true,\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 // TODO: Add proper type for newsletter email service\n console.log('[Newsletter Plugin] Creating subscriber:', {\n email: doc.email,\n hasEmailService: !!emailService\n })\n \n if (emailService) {\n try {\n await emailService.addContact(doc)\n console.log('[Newsletter Plugin] Successfully added contact to email service')\n } catch (error) {\n console.error('[Newsletter Plugin] Failed to add contact to email service:', error)\n }\n } else {\n console.warn('[Newsletter Plugin] No email service configured for subscriber creation')\n }\n\n // Send welcome email if active and not imported from provider\n if (doc.subscriptionStatus === 'active' && emailService && !doc.importedFromProvider) {\n try {\n // Get settings for site name\n const settings = await req.payload.findGlobal({\n slug: pluginConfig.settingsSlug || 'newsletter-settings',\n })\n \n // Render welcome email\n const serverURL = req.payload.config.serverURL || process.env.PAYLOAD_PUBLIC_SERVER_URL || ''\n const html = await renderEmail('welcome', {\n email: doc.email,\n siteName: settings?.brandSettings?.siteName || 'Newsletter',\n preferencesUrl: `${serverURL}/account/preferences`, // This could be customized\n }, pluginConfig)\n \n // Send email\n await emailService.send({\n to: doc.email,\n subject: settings?.brandSettings?.siteName ? `Welcome to ${settings.brandSettings.siteName}!` : 'Welcome!',\n html,\n })\n \n console.warn(`Welcome email sent to: ${doc.email}`)\n } catch (error) {\n console.error('Failed to send welcome email:', error)\n // Don't fail the subscription if welcome email fails\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 // TODO: Add proper type for newsletter email service\n \n if (doc.subscriptionStatus !== previousDoc.subscriptionStatus) {\n console.log('[Newsletter Plugin] Subscription status changed:', {\n email: doc.email,\n from: previousDoc.subscriptionStatus,\n to: doc.subscriptionStatus,\n hasEmailService: !!emailService\n })\n \n if (emailService) {\n try {\n await emailService.updateContact(doc)\n console.log('[Newsletter Plugin] Successfully updated contact in email service')\n } catch (error) {\n console.error('[Newsletter Plugin] Failed to update contact in email service:', error)\n }\n } else {\n console.warn('[Newsletter Plugin] No email service configured')\n }\n }\n\n // Handle resubscribe - send welcome email for user-initiated resubscriptions\n if (\n doc.subscriptionStatus === 'active' &&\n previousDoc.subscriptionStatus === 'unsubscribed' &&\n !doc.importedFromProvider &&\n emailService\n ) {\n try {\n // Get settings for site name\n const settings = await req.payload.findGlobal({\n slug: pluginConfig.settingsSlug || 'newsletter-settings',\n })\n \n // Render welcome email\n const serverURL = req.payload.config.serverURL || process.env.PAYLOAD_PUBLIC_SERVER_URL || ''\n const html = await renderEmail('welcome', {\n email: doc.email,\n siteName: settings?.brandSettings?.siteName || 'Newsletter',\n preferencesUrl: `${serverURL}/account/preferences`,\n }, pluginConfig)\n \n // Send email\n await emailService.send({\n to: doc.email,\n subject: settings?.brandSettings?.siteName ? `Welcome back to ${settings.brandSettings.siteName}!` : 'Welcome back!',\n html,\n })\n \n console.warn(`Welcome email sent to resubscribed user: ${doc.email}`)\n } catch (error) {\n console.error('Failed to send resubscription welcome email:', error)\n // Don't fail the resubscription if welcome email fails\n }\n \n // Call custom after subscribe hook for resubscriptions\n if (pluginConfig.hooks?.afterSubscribe) {\n await pluginConfig.hooks.afterSubscribe({ doc, req })\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 // TODO: Add proper type for newsletter email service\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}"],"mappings":"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","names":["init_broadcast","DOMPurify","styles","BroadcastApiProvider","BroadcastApiProvider","BroadcastApiProvider","import_components","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
|