payload-plugin-newsletter 0.19.0 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +55 -0
- package/README.md +97 -0
- package/dist/collections.cjs +11 -2
- package/dist/collections.cjs.map +1 -1
- package/dist/collections.js +11 -2
- package/dist/collections.js.map +1 -1
- package/dist/components.cjs +148 -125
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.cts +2 -0
- package/dist/components.d.ts +2 -0
- package/dist/components.js +85 -62
- package/dist/components.js.map +1 -1
- package/dist/index.cjs +35 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +32 -2
- package/dist/index.js.map +1 -1
- package/dist/types.d.cts +23 -0
- package/dist/types.d.ts +23 -0
- package/dist/utils.cjs +6 -0
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +5 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +6 -0
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
- package/ESM_FIX_SUMMARY.md +0 -74
package/dist/index.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/index.ts","../src/utils/access.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","../src/globals/NewsletterSettings.ts","../src/providers/resend.ts","../src/providers/types.ts","../src/providers/broadcast.ts","../src/providers/index.ts","../src/utils/validation.ts","../src/utils/jwt.ts","../src/endpoints/subscribe.ts","../src/endpoints/verify-magic-link.ts","../src/endpoints/preferences.ts","../src/endpoints/unsubscribe.ts","../src/utils/rate-limiter.ts","../src/endpoints/signin.ts","../src/endpoints/me.ts","../src/endpoints/signout.ts","../src/endpoints/broadcasts/index.ts","../src/endpoints/index.ts","../src/fields/newsletterScheduling.ts","../src/jobs/sync-unsubscribes.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/auth.ts","../src/endpoints/broadcasts/schedule.ts","../src/endpoints/broadcasts/test.ts","../src/endpoints/broadcasts/preview.ts","../src/providers/resend/broadcast.ts","../src/utilities/session.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// 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\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 afterUnsubscribeSync?: (args: AfterUnsubscribeSyncArgs) => 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 * Unsubscribe sync configuration\n */\n unsubscribeSync?: {\n /**\n * Enable sync of unsubscribes from email service to Payload\n * @default false\n */\n enabled?: boolean\n /**\n * Cron schedule for sync job (e.g., '0 * * * *' for hourly)\n * If not provided, job must be triggered manually\n */\n schedule?: string\n /**\n * Queue name for the sync job\n * @default 'newsletter-sync'\n */\n queue?: string\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 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\nexport interface AfterUnsubscribeSyncArgs {\n req: any\n syncedCount: number\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 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 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 result = await response.json()\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}","import type { Config } from 'payload'\nimport type { NewsletterPluginConfig, BroadcastProvider } from './types'\nimport { createSubscribersCollection } from './collections/Subscribers'\nimport { createNewsletterSettingsGlobal } from './globals/NewsletterSettings'\nimport { createEmailService } from './providers'\nimport { createNewsletterEndpoints } from './endpoints'\nimport { createNewsletterSchedulingFields } from './fields/newsletterScheduling'\nimport { createUnsubscribeSyncJob } from './jobs/sync-unsubscribes'\nimport { createBroadcastsCollection } from './collections/Broadcasts'\nimport { BroadcastApiProvider } from './providers/broadcast/broadcast'\nimport { ResendBroadcastProvider } from './providers/resend/broadcast'\n\n// Extend Payload type to include our email service and broadcast provider\ndeclare module 'payload' {\n interface BasePayload {\n newsletterEmailService?: any\n broadcastProvider?: BroadcastProvider\n // Legacy support\n newsletterProvider?: BroadcastProvider\n }\n}\n\nexport const newsletterPlugin = (pluginConfig: NewsletterPluginConfig) => (incomingConfig: Config): Config => {\n // Validate and set defaults\n const config: NewsletterPluginConfig = {\n enabled: true,\n subscribersSlug: 'subscribers',\n settingsSlug: 'newsletter-settings',\n auth: {\n enabled: true,\n tokenExpiration: '7d',\n magicLinkPath: '/newsletter/verify',\n ...pluginConfig.auth,\n },\n ...pluginConfig,\n }\n\n // If plugin is disabled, return config unchanged\n if (!config.enabled) {\n return incomingConfig\n }\n\n // Create plugin collections and globals\n const subscribersCollection = createSubscribersCollection(config)\n const settingsGlobal = createNewsletterSettingsGlobal(config)\n\n // Build collections array\n let collections = [...(incomingConfig.collections || []), subscribersCollection]\n\n // Add broadcast management collection if enabled\n if (config.features?.newsletterManagement?.enabled) {\n const broadcastsCollection = createBroadcastsCollection(config)\n collections.push(broadcastsCollection)\n }\n\n // Extend collections with newsletter scheduling fields if enabled\n if (config.features?.newsletterScheduling?.enabled) {\n const targetCollections = config.features.newsletterScheduling.collections || 'articles'\n const collectionsToExtend = Array.isArray(targetCollections) ? targetCollections : [targetCollections]\n const schedulingFields = createNewsletterSchedulingFields(config)\n \n collections = collections.map(collection => {\n if (collectionsToExtend.includes(collection.slug)) {\n return {\n ...collection,\n fields: [\n ...collection.fields,\n ...schedulingFields,\n ],\n }\n }\n return collection\n })\n }\n\n // Create API endpoints\n const endpoints = createNewsletterEndpoints(config)\n\n // Create sync job if enabled\n const syncJob = config.features?.unsubscribeSync?.enabled ? createUnsubscribeSyncJob(config) : null\n\n // Build the modified config\n const modifiedConfig: Config = {\n ...incomingConfig,\n collections,\n globals: [\n ...(incomingConfig.globals || []),\n settingsGlobal,\n ],\n endpoints: [\n ...(incomingConfig.endpoints || []),\n ...endpoints,\n ],\n jobs: syncJob ? {\n ...(incomingConfig.jobs || {}),\n tasks: [\n ...(incomingConfig.jobs?.tasks || []),\n syncJob,\n ],\n // Add cron schedule if specified\n autoRun: config.features?.unsubscribeSync?.schedule ? (\n Array.isArray(incomingConfig.jobs?.autoRun) \n ? [...incomingConfig.jobs.autoRun, {\n cron: config.features.unsubscribeSync.schedule,\n queue: 'newsletter-sync',\n limit: 100,\n }]\n : typeof incomingConfig.jobs?.autoRun === 'function'\n ? async (payload: any) => {\n const autoRunFn = incomingConfig.jobs!.autoRun as (payload: any) => any[] | Promise<any[]>\n const existingConfigs = await autoRunFn(payload)\n return [...existingConfigs, {\n cron: config.features!.unsubscribeSync!.schedule,\n queue: 'newsletter-sync',\n limit: 100,\n }]\n }\n : [{\n cron: config.features!.unsubscribeSync!.schedule,\n queue: 'newsletter-sync',\n limit: 100,\n }]\n ) : incomingConfig.jobs?.autoRun,\n } : incomingConfig.jobs,\n onInit: async (payload) => {\n // Initialize email service\n try {\n // Get settings from global\n const settings = await payload.findGlobal({\n slug: config.settingsSlug || 'newsletter-settings',\n })\n\n console.log('[Newsletter Plugin] Initializing with settings:', {\n hasSettings: !!settings,\n settingsProvider: settings?.provider,\n configProvider: config.providers?.default,\n hasBroadcastConfig: !!config.providers?.broadcast\n })\n\n let emailServiceConfig: any\n \n if (settings) {\n emailServiceConfig = {\n provider: settings.provider || config.providers.default,\n fromAddress: settings.fromAddress || config.providers.resend?.fromAddress || config.providers.broadcast?.fromAddress || 'noreply@example.com',\n fromName: settings.fromName || config.providers.resend?.fromName || config.providers.broadcast?.fromName || 'Newsletter',\n replyTo: settings.replyTo,\n resend: settings.provider === 'resend' ? {\n apiKey: settings.resendSettings?.apiKey || config.providers.resend?.apiKey || '',\n audienceIds: settings.resendSettings?.audienceIds?.reduce((acc: any, item: any) => {\n acc[item.locale] = {\n production: item.production,\n development: item.development,\n }\n return acc\n }, {}) || config.providers.resend?.audienceIds,\n } : config.providers.resend,\n broadcast: settings.provider === 'broadcast' ? {\n apiUrl: settings.broadcastSettings?.apiUrl || config.providers.broadcast?.apiUrl || '',\n token: settings.broadcastSettings?.token || config.providers.broadcast?.token || '',\n fromAddress: settings.fromAddress || config.providers.broadcast?.fromAddress,\n fromName: settings.fromName || config.providers.broadcast?.fromName,\n replyTo: settings.replyTo || config.providers.broadcast?.replyTo,\n } : config.providers.broadcast,\n }\n } else {\n // Use config defaults\n emailServiceConfig = {\n provider: config.providers.default,\n fromAddress: config.providers.resend?.fromAddress || config.providers.broadcast?.fromAddress || 'noreply@example.com',\n fromName: config.providers.resend?.fromName || config.providers.broadcast?.fromName || 'Newsletter',\n resend: config.providers.resend,\n broadcast: config.providers.broadcast,\n }\n }\n\n console.log('[Newsletter Plugin] Email service config:', {\n provider: emailServiceConfig.provider,\n hasBroadcastConfig: !!emailServiceConfig.broadcast,\n broadcastUrl: emailServiceConfig.broadcast?.apiUrl,\n hasToken: !!emailServiceConfig.broadcast?.token\n })\n\n try {\n const emailService = createEmailService(emailServiceConfig)\n ;(payload as any).newsletterEmailService = emailService\n\n console.log('[Newsletter Plugin] Email service initialized:', {\n provider: emailService.getProvider(),\n hasProvider: !!emailService,\n payloadHasService: !!(payload as any).newsletterEmailService\n })\n } catch (emailServiceError) {\n console.error('[Newsletter Plugin] Failed to create email service:', emailServiceError)\n console.error('[Newsletter Plugin] Email service config was:', emailServiceConfig)\n // Don't throw - let the plugin work without email service\n }\n \n // Initialize broadcast management provider if enabled\n if (config.features?.newsletterManagement?.enabled) {\n try {\n // Use custom provider if provided\n let broadcastProvider: BroadcastProvider\n \n if (config.features.newsletterManagement.provider) {\n broadcastProvider = config.features.newsletterManagement.provider\n } else {\n // Create provider based on email service config\n const providerType = emailServiceConfig.provider || config.providers.default\n \n if (providerType === 'broadcast' && emailServiceConfig.broadcast) {\n broadcastProvider = new BroadcastApiProvider(emailServiceConfig.broadcast)\n } else if (providerType === 'resend' && emailServiceConfig.resend) {\n broadcastProvider = new ResendBroadcastProvider(emailServiceConfig.resend)\n } else {\n throw new Error(`Unsupported broadcast provider: ${providerType}`)\n }\n }\n \n // Attach broadcast provider to payload instance\n const payloadWithProvider = payload as any\n payloadWithProvider.broadcastProvider = broadcastProvider\n // Legacy support\n payloadWithProvider.newsletterProvider = broadcastProvider\n \n console.warn('Broadcast management initialized with', broadcastProvider.name, 'provider')\n } catch (error) {\n console.error('Failed to initialize broadcast management provider:', error)\n }\n }\n } catch (error) {\n console.error('Failed to initialize newsletter email service:', error)\n }\n\n // Call original onInit if it exists\n if (incomingConfig.onInit) {\n await incomingConfig.onInit(payload)\n }\n },\n }\n\n return modifiedConfig\n}\n\nexport { newsletterPlugin as default }\n\n// Export session utilities\nexport * from './utilities/session'","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 { 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 // Subscription status\n {\n name: 'subscriptionStatus',\n type: 'select',\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Unsubscribed', value: 'unsubscribed' },\n { label: 'Pending', value: 'pending' },\n ],\n defaultValue: 'pending',\n required: true,\n admin: {\n description: 'Current subscription status',\n },\n },\n {\n name: 'unsubscribedAt',\n type: 'date',\n admin: {\n condition: (data) => data?.subscriptionStatus === 'unsubscribed',\n description: 'When the user unsubscribed',\n readOnly: true,\n },\n },\n \n // Email preferences\n {\n name: 'emailPreferences',\n type: 'group',\n fields: [\n {\n name: 'newsletter',\n type: 'checkbox',\n defaultValue: true,\n label: 'Newsletter',\n admin: {\n description: 'Receive regular newsletter updates',\n },\n },\n {\n name: 'announcements',\n type: 'checkbox',\n defaultValue: true,\n label: 'Announcements',\n admin: {\n description: 'Receive important announcements',\n },\n },\n ],\n admin: {\n description: 'Email communication preferences',\n },\n },\n \n // Source tracking\n {\n name: 'source',\n type: 'text',\n admin: {\n description: 'Where the subscriber signed up from',\n },\n },\n ]\n\n // Add UTM tracking fields if enabled\n if (pluginConfig.features?.utmTracking?.enabled) {\n const utmFields = pluginConfig.features.utmTracking.fields || [\n 'source',\n 'medium',\n 'campaign',\n 'content',\n 'term',\n ]\n \n defaultFields.push({\n name: 'utmParameters',\n type: 'group',\n fields: utmFields.map(field => ({\n name: field,\n type: 'text',\n admin: {\n description: `UTM ${field} parameter`,\n },\n })),\n admin: {\n description: 'UTM tracking parameters',\n },\n })\n }\n\n // Add signup metadata\n defaultFields.push({\n name: 'signupMetadata',\n type: 'group',\n fields: [\n {\n name: 'ipAddress',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'userAgent',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'referrer',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'signupPage',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n ],\n admin: {\n description: 'Technical information about signup',\n },\n })\n\n // Add lead magnet field if enabled\n if (pluginConfig.features?.leadMagnets?.enabled) {\n defaultFields.push({\n name: 'leadMagnet',\n type: 'relationship',\n relationTo: pluginConfig.features.leadMagnets.collection || 'media',\n admin: {\n description: 'Lead magnet downloaded at signup',\n },\n })\n }\n\n // Allow field customization\n let fields = defaultFields\n if (pluginConfig.fields?.overrides) {\n fields = pluginConfig.fields.overrides({ defaultFields })\n }\n if (pluginConfig.fields?.additional) {\n fields = [...fields, ...pluginConfig.fields.additional]\n }\n\n const subscribersCollection: CollectionConfig = {\n slug,\n labels: {\n singular: 'Subscriber',\n plural: 'Subscribers',\n },\n admin: {\n useAsTitle: 'email',\n defaultColumns: ['email', 'name', 'subscriptionStatus', 'createdAt'],\n group: 'Newsletter',\n },\n fields,\n hooks: {\n afterChange: [\n async ({ doc, req, operation, previousDoc }) => {\n // After create logic\n if (operation === 'create') {\n // Add to email service\n const emailService = (req.payload as any).newsletterEmailService // 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\n if (doc.subscriptionStatus === 'active' && emailService) {\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 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}","import type { GlobalConfig } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { adminOnly } from '../utils/access'\n\nexport const createNewsletterSettingsGlobal = (\n pluginConfig: NewsletterPluginConfig\n): GlobalConfig => {\n const slug = pluginConfig.settingsSlug || 'newsletter-settings'\n \n return {\n slug,\n label: 'Newsletter Settings',\n admin: {\n group: 'Newsletter',\n description: 'Configure email provider settings and templates',\n },\n fields: [\n {\n type: 'tabs',\n tabs: [\n {\n label: 'Provider Settings',\n fields: [\n {\n name: 'provider',\n type: 'select',\n label: 'Email Provider',\n required: true,\n options: [\n { label: 'Resend', value: 'resend' },\n { label: 'Broadcast (Self-Hosted)', value: 'broadcast' },\n ],\n defaultValue: pluginConfig.providers.default,\n admin: {\n description: 'Choose which email service to use',\n },\n },\n {\n name: 'resendSettings',\n type: 'group',\n label: 'Resend Settings',\n admin: {\n condition: (data) => data?.provider === 'resend',\n },\n fields: [\n {\n name: 'apiKey',\n type: 'text',\n label: 'API Key',\n required: true,\n admin: {\n description: 'Your Resend API key',\n },\n },\n {\n name: 'audienceIds',\n type: 'array',\n label: 'Audience IDs by Locale',\n fields: [\n {\n name: 'locale',\n type: 'select',\n label: 'Locale',\n required: true,\n options: pluginConfig.i18n?.locales?.map(locale => ({\n label: locale.toUpperCase(),\n value: locale,\n })) || [\n { label: 'EN', value: 'en' },\n ],\n },\n {\n name: 'production',\n type: 'text',\n label: 'Production Audience ID',\n },\n {\n name: 'development',\n type: 'text',\n label: 'Development Audience ID',\n },\n ],\n },\n ],\n },\n {\n name: 'broadcastSettings',\n type: 'group',\n label: 'Broadcast Settings',\n admin: {\n condition: (data) => data?.provider === 'broadcast',\n },\n fields: [\n {\n name: 'apiUrl',\n type: 'text',\n label: 'API URL',\n required: true,\n admin: {\n description: 'Your Broadcast instance URL',\n },\n },\n {\n name: 'token',\n type: 'text',\n label: 'API Token',\n required: true,\n admin: {\n description: 'Your Broadcast API token',\n },\n },\n ],\n },\n {\n name: 'fromAddress',\n type: 'email',\n label: 'From Address',\n required: true,\n admin: {\n description: 'Default sender email address',\n },\n },\n {\n name: 'fromName',\n type: 'text',\n label: 'From Name',\n required: true,\n admin: {\n description: 'Default sender name',\n },\n },\n {\n name: 'replyTo',\n type: 'email',\n label: 'Reply-To Address',\n admin: {\n description: 'Optional reply-to email address',\n },\n },\n ],\n },\n {\n label: 'Brand Settings',\n fields: [\n {\n name: 'brandSettings',\n type: 'group',\n label: 'Brand Settings',\n fields: [\n {\n name: 'siteName',\n type: 'text',\n label: 'Site Name',\n required: true,\n defaultValue: 'Newsletter',\n admin: {\n description: 'Your website or newsletter name',\n },\n },\n {\n name: 'siteUrl',\n type: 'text',\n label: 'Site URL',\n admin: {\n description: 'Your website URL (optional)',\n },\n },\n {\n name: 'logoUrl',\n type: 'text',\n label: 'Logo URL',\n admin: {\n description: 'URL to your logo image (optional)',\n },\n },\n ],\n },\n ],\n },\n {\n label: 'Email Templates',\n fields: [\n {\n name: 'emailTemplates',\n type: 'group',\n label: 'Email Templates',\n fields: [\n {\n name: 'welcome',\n type: 'group',\n label: 'Welcome Email',\n fields: [\n {\n name: 'enabled',\n type: 'checkbox',\n label: 'Send Welcome Email',\n defaultValue: true,\n },\n {\n name: 'subject',\n type: 'text',\n label: 'Subject Line',\n defaultValue: 'Welcome to {{fromName}}!',\n admin: {\n condition: (data) => data?.emailTemplates?.welcome?.enabled,\n },\n },\n {\n name: 'preheader',\n type: 'text',\n label: 'Preheader Text',\n admin: {\n condition: (data) => data?.emailTemplates?.welcome?.enabled,\n },\n },\n ],\n },\n {\n name: 'magicLink',\n type: 'group',\n label: 'Magic Link Email',\n fields: [\n {\n name: 'subject',\n type: 'text',\n label: 'Subject Line',\n defaultValue: 'Sign in to {{fromName}}',\n },\n {\n name: 'preheader',\n type: 'text',\n label: 'Preheader Text',\n defaultValue: 'Click the link to access your preferences',\n },\n {\n name: 'expirationTime',\n type: 'select',\n label: 'Link Expiration',\n defaultValue: '7d',\n options: [\n { label: '1 hour', value: '1h' },\n { label: '24 hours', value: '24h' },\n { label: '7 days', value: '7d' },\n { label: '30 days', value: '30d' },\n ],\n },\n ],\n },\n ],\n },\n ],\n },\n {\n label: 'Subscription Settings',\n fields: [\n {\n name: 'subscriptionSettings',\n type: 'group',\n label: 'Subscription Settings',\n fields: [\n {\n name: 'requireDoubleOptIn',\n type: 'checkbox',\n label: 'Require Double Opt-In',\n defaultValue: false,\n admin: {\n description: 'Require email confirmation before activating subscriptions',\n },\n },\n {\n name: 'allowedDomains',\n type: 'array',\n label: 'Allowed Email Domains',\n admin: {\n description: 'Leave empty to allow all domains',\n },\n fields: [\n {\n name: 'domain',\n type: 'text',\n label: 'Domain',\n required: true,\n admin: {\n placeholder: 'example.com',\n },\n },\n ],\n },\n {\n name: 'maxSubscribersPerIP',\n type: 'number',\n label: 'Max Subscribers per IP',\n defaultValue: 10,\n min: 1,\n admin: {\n description: 'Maximum number of subscriptions allowed from a single IP address',\n },\n },\n ],\n },\n ],\n },\n ],\n },\n ],\n hooks: {\n beforeChange: [\n async ({ data, req }) => {\n // Verify admin access for settings changes\n if (!req.user || req.user.collection !== 'users') {\n throw new Error('Only administrators can modify newsletter settings')\n }\n \n return data\n },\n ],\n afterChange: [\n async ({ doc, req }) => {\n // Reinitialize email service when settings change\n if ((req.payload as any).newsletterEmailService) {\n try {\n // TODO: Implement email service reinitialization\n console.warn('Newsletter settings updated, reinitializing service...')\n } catch {\n // Failed to reinitialize email service\n }\n }\n \n return doc\n },\n ],\n },\n access: {\n read: () => true, // Settings can be read publicly for validation\n update: adminOnly(pluginConfig),\n },\n }\n}","import { Resend } from 'resend'\nimport type { EmailProvider, SendEmailParams } from './types'\nimport { EmailProviderError } from './types'\nimport type { Subscriber, ResendProviderConfig } from '../types'\n\nexport class ResendProvider implements EmailProvider {\n private client: Resend\n private audienceIds: ResendProviderConfig['audienceIds']\n private fromAddress: string\n private fromName: string\n private isDevelopment: boolean\n\n constructor(config: ResendProviderConfig & { \n fromAddress: string\n fromName: string \n }) {\n this.client = new Resend(config.apiKey)\n this.audienceIds = config.audienceIds || {}\n this.fromAddress = config.fromAddress\n this.fromName = config.fromName\n this.isDevelopment = process.env.NODE_ENV !== 'production'\n }\n\n getProvider(): string {\n return 'resend'\n }\n\n async send(params: SendEmailParams): Promise<void> {\n try {\n const from = params.from || {\n email: this.fromAddress,\n name: this.fromName,\n }\n\n if (!params.html && !params.text) {\n throw new Error('Either html or text content is required')\n }\n\n await this.client.emails.send({\n from: `${from.name} <${from.email}>`,\n to: Array.isArray(params.to) ? params.to : [params.to],\n subject: params.subject,\n html: params.html || '',\n text: params.text,\n replyTo: params.replyTo,\n })\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to send email via Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n try {\n const audienceId = this.getAudienceId(contact.locale)\n if (!audienceId) {\n console.warn(`No audience ID configured for locale: ${contact.locale}`)\n return\n }\n\n await this.client.contacts.create({\n email: contact.email,\n firstName: contact.name?.split(' ')[0],\n lastName: contact.name?.split(' ').slice(1).join(' '),\n unsubscribed: contact.subscriptionStatus === 'unsubscribed',\n audienceId,\n })\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to add contact to Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n try {\n const audienceId = this.getAudienceId(contact.locale)\n if (!audienceId) {\n console.warn(`No audience ID configured for locale: ${contact.locale}`)\n return\n }\n\n // Resend requires finding the contact first\n const contacts = await this.client.contacts.list({ audienceId })\n const existingContact = contacts.data?.data?.find(c => c.email === contact.email)\n\n if (existingContact) {\n await this.client.contacts.update({\n id: existingContact.id,\n audienceId,\n firstName: contact.name?.split(' ')[0],\n lastName: contact.name?.split(' ').slice(1).join(' '),\n unsubscribed: contact.subscriptionStatus === 'unsubscribed',\n })\n } else {\n // If contact doesn't exist, add them\n await this.addContact(contact)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to update contact in Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async removeContact(email: string): Promise<void> {\n try {\n // Resend doesn't have a direct remove method, so we unsubscribe instead\n // First, we need to find the contact across all audiences\n for (const locale in this.audienceIds) {\n const audienceId = this.getAudienceId(locale)\n if (!audienceId) continue\n\n const contacts = await this.client.contacts.list({ audienceId })\n const contact = contacts.data?.data?.find(c => c.email === email)\n\n if (contact) {\n await this.client.contacts.update({\n id: contact.id,\n audienceId,\n unsubscribed: true,\n })\n break\n }\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to remove contact from Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n private getAudienceId(locale?: string): string | undefined {\n const localeKey = locale || 'en'\n if (!this.audienceIds) return undefined\n \n const localeConfig = this.audienceIds[localeKey]\n if (!localeConfig) return undefined\n\n const audienceId = this.isDevelopment \n ? (localeConfig.development || localeConfig.production)\n : (localeConfig.production || localeConfig.development)\n \n return audienceId\n }\n}","import type { Subscriber } from '../types'\n\nexport interface EmailProvider {\n send(params: SendEmailParams): Promise<void>\n addContact(contact: Subscriber): Promise<void>\n updateContact(contact: Subscriber): Promise<void>\n removeContact(email: string): Promise<void>\n getProvider(): string\n}\n\nexport interface SendEmailParams {\n to: string | string[]\n subject: string\n html?: string\n text?: string\n react?: React.ReactElement\n from?: {\n email: string\n name?: string\n }\n replyTo?: string\n}\n\nexport interface EmailServiceConfig {\n provider: 'resend' | 'broadcast' | string\n fromAddress: string\n fromName: string\n replyTo?: string\n resend?: {\n apiKey: string\n audienceIds?: Record<string, { production?: string; development?: string }>\n }\n broadcast?: {\n apiUrl: string\n token: string\n }\n}\n\nexport class EmailProviderError extends Error {\n provider: string\n originalError?: any\n\n constructor(message: string, provider: string, originalError?: any) {\n super(message)\n this.name = 'EmailProviderError'\n this.provider = provider\n this.originalError = originalError\n }\n}","import type { EmailProvider, SendEmailParams } from './types'\nimport { EmailProviderError } from './types'\nimport type { Subscriber, BroadcastProviderConfig } from '../types'\n\nexport class BroadcastProvider implements EmailProvider {\n private apiUrl: string\n private token: string\n private fromAddress: string\n private fromName: string\n private replyTo?: string\n\n constructor(config: BroadcastProviderConfig & { \n fromAddress: string\n fromName: string \n }) {\n this.apiUrl = config.apiUrl.replace(/\\/$/, '') // Remove trailing slash\n this.token = config.token\n this.fromAddress = config.fromAddress\n this.fromName = config.fromName\n this.replyTo = config.replyTo\n }\n\n getProvider(): string {\n return 'broadcast'\n }\n\n async send(params: SendEmailParams): Promise<void> {\n try {\n const from = params.from || {\n email: this.fromAddress,\n name: this.fromName,\n }\n\n const recipients = Array.isArray(params.to) ? params.to : [params.to]\n \n // Broadcast expects a specific format\n const response = await fetch(`${this.apiUrl}/api/v1/transactionals.json`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n to: recipients[0], // Broadcast API expects a single recipient for transactional emails\n from: `${from.name} <${from.email}>`, // Include from name and email\n subject: params.subject,\n body: params.html || params.text || '',\n reply_to: params.replyTo || this.replyTo || from.email,\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to send email via Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n try {\n const [firstName, ...lastNameParts] = (contact.name || '').split(' ')\n const lastName = lastNameParts.join(' ')\n\n const response = await fetch(`${this.apiUrl}/api/v1/subscribers.json`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n subscriber: {\n email: contact.email,\n first_name: firstName || undefined,\n last_name: lastName || undefined,\n tags: [`lang:${contact.locale || 'en'}`],\n is_active: contact.subscriptionStatus === 'active',\n source: contact.source,\n },\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to add contact to Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n try {\n // First, try to find the contact\n const searchResponse = await fetch(\n `${this.apiUrl}/api/v1/subscribers/find.json?email=${encodeURIComponent(contact.email)}`,\n {\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n },\n }\n )\n\n if (!searchResponse.ok) {\n // If contact doesn't exist, create it\n await this.addContact(contact)\n return\n }\n\n const existingContact = await searchResponse.json()\n\n if (!existingContact || !existingContact.id) {\n await this.addContact(contact)\n return\n }\n\n const [firstName, ...lastNameParts] = (contact.name || '').split(' ')\n const lastName = lastNameParts.join(' ')\n\n // Update existing contact\n // According to Broadcast docs, email should be at root level for identification\n const response = await fetch(`${this.apiUrl}/api/v1/subscribers.json`, {\n method: 'PATCH',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n email: contact.email, // Email at root level to identify the subscriber\n subscriber: {\n first_name: firstName || undefined,\n last_name: lastName || undefined,\n tags: [`lang:${contact.locale || 'en'}`],\n is_active: contact.subscriptionStatus === 'active',\n source: contact.source,\n },\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to update contact in Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async removeContact(email: string): Promise<void> {\n try {\n // First, find the contact\n const searchResponse = await fetch(\n `${this.apiUrl}/api/v1/subscribers/find.json?email=${encodeURIComponent(email)}`,\n {\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n },\n }\n )\n\n if (!searchResponse.ok) {\n // Contact doesn't exist, nothing to remove\n return\n }\n\n const contact = await searchResponse.json()\n\n if (!contact || !contact.id) {\n return\n }\n\n // Deactivate the contact\n const response = await fetch(`${this.apiUrl}/api/v1/subscribers/deactivate.json`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ email }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to remove contact from Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n}","import type { EmailProvider, EmailServiceConfig, SendEmailParams } from './types'\nimport type { Subscriber } from '../types'\nimport { ResendProvider } from './resend'\nimport { BroadcastProvider } from './broadcast'\n\nexport * from './types'\n\nexport class EmailService {\n private provider: EmailProvider\n\n constructor(config: EmailServiceConfig) {\n this.provider = this.createProvider(config)\n }\n\n private createProvider(config: EmailServiceConfig): EmailProvider {\n const baseConfig = {\n fromAddress: config.fromAddress,\n fromName: config.fromName,\n }\n\n switch (config.provider) {\n case 'resend':\n if (!config.resend) {\n throw new Error('Resend configuration is required when using Resend provider')\n }\n return new ResendProvider({\n ...config.resend,\n ...baseConfig,\n })\n\n case 'broadcast':\n if (!config.broadcast) {\n throw new Error('Broadcast configuration is required when using Broadcast provider')\n }\n return new BroadcastProvider({\n ...config.broadcast,\n ...baseConfig,\n })\n\n default:\n throw new Error(`Unknown email provider: ${config.provider}`)\n }\n }\n\n async send(params: SendEmailParams): Promise<void> {\n return this.provider.send(params)\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n return this.provider.addContact(contact)\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n return this.provider.updateContact(contact)\n }\n\n async removeContact(email: string): Promise<void> {\n return this.provider.removeContact(email)\n }\n\n getProvider(): string {\n return this.provider.getProvider()\n }\n\n /**\n * Update the provider configuration\n * Useful when settings are changed in the admin UI\n */\n updateConfig(config: EmailServiceConfig): void {\n this.provider = this.createProvider(config)\n }\n}\n\n/**\n * Create email service from plugin configuration\n */\nexport function createEmailService(config: EmailServiceConfig): EmailService {\n return new EmailService(config)\n}","import DOMPurify from 'isomorphic-dompurify'\n\n/**\n * Validate email address format\n */\nexport function isValidEmail(email: string): boolean {\n if (!email || typeof email !== 'string') return false\n \n // Trim whitespace\n const trimmed = email.trim()\n \n // Length limits\n if (trimmed.length > 255) return false\n \n // Check for dangerous patterns\n if (trimmed.includes('<') || trimmed.includes('>')) return false\n if (trimmed.includes('javascript:')) return false\n if (trimmed.includes('data:')) return false\n \n // Basic format validation with stricter regex\n const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/\n if (!emailRegex.test(trimmed)) return false\n \n // Additional validation rules\n const parts = trimmed.split('@')\n if (parts.length !== 2) return false\n \n const [localPart, domain] = parts\n \n // Check local part length\n if (localPart.length > 64 || localPart.length === 0) return false\n \n // Check for invalid patterns\n if (localPart.startsWith('.') || localPart.endsWith('.')) return false\n if (domain.startsWith('.') || domain.endsWith('.')) return false\n if (domain.includes('..')) return false\n if (localPart.includes('..')) return false\n \n return true\n}\n\n/**\n * Normalize email for rate limiting and deduplication\n */\nexport function normalizeEmail(email: string): string {\n if (!email || typeof email !== 'string') return ''\n \n const parts = email.toLowerCase().trim().split('@')\n if (parts.length !== 2) return email.toLowerCase().trim()\n \n let [localPart] = parts\n const [, domain] = parts\n \n // Remove dots from local part (Gmail-style)\n localPart = localPart.replace(/\\./g, '')\n \n // Remove everything after + (Gmail-style aliases)\n const plusIndex = localPart.indexOf('+')\n if (plusIndex > -1) {\n localPart = localPart.substring(0, plusIndex)\n }\n \n return `${localPart}@${domain}`\n}\n\n/**\n * Check if email domain is allowed\n */\nexport function isDomainAllowed(\n email: string,\n allowedDomains?: string[]\n): boolean {\n // Validate email format first\n if (!isValidEmail(email)) {\n return false\n }\n \n // If no domains specified, allow all valid emails\n if (!allowedDomains || allowedDomains.length === 0) {\n return true\n }\n\n const domain = email.split('@')[1]?.toLowerCase()\n if (!domain) return false\n\n return allowedDomains.some(\n allowedDomain => domain === allowedDomain.toLowerCase()\n )\n}\n\n/**\n * Sanitize user input to prevent XSS\n */\nexport function sanitizeInput(input: string): string {\n if (!input) return ''\n \n // First, remove all HTML tags and scripts\n let cleaned = DOMPurify.sanitize(input, { \n ALLOWED_TAGS: [],\n ALLOWED_ATTR: [],\n KEEP_CONTENT: true\n })\n \n // Additional security: remove dangerous patterns\n cleaned = cleaned\n .replace(/javascript:/gi, '')\n .replace(/data:/gi, '')\n .replace(/vbscript:/gi, '')\n .replace(/file:\\/\\//gi, '')\n .replace(/onload/gi, '')\n .replace(/onerror/gi, '')\n .replace(/onclick/gi, '')\n .replace(/onmouseover/gi, '')\n .replace(/alert\\(/gi, '')\n .replace(/prompt\\(/gi, '')\n .replace(/confirm\\(/gi, '')\n .replace(/\\|/g, '') // Remove pipe character (command injection)\n .replace(/;/g, '') // Remove semicolon (command chaining)\n .replace(/`/g, '') // Remove backticks (command substitution)\n .replace(/&&/g, '') // Remove command chaining\n .replace(/\\$\\(/g, '') // Remove command substitution pattern $()\n .replace(/\\.\\./g, '') // Remove directory traversal\n .replace(/\\/..\\//g, '') // Remove path traversal\n .replace(/\\0/g, '') // Remove null bytes\n \n return cleaned.trim()\n}\n\n/**\n * Extract UTM parameters from URL search params\n */\nexport function extractUTMParams(searchParams: URLSearchParams): Record<string, string> {\n const utmParams: Record<string, string> = {}\n const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']\n\n utmKeys.forEach(key => {\n const value = searchParams.get(key)\n if (value) {\n // Remove 'utm_' prefix for storage\n const shortKey = key.replace('utm_', '')\n utmParams[shortKey] = value\n }\n })\n\n return utmParams\n}\n\n/**\n * Validate source field - only allow predefined values\n */\nexport function isValidSource(source: string): boolean {\n if (!source || typeof source !== 'string') return false\n \n const allowedSources = [\n 'website',\n 'api',\n 'import',\n 'admin',\n 'signup-form',\n 'magic-link',\n 'preferences',\n 'external'\n ]\n \n return allowedSources.includes(source)\n}\n\n/**\n * Validate subscriber data before creation\n */\nexport interface ValidateSubscriberResult {\n valid: boolean\n errors: string[]\n}\n\nexport function validateSubscriberData(data: any): ValidateSubscriberResult {\n const errors: string[] = []\n\n // Email validation\n if (!data.email) {\n errors.push('Email is required')\n } else if (!isValidEmail(data.email)) {\n errors.push('Invalid email format')\n }\n\n // Name validation (optional but if provided, should be reasonable)\n if (data.name && data.name.length > 100) {\n errors.push('Name is too long (max 100 characters)')\n }\n\n // Source validation\n if (data.source !== undefined) {\n if (!data.source || data.source.length === 0) {\n errors.push('Source cannot be empty')\n } else if (data.source.length > 50) {\n errors.push('Source is too long (max 50 characters)')\n } else if (!isValidSource(data.source)) {\n errors.push('Invalid source value')\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n }\n}","import jwt from 'jsonwebtoken'\nimport type { NewsletterPluginConfig } from '../types'\n\nexport interface MagicLinkTokenPayload {\n subscriberId: string\n email: string\n type: 'magic-link'\n}\n\nexport interface SessionTokenPayload {\n subscriberId: string\n email: string\n type: 'session'\n}\n\n/**\n * Get JWT secret from environment or generate a warning\n */\nfunction getJWTSecret(): string {\n const secret = process.env.JWT_SECRET || process.env.PAYLOAD_SECRET\n\n if (!secret) {\n console.warn(\n 'WARNING: No JWT_SECRET or PAYLOAD_SECRET found in environment variables. ' +\n 'Magic link authentication will not work properly. ' +\n 'Please set JWT_SECRET in your environment.'\n )\n // Return a placeholder to prevent crashes during development\n return 'INSECURE_DEVELOPMENT_SECRET_PLEASE_SET_JWT_SECRET'\n }\n\n return secret\n}\n\n/**\n * Generate a magic link token for email authentication\n */\nexport function generateMagicLinkToken(\n subscriberId: string,\n email: string,\n config: NewsletterPluginConfig\n): string {\n const payload: MagicLinkTokenPayload = {\n subscriberId,\n email,\n type: 'magic-link',\n }\n\n const expiresIn = config.auth?.tokenExpiration || '7d'\n\n return jwt.sign(payload, getJWTSecret(), {\n expiresIn: expiresIn,\n issuer: 'payload-newsletter-plugin',\n } as jwt.SignOptions)\n}\n\n/**\n * Verify a magic link token\n */\nexport function verifyMagicLinkToken(token: string): MagicLinkTokenPayload {\n try {\n const payload = jwt.verify(token, getJWTSecret(), {\n issuer: 'payload-newsletter-plugin',\n }) as any\n\n if (payload.type !== 'magic-link') {\n throw new Error('Invalid token type')\n }\n\n return payload as MagicLinkTokenPayload\n } catch (error: unknown) {\n if (error instanceof Error && error.name === 'TokenExpiredError') {\n throw new Error('Magic link has expired. Please request a new one.')\n }\n if (error instanceof Error && error.name === 'JsonWebTokenError') {\n throw new Error('Invalid magic link token')\n }\n throw error\n }\n}\n\n/**\n * Generate a session token after successful magic link verification\n */\nexport function generateSessionToken(\n subscriberId: string,\n email: string\n): string {\n const payload: SessionTokenPayload = {\n subscriberId,\n email,\n type: 'session',\n }\n\n return jwt.sign(payload, getJWTSecret(), {\n expiresIn: '30d',\n issuer: 'payload-newsletter-plugin',\n })\n}\n\n/**\n * Verify a session token\n */\nexport function verifySessionToken(token: string): SessionTokenPayload {\n try {\n const payload = jwt.verify(token, getJWTSecret(), {\n issuer: 'payload-newsletter-plugin',\n }) as any\n\n if (payload.type !== 'session') {\n throw new Error('Invalid token type')\n }\n\n return payload as SessionTokenPayload\n } catch (error: unknown) {\n if (error instanceof Error && error.name === 'TokenExpiredError') {\n throw new Error('Session has expired. Please sign in again.')\n }\n if (error instanceof Error && error.name === 'JsonWebTokenError') {\n throw new Error('Invalid session token')\n }\n throw error\n }\n}\n\n/**\n * Generate a magic link URL\n */\nexport function generateMagicLinkURL(\n token: string,\n baseURL: string,\n config: NewsletterPluginConfig,\n redirectUrl?: string\n): string {\n const path = config.auth?.magicLinkPath || '/newsletter/verify'\n const url = new URL(path, baseURL)\n url.searchParams.set('token', token)\n if (redirectUrl) {\n url.searchParams.set('redirect', redirectUrl)\n }\n return url.toString()\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig, Subscriber, SubscribeRequestData, ExtendedPayloadRequest } from '../types'\nimport { \n isDomainAllowed, \n sanitizeInput, \n validateSubscriberData,\n extractUTMParams \n} from '../utils/validation'\nimport { generateMagicLinkToken, generateMagicLinkURL } from '../utils/jwt'\nimport { renderEmail } from '../emails/render'\n\nexport const createSubscribeEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/subscribe',\n method: 'post',\n handler: (async (req: ExtendedPayloadRequest) => {\n try {\n const data = await req.json()\n const { \n email, \n name, \n source,\n preferences,\n leadMagnet,\n surveyResponses,\n metadata = {}\n } = data as SubscribeRequestData\n\n // Trim email before validation\n const trimmedEmail = email?.trim()\n\n // Validate input\n const validation = validateSubscriberData({ email: trimmedEmail, name, source })\n if (!validation.valid) {\n return Response.json({\n success: false,\n errors: validation.errors,\n }, { status: 400 })\n }\n\n // Check domain restrictions from global settings\n // Settings are public info needed for validation, but we can still respect access control\n const settings = await req.payload.findGlobal({\n slug: config.settingsSlug || 'newsletter-settings',\n overrideAccess: false,\n // No user context for public endpoint\n })\n\n const allowedDomains = settings?.subscriptionSettings?.allowedDomains?.map((d: { domain: string }) => d.domain) || []\n if (!isDomainAllowed(trimmedEmail, allowedDomains)) {\n return Response.json({\n success: false,\n error: 'Email domain not allowed',\n }, { status: 400 })\n }\n\n // Check if already subscribed\n // This needs admin access to check for existing email\n const existing = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n email: {\n equals: trimmedEmail.toLowerCase(),\n },\n },\n overrideAccess: true, // Need to check for duplicates in public endpoint\n })\n\n if (existing.docs.length > 0) {\n const subscriber = existing.docs[0]\n \n // Handle unsubscribed users\n if (subscriber.subscriptionStatus === 'unsubscribed') {\n const allowResubscribe = config.auth?.allowResubscribe ?? false\n \n if (!allowResubscribe) {\n return Response.json({\n success: false,\n error: 'This email has been unsubscribed. Please contact support to resubscribe.',\n }, { status: 400 })\n }\n \n // Resubscribe the user\n const updated = await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: subscriber.id,\n data: {\n subscriptionStatus: 'active',\n resubscribedAt: new Date().toISOString(),\n // Preserve preferences but update metadata\n signupMetadata: {\n ...metadata,\n source: source || 'resubscribe',\n resubscribedFrom: subscriber.signupMetadata?.source,\n },\n },\n overrideAccess: true,\n })\n \n // Fire afterSubscribe hook for resubscription\n if (config.hooks?.afterSubscribe) {\n await config.hooks.afterSubscribe({\n doc: updated,\n req,\n })\n }\n \n // Send welcome back email\n const emailService = (req.payload as any).newsletterEmailService\n if (emailService) {\n const settings = await req.payload.findGlobal({\n slug: config.settingsSlug || 'newsletter-settings',\n })\n \n const html = await renderEmail('welcome', {\n name: updated.name || '',\n email: updated.email,\n siteName: settings?.brandSettings?.siteName || 'Newsletter',\n siteUrl: req.payload.config.serverURL || '',\n }, config)\n \n await emailService.send({\n to: updated.email,\n subject: `Welcome back to ${settings?.brandSettings?.siteName || 'our newsletter'}!`,\n html,\n })\n }\n \n return Response.json({\n success: true,\n message: 'Welcome back! You have been resubscribed.',\n subscriber: {\n id: updated.id,\n email: updated.email,\n subscriptionStatus: updated.subscriptionStatus,\n },\n wasResubscribed: true,\n })\n }\n \n // Already active subscriber - send sign-in link instead\n if (subscriber.subscriptionStatus === 'active') {\n // Generate magic link for signin\n const token = generateMagicLinkToken(\n String(subscriber.id),\n subscriber.email,\n config\n )\n \n const serverURL = req.payload.config.serverURL || process.env.PAYLOAD_PUBLIC_SERVER_URL || ''\n const magicLinkURL = generateMagicLinkURL(token, serverURL, config)\n \n // Send signin email\n const emailService = (req.payload as any).newsletterEmailService\n if (emailService) {\n const settings = await req.payload.findGlobal({\n slug: config.settingsSlug || 'newsletter-settings',\n })\n \n const html = await renderEmail('signin', {\n magicLink: magicLinkURL,\n email: subscriber.email,\n siteName: settings?.brandSettings?.siteName || 'Newsletter',\n expiresIn: config.auth?.tokenExpiration || '7d',\n }, config)\n \n await emailService.send({\n to: subscriber.email,\n subject: `Sign in to ${settings?.brandSettings?.siteName || 'your account'}`,\n html,\n })\n }\n \n return Response.json({\n success: true,\n message: 'You are already subscribed! Check your email for a sign-in link.',\n alreadySubscribed: true,\n })\n }\n }\n\n // Check IP rate limiting\n const ipAddress = req.ip || req.connection?.remoteAddress\n const maxPerIP = settings?.subscriptionSettings?.maxSubscribersPerIP || 10\n\n const ipSubscribers = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n 'signupMetadata.ipAddress': {\n equals: ipAddress,\n },\n },\n overrideAccess: true, // Need to check IP limits in public endpoint\n })\n\n if (ipSubscribers.docs.length >= maxPerIP) {\n return Response.json({\n success: false,\n error: 'Too many subscriptions from this IP address',\n }, { status: 429 })\n }\n\n // Extract UTM parameters\n const referer = req.headers.get('referer') || req.headers.get('referrer') || ''\n let utmParams = {}\n if (referer) {\n try {\n utmParams = extractUTMParams(new URL(referer).searchParams)\n } catch {\n // Invalid URL, ignore UTM params\n }\n }\n\n // Prepare subscriber data\n const subscriberData: Partial<Subscriber> = {\n email: trimmedEmail.toLowerCase(),\n name: name ? sanitizeInput(name) : undefined,\n locale: metadata.locale || config.i18n?.defaultLocale || 'en',\n subscriptionStatus: settings?.subscriptionSettings?.requireDoubleOptIn ? 'pending' : 'active',\n source: source || 'api',\n emailPreferences: {\n newsletter: true,\n announcements: true,\n ...(preferences || {}),\n },\n signupMetadata: {\n ipAddress,\n userAgent: req.headers.get('user-agent') || undefined,\n referrer: referer,\n signupPage: metadata.signupPage || referer,\n },\n }\n\n // Add UTM parameters if tracking is enabled\n if (config.features?.utmTracking?.enabled && Object.keys(utmParams).length > 0) {\n subscriberData.utmParameters = utmParams\n }\n\n // Add lead magnet if provided\n if (config.features?.leadMagnets?.enabled && leadMagnet) {\n subscriberData.leadMagnet = leadMagnet\n }\n\n // Create subscriber\n // Public endpoint needs to create subscribers\n const subscriber = await req.payload.create({\n collection: config.subscribersSlug || 'subscribers',\n data: subscriberData,\n overrideAccess: true, // Public endpoint needs to create subscribers\n })\n\n // Handle survey responses if provided\n if (config.features?.surveys?.enabled && surveyResponses) {\n // TODO: Store survey responses\n }\n\n // Send confirmation email if double opt-in\n if (settings?.subscriptionSettings?.requireDoubleOptIn) {\n try {\n // Generate magic link token\n const token = generateMagicLinkToken(\n String(subscriber.id),\n subscriber.email,\n config\n )\n \n // Generate magic link URL\n const serverURL = req.payload.config.serverURL || process.env.PAYLOAD_PUBLIC_SERVER_URL || ''\n const magicLinkURL = generateMagicLinkURL(token, serverURL, config)\n \n // Get email service\n const emailService = (req.payload as any).newsletterEmailService // TODO: Add proper type for newsletter email service\n \n if (emailService) {\n // Render email\n const html = await renderEmail('magic-link', {\n magicLink: magicLinkURL,\n email: subscriber.email,\n siteName: settings?.brandSettings?.siteName || 'Newsletter',\n expiresIn: config.auth?.tokenExpiration || '7d',\n }, config)\n \n // Send email\n await emailService.send({\n to: subscriber.email,\n subject: settings?.brandSettings?.siteName ? `Verify your email for ${settings.brandSettings.siteName}` : 'Verify your email',\n html,\n })\n \n // Magic link email sent successfully\n } else {\n console.warn('Email service not initialized, cannot send magic link')\n }\n } catch (error) {\n console.error('Failed to send magic link email:', error)\n // Don't fail the subscription if email fails\n }\n }\n\n return Response.json({\n success: true,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n message: settings?.subscriptionSettings?.requireDoubleOptIn \n ? 'Please check your email to confirm your subscription'\n : 'Successfully subscribed',\n })\n } catch {\n return Response.json({\n success: false,\n error: 'Failed to subscribe. Please try again.',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig, VerifyMagicLinkRequestData, ExtendedPayloadRequest } from '../types'\nimport { \n verifyMagicLinkToken, \n generateSessionToken \n} from '../utils/jwt'\nimport { renderEmail } from '../emails/render'\n\nexport const createVerifyMagicLinkEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/verify-magic-link',\n method: 'post',\n handler: (async (req: ExtendedPayloadRequest) => {\n try {\n const data = await req.json()\n const { token } = data as VerifyMagicLinkRequestData\n\n if (!token) {\n return Response.json({\n success: false,\n error: 'Token is required',\n }, { status: 400 })\n }\n\n // Verify the magic link token\n let payload\n try {\n payload = verifyMagicLinkToken(token)\n } catch (error: unknown) {\n return Response.json({\n success: false,\n error: error instanceof Error ? error.message : 'Invalid token',\n }, { status: 401 })\n }\n\n // Find the subscriber - token verified so we can use admin access for initial lookup\n const subscriber = await req.payload.findByID({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n // Keep overrideAccess: true for token verification\n })\n\n if (!subscriber) {\n return Response.json({\n success: false,\n error: 'Subscriber not found',\n }, { status: 404 })\n }\n\n // Check if email matches\n if (subscriber.email !== payload.email) {\n return Response.json({\n success: false,\n error: 'Invalid token',\n }, { status: 401 })\n }\n\n // Check if subscriber is active\n if (subscriber.subscriptionStatus === 'unsubscribed') {\n return Response.json({\n success: false,\n error: 'This email has been unsubscribed',\n }, { status: 403 })\n }\n\n // Create synthetic user for subscriber operations\n const syntheticUser = {\n collection: 'subscribers',\n id: subscriber.id,\n email: subscriber.email,\n }\n\n // Update subscription status if pending\n let isNewlyActivated = false\n if (subscriber.subscriptionStatus === 'pending') {\n await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: subscriber.id,\n data: {\n subscriptionStatus: 'active',\n },\n overrideAccess: false,\n user: syntheticUser,\n })\n isNewlyActivated = true\n }\n\n // Clear the magic link token\n await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: subscriber.id,\n data: {\n magicLinkToken: null,\n magicLinkTokenExpiry: null,\n },\n overrideAccess: false,\n user: syntheticUser,\n })\n\n // Generate session token\n const sessionToken = generateSessionToken(\n String(subscriber.id),\n subscriber.email\n )\n\n // Send welcome email if newly activated\n if (isNewlyActivated) {\n try {\n // Get email service\n const emailService = (req.payload as any).newsletterEmailService // TODO: Add proper type for newsletter email service\n \n if (emailService) {\n // Get settings for site name\n const settings = await req.payload.findGlobal({\n slug: config.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: subscriber.email,\n siteName: settings?.brandSettings?.siteName || 'Newsletter',\n preferencesUrl: `${serverURL}/account/preferences`, // This could be customized\n }, config)\n \n // Send email\n await emailService.send({\n to: subscriber.email,\n subject: settings?.brandSettings?.siteName ? `Welcome to ${settings.brandSettings.siteName}!` : 'Welcome!',\n html,\n })\n \n // Welcome email sent successfully\n } else {\n console.warn('Email service not initialized, cannot send welcome email')\n }\n } catch (error) {\n console.error('Failed to send welcome email:', error)\n // Don't fail the verification if welcome email fails\n }\n }\n\n // Set the session cookie\n const headers = new Headers()\n headers.append('Set-Cookie', `newsletter-auth=${sessionToken}; HttpOnly; Secure=${process.env.NODE_ENV === 'production'}; SameSite=Lax; Path=/; Max-Age=${30 * 24 * 60 * 60}`)\n\n return Response.json({\n success: true,\n sessionToken,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n name: subscriber.name,\n locale: subscriber.locale,\n emailPreferences: subscriber.emailPreferences,\n },\n }, { headers })\n } catch (error: unknown) {\n console.error('Verify magic link error:', error)\n return Response.json({\n success: false,\n error: 'Failed to verify magic link',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig, Subscriber, UpdatePreferencesRequestData, ExtendedPayloadRequest } from '../types'\nimport { verifySessionToken } from '../utils/jwt'\n\nexport const createPreferencesEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/preferences',\n method: 'get',\n handler: (async (req: ExtendedPayloadRequest) => {\n try {\n // Get token from Authorization header\n const authHeader = req.headers.get('authorization')\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n return Response.json({\n success: false,\n error: 'Authorization required',\n }, { status: 401 })\n }\n\n const token = authHeader.substring(7)\n\n // Verify session token\n let payload\n try {\n payload = verifySessionToken(token)\n } catch (error: unknown) {\n return Response.json({\n success: false,\n error: error instanceof Error ? error.message : 'Invalid token',\n }, { status: 401 })\n }\n\n // Get subscriber - use synthetic user to ensure access control\n const subscriber = await req.payload.findByID({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n overrideAccess: false,\n user: {\n collection: 'subscribers',\n id: payload.subscriberId,\n email: payload.email,\n },\n })\n\n if (!subscriber) {\n return Response.json({\n success: false,\n error: 'Subscriber not found',\n }, { status: 404 })\n }\n\n return Response.json({\n success: true,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n name: subscriber.name,\n locale: subscriber.locale,\n emailPreferences: subscriber.emailPreferences,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n })\n } catch (error: unknown) {\n console.error('Get preferences error:', error)\n return Response.json({\n success: false,\n error: 'Failed to get preferences',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}\n\nexport const createUpdatePreferencesEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/preferences',\n method: 'post',\n handler: (async (req: ExtendedPayloadRequest) => {\n try {\n // Get token from Authorization header\n const authHeader = req.headers.get('authorization')\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n return Response.json({\n success: false,\n error: 'Authorization required',\n }, { status: 401 })\n }\n\n const token = authHeader.substring(7)\n\n // Verify session token\n let payload\n try {\n payload = verifySessionToken(token)\n } catch (error: unknown) {\n return Response.json({\n success: false,\n error: error instanceof Error ? error.message : 'Invalid token',\n }, { status: 401 })\n }\n\n const data = await req.json()\n const { name, locale, emailPreferences } = data as UpdatePreferencesRequestData\n\n // Prepare update data\n const updateData: Partial<Subscriber> = {}\n \n if (name !== undefined) {\n updateData.name = name\n }\n \n if (locale !== undefined) {\n updateData.locale = locale\n }\n \n if (emailPreferences !== undefined) {\n updateData.emailPreferences = emailPreferences\n }\n\n // Update subscriber - use synthetic user to ensure only updating own data\n const subscriber = await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n data: updateData,\n overrideAccess: false,\n user: {\n collection: 'subscribers',\n id: payload.subscriberId,\n email: payload.email,\n },\n })\n\n return Response.json({\n success: true,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n name: subscriber.name,\n locale: subscriber.locale,\n emailPreferences: subscriber.emailPreferences,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n })\n } catch (error: unknown) {\n console.error('Update preferences error:', error)\n return Response.json({\n success: false,\n error: 'Failed to update preferences',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig, UnsubscribeRequestData, ExtendedPayloadRequest } from '../types'\nimport { isValidEmail } from '../utils/validation'\n\nexport const createUnsubscribeEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/unsubscribe',\n method: 'post',\n handler: (async (req: ExtendedPayloadRequest) => {\n try {\n const data = await req.json()\n const { email, token } = data as UnsubscribeRequestData\n\n // Two methods: email or token\n if (!email && !token) {\n return Response.json({\n success: false,\n error: 'Email or token is required',\n }, { status: 400 })\n }\n\n let subscriber\n\n if (token) {\n // Token-based unsubscribe (from email link)\n try {\n const jwt = await import('jsonwebtoken')\n const payload = jwt.verify(\n token,\n process.env.JWT_SECRET || process.env.PAYLOAD_SECRET || ''\n ) as { type: string; subscriberId: string; email: string }\n\n if (payload.type !== 'unsubscribe') {\n throw new Error('Invalid token type')\n }\n\n // Token verified, so we can look up the subscriber\n // Using overrideAccess: true here is OK since we verified the token\n subscriber = await req.payload.findByID({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n })\n } catch {\n return Response.json({\n success: false,\n error: 'Invalid or expired unsubscribe link',\n }, { status: 401 })\n }\n } else {\n // Email-based unsubscribe\n if (!email || !isValidEmail(email)) {\n return Response.json({\n success: false,\n error: 'Invalid email format',\n }, { status: 400 })\n }\n\n const result = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n email: {\n equals: email!.toLowerCase(),\n },\n },\n })\n\n if (result.docs.length === 0) {\n // Don't reveal if email exists or not\n return Response.json({\n success: true,\n message: 'If this email was subscribed, it has been unsubscribed.',\n })\n }\n\n subscriber = result.docs[0]\n }\n\n if (!subscriber) {\n return Response.json({\n success: true,\n message: 'If this email was subscribed, it has been unsubscribed.',\n })\n }\n\n // Check if already unsubscribed\n if (subscriber.subscriptionStatus === 'unsubscribed') {\n return Response.json({\n success: true,\n message: 'Already unsubscribed',\n })\n }\n\n // Update subscription status - use synthetic user to ensure proper access\n await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: subscriber.id,\n data: {\n subscriptionStatus: 'unsubscribed',\n unsubscribedAt: new Date().toISOString(),\n },\n overrideAccess: false,\n user: {\n collection: 'subscribers',\n id: subscriber.id,\n email: subscriber.email,\n },\n })\n\n return Response.json({\n success: true,\n message: 'Successfully unsubscribed',\n })\n } catch (error: unknown) {\n console.error('Unsubscribe error:', error)\n return Response.json({\n success: false,\n error: 'Failed to unsubscribe. Please try again.',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","export interface RateLimiterOptions {\n maxAttempts: number\n windowMs: number\n prefix?: string\n}\n\nexport class RateLimiter {\n private attempts: Map<string, { count: number; resetTime: number }> = new Map()\n private options: RateLimiterOptions\n\n constructor(options: RateLimiterOptions) {\n this.options = options\n }\n\n async checkLimit(key: string): Promise<boolean> {\n const now = Date.now()\n const record = this.attempts.get(key)\n\n if (!record || record.resetTime < now) {\n this.attempts.set(key, {\n count: 1,\n resetTime: now + this.options.windowMs\n })\n return true\n }\n\n if (record.count >= this.options.maxAttempts) {\n return false\n }\n\n record.count++\n return true\n }\n\n async incrementAttempt(key: string): Promise<void> {\n const now = Date.now()\n const record = this.attempts.get(key)\n\n if (!record || record.resetTime < now) {\n this.attempts.set(key, {\n count: 1,\n resetTime: now + this.options.windowMs\n })\n } else {\n record.count++\n }\n }\n\n async reset(key: string): Promise<void> {\n this.attempts.delete(key)\n }\n\n async resetAll(): Promise<void> {\n this.attempts.clear()\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig, SigninRequestData, ExtendedPayloadRequest } from '../types'\nimport { validateSubscriberData } from '../utils/validation'\nimport { generateMagicLinkToken, generateMagicLinkURL } from '../utils/jwt'\nimport { renderEmail } from '../emails/render'\nimport { RateLimiter } from '../utils/rate-limiter'\n\n// Create rate limiter: 5 attempts per 15 minutes\nconst signinRateLimiter = new RateLimiter({\n maxAttempts: 5,\n windowMs: 15 * 60 * 1000, // 15 minutes\n prefix: 'signin',\n})\n\nexport const createSigninEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/signin',\n method: 'post',\n handler: (async (req: ExtendedPayloadRequest) => {\n try {\n const data = await req.json()\n const { email, redirectUrl } = data as SigninRequestData & { redirectUrl?: string }\n\n // Validate email\n const validation = validateSubscriberData({ email })\n if (!validation.valid) {\n return Response.json({\n success: false,\n errors: validation.errors,\n }, { status: 400 })\n }\n\n // Check rate limit (per email to prevent abuse)\n const rateLimitKey = `signin:${email.toLowerCase()}`\n const allowed = await signinRateLimiter.checkLimit(rateLimitKey)\n \n if (!allowed) {\n return Response.json({\n success: false,\n error: 'Too many sign-in attempts. Please try again later.',\n }, { status: 429 })\n }\n\n // Find existing subscriber (including unsubscribed)\n const result = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n email: { equals: email.toLowerCase() },\n },\n limit: 1,\n overrideAccess: true, // Need to check subscriber exists\n })\n\n if (result.docs.length === 0) {\n return Response.json({\n success: false,\n error: 'Email not found. Please subscribe first.',\n requiresSubscribe: true,\n }, { status: 404 })\n }\n\n const subscriber = result.docs[0]\n \n // Check if unsubscribed and whether we allow unsubscribed signin\n const allowUnsubscribed = config.auth?.allowUnsubscribedSignin ?? false\n \n if (subscriber.subscriptionStatus === 'unsubscribed' && !allowUnsubscribed) {\n return Response.json({\n success: false,\n error: 'Your subscription is inactive. Please resubscribe to sign in.',\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n requiresResubscribe: true,\n }, { status: 403 })\n }\n\n // Generate magic link token\n const token = generateMagicLinkToken(\n String(subscriber.id),\n subscriber.email,\n config\n )\n\n // Generate magic link URL\n const serverURL = req.payload.config.serverURL || process.env.PAYLOAD_PUBLIC_SERVER_URL || ''\n const magicLinkURL = generateMagicLinkURL(token, serverURL, config, redirectUrl)\n\n // Get email service\n const emailService = (req.payload as any).newsletterEmailService // TODO: Add proper type for newsletter email service\n\n if (emailService) {\n // Get settings for customization\n const settings = await req.payload.findGlobal({\n slug: config.settingsSlug || 'newsletter-settings',\n })\n\n // Render email - pass config to use custom templates\n const html = await renderEmail('signin', {\n magicLink: magicLinkURL,\n email: subscriber.email,\n siteName: settings?.brandSettings?.siteName || 'Newsletter',\n expiresIn: config.auth?.tokenExpiration || '7d',\n }, config)\n\n // Use magic link subject from settings if available\n const subject = settings?.emailTemplates?.magicLink?.subjectLine || \n (settings?.brandSettings?.siteName \n ? `Sign in to ${settings.brandSettings.siteName}` \n : 'Sign in to your account')\n\n // Send email\n await emailService.send({\n to: subscriber.email,\n subject,\n html,\n })\n\n // Sign-in email sent successfully\n } else {\n console.warn('Email service not initialized, cannot send sign-in link')\n }\n\n return Response.json({\n success: true,\n message: 'Check your email for the sign-in link',\n })\n } catch (error) {\n console.error('Sign-in error:', error)\n return Response.json({\n success: false,\n error: 'Failed to process sign-in request',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig, ExtendedPayloadRequest } from '../types'\nimport { verifySessionToken } from '../utils/jwt'\n\nexport const createMeEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/me',\n method: 'get',\n handler: (async (req: ExtendedPayloadRequest) => {\n try {\n // Get token from cookie header\n const cookieHeader = req.headers.get('cookie') || ''\n const cookies = Object.fromEntries(\n cookieHeader.split('; ').map(c => {\n const [key, ...value] = c.split('=')\n return [key, value.join('=')]\n })\n )\n const token = cookies['newsletter-auth']\n \n if (!token) {\n return Response.json({\n success: false,\n error: 'Not authenticated',\n }, { status: 401 })\n }\n\n // Verify the session token\n let payload\n try {\n payload = verifySessionToken(token)\n } catch {\n return Response.json({\n success: false,\n error: 'Invalid or expired session',\n }, { status: 401 })\n }\n\n // Get fresh subscriber data\n const subscriber = await req.payload.findByID({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n overrideAccess: true, // Need to get subscriber data\n })\n\n if (!subscriber || subscriber.subscriptionStatus !== 'active') {\n return Response.json({\n success: false,\n error: 'Not authenticated',\n }, { status: 401 })\n }\n\n return Response.json({\n success: true,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n name: subscriber.name,\n status: subscriber.subscriptionStatus,\n preferences: {\n frequency: subscriber.emailPreferences?.frequency,\n categories: subscriber.emailPreferences?.categories,\n },\n createdAt: subscriber.createdAt,\n updatedAt: subscriber.updatedAt,\n },\n })\n } catch (error) {\n console.error('Me endpoint error:', error)\n return Response.json({\n success: false,\n error: 'Internal server error',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig, ExtendedPayloadRequest } from '../types'\n\nexport const createSignoutEndpoint = (\n _config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/signout',\n method: 'post',\n handler: ((_req: ExtendedPayloadRequest) => {\n try {\n // In Payload v3, cookies are handled differently\n // The Response object doesn't have a clearCookie method\n // We'll need to set the cookie with an expired date\n const headers = new Headers()\n headers.append('Set-Cookie', `newsletter-auth=; HttpOnly; Secure=${process.env.NODE_ENV === 'production'}; SameSite=Lax; Path=/; Max-Age=0`)\n \n return Response.json({ \n success: true, \n message: 'Signed out successfully' \n }, { headers })\n } catch (error) {\n console.error('Signout error:', error)\n return Response.json({\n success: false,\n error: 'Failed to sign out',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint } from 'payload'\nimport type { NewsletterPluginConfig } from '../../types'\n\nexport const createBroadcastManagementEndpoints = (\n _config: NewsletterPluginConfig\n): Endpoint[] => {\n // Broadcast endpoints are now added directly to the broadcasts collection\n // This function is kept for backward compatibility but returns empty array\n return []\n}","import type { Endpoint } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { createSubscribeEndpoint } from './subscribe'\nimport { createVerifyMagicLinkEndpoint } from './verify-magic-link'\nimport { createPreferencesEndpoint, createUpdatePreferencesEndpoint } from './preferences'\nimport { createUnsubscribeEndpoint } from './unsubscribe'\nimport { createSigninEndpoint } from './signin'\nimport { createMeEndpoint } from './me'\nimport { createSignoutEndpoint } from './signout'\nimport { createBroadcastManagementEndpoints } from './broadcasts'\n\nexport function createNewsletterEndpoints(\n config: NewsletterPluginConfig\n): Endpoint[] {\n const endpoints: Endpoint[] = [\n createSubscribeEndpoint(config),\n createUnsubscribeEndpoint(config),\n ]\n\n // Add auth endpoints if enabled\n if (config.auth?.enabled !== false) {\n endpoints.push(\n createVerifyMagicLinkEndpoint(config),\n createPreferencesEndpoint(config),\n createUpdatePreferencesEndpoint(config),\n createSigninEndpoint(config),\n createMeEndpoint(config),\n createSignoutEndpoint(config)\n )\n }\n\n // Add broadcast management endpoints if enabled\n endpoints.push(...createBroadcastManagementEndpoints(config))\n\n return endpoints\n}","import type { Field } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\n\nexport function createNewsletterSchedulingFields(\n config: NewsletterPluginConfig\n): Field[] {\n const groupName = config.features?.newsletterScheduling?.fields?.groupName || 'newsletterScheduling'\n const contentField = config.features?.newsletterScheduling?.fields?.contentField || 'content'\n const createMarkdownField = config.features?.newsletterScheduling?.fields?.createMarkdownField !== false\n\n const fields: Field[] = [\n {\n name: groupName,\n type: 'group',\n label: 'Newsletter Scheduling',\n admin: {\n condition: (data, { user }) => user?.collection === 'users', // Only show for admin users\n },\n fields: [\n {\n name: 'scheduled',\n type: 'checkbox',\n label: 'Schedule for Newsletter',\n defaultValue: false,\n admin: {\n description: 'Schedule this content to be sent as a newsletter',\n },\n },\n {\n name: 'scheduledDate',\n type: 'date',\n label: 'Send Date',\n required: true,\n admin: {\n date: {\n pickerAppearance: 'dayAndTime',\n },\n condition: (data) => data?.[groupName]?.scheduled,\n description: 'When to send this newsletter',\n },\n },\n {\n name: 'sentDate',\n type: 'date',\n label: 'Sent Date',\n admin: {\n readOnly: true,\n condition: (data) => data?.[groupName]?.sendStatus === 'sent',\n description: 'When this newsletter was sent',\n },\n },\n {\n name: 'sendStatus',\n type: 'select',\n label: 'Status',\n options: [\n { label: 'Draft', value: 'draft' },\n { label: 'Scheduled', value: 'scheduled' },\n { label: 'Sending', value: 'sending' },\n { label: 'Sent', value: 'sent' },\n { label: 'Failed', value: 'failed' },\n ],\n defaultValue: 'draft',\n admin: {\n readOnly: true,\n description: 'Current send status',\n },\n },\n {\n name: 'emailSubject',\n type: 'text',\n label: 'Email Subject',\n required: true,\n admin: {\n condition: (data) => data?.[groupName]?.scheduled,\n description: 'Subject line for the newsletter email',\n },\n },\n {\n name: 'preheader',\n type: 'text',\n label: 'Email Preheader',\n admin: {\n condition: (data) => data?.[groupName]?.scheduled,\n description: 'Preview text that appears after the subject line',\n },\n },\n {\n name: 'segments',\n type: 'select',\n label: 'Target Segments',\n hasMany: true,\n options: [\n { label: 'All Subscribers', value: 'all' },\n ...(config.i18n?.locales?.map(locale => ({\n label: `${locale.toUpperCase()} Subscribers`,\n value: locale,\n })) || []),\n ],\n defaultValue: ['all'],\n admin: {\n condition: (data) => data?.[groupName]?.scheduled,\n description: 'Which subscriber segments to send to',\n },\n },\n {\n name: 'testEmails',\n type: 'array',\n label: 'Test Email Recipients',\n admin: {\n condition: (data) => data?.[groupName]?.scheduled && data?.[groupName]?.sendStatus === 'draft',\n description: 'Send test emails before scheduling',\n },\n fields: [\n {\n name: 'email',\n type: 'email',\n required: true,\n },\n ],\n },\n ],\n },\n ]\n\n // Add markdown companion field if requested\n if (createMarkdownField) {\n fields.push(createMarkdownFieldInternal({\n name: `${contentField}Markdown`,\n richTextField: contentField,\n label: 'Email Content (Markdown)',\n admin: {\n position: 'sidebar',\n condition: (data: any) => Boolean(data?.[contentField] && data?.[groupName]?.scheduled),\n description: 'Markdown version for email rendering',\n readOnly: true,\n },\n }))\n }\n\n return fields\n}\n\n/**\n * Create a markdown companion field for rich text\n * This creates a virtual field that converts rich text to markdown\n */\nfunction createMarkdownFieldInternal(config: {\n name: string\n richTextField: string\n label?: string\n admin?: any\n}): Field {\n return {\n name: config.name,\n type: 'textarea',\n label: config.label || 'Markdown',\n admin: {\n ...config.admin,\n description: config.admin?.description || 'Auto-generated from rich text content',\n },\n hooks: {\n afterRead: [\n async ({ data }) => {\n // Convert rich text to markdown on read\n if (data?.[config.richTextField]) {\n try {\n const { convertLexicalToMarkdown } = await import('@payloadcms/richtext-lexical')\n return convertLexicalToMarkdown({\n data: data[config.richTextField],\n } as any)\n } catch {\n return ''\n }\n }\n return ''\n },\n ],\n beforeChange: [\n () => {\n // Don't save markdown to database\n return null\n },\n ],\n },\n }\n}","import type { TaskConfig, PayloadRequest } from 'payload'\nimport type { NewsletterPluginConfig } from '../types/index'\n\nexport const createUnsubscribeSyncJob = (\n pluginConfig: NewsletterPluginConfig\n): TaskConfig => {\n return {\n slug: 'sync-unsubscribes',\n label: 'Sync Unsubscribes from Email Service',\n handler: async ({ req }: { req: PayloadRequest }) => {\n const subscribersSlug = pluginConfig.subscribersSlug || 'subscribers'\n const emailService = (req.payload as any).newsletterEmailService // TODO: Add proper type for newsletter email service\n \n if (!emailService) {\n console.error('Email service not configured')\n return {\n output: {\n syncedCount: 0\n }\n }\n }\n\n let syncedCount = 0\n \n try {\n // For Broadcast: Poll all subscribers\n if (emailService.getProvider() === 'broadcast') {\n console.warn('Starting Broadcast unsubscribe sync...')\n \n // Get Broadcast configuration\n const broadcastConfig = pluginConfig.providers?.broadcast\n if (!broadcastConfig) {\n throw new Error('Broadcast configuration not found')\n }\n\n const apiUrl = broadcastConfig.apiUrl.replace(/\\/$/, '')\n const token = broadcastConfig.token\n\n let page = 1\n let hasMore = true\n\n while (hasMore) {\n // Fetch subscribers from Broadcast\n const response = await fetch(\n `${apiUrl}/api/v1/subscribers.json?page=${page}`,\n {\n headers: {\n 'Authorization': `Bearer ${token}`,\n },\n }\n )\n\n if (!response.ok) {\n throw new Error(`Broadcast API error: ${response.status}`)\n }\n\n const data = await response.json()\n const broadcastSubscribers = data.subscribers || []\n \n // Process each subscriber\n for (const broadcastSub of broadcastSubscribers) {\n // Find corresponding subscriber in Payload\n const payloadSubscribers = await req.payload.find({\n collection: subscribersSlug,\n where: {\n email: {\n equals: broadcastSub.email,\n },\n },\n limit: 1,\n })\n\n if (payloadSubscribers.docs.length > 0) {\n const payloadSub = payloadSubscribers.docs[0]\n \n // Check if unsubscribe status differs\n const broadcastUnsubscribed = !broadcastSub.is_active || broadcastSub.unsubscribed_at\n const payloadUnsubscribed = payloadSub.subscriptionStatus === 'unsubscribed'\n \n if (broadcastUnsubscribed && !payloadUnsubscribed) {\n // Update Payload subscriber to unsubscribed\n await req.payload.update({\n collection: subscribersSlug,\n id: payloadSub.id,\n data: {\n subscriptionStatus: 'unsubscribed',\n unsubscribedAt: broadcastSub.unsubscribed_at || new Date().toISOString(),\n },\n })\n syncedCount++\n console.warn(`Unsubscribed: ${broadcastSub.email}`)\n }\n }\n }\n\n // Check pagination\n if (data.pagination && data.pagination.current < data.pagination.total_pages) {\n page++\n } else {\n hasMore = false\n }\n }\n\n console.warn(`Broadcast sync complete. Unsubscribed ${syncedCount} contacts.`)\n }\n\n // For Resend: Use Audiences API\n if (emailService.getProvider() === 'resend') {\n console.warn('Starting Resend unsubscribe sync...')\n \n // Note: Resend webhooks are preferred over polling\n // This is a fallback polling implementation\n \n // First, get all audiences\n const resendConfig = pluginConfig.providers?.resend\n if (!resendConfig) {\n throw new Error('Resend configuration not found')\n }\n\n // You would need to implement audience/contact polling here\n // Resend's API structure would require:\n // 1. List audiences\n // 2. For each audience, list contacts\n // 3. Check unsubscribed status\n \n console.warn('Resend polling implementation needed - webhooks recommended')\n }\n\n // Custom after sync hook\n if (pluginConfig.hooks?.afterUnsubscribeSync) {\n await pluginConfig.hooks.afterUnsubscribeSync({ \n req, \n syncedCount: syncedCount\n })\n }\n\n } catch (error) {\n console.error('Unsubscribe sync error:', error)\n throw error\n }\n \n return {\n output: {\n syncedCount\n }\n }\n },\n }\n}","import type { CollectionConfig } from 'payload'\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: 'providerData',\n type: 'json',\n admin: {\n readOnly: true,\n condition: () => false, // Hidden by default\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 // Handle create operation\n if (operation === 'create') {\n // Skip provider sync if essential fields are missing\n // Broadcast API requires both subject and body\n if (!doc.subject || !doc.contentSection?.content) {\n req.payload.logger.info('Skipping provider sync - broadcast has no subject or content yet')\n return doc\n }\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 // Populate media fields and convert rich text to HTML\n req.payload.logger.info('Populating media fields and converting content to HTML...')\n const populatedContent = await populateMediaFields(doc.contentSection?.content, req.payload, pluginConfig)\n const htmlContent = await convertToEmailSafeHtml(populatedContent, {\n customBlockConverter: pluginConfig.customizations?.broadcasts?.customBlockConverter\n })\n \n // Skip if content is empty after conversion\n if (!htmlContent || htmlContent.trim() === '') {\n req.payload.logger.info('Skipping provider sync - content is empty after conversion')\n return doc\n }\n \n // Log what we're about to send\n const createData = {\n name: doc.subject, // Use subject as name since we removed the name field\n subject: doc.subject,\n preheader: doc.contentSection?.preheader,\n content: htmlContent,\n trackOpens: doc.settings?.trackOpens,\n trackClicks: doc.settings?.trackClicks,\n replyTo: doc.settings?.replyTo || providerConfig.replyTo,\n audienceIds: doc.audienceIds?.map((a: any) => a.audienceId),\n }\n \n req.payload.logger.info('Creating broadcast with data:', {\n name: createData.name,\n subject: createData.subject,\n preheader: createData.preheader || 'NONE',\n contentLength: htmlContent ? htmlContent.length : 0,\n contentPreview: htmlContent ? htmlContent.substring(0, 100) + '...' : 'EMPTY',\n trackOpens: createData.trackOpens,\n trackClicks: createData.trackClicks,\n replyTo: createData.replyTo,\n audienceIds: createData.audienceIds || [],\n apiUrl: providerConfig.apiUrl,\n hasToken: !!providerConfig.token,\n })\n\n // Create broadcast in provider\n const providerBroadcast = await provider.create(createData)\n\n // Update with provider ID\n await req.payload.update({\n collection: 'broadcasts',\n id: doc.id,\n data: {\n providerId: providerBroadcast.id,\n providerData: providerBroadcast.providerData,\n },\n req,\n })\n\n return {\n ...doc,\n providerId: providerBroadcast.id,\n providerData: providerBroadcast.providerData,\n }\n } catch (error: unknown) {\n // Log the raw error first to see what we're dealing with\n req.payload.logger.error('Raw error from broadcast provider:')\n req.payload.logger.error(error)\n \n // Try different error formats\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 // If it's a BroadcastProviderError, it might have additional details\n ...(error as any).details,\n // Check if it's a fetch response error\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('Error is a string:', error)\n } else if (error && typeof error === 'object') {\n req.payload.logger.error('Error is an object:', JSON.stringify(error, null, 2))\n } else {\n req.payload.logger.error('Unknown error type:', typeof error)\n }\n \n // Also log the doc info for context\n req.payload.logger.error('Failed broadcast document:', {\n id: doc.id,\n subject: doc.subject,\n hasContent: !!doc.contentSection?.content,\n contentType: doc.contentSection?.content ? typeof doc.contentSection.content : 'none',\n })\n \n return doc\n }\n }\n \n // Handle update operation\n if (operation === 'update') {\n req.payload.logger.info('Broadcast afterChange update hook triggered', {\n operation,\n hasProviderId: !!doc.providerId,\n sendStatus: doc.sendStatus,\n publishStatus: doc._status\n })\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 exists yet, we need to create in provider first (deferred from initial create)\n if (!doc.providerId) {\n // Check if we have minimum required fields now\n if (!doc.subject || !doc.contentSection?.content) {\n req.payload.logger.info('Still missing required fields for provider sync')\n return doc\n }\n\n // Populate media fields and convert rich text to HTML\n req.payload.logger.info('Creating broadcast in provider (deferred from initial create)...')\n const populatedContent = await populateMediaFields(doc.contentSection?.content, req.payload, pluginConfig)\n const htmlContent = await convertToEmailSafeHtml(populatedContent, {\n customBlockConverter: pluginConfig.customizations?.broadcasts?.customBlockConverter\n })\n\n // Skip if content is empty after conversion\n if (!htmlContent || htmlContent.trim() === '') {\n req.payload.logger.info('Skipping provider sync - content is empty after conversion')\n return doc\n }\n\n // Create broadcast in provider\n const createData = {\n name: doc.subject,\n subject: doc.subject,\n preheader: doc.contentSection?.preheader,\n content: htmlContent,\n trackOpens: doc.settings?.trackOpens,\n trackClicks: doc.settings?.trackClicks,\n replyTo: doc.settings?.replyTo || providerConfig.replyTo,\n audienceIds: doc.audienceIds?.map((a: any) => a.audienceId),\n }\n\n req.payload.logger.info('Creating broadcast with data:', {\n name: createData.name,\n subject: createData.subject,\n preheader: createData.preheader || 'NONE',\n contentLength: htmlContent ? htmlContent.length : 0,\n contentPreview: htmlContent ? htmlContent.substring(0, 100) + '...' : 'EMPTY',\n apiUrl: providerConfig.apiUrl,\n hasToken: !!providerConfig.token,\n })\n\n const providerBroadcast = await provider.create(createData)\n\n // Update with provider ID\n await req.payload.update({\n collection: 'broadcasts',\n id: doc.id,\n data: {\n providerId: providerBroadcast.id,\n providerData: providerBroadcast.providerData,\n },\n req,\n })\n\n req.payload.logger.info(`Broadcast ${doc.id} created in provider successfully (deferred)`)\n\n return {\n ...doc,\n providerId: providerBroadcast.id,\n providerData: providerBroadcast.providerData,\n }\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)\n updates.content = await convertToEmailSafeHtml(populatedContent, {\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('Syncing broadcast updates to provider', {\n providerId: doc.providerId,\n updates\n })\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('Error is a string:', error)\n } else if (error && typeof error === 'object') {\n req.payload.logger.error('Error is an object:', JSON.stringify(error, null, 2))\n } else {\n req.payload.logger.error('Unknown error type:', typeof error)\n }\n \n req.payload.logger.error('Failed broadcast document (update operation):', {\n id: doc.id,\n subject: doc.subject,\n hasContent: !!doc.contentSection?.content,\n contentType: doc.contentSection?.content ? typeof doc.contentSection.content : 'none',\n })\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(`Failed to send broadcast ${doc.id}:`, error)\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('Failed to delete broadcast from provider:', error)\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 with enhanced configuration\n LinkFeature({\n fields: [\n {\n name: 'url',\n type: 'text',\n required: true,\n admin: {\n description: 'Enter the full URL (including https://)',\n },\n },\n {\n name: 'newTab',\n type: 'checkbox',\n label: 'Open in new tab',\n defaultValue: false,\n },\n ],\n }),\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 with enhanced configuration\n LinkFeature({\n fields: [\n {\n name: 'url',\n type: 'text',\n required: true,\n admin: {\n description: 'Enter the full URL (including https://)',\n },\n },\n {\n name: 'newTab',\n type: 'checkbox',\n label: 'Open in new tab',\n defaultValue: false,\n },\n ],\n }),\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 }\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 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('Failed to get broadcast config from settings:', error)\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 { 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 { Endpoint, PayloadHandler, PayloadRequest, Payload } from 'payload'\nimport type { NewsletterPluginConfig } from '../../types'\nimport { convertToEmailSafeHtml } from '../../utils/emailSafeHtml'\n\n// Helper function to recursively find and populate media fields in content\nexport async function populateMediaFields(content: any, payload: Payload, config: NewsletterPluginConfig): Promise<any> {\n if (!content || typeof content !== 'object') return content\n \n // Handle Lexical editor state\n if (content.root?.children) {\n for (const child of content.root.children) {\n await populateBlockMediaFields(child, payload, config)\n }\n }\n \n return content\n}\n\n// Helper function to populate media fields in individual blocks\nasync function populateBlockMediaFields(node: any, payload: Payload, config: NewsletterPluginConfig): Promise<void> {\n // Check if this is a block node\n if (node.type === 'block' && node.fields) {\n const blockType = node.fields.blockType || node.fields.blockName\n \n // Get custom blocks configuration\n const customBlocks = config.customizations?.broadcasts?.customBlocks || []\n const blockConfig = customBlocks.find((b: any) => 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 && node.fields[field.name]) {\n const fieldValue = node.fields[field.name]\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: field.relationTo,\n id: fieldValue,\n depth: 0,\n })\n \n if (media) {\n node.fields[field.name] = media\n payload.logger?.info(`Populated ${field.name} for block ${blockType}:`, {\n mediaId: fieldValue,\n mediaUrl: media.url,\n filename: media.filename\n })\n }\n } catch (error) {\n payload.logger?.error(`Failed to populate ${field.name} for block ${blockType}:`, error)\n }\n }\n }\n \n // Also handle arrays of uploads\n if (field.type === 'array' && field.fields) {\n const arrayValue = node.fields[field.name]\n if (Array.isArray(arrayValue)) {\n for (const arrayItem of arrayValue) {\n if (arrayItem && typeof arrayItem === 'object') {\n // Recursively process array items for upload fields\n for (const arrayField of field.fields) {\n if (arrayField.type === 'upload' && arrayField.relationTo && arrayItem[arrayField.name]) {\n const arrayFieldValue = arrayItem[arrayField.name]\n \n if (typeof arrayFieldValue === 'string' && arrayFieldValue.match(/^[a-f0-9]{24}$/i)) {\n try {\n const media = await payload.findByID({\n collection: arrayField.relationTo,\n id: arrayFieldValue,\n depth: 0,\n })\n \n if (media) {\n arrayItem[arrayField.name] = media\n payload.logger?.info(`Populated array ${arrayField.name} for block ${blockType}:`, {\n mediaId: arrayFieldValue,\n mediaUrl: media.url,\n filename: media.filename\n })\n }\n } catch (error) {\n payload.logger?.error(`Failed to populate array ${arrayField.name} for block ${blockType}:`, error)\n }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n \n // Recursively process children\n if (node.children) {\n for (const child of node.children) {\n await populateBlockMediaFields(child, payload, config)\n }\n }\n}\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 } = 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 // Convert content to email-safe HTML with custom block converter\n const htmlContent = await convertToEmailSafeHtml(populatedContent, {\n wrapInTemplate: true,\n preheader: preheader,\n mediaUrl: mediaUrl,\n customBlockConverter: config.customizations?.broadcasts?.customBlockConverter,\n })\n\n return Response.json({\n success: true,\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 { Resend } from 'resend'\nimport 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 { ResendProviderConfig } from '../../types'\n\n/**\n * Resend Broadcast Provider\n * \n * IMPORTANT LIMITATIONS:\n * - Resend's Broadcast API is not fully documented publicly\n * - Many operations may not be available via API\n * - Broadcasts created via API can only be edited via API (not in dashboard)\n * - Channel management maps to Resend's Audience API\n * - Some methods below are marked as TODO pending official API documentation\n */\nexport class ResendBroadcastProvider extends BaseBroadcastProvider {\n readonly name = 'resend'\n private client: Resend\n private audienceIds: ResendProviderConfig['audienceIds']\n private isDevelopment: boolean\n\n constructor(config: ResendProviderConfig) {\n super(config)\n this.client = new Resend(config.apiKey)\n this.audienceIds = config.audienceIds || {}\n this.isDevelopment = process.env.NODE_ENV !== 'production'\n \n if (!config.apiKey) {\n throw new BroadcastProviderError(\n 'Resend API key is required',\n BroadcastErrorCode.CONFIGURATION_ERROR,\n this.name\n )\n }\n }\n\n\n // Broadcast Management Methods\n async list(_options?: ListBroadcastOptions): Promise<ListBroadcastResponse<Broadcast>> {\n // TODO: Resend broadcast list API is not documented\n // The SDK may have undocumented methods we could explore\n // For now, we throw a not supported error\n throw new BroadcastProviderError(\n 'Listing broadcasts is not currently supported by Resend API. ' +\n 'This feature may be available in the dashboard only.',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\n }\n\n async get(_id: string): Promise<Broadcast> {\n // TODO: Resend broadcast get API is not documented\n // We would need to explore if the SDK has undocumented methods\n throw new BroadcastProviderError(\n 'Getting individual broadcasts is not currently supported by Resend API. ' +\n 'This feature may be available in the dashboard only.',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\n }\n\n async create(data: CreateBroadcastInput): Promise<Broadcast> {\n try {\n this.validateRequiredFields(data, ['name', 'subject', 'content'])\n\n // Get the appropriate audience ID\n const locale = 'en' // TODO: Make this configurable\n const audienceConfig = this.audienceIds?.[locale]\n const audienceId = this.isDevelopment \n ? audienceConfig?.development || audienceConfig?.production\n : audienceConfig?.production || audienceConfig?.development\n\n if (!audienceId && data.audienceIds?.length) {\n // Use provided audience ID if no default configured\n // Note: Resend might only support one audience per broadcast\n }\n\n // TODO: The exact Resend broadcast creation API is not documented\n // Based on their blog posts, it seems broadcasts can be created via API\n // but the exact endpoint/method is unclear\n \n // Attempt to use broadcasts if available in SDK\n const resendClient = this.client as any\n if (resendClient.broadcasts?.create) {\n const broadcast = await resendClient.broadcasts.create({\n name: data.name,\n subject: data.subject,\n from: `${(this.config as ResendProviderConfig).fromName || 'Newsletter'} <${(this.config as ResendProviderConfig).fromEmail || 'noreply@example.com'}>`,\n reply_to: data.replyTo,\n audience_id: audienceId || data.audienceIds?.[0],\n content: {\n html: data.content,\n // TODO: Handle plain text version\n }\n })\n\n // Transform to our Broadcast type\n return this.transformResendToBroadcast(broadcast)\n }\n\n // If broadcasts API not available, throw error\n throw new BroadcastProviderError(\n 'Creating broadcasts via API is not currently supported. ' +\n 'Please check if Resend has released their Broadcasts API.',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\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 // TODO: Resend broadcast update API is not documented\n // Important: Resend has restrictions where broadcasts created via API\n // can only be edited via API (not in dashboard)\n throw new BroadcastProviderError(\n 'Updating broadcasts is not currently supported by Resend API. ' +\n 'Note: Resend broadcasts can only be edited where they were created.',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\n }\n\n async delete(_id: string): Promise<void> {\n // TODO: Resend broadcast delete API is not documented\n throw new BroadcastProviderError(\n 'Deleting broadcasts is not currently supported by Resend API.',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\n }\n\n async send(id: string, options?: SendBroadcastOptions): Promise<Broadcast> {\n try {\n // TODO: The exact Resend broadcast send API is not documented\n // Based on their features, sending broadcasts is supported\n \n const resendClient = this.client as any\n if (resendClient.broadcasts?.send) {\n await resendClient.broadcasts.send(id, {\n audience_id: options?.audienceIds?.[0],\n // TODO: Handle test mode if supported\n })\n\n // We can't get the updated broadcast, so return a mock\n return {\n id,\n name: 'Unknown',\n subject: 'Unknown',\n content: '',\n sendStatus: BroadcastStatus.SENDING,\n trackOpens: true,\n trackClicks: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n providerType: 'resend'\n } as Broadcast\n }\n\n throw new BroadcastProviderError(\n 'Sending broadcasts via API is not currently supported. ' +\n 'Please check if Resend has released their Broadcasts API.',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\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 // Scheduling is not supported according to our research\n throw new BroadcastProviderError(\n 'Scheduling broadcasts is not supported by Resend',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\n }\n\n async getAnalytics(_id: string): Promise<BroadcastAnalytics> {\n // TODO: Resend does support analytics, but the API is not documented\n // They have dashboard analytics for broadcasts\n throw new BroadcastProviderError(\n 'Getting broadcast analytics via API is not currently supported. ' +\n 'Analytics may be available in the Resend dashboard.',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\n }\n\n getCapabilities(): BroadcastProviderCapabilities {\n return {\n supportsScheduling: false, // Not documented\n supportsSegmentation: true, // Via Audiences\n supportsAnalytics: true, // Available in dashboard, API unclear\n supportsABTesting: false,\n supportsTemplates: false, // Not clear from docs\n supportsPersonalization: true, // Via merge tags\n supportsMultipleChannels: false,\n supportsChannelSegmentation: false,\n editableStatuses: [], // Unclear which statuses can be edited\n supportedContentTypes: ['html'] // React components via SDK\n }\n }\n\n async validateConfiguration(): Promise<boolean> {\n try {\n // Try to use the API key to validate it works\n // We can try to list audiences as a validation check\n const resendClient = this.client as any\n if (resendClient.audiences?.list) {\n await resendClient.audiences.list({ limit: 1 })\n return true\n }\n \n // Fallback: try to send a test email to validate API key\n await this.client.emails.send({\n from: 'onboarding@resend.dev',\n to: 'delivered@resend.dev',\n subject: 'Configuration Test',\n html: '<p>Testing configuration</p>'\n })\n return true\n } catch {\n return false\n }\n }\n\n /**\n * Transform Resend broadcast to our Broadcast type\n * NOTE: This is speculative based on what the API might return\n */\n private transformResendToBroadcast(broadcast: any): Broadcast {\n return {\n id: broadcast.id,\n name: broadcast.name || 'Untitled',\n subject: broadcast.subject,\n preheader: broadcast.preheader,\n content: broadcast.content?.html || broadcast.html || '',\n sendStatus: this.mapResendStatus(broadcast.status),\n trackOpens: true, // Resend tracks by default\n trackClicks: true, // Resend tracks by default\n replyTo: broadcast.reply_to,\n recipientCount: broadcast.recipient_count,\n sentAt: broadcast.sent_at ? new Date(broadcast.sent_at) : undefined,\n scheduledAt: broadcast.scheduled_at ? new Date(broadcast.scheduled_at) : undefined,\n createdAt: new Date(broadcast.created_at || Date.now()),\n updatedAt: new Date(broadcast.updated_at || Date.now()),\n providerData: { broadcast },\n providerId: broadcast.id,\n providerType: 'resend'\n }\n }\n\n private mapResendStatus(status?: string): BroadcastStatus {\n if (!status) return BroadcastStatus.DRAFT\n \n // NOTE: Resend statuses are not documented, these are guesses\n const statusMap: Record<string, BroadcastStatus> = {\n 'draft': BroadcastStatus.DRAFT,\n 'scheduled': BroadcastStatus.SCHEDULED,\n 'sending': BroadcastStatus.SENDING,\n 'sent': BroadcastStatus.SENT,\n 'failed': BroadcastStatus.FAILED\n }\n return statusMap[status.toLowerCase()] || BroadcastStatus.DRAFT\n }\n}\n\n/**\n * IMPLEMENTATION NOTES:\n * \n * 1. Most methods throw NOT_SUPPORTED errors because Resend's Broadcast API\n * is not publicly documented\n * \n * 2. The SDK might have undocumented methods (broadcasts.create, broadcasts.send, etc.)\n * that we attempt to use, but we can't guarantee they exist\n * \n * 3. Important limitation: Broadcasts created via API can only be edited via API,\n * not in the Resend dashboard\n * \n * 4. Resend uses \"Audiences\" instead of \"Segments\" for targeting\n * \n * 5. Analytics are available in the dashboard but API access is unclear\n * \n * FUTURE IMPROVEMENTS:\n * - Monitor Resend's documentation for Broadcast API updates\n * - Explore SDK source code for undocumented methods\n * - Consider using Resend's email API to simulate broadcasts\n * - Add webhook support for delivery/open/click tracking\n */","import type { PayloadRequest } from 'payload'\nimport jwt from 'jsonwebtoken'\n\n// Next.js types - these are optional and only used when Next.js is available\ninterface NextApiRequest {\n cookies?: { [key: string]: string }\n headers?: { [key: string]: string | string[] | undefined }\n [key: string]: any\n}\n\ninterface GetServerSidePropsContext {\n req: {\n cookies?: { [key: string]: string }\n headers?: { [key: string]: string | string[] | undefined }\n [key: string]: any\n }\n [key: string]: any\n}\n\ninterface TokenPayload {\n id: string\n email: string\n type?: string\n iat?: number\n exp?: number\n}\n\n/**\n * Extract token from request cookies\n */\nexport const getTokenFromRequest = (\n req: NextApiRequest | GetServerSidePropsContext['req'] | PayloadRequest\n): string | null => {\n // Handle different request types\n const cookies = (req as any).cookies || (req as any).headers?.cookie\n \n if (!cookies) return null\n \n // Parse cookies if it's a string\n if (typeof cookies === 'string') {\n const parsed = cookies.split(';').reduce((acc, cookie) => {\n const [key, value] = cookie.trim().split('=')\n acc[key] = value\n return acc\n }, {} as Record<string, string>)\n return parsed['newsletter-auth'] || null\n }\n \n // Direct cookie object\n return cookies['newsletter-auth'] || null\n}\n\n/**\n * Verify JWT token\n */\nexport const verifyToken = (\n token: string, \n secret: string\n): TokenPayload | null => {\n try {\n const decoded = jwt.verify(token, secret) as TokenPayload\n return decoded\n } catch {\n return null\n }\n}\n\n/**\n * Get authentication state for server-side rendering\n */\nexport const getServerSideAuth = async (\n context: GetServerSidePropsContext,\n secret?: string\n): Promise<{ subscriber: TokenPayload | null; isAuthenticated: boolean }> => {\n const token = getTokenFromRequest(context.req)\n \n if (!token) {\n return { subscriber: null, isAuthenticated: false }\n }\n \n const payloadSecret = secret || process.env.PAYLOAD_SECRET\n if (!payloadSecret) {\n console.error('No secret provided for token verification')\n return { subscriber: null, isAuthenticated: false }\n }\n \n const decoded = verifyToken(token, payloadSecret)\n \n if (!decoded) {\n return { subscriber: null, isAuthenticated: false }\n }\n \n return {\n subscriber: decoded,\n isAuthenticated: true,\n }\n}\n\n/**\n * Higher-order function for protecting pages\n */\nexport const requireAuth = <P extends { [key: string]: any }>(\n gssp?: (context: GetServerSidePropsContext) => Promise<{ props: P }>\n) => {\n return async (context: GetServerSidePropsContext) => {\n const { isAuthenticated, subscriber } = await getServerSideAuth(context)\n \n if (!isAuthenticated) {\n return {\n redirect: {\n destination: '/auth/signin',\n permanent: false,\n },\n }\n }\n \n // If there's a custom getServerSideProps, run it\n if (gssp) {\n const result = await gssp(context)\n return {\n ...result,\n props: {\n ...result.props,\n subscriber,\n },\n }\n }\n \n // Otherwise just return the subscriber\n return {\n props: {\n subscriber,\n } as any as P,\n }\n }\n}\n\n/**\n * Check if request has valid authentication\n */\nexport const isAuthenticated = (\n req: PayloadRequest | NextApiRequest,\n secret: string\n): boolean => {\n const token = getTokenFromRequest(req)\n if (!token) return false\n \n const decoded = verifyToken(token, secret)\n return !!decoded\n}"],"mappings":"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","names":["init_broadcast","import_components","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","DOMPurify","jwt","subscriber","settings","jwt","import_isomorphic_dompurify","DOMPurify","styles","BroadcastApiProvider","BroadcastApiProvider","BroadcastApiProvider","init_broadcast","import_resend","import_jsonwebtoken","jwt","isAuthenticated"]}
|
|
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/index.ts","../src/utils/access.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","../src/globals/NewsletterSettings.ts","../src/providers/resend.ts","../src/providers/types.ts","../src/providers/broadcast.ts","../src/providers/index.ts","../src/utils/validation.ts","../src/utils/jwt.ts","../src/endpoints/subscribe.ts","../src/endpoints/verify-magic-link.ts","../src/endpoints/preferences.ts","../src/endpoints/unsubscribe.ts","../src/utils/rate-limiter.ts","../src/endpoints/signin.ts","../src/endpoints/me.ts","../src/endpoints/signout.ts","../src/endpoints/broadcasts/index.ts","../src/endpoints/index.ts","../src/fields/newsletterScheduling.ts","../src/jobs/sync-unsubscribes.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/auth.ts","../src/endpoints/broadcasts/schedule.ts","../src/endpoints/broadcasts/test.ts","../src/endpoints/broadcasts/preview.ts","../src/providers/resend/broadcast.ts","../src/utilities/session.ts","../src/contexts/PluginConfigContext.tsx"],"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// 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?: {\n subject?: string\n preheader?: string\n }) => 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 afterUnsubscribeSync?: (args: AfterUnsubscribeSyncArgs) => 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 * Unsubscribe sync configuration\n */\n unsubscribeSync?: {\n /**\n * Enable sync of unsubscribes from email service to Payload\n * @default false\n */\n enabled?: boolean\n /**\n * Cron schedule for sync job (e.g., '0 * * * *' for hourly)\n * If not provided, job must be triggered manually\n */\n schedule?: string\n /**\n * Queue name for the sync job\n * @default 'newsletter-sync'\n */\n queue?: string\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 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\nexport interface AfterUnsubscribeSyncArgs {\n req: any\n syncedCount: number\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 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 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 result = await response.json()\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}","import type { Config } from 'payload'\nimport type { NewsletterPluginConfig, BroadcastProvider } from './types'\nimport { createSubscribersCollection } from './collections/Subscribers'\nimport { createNewsletterSettingsGlobal } from './globals/NewsletterSettings'\nimport { createEmailService } from './providers'\nimport { createNewsletterEndpoints } from './endpoints'\nimport { createNewsletterSchedulingFields } from './fields/newsletterScheduling'\nimport { createUnsubscribeSyncJob } from './jobs/sync-unsubscribes'\nimport { createBroadcastsCollection } from './collections/Broadcasts'\nimport { BroadcastApiProvider } from './providers/broadcast/broadcast'\nimport { ResendBroadcastProvider } from './providers/resend/broadcast'\n\n// Extend Payload type to include our email service and broadcast provider\ndeclare module 'payload' {\n interface BasePayload {\n newsletterEmailService?: any\n broadcastProvider?: BroadcastProvider\n // Legacy support\n newsletterProvider?: BroadcastProvider\n }\n}\n\nexport const newsletterPlugin = (pluginConfig: NewsletterPluginConfig) => (incomingConfig: Config): Config => {\n // Validate and set defaults\n const config: NewsletterPluginConfig = {\n enabled: true,\n subscribersSlug: 'subscribers',\n settingsSlug: 'newsletter-settings',\n auth: {\n enabled: true,\n tokenExpiration: '7d',\n magicLinkPath: '/newsletter/verify',\n ...pluginConfig.auth,\n },\n ...pluginConfig,\n }\n\n // If plugin is disabled, return config unchanged\n if (!config.enabled) {\n return incomingConfig\n }\n\n // Create plugin collections and globals\n const subscribersCollection = createSubscribersCollection(config)\n const settingsGlobal = createNewsletterSettingsGlobal(config)\n\n // Build collections array\n let collections = [...(incomingConfig.collections || []), subscribersCollection]\n\n // Add broadcast management collection if enabled\n if (config.features?.newsletterManagement?.enabled) {\n const broadcastsCollection = createBroadcastsCollection(config)\n collections.push(broadcastsCollection)\n }\n\n // Extend collections with newsletter scheduling fields if enabled\n if (config.features?.newsletterScheduling?.enabled) {\n const targetCollections = config.features.newsletterScheduling.collections || 'articles'\n const collectionsToExtend = Array.isArray(targetCollections) ? targetCollections : [targetCollections]\n const schedulingFields = createNewsletterSchedulingFields(config)\n \n collections = collections.map(collection => {\n if (collectionsToExtend.includes(collection.slug)) {\n return {\n ...collection,\n fields: [\n ...collection.fields,\n ...schedulingFields,\n ],\n }\n }\n return collection\n })\n }\n\n // Create API endpoints\n const endpoints = createNewsletterEndpoints(config)\n\n // Create sync job if enabled\n const syncJob = config.features?.unsubscribeSync?.enabled ? createUnsubscribeSyncJob(config) : null\n\n // Build the modified config\n const modifiedConfig: Config = {\n ...incomingConfig,\n collections,\n globals: [\n ...(incomingConfig.globals || []),\n settingsGlobal,\n ],\n endpoints: [\n ...(incomingConfig.endpoints || []),\n ...endpoints,\n ],\n jobs: syncJob ? {\n ...(incomingConfig.jobs || {}),\n tasks: [\n ...(incomingConfig.jobs?.tasks || []),\n syncJob,\n ],\n // Add cron schedule if specified\n autoRun: config.features?.unsubscribeSync?.schedule ? (\n Array.isArray(incomingConfig.jobs?.autoRun) \n ? [...incomingConfig.jobs.autoRun, {\n cron: config.features.unsubscribeSync.schedule,\n queue: 'newsletter-sync',\n limit: 100,\n }]\n : typeof incomingConfig.jobs?.autoRun === 'function'\n ? async (payload: any) => {\n const autoRunFn = incomingConfig.jobs!.autoRun as (payload: any) => any[] | Promise<any[]>\n const existingConfigs = await autoRunFn(payload)\n return [...existingConfigs, {\n cron: config.features!.unsubscribeSync!.schedule,\n queue: 'newsletter-sync',\n limit: 100,\n }]\n }\n : [{\n cron: config.features!.unsubscribeSync!.schedule,\n queue: 'newsletter-sync',\n limit: 100,\n }]\n ) : incomingConfig.jobs?.autoRun,\n } : incomingConfig.jobs,\n onInit: async (payload) => {\n // Initialize email service\n try {\n // Get settings from global\n const settings = await payload.findGlobal({\n slug: config.settingsSlug || 'newsletter-settings',\n })\n\n console.log('[Newsletter Plugin] Initializing with settings:', {\n hasSettings: !!settings,\n settingsProvider: settings?.provider,\n configProvider: config.providers?.default,\n hasBroadcastConfig: !!config.providers?.broadcast\n })\n\n let emailServiceConfig: any\n \n if (settings) {\n emailServiceConfig = {\n provider: settings.provider || config.providers.default,\n fromAddress: settings.fromAddress || config.providers.resend?.fromAddress || config.providers.broadcast?.fromAddress || 'noreply@example.com',\n fromName: settings.fromName || config.providers.resend?.fromName || config.providers.broadcast?.fromName || 'Newsletter',\n replyTo: settings.replyTo,\n resend: settings.provider === 'resend' ? {\n apiKey: settings.resendSettings?.apiKey || config.providers.resend?.apiKey || '',\n audienceIds: settings.resendSettings?.audienceIds?.reduce((acc: any, item: any) => {\n acc[item.locale] = {\n production: item.production,\n development: item.development,\n }\n return acc\n }, {}) || config.providers.resend?.audienceIds,\n } : config.providers.resend,\n broadcast: settings.provider === 'broadcast' ? {\n apiUrl: settings.broadcastSettings?.apiUrl || config.providers.broadcast?.apiUrl || '',\n token: settings.broadcastSettings?.token || config.providers.broadcast?.token || '',\n fromAddress: settings.fromAddress || config.providers.broadcast?.fromAddress,\n fromName: settings.fromName || config.providers.broadcast?.fromName,\n replyTo: settings.replyTo || config.providers.broadcast?.replyTo,\n } : config.providers.broadcast,\n }\n } else {\n // Use config defaults\n emailServiceConfig = {\n provider: config.providers.default,\n fromAddress: config.providers.resend?.fromAddress || config.providers.broadcast?.fromAddress || 'noreply@example.com',\n fromName: config.providers.resend?.fromName || config.providers.broadcast?.fromName || 'Newsletter',\n resend: config.providers.resend,\n broadcast: config.providers.broadcast,\n }\n }\n\n console.log('[Newsletter Plugin] Email service config:', {\n provider: emailServiceConfig.provider,\n hasBroadcastConfig: !!emailServiceConfig.broadcast,\n broadcastUrl: emailServiceConfig.broadcast?.apiUrl,\n hasToken: !!emailServiceConfig.broadcast?.token\n })\n\n try {\n const emailService = createEmailService(emailServiceConfig)\n ;(payload as any).newsletterEmailService = emailService\n\n console.log('[Newsletter Plugin] Email service initialized:', {\n provider: emailService.getProvider(),\n hasProvider: !!emailService,\n payloadHasService: !!(payload as any).newsletterEmailService\n })\n } catch (emailServiceError) {\n console.error('[Newsletter Plugin] Failed to create email service:', emailServiceError)\n console.error('[Newsletter Plugin] Email service config was:', emailServiceConfig)\n // Don't throw - let the plugin work without email service\n }\n \n // Initialize broadcast management provider if enabled\n if (config.features?.newsletterManagement?.enabled) {\n try {\n // Use custom provider if provided\n let broadcastProvider: BroadcastProvider\n \n if (config.features.newsletterManagement.provider) {\n broadcastProvider = config.features.newsletterManagement.provider\n } else {\n // Create provider based on email service config\n const providerType = emailServiceConfig.provider || config.providers.default\n \n if (providerType === 'broadcast' && emailServiceConfig.broadcast) {\n broadcastProvider = new BroadcastApiProvider(emailServiceConfig.broadcast)\n } else if (providerType === 'resend' && emailServiceConfig.resend) {\n broadcastProvider = new ResendBroadcastProvider(emailServiceConfig.resend)\n } else {\n throw new Error(`Unsupported broadcast provider: ${providerType}`)\n }\n }\n \n // Attach broadcast provider to payload instance\n const payloadWithProvider = payload as any\n payloadWithProvider.broadcastProvider = broadcastProvider\n // Legacy support\n payloadWithProvider.newsletterProvider = broadcastProvider\n \n console.warn('Broadcast management initialized with', broadcastProvider.name, 'provider')\n } catch (error) {\n console.error('Failed to initialize broadcast management provider:', error)\n }\n }\n } catch (error) {\n console.error('Failed to initialize newsletter email service:', error)\n }\n\n // Call original onInit if it exists\n if (incomingConfig.onInit) {\n await incomingConfig.onInit(payload)\n }\n },\n }\n\n return modifiedConfig\n}\n\nexport { newsletterPlugin as default }\n\n// Export session utilities\nexport * from './utilities/session'\n\n// Export contexts for advanced users\nexport * from './contexts/PluginConfigContext'","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 { 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 // Subscription status\n {\n name: 'subscriptionStatus',\n type: 'select',\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Unsubscribed', value: 'unsubscribed' },\n { label: 'Pending', value: 'pending' },\n ],\n defaultValue: 'pending',\n required: true,\n admin: {\n description: 'Current subscription status',\n },\n },\n {\n name: 'unsubscribedAt',\n type: 'date',\n admin: {\n condition: (data) => data?.subscriptionStatus === 'unsubscribed',\n description: 'When the user unsubscribed',\n readOnly: true,\n },\n },\n \n // Email preferences\n {\n name: 'emailPreferences',\n type: 'group',\n fields: [\n {\n name: 'newsletter',\n type: 'checkbox',\n defaultValue: true,\n label: 'Newsletter',\n admin: {\n description: 'Receive regular newsletter updates',\n },\n },\n {\n name: 'announcements',\n type: 'checkbox',\n defaultValue: true,\n label: 'Announcements',\n admin: {\n description: 'Receive important announcements',\n },\n },\n ],\n admin: {\n description: 'Email communication preferences',\n },\n },\n \n // Source tracking\n {\n name: 'source',\n type: 'text',\n admin: {\n description: 'Where the subscriber signed up from',\n },\n },\n ]\n\n // Add UTM tracking fields if enabled\n if (pluginConfig.features?.utmTracking?.enabled) {\n const utmFields = pluginConfig.features.utmTracking.fields || [\n 'source',\n 'medium',\n 'campaign',\n 'content',\n 'term',\n ]\n \n defaultFields.push({\n name: 'utmParameters',\n type: 'group',\n fields: utmFields.map(field => ({\n name: field,\n type: 'text',\n admin: {\n description: `UTM ${field} parameter`,\n },\n })),\n admin: {\n description: 'UTM tracking parameters',\n },\n })\n }\n\n // Add signup metadata\n defaultFields.push({\n name: 'signupMetadata',\n type: 'group',\n fields: [\n {\n name: 'ipAddress',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'userAgent',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'referrer',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'signupPage',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n ],\n admin: {\n description: 'Technical information about signup',\n },\n })\n\n // Add lead magnet field if enabled\n if (pluginConfig.features?.leadMagnets?.enabled) {\n defaultFields.push({\n name: 'leadMagnet',\n type: 'relationship',\n relationTo: pluginConfig.features.leadMagnets.collection || 'media',\n admin: {\n description: 'Lead magnet downloaded at signup',\n },\n })\n }\n\n // Allow field customization\n let fields = defaultFields\n if (pluginConfig.fields?.overrides) {\n fields = pluginConfig.fields.overrides({ defaultFields })\n }\n if (pluginConfig.fields?.additional) {\n fields = [...fields, ...pluginConfig.fields.additional]\n }\n\n const subscribersCollection: CollectionConfig = {\n slug,\n labels: {\n singular: 'Subscriber',\n plural: 'Subscribers',\n },\n admin: {\n useAsTitle: 'email',\n defaultColumns: ['email', 'name', 'subscriptionStatus', 'createdAt'],\n group: 'Newsletter',\n },\n fields,\n hooks: {\n afterChange: [\n async ({ doc, req, operation, previousDoc }) => {\n // After create logic\n if (operation === 'create') {\n // Add to email service\n const emailService = (req.payload as any).newsletterEmailService // 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\n if (doc.subscriptionStatus === 'active' && emailService) {\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 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}","import type { GlobalConfig } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { adminOnly } from '../utils/access'\n\nexport const createNewsletterSettingsGlobal = (\n pluginConfig: NewsletterPluginConfig\n): GlobalConfig => {\n const slug = pluginConfig.settingsSlug || 'newsletter-settings'\n \n return {\n slug,\n label: 'Newsletter Settings',\n admin: {\n group: 'Newsletter',\n description: 'Configure email provider settings and templates',\n },\n fields: [\n {\n type: 'tabs',\n tabs: [\n {\n label: 'Provider Settings',\n fields: [\n {\n name: 'provider',\n type: 'select',\n label: 'Email Provider',\n required: true,\n options: [\n { label: 'Resend', value: 'resend' },\n { label: 'Broadcast (Self-Hosted)', value: 'broadcast' },\n ],\n defaultValue: pluginConfig.providers.default,\n admin: {\n description: 'Choose which email service to use',\n },\n },\n {\n name: 'resendSettings',\n type: 'group',\n label: 'Resend Settings',\n admin: {\n condition: (data) => data?.provider === 'resend',\n },\n fields: [\n {\n name: 'apiKey',\n type: 'text',\n label: 'API Key',\n required: true,\n admin: {\n description: 'Your Resend API key',\n },\n },\n {\n name: 'audienceIds',\n type: 'array',\n label: 'Audience IDs by Locale',\n fields: [\n {\n name: 'locale',\n type: 'select',\n label: 'Locale',\n required: true,\n options: pluginConfig.i18n?.locales?.map(locale => ({\n label: locale.toUpperCase(),\n value: locale,\n })) || [\n { label: 'EN', value: 'en' },\n ],\n },\n {\n name: 'production',\n type: 'text',\n label: 'Production Audience ID',\n },\n {\n name: 'development',\n type: 'text',\n label: 'Development Audience ID',\n },\n ],\n },\n ],\n },\n {\n name: 'broadcastSettings',\n type: 'group',\n label: 'Broadcast Settings',\n admin: {\n condition: (data) => data?.provider === 'broadcast',\n },\n fields: [\n {\n name: 'apiUrl',\n type: 'text',\n label: 'API URL',\n required: true,\n admin: {\n description: 'Your Broadcast instance URL',\n },\n },\n {\n name: 'token',\n type: 'text',\n label: 'API Token',\n required: true,\n admin: {\n description: 'Your Broadcast API token',\n },\n },\n ],\n },\n {\n name: 'fromAddress',\n type: 'email',\n label: 'From Address',\n required: true,\n admin: {\n description: 'Default sender email address',\n },\n },\n {\n name: 'fromName',\n type: 'text',\n label: 'From Name',\n required: true,\n admin: {\n description: 'Default sender name',\n },\n },\n {\n name: 'replyTo',\n type: 'email',\n label: 'Reply-To Address',\n admin: {\n description: 'Optional reply-to email address',\n },\n },\n ],\n },\n {\n label: 'Brand Settings',\n fields: [\n {\n name: 'brandSettings',\n type: 'group',\n label: 'Brand Settings',\n fields: [\n {\n name: 'siteName',\n type: 'text',\n label: 'Site Name',\n required: true,\n defaultValue: 'Newsletter',\n admin: {\n description: 'Your website or newsletter name',\n },\n },\n {\n name: 'siteUrl',\n type: 'text',\n label: 'Site URL',\n admin: {\n description: 'Your website URL (optional)',\n },\n },\n {\n name: 'logoUrl',\n type: 'text',\n label: 'Logo URL',\n admin: {\n description: 'URL to your logo image (optional)',\n },\n },\n ],\n },\n ],\n },\n {\n label: 'Email Templates',\n fields: [\n {\n name: 'emailTemplates',\n type: 'group',\n label: 'Email Templates',\n fields: [\n {\n name: 'welcome',\n type: 'group',\n label: 'Welcome Email',\n fields: [\n {\n name: 'enabled',\n type: 'checkbox',\n label: 'Send Welcome Email',\n defaultValue: true,\n },\n {\n name: 'subject',\n type: 'text',\n label: 'Subject Line',\n defaultValue: 'Welcome to {{fromName}}!',\n admin: {\n condition: (data) => data?.emailTemplates?.welcome?.enabled,\n },\n },\n {\n name: 'preheader',\n type: 'text',\n label: 'Preheader Text',\n admin: {\n condition: (data) => data?.emailTemplates?.welcome?.enabled,\n },\n },\n ],\n },\n {\n name: 'magicLink',\n type: 'group',\n label: 'Magic Link Email',\n fields: [\n {\n name: 'subject',\n type: 'text',\n label: 'Subject Line',\n defaultValue: 'Sign in to {{fromName}}',\n },\n {\n name: 'preheader',\n type: 'text',\n label: 'Preheader Text',\n defaultValue: 'Click the link to access your preferences',\n },\n {\n name: 'expirationTime',\n type: 'select',\n label: 'Link Expiration',\n defaultValue: '7d',\n options: [\n { label: '1 hour', value: '1h' },\n { label: '24 hours', value: '24h' },\n { label: '7 days', value: '7d' },\n { label: '30 days', value: '30d' },\n ],\n },\n ],\n },\n ],\n },\n ],\n },\n {\n label: 'Subscription Settings',\n fields: [\n {\n name: 'subscriptionSettings',\n type: 'group',\n label: 'Subscription Settings',\n fields: [\n {\n name: 'requireDoubleOptIn',\n type: 'checkbox',\n label: 'Require Double Opt-In',\n defaultValue: false,\n admin: {\n description: 'Require email confirmation before activating subscriptions',\n },\n },\n {\n name: 'allowedDomains',\n type: 'array',\n label: 'Allowed Email Domains',\n admin: {\n description: 'Leave empty to allow all domains',\n },\n fields: [\n {\n name: 'domain',\n type: 'text',\n label: 'Domain',\n required: true,\n admin: {\n placeholder: 'example.com',\n },\n },\n ],\n },\n {\n name: 'maxSubscribersPerIP',\n type: 'number',\n label: 'Max Subscribers per IP',\n defaultValue: 10,\n min: 1,\n admin: {\n description: 'Maximum number of subscriptions allowed from a single IP address',\n },\n },\n ],\n },\n ],\n },\n ],\n },\n ],\n hooks: {\n beforeChange: [\n async ({ data, req }) => {\n // Verify admin access for settings changes\n if (!req.user || req.user.collection !== 'users') {\n throw new Error('Only administrators can modify newsletter settings')\n }\n \n return data\n },\n ],\n afterChange: [\n async ({ doc, req }) => {\n // Reinitialize email service when settings change\n if ((req.payload as any).newsletterEmailService) {\n try {\n // TODO: Implement email service reinitialization\n console.warn('Newsletter settings updated, reinitializing service...')\n } catch {\n // Failed to reinitialize email service\n }\n }\n \n return doc\n },\n ],\n },\n access: {\n read: () => true, // Settings can be read publicly for validation\n update: adminOnly(pluginConfig),\n },\n }\n}","import { Resend } from 'resend'\nimport type { EmailProvider, SendEmailParams } from './types'\nimport { EmailProviderError } from './types'\nimport type { Subscriber, ResendProviderConfig } from '../types'\n\nexport class ResendProvider implements EmailProvider {\n private client: Resend\n private audienceIds: ResendProviderConfig['audienceIds']\n private fromAddress: string\n private fromName: string\n private isDevelopment: boolean\n\n constructor(config: ResendProviderConfig & { \n fromAddress: string\n fromName: string \n }) {\n this.client = new Resend(config.apiKey)\n this.audienceIds = config.audienceIds || {}\n this.fromAddress = config.fromAddress\n this.fromName = config.fromName\n this.isDevelopment = process.env.NODE_ENV !== 'production'\n }\n\n getProvider(): string {\n return 'resend'\n }\n\n async send(params: SendEmailParams): Promise<void> {\n try {\n const from = params.from || {\n email: this.fromAddress,\n name: this.fromName,\n }\n\n if (!params.html && !params.text) {\n throw new Error('Either html or text content is required')\n }\n\n await this.client.emails.send({\n from: `${from.name} <${from.email}>`,\n to: Array.isArray(params.to) ? params.to : [params.to],\n subject: params.subject,\n html: params.html || '',\n text: params.text,\n replyTo: params.replyTo,\n })\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to send email via Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n try {\n const audienceId = this.getAudienceId(contact.locale)\n if (!audienceId) {\n console.warn(`No audience ID configured for locale: ${contact.locale}`)\n return\n }\n\n await this.client.contacts.create({\n email: contact.email,\n firstName: contact.name?.split(' ')[0],\n lastName: contact.name?.split(' ').slice(1).join(' '),\n unsubscribed: contact.subscriptionStatus === 'unsubscribed',\n audienceId,\n })\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to add contact to Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n try {\n const audienceId = this.getAudienceId(contact.locale)\n if (!audienceId) {\n console.warn(`No audience ID configured for locale: ${contact.locale}`)\n return\n }\n\n // Resend requires finding the contact first\n const contacts = await this.client.contacts.list({ audienceId })\n const existingContact = contacts.data?.data?.find(c => c.email === contact.email)\n\n if (existingContact) {\n await this.client.contacts.update({\n id: existingContact.id,\n audienceId,\n firstName: contact.name?.split(' ')[0],\n lastName: contact.name?.split(' ').slice(1).join(' '),\n unsubscribed: contact.subscriptionStatus === 'unsubscribed',\n })\n } else {\n // If contact doesn't exist, add them\n await this.addContact(contact)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to update contact in Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async removeContact(email: string): Promise<void> {\n try {\n // Resend doesn't have a direct remove method, so we unsubscribe instead\n // First, we need to find the contact across all audiences\n for (const locale in this.audienceIds) {\n const audienceId = this.getAudienceId(locale)\n if (!audienceId) continue\n\n const contacts = await this.client.contacts.list({ audienceId })\n const contact = contacts.data?.data?.find(c => c.email === email)\n\n if (contact) {\n await this.client.contacts.update({\n id: contact.id,\n audienceId,\n unsubscribed: true,\n })\n break\n }\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to remove contact from Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n private getAudienceId(locale?: string): string | undefined {\n const localeKey = locale || 'en'\n if (!this.audienceIds) return undefined\n \n const localeConfig = this.audienceIds[localeKey]\n if (!localeConfig) return undefined\n\n const audienceId = this.isDevelopment \n ? (localeConfig.development || localeConfig.production)\n : (localeConfig.production || localeConfig.development)\n \n return audienceId\n }\n}","import type { Subscriber } from '../types'\n\nexport interface EmailProvider {\n send(params: SendEmailParams): Promise<void>\n addContact(contact: Subscriber): Promise<void>\n updateContact(contact: Subscriber): Promise<void>\n removeContact(email: string): Promise<void>\n getProvider(): string\n}\n\nexport interface SendEmailParams {\n to: string | string[]\n subject: string\n html?: string\n text?: string\n react?: React.ReactElement\n from?: {\n email: string\n name?: string\n }\n replyTo?: string\n}\n\nexport interface EmailServiceConfig {\n provider: 'resend' | 'broadcast' | string\n fromAddress: string\n fromName: string\n replyTo?: string\n resend?: {\n apiKey: string\n audienceIds?: Record<string, { production?: string; development?: string }>\n }\n broadcast?: {\n apiUrl: string\n token: string\n }\n}\n\nexport class EmailProviderError extends Error {\n provider: string\n originalError?: any\n\n constructor(message: string, provider: string, originalError?: any) {\n super(message)\n this.name = 'EmailProviderError'\n this.provider = provider\n this.originalError = originalError\n }\n}","import type { EmailProvider, SendEmailParams } from './types'\nimport { EmailProviderError } from './types'\nimport type { Subscriber, BroadcastProviderConfig } from '../types'\n\nexport class BroadcastProvider implements EmailProvider {\n private apiUrl: string\n private token: string\n private fromAddress: string\n private fromName: string\n private replyTo?: string\n\n constructor(config: BroadcastProviderConfig & { \n fromAddress: string\n fromName: string \n }) {\n this.apiUrl = config.apiUrl.replace(/\\/$/, '') // Remove trailing slash\n this.token = config.token\n this.fromAddress = config.fromAddress\n this.fromName = config.fromName\n this.replyTo = config.replyTo\n }\n\n getProvider(): string {\n return 'broadcast'\n }\n\n async send(params: SendEmailParams): Promise<void> {\n try {\n const from = params.from || {\n email: this.fromAddress,\n name: this.fromName,\n }\n\n const recipients = Array.isArray(params.to) ? params.to : [params.to]\n \n // Broadcast expects a specific format\n const response = await fetch(`${this.apiUrl}/api/v1/transactionals.json`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n to: recipients[0], // Broadcast API expects a single recipient for transactional emails\n from: `${from.name} <${from.email}>`, // Include from name and email\n subject: params.subject,\n body: params.html || params.text || '',\n reply_to: params.replyTo || this.replyTo || from.email,\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to send email via Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n try {\n const [firstName, ...lastNameParts] = (contact.name || '').split(' ')\n const lastName = lastNameParts.join(' ')\n\n const response = await fetch(`${this.apiUrl}/api/v1/subscribers.json`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n subscriber: {\n email: contact.email,\n first_name: firstName || undefined,\n last_name: lastName || undefined,\n tags: [`lang:${contact.locale || 'en'}`],\n is_active: contact.subscriptionStatus === 'active',\n source: contact.source,\n },\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to add contact to Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n try {\n // First, try to find the contact\n const searchResponse = await fetch(\n `${this.apiUrl}/api/v1/subscribers/find.json?email=${encodeURIComponent(contact.email)}`,\n {\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n },\n }\n )\n\n if (!searchResponse.ok) {\n // If contact doesn't exist, create it\n await this.addContact(contact)\n return\n }\n\n const existingContact = await searchResponse.json()\n\n if (!existingContact || !existingContact.id) {\n await this.addContact(contact)\n return\n }\n\n const [firstName, ...lastNameParts] = (contact.name || '').split(' ')\n const lastName = lastNameParts.join(' ')\n\n // Update existing contact\n // According to Broadcast docs, email should be at root level for identification\n const response = await fetch(`${this.apiUrl}/api/v1/subscribers.json`, {\n method: 'PATCH',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n email: contact.email, // Email at root level to identify the subscriber\n subscriber: {\n first_name: firstName || undefined,\n last_name: lastName || undefined,\n tags: [`lang:${contact.locale || 'en'}`],\n is_active: contact.subscriptionStatus === 'active',\n source: contact.source,\n },\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to update contact in Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async removeContact(email: string): Promise<void> {\n try {\n // First, find the contact\n const searchResponse = await fetch(\n `${this.apiUrl}/api/v1/subscribers/find.json?email=${encodeURIComponent(email)}`,\n {\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n },\n }\n )\n\n if (!searchResponse.ok) {\n // Contact doesn't exist, nothing to remove\n return\n }\n\n const contact = await searchResponse.json()\n\n if (!contact || !contact.id) {\n return\n }\n\n // Deactivate the contact\n const response = await fetch(`${this.apiUrl}/api/v1/subscribers/deactivate.json`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ email }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to remove contact from Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n}","import type { EmailProvider, EmailServiceConfig, SendEmailParams } from './types'\nimport type { Subscriber } from '../types'\nimport { ResendProvider } from './resend'\nimport { BroadcastProvider } from './broadcast'\n\nexport * from './types'\n\nexport class EmailService {\n private provider: EmailProvider\n\n constructor(config: EmailServiceConfig) {\n this.provider = this.createProvider(config)\n }\n\n private createProvider(config: EmailServiceConfig): EmailProvider {\n const baseConfig = {\n fromAddress: config.fromAddress,\n fromName: config.fromName,\n }\n\n switch (config.provider) {\n case 'resend':\n if (!config.resend) {\n throw new Error('Resend configuration is required when using Resend provider')\n }\n return new ResendProvider({\n ...config.resend,\n ...baseConfig,\n })\n\n case 'broadcast':\n if (!config.broadcast) {\n throw new Error('Broadcast configuration is required when using Broadcast provider')\n }\n return new BroadcastProvider({\n ...config.broadcast,\n ...baseConfig,\n })\n\n default:\n throw new Error(`Unknown email provider: ${config.provider}`)\n }\n }\n\n async send(params: SendEmailParams): Promise<void> {\n return this.provider.send(params)\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n return this.provider.addContact(contact)\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n return this.provider.updateContact(contact)\n }\n\n async removeContact(email: string): Promise<void> {\n return this.provider.removeContact(email)\n }\n\n getProvider(): string {\n return this.provider.getProvider()\n }\n\n /**\n * Update the provider configuration\n * Useful when settings are changed in the admin UI\n */\n updateConfig(config: EmailServiceConfig): void {\n this.provider = this.createProvider(config)\n }\n}\n\n/**\n * Create email service from plugin configuration\n */\nexport function createEmailService(config: EmailServiceConfig): EmailService {\n return new EmailService(config)\n}","import DOMPurify from 'isomorphic-dompurify'\n\n/**\n * Validate email address format\n */\nexport function isValidEmail(email: string): boolean {\n if (!email || typeof email !== 'string') return false\n \n // Trim whitespace\n const trimmed = email.trim()\n \n // Length limits\n if (trimmed.length > 255) return false\n \n // Check for dangerous patterns\n if (trimmed.includes('<') || trimmed.includes('>')) return false\n if (trimmed.includes('javascript:')) return false\n if (trimmed.includes('data:')) return false\n \n // Basic format validation with stricter regex\n const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/\n if (!emailRegex.test(trimmed)) return false\n \n // Additional validation rules\n const parts = trimmed.split('@')\n if (parts.length !== 2) return false\n \n const [localPart, domain] = parts\n \n // Check local part length\n if (localPart.length > 64 || localPart.length === 0) return false\n \n // Check for invalid patterns\n if (localPart.startsWith('.') || localPart.endsWith('.')) return false\n if (domain.startsWith('.') || domain.endsWith('.')) return false\n if (domain.includes('..')) return false\n if (localPart.includes('..')) return false\n \n return true\n}\n\n/**\n * Normalize email for rate limiting and deduplication\n */\nexport function normalizeEmail(email: string): string {\n if (!email || typeof email !== 'string') return ''\n \n const parts = email.toLowerCase().trim().split('@')\n if (parts.length !== 2) return email.toLowerCase().trim()\n \n let [localPart] = parts\n const [, domain] = parts\n \n // Remove dots from local part (Gmail-style)\n localPart = localPart.replace(/\\./g, '')\n \n // Remove everything after + (Gmail-style aliases)\n const plusIndex = localPart.indexOf('+')\n if (plusIndex > -1) {\n localPart = localPart.substring(0, plusIndex)\n }\n \n return `${localPart}@${domain}`\n}\n\n/**\n * Check if email domain is allowed\n */\nexport function isDomainAllowed(\n email: string,\n allowedDomains?: string[]\n): boolean {\n // Validate email format first\n if (!isValidEmail(email)) {\n return false\n }\n \n // If no domains specified, allow all valid emails\n if (!allowedDomains || allowedDomains.length === 0) {\n return true\n }\n\n const domain = email.split('@')[1]?.toLowerCase()\n if (!domain) return false\n\n return allowedDomains.some(\n allowedDomain => domain === allowedDomain.toLowerCase()\n )\n}\n\n/**\n * Sanitize user input to prevent XSS\n */\nexport function sanitizeInput(input: string): string {\n if (!input) return ''\n \n // First, remove all HTML tags and scripts\n let cleaned = DOMPurify.sanitize(input, { \n ALLOWED_TAGS: [],\n ALLOWED_ATTR: [],\n KEEP_CONTENT: true\n })\n \n // Additional security: remove dangerous patterns\n cleaned = cleaned\n .replace(/javascript:/gi, '')\n .replace(/data:/gi, '')\n .replace(/vbscript:/gi, '')\n .replace(/file:\\/\\//gi, '')\n .replace(/onload/gi, '')\n .replace(/onerror/gi, '')\n .replace(/onclick/gi, '')\n .replace(/onmouseover/gi, '')\n .replace(/alert\\(/gi, '')\n .replace(/prompt\\(/gi, '')\n .replace(/confirm\\(/gi, '')\n .replace(/\\|/g, '') // Remove pipe character (command injection)\n .replace(/;/g, '') // Remove semicolon (command chaining)\n .replace(/`/g, '') // Remove backticks (command substitution)\n .replace(/&&/g, '') // Remove command chaining\n .replace(/\\$\\(/g, '') // Remove command substitution pattern $()\n .replace(/\\.\\./g, '') // Remove directory traversal\n .replace(/\\/..\\//g, '') // Remove path traversal\n .replace(/\\0/g, '') // Remove null bytes\n \n return cleaned.trim()\n}\n\n/**\n * Extract UTM parameters from URL search params\n */\nexport function extractUTMParams(searchParams: URLSearchParams): Record<string, string> {\n const utmParams: Record<string, string> = {}\n const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']\n\n utmKeys.forEach(key => {\n const value = searchParams.get(key)\n if (value) {\n // Remove 'utm_' prefix for storage\n const shortKey = key.replace('utm_', '')\n utmParams[shortKey] = value\n }\n })\n\n return utmParams\n}\n\n/**\n * Validate source field - only allow predefined values\n */\nexport function isValidSource(source: string): boolean {\n if (!source || typeof source !== 'string') return false\n \n const allowedSources = [\n 'website',\n 'api',\n 'import',\n 'admin',\n 'signup-form',\n 'magic-link',\n 'preferences',\n 'external'\n ]\n \n return allowedSources.includes(source)\n}\n\n/**\n * Validate subscriber data before creation\n */\nexport interface ValidateSubscriberResult {\n valid: boolean\n errors: string[]\n}\n\nexport function validateSubscriberData(data: any): ValidateSubscriberResult {\n const errors: string[] = []\n\n // Email validation\n if (!data.email) {\n errors.push('Email is required')\n } else if (!isValidEmail(data.email)) {\n errors.push('Invalid email format')\n }\n\n // Name validation (optional but if provided, should be reasonable)\n if (data.name && data.name.length > 100) {\n errors.push('Name is too long (max 100 characters)')\n }\n\n // Source validation\n if (data.source !== undefined) {\n if (!data.source || data.source.length === 0) {\n errors.push('Source cannot be empty')\n } else if (data.source.length > 50) {\n errors.push('Source is too long (max 50 characters)')\n } else if (!isValidSource(data.source)) {\n errors.push('Invalid source value')\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n }\n}","import jwt from 'jsonwebtoken'\nimport type { NewsletterPluginConfig } from '../types'\n\nexport interface MagicLinkTokenPayload {\n subscriberId: string\n email: string\n type: 'magic-link'\n}\n\nexport interface SessionTokenPayload {\n subscriberId: string\n email: string\n type: 'session'\n}\n\n/**\n * Get JWT secret from environment or generate a warning\n */\nfunction getJWTSecret(): string {\n const secret = process.env.JWT_SECRET || process.env.PAYLOAD_SECRET\n\n if (!secret) {\n console.warn(\n 'WARNING: No JWT_SECRET or PAYLOAD_SECRET found in environment variables. ' +\n 'Magic link authentication will not work properly. ' +\n 'Please set JWT_SECRET in your environment.'\n )\n // Return a placeholder to prevent crashes during development\n return 'INSECURE_DEVELOPMENT_SECRET_PLEASE_SET_JWT_SECRET'\n }\n\n return secret\n}\n\n/**\n * Generate a magic link token for email authentication\n */\nexport function generateMagicLinkToken(\n subscriberId: string,\n email: string,\n config: NewsletterPluginConfig\n): string {\n const payload: MagicLinkTokenPayload = {\n subscriberId,\n email,\n type: 'magic-link',\n }\n\n const expiresIn = config.auth?.tokenExpiration || '7d'\n\n return jwt.sign(payload, getJWTSecret(), {\n expiresIn: expiresIn,\n issuer: 'payload-newsletter-plugin',\n } as jwt.SignOptions)\n}\n\n/**\n * Verify a magic link token\n */\nexport function verifyMagicLinkToken(token: string): MagicLinkTokenPayload {\n try {\n const payload = jwt.verify(token, getJWTSecret(), {\n issuer: 'payload-newsletter-plugin',\n }) as any\n\n if (payload.type !== 'magic-link') {\n throw new Error('Invalid token type')\n }\n\n return payload as MagicLinkTokenPayload\n } catch (error: unknown) {\n if (error instanceof Error && error.name === 'TokenExpiredError') {\n throw new Error('Magic link has expired. Please request a new one.')\n }\n if (error instanceof Error && error.name === 'JsonWebTokenError') {\n throw new Error('Invalid magic link token')\n }\n throw error\n }\n}\n\n/**\n * Generate a session token after successful magic link verification\n */\nexport function generateSessionToken(\n subscriberId: string,\n email: string\n): string {\n const payload: SessionTokenPayload = {\n subscriberId,\n email,\n type: 'session',\n }\n\n return jwt.sign(payload, getJWTSecret(), {\n expiresIn: '30d',\n issuer: 'payload-newsletter-plugin',\n })\n}\n\n/**\n * Verify a session token\n */\nexport function verifySessionToken(token: string): SessionTokenPayload {\n try {\n const payload = jwt.verify(token, getJWTSecret(), {\n issuer: 'payload-newsletter-plugin',\n }) as any\n\n if (payload.type !== 'session') {\n throw new Error('Invalid token type')\n }\n\n return payload as SessionTokenPayload\n } catch (error: unknown) {\n if (error instanceof Error && error.name === 'TokenExpiredError') {\n throw new Error('Session has expired. Please sign in again.')\n }\n if (error instanceof Error && error.name === 'JsonWebTokenError') {\n throw new Error('Invalid session token')\n }\n throw error\n }\n}\n\n/**\n * Generate a magic link URL\n */\nexport function generateMagicLinkURL(\n token: string,\n baseURL: string,\n config: NewsletterPluginConfig,\n redirectUrl?: string\n): string {\n const path = config.auth?.magicLinkPath || '/newsletter/verify'\n const url = new URL(path, baseURL)\n url.searchParams.set('token', token)\n if (redirectUrl) {\n url.searchParams.set('redirect', redirectUrl)\n }\n return url.toString()\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig, Subscriber, SubscribeRequestData, ExtendedPayloadRequest } from '../types'\nimport { \n isDomainAllowed, \n sanitizeInput, \n validateSubscriberData,\n extractUTMParams \n} from '../utils/validation'\nimport { generateMagicLinkToken, generateMagicLinkURL } from '../utils/jwt'\nimport { renderEmail } from '../emails/render'\n\nexport const createSubscribeEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/subscribe',\n method: 'post',\n handler: (async (req: ExtendedPayloadRequest) => {\n try {\n const data = await req.json()\n const { \n email, \n name, \n source,\n preferences,\n leadMagnet,\n surveyResponses,\n metadata = {}\n } = data as SubscribeRequestData\n\n // Trim email before validation\n const trimmedEmail = email?.trim()\n\n // Validate input\n const validation = validateSubscriberData({ email: trimmedEmail, name, source })\n if (!validation.valid) {\n return Response.json({\n success: false,\n errors: validation.errors,\n }, { status: 400 })\n }\n\n // Check domain restrictions from global settings\n // Settings are public info needed for validation, but we can still respect access control\n const settings = await req.payload.findGlobal({\n slug: config.settingsSlug || 'newsletter-settings',\n overrideAccess: false,\n // No user context for public endpoint\n })\n\n const allowedDomains = settings?.subscriptionSettings?.allowedDomains?.map((d: { domain: string }) => d.domain) || []\n if (!isDomainAllowed(trimmedEmail, allowedDomains)) {\n return Response.json({\n success: false,\n error: 'Email domain not allowed',\n }, { status: 400 })\n }\n\n // Check if already subscribed\n // This needs admin access to check for existing email\n const existing = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n email: {\n equals: trimmedEmail.toLowerCase(),\n },\n },\n overrideAccess: true, // Need to check for duplicates in public endpoint\n })\n\n if (existing.docs.length > 0) {\n const subscriber = existing.docs[0]\n \n // Handle unsubscribed users\n if (subscriber.subscriptionStatus === 'unsubscribed') {\n const allowResubscribe = config.auth?.allowResubscribe ?? false\n \n if (!allowResubscribe) {\n return Response.json({\n success: false,\n error: 'This email has been unsubscribed. Please contact support to resubscribe.',\n }, { status: 400 })\n }\n \n // Resubscribe the user\n const updated = await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: subscriber.id,\n data: {\n subscriptionStatus: 'active',\n resubscribedAt: new Date().toISOString(),\n // Preserve preferences but update metadata\n signupMetadata: {\n ...metadata,\n source: source || 'resubscribe',\n resubscribedFrom: subscriber.signupMetadata?.source,\n },\n },\n overrideAccess: true,\n })\n \n // Fire afterSubscribe hook for resubscription\n if (config.hooks?.afterSubscribe) {\n await config.hooks.afterSubscribe({\n doc: updated,\n req,\n })\n }\n \n // Send welcome back email\n const emailService = (req.payload as any).newsletterEmailService\n if (emailService) {\n const settings = await req.payload.findGlobal({\n slug: config.settingsSlug || 'newsletter-settings',\n })\n \n const html = await renderEmail('welcome', {\n name: updated.name || '',\n email: updated.email,\n siteName: settings?.brandSettings?.siteName || 'Newsletter',\n siteUrl: req.payload.config.serverURL || '',\n }, config)\n \n await emailService.send({\n to: updated.email,\n subject: `Welcome back to ${settings?.brandSettings?.siteName || 'our newsletter'}!`,\n html,\n })\n }\n \n return Response.json({\n success: true,\n message: 'Welcome back! You have been resubscribed.',\n subscriber: {\n id: updated.id,\n email: updated.email,\n subscriptionStatus: updated.subscriptionStatus,\n },\n wasResubscribed: true,\n })\n }\n \n // Already active subscriber - send sign-in link instead\n if (subscriber.subscriptionStatus === 'active') {\n // Generate magic link for signin\n const token = generateMagicLinkToken(\n String(subscriber.id),\n subscriber.email,\n config\n )\n \n const serverURL = req.payload.config.serverURL || process.env.PAYLOAD_PUBLIC_SERVER_URL || ''\n const magicLinkURL = generateMagicLinkURL(token, serverURL, config)\n \n // Send signin email\n const emailService = (req.payload as any).newsletterEmailService\n if (emailService) {\n const settings = await req.payload.findGlobal({\n slug: config.settingsSlug || 'newsletter-settings',\n })\n \n const html = await renderEmail('signin', {\n magicLink: magicLinkURL,\n email: subscriber.email,\n siteName: settings?.brandSettings?.siteName || 'Newsletter',\n expiresIn: config.auth?.tokenExpiration || '7d',\n }, config)\n \n await emailService.send({\n to: subscriber.email,\n subject: `Sign in to ${settings?.brandSettings?.siteName || 'your account'}`,\n html,\n })\n }\n \n return Response.json({\n success: true,\n message: 'You are already subscribed! Check your email for a sign-in link.',\n alreadySubscribed: true,\n })\n }\n }\n\n // Check IP rate limiting\n const ipAddress = req.ip || req.connection?.remoteAddress\n const maxPerIP = settings?.subscriptionSettings?.maxSubscribersPerIP || 10\n\n const ipSubscribers = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n 'signupMetadata.ipAddress': {\n equals: ipAddress,\n },\n },\n overrideAccess: true, // Need to check IP limits in public endpoint\n })\n\n if (ipSubscribers.docs.length >= maxPerIP) {\n return Response.json({\n success: false,\n error: 'Too many subscriptions from this IP address',\n }, { status: 429 })\n }\n\n // Extract UTM parameters\n const referer = req.headers.get('referer') || req.headers.get('referrer') || ''\n let utmParams = {}\n if (referer) {\n try {\n utmParams = extractUTMParams(new URL(referer).searchParams)\n } catch {\n // Invalid URL, ignore UTM params\n }\n }\n\n // Prepare subscriber data\n const subscriberData: Partial<Subscriber> = {\n email: trimmedEmail.toLowerCase(),\n name: name ? sanitizeInput(name) : undefined,\n locale: metadata.locale || config.i18n?.defaultLocale || 'en',\n subscriptionStatus: settings?.subscriptionSettings?.requireDoubleOptIn ? 'pending' : 'active',\n source: source || 'api',\n emailPreferences: {\n newsletter: true,\n announcements: true,\n ...(preferences || {}),\n },\n signupMetadata: {\n ipAddress,\n userAgent: req.headers.get('user-agent') || undefined,\n referrer: referer,\n signupPage: metadata.signupPage || referer,\n },\n }\n\n // Add UTM parameters if tracking is enabled\n if (config.features?.utmTracking?.enabled && Object.keys(utmParams).length > 0) {\n subscriberData.utmParameters = utmParams\n }\n\n // Add lead magnet if provided\n if (config.features?.leadMagnets?.enabled && leadMagnet) {\n subscriberData.leadMagnet = leadMagnet\n }\n\n // Create subscriber\n // Public endpoint needs to create subscribers\n const subscriber = await req.payload.create({\n collection: config.subscribersSlug || 'subscribers',\n data: subscriberData,\n overrideAccess: true, // Public endpoint needs to create subscribers\n })\n\n // Handle survey responses if provided\n if (config.features?.surveys?.enabled && surveyResponses) {\n // TODO: Store survey responses\n }\n\n // Send confirmation email if double opt-in\n if (settings?.subscriptionSettings?.requireDoubleOptIn) {\n try {\n // Generate magic link token\n const token = generateMagicLinkToken(\n String(subscriber.id),\n subscriber.email,\n config\n )\n \n // Generate magic link URL\n const serverURL = req.payload.config.serverURL || process.env.PAYLOAD_PUBLIC_SERVER_URL || ''\n const magicLinkURL = generateMagicLinkURL(token, serverURL, config)\n \n // Get email service\n const emailService = (req.payload as any).newsletterEmailService // TODO: Add proper type for newsletter email service\n \n if (emailService) {\n // Render email\n const html = await renderEmail('magic-link', {\n magicLink: magicLinkURL,\n email: subscriber.email,\n siteName: settings?.brandSettings?.siteName || 'Newsletter',\n expiresIn: config.auth?.tokenExpiration || '7d',\n }, config)\n \n // Send email\n await emailService.send({\n to: subscriber.email,\n subject: settings?.brandSettings?.siteName ? `Verify your email for ${settings.brandSettings.siteName}` : 'Verify your email',\n html,\n })\n \n // Magic link email sent successfully\n } else {\n console.warn('Email service not initialized, cannot send magic link')\n }\n } catch (error) {\n console.error('Failed to send magic link email:', error)\n // Don't fail the subscription if email fails\n }\n }\n\n return Response.json({\n success: true,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n message: settings?.subscriptionSettings?.requireDoubleOptIn \n ? 'Please check your email to confirm your subscription'\n : 'Successfully subscribed',\n })\n } catch {\n return Response.json({\n success: false,\n error: 'Failed to subscribe. Please try again.',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig, VerifyMagicLinkRequestData, ExtendedPayloadRequest } from '../types'\nimport { \n verifyMagicLinkToken, \n generateSessionToken \n} from '../utils/jwt'\nimport { renderEmail } from '../emails/render'\n\nexport const createVerifyMagicLinkEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/verify-magic-link',\n method: 'post',\n handler: (async (req: ExtendedPayloadRequest) => {\n try {\n const data = await req.json()\n const { token } = data as VerifyMagicLinkRequestData\n\n if (!token) {\n return Response.json({\n success: false,\n error: 'Token is required',\n }, { status: 400 })\n }\n\n // Verify the magic link token\n let payload\n try {\n payload = verifyMagicLinkToken(token)\n } catch (error: unknown) {\n return Response.json({\n success: false,\n error: error instanceof Error ? error.message : 'Invalid token',\n }, { status: 401 })\n }\n\n // Find the subscriber - token verified so we can use admin access for initial lookup\n const subscriber = await req.payload.findByID({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n // Keep overrideAccess: true for token verification\n })\n\n if (!subscriber) {\n return Response.json({\n success: false,\n error: 'Subscriber not found',\n }, { status: 404 })\n }\n\n // Check if email matches\n if (subscriber.email !== payload.email) {\n return Response.json({\n success: false,\n error: 'Invalid token',\n }, { status: 401 })\n }\n\n // Check if subscriber is active\n if (subscriber.subscriptionStatus === 'unsubscribed') {\n return Response.json({\n success: false,\n error: 'This email has been unsubscribed',\n }, { status: 403 })\n }\n\n // Create synthetic user for subscriber operations\n const syntheticUser = {\n collection: 'subscribers',\n id: subscriber.id,\n email: subscriber.email,\n }\n\n // Update subscription status if pending\n let isNewlyActivated = false\n if (subscriber.subscriptionStatus === 'pending') {\n await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: subscriber.id,\n data: {\n subscriptionStatus: 'active',\n },\n overrideAccess: false,\n user: syntheticUser,\n })\n isNewlyActivated = true\n }\n\n // Clear the magic link token\n await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: subscriber.id,\n data: {\n magicLinkToken: null,\n magicLinkTokenExpiry: null,\n },\n overrideAccess: false,\n user: syntheticUser,\n })\n\n // Generate session token\n const sessionToken = generateSessionToken(\n String(subscriber.id),\n subscriber.email\n )\n\n // Send welcome email if newly activated\n if (isNewlyActivated) {\n try {\n // Get email service\n const emailService = (req.payload as any).newsletterEmailService // TODO: Add proper type for newsletter email service\n \n if (emailService) {\n // Get settings for site name\n const settings = await req.payload.findGlobal({\n slug: config.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: subscriber.email,\n siteName: settings?.brandSettings?.siteName || 'Newsletter',\n preferencesUrl: `${serverURL}/account/preferences`, // This could be customized\n }, config)\n \n // Send email\n await emailService.send({\n to: subscriber.email,\n subject: settings?.brandSettings?.siteName ? `Welcome to ${settings.brandSettings.siteName}!` : 'Welcome!',\n html,\n })\n \n // Welcome email sent successfully\n } else {\n console.warn('Email service not initialized, cannot send welcome email')\n }\n } catch (error) {\n console.error('Failed to send welcome email:', error)\n // Don't fail the verification if welcome email fails\n }\n }\n\n // Set the session cookie\n const headers = new Headers()\n headers.append('Set-Cookie', `newsletter-auth=${sessionToken}; HttpOnly; Secure=${process.env.NODE_ENV === 'production'}; SameSite=Lax; Path=/; Max-Age=${30 * 24 * 60 * 60}`)\n\n return Response.json({\n success: true,\n sessionToken,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n name: subscriber.name,\n locale: subscriber.locale,\n emailPreferences: subscriber.emailPreferences,\n },\n }, { headers })\n } catch (error: unknown) {\n console.error('Verify magic link error:', error)\n return Response.json({\n success: false,\n error: 'Failed to verify magic link',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig, Subscriber, UpdatePreferencesRequestData, ExtendedPayloadRequest } from '../types'\nimport { verifySessionToken } from '../utils/jwt'\n\nexport const createPreferencesEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/preferences',\n method: 'get',\n handler: (async (req: ExtendedPayloadRequest) => {\n try {\n // Get token from Authorization header\n const authHeader = req.headers.get('authorization')\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n return Response.json({\n success: false,\n error: 'Authorization required',\n }, { status: 401 })\n }\n\n const token = authHeader.substring(7)\n\n // Verify session token\n let payload\n try {\n payload = verifySessionToken(token)\n } catch (error: unknown) {\n return Response.json({\n success: false,\n error: error instanceof Error ? error.message : 'Invalid token',\n }, { status: 401 })\n }\n\n // Get subscriber - use synthetic user to ensure access control\n const subscriber = await req.payload.findByID({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n overrideAccess: false,\n user: {\n collection: 'subscribers',\n id: payload.subscriberId,\n email: payload.email,\n },\n })\n\n if (!subscriber) {\n return Response.json({\n success: false,\n error: 'Subscriber not found',\n }, { status: 404 })\n }\n\n return Response.json({\n success: true,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n name: subscriber.name,\n locale: subscriber.locale,\n emailPreferences: subscriber.emailPreferences,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n })\n } catch (error: unknown) {\n console.error('Get preferences error:', error)\n return Response.json({\n success: false,\n error: 'Failed to get preferences',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}\n\nexport const createUpdatePreferencesEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/preferences',\n method: 'post',\n handler: (async (req: ExtendedPayloadRequest) => {\n try {\n // Get token from Authorization header\n const authHeader = req.headers.get('authorization')\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n return Response.json({\n success: false,\n error: 'Authorization required',\n }, { status: 401 })\n }\n\n const token = authHeader.substring(7)\n\n // Verify session token\n let payload\n try {\n payload = verifySessionToken(token)\n } catch (error: unknown) {\n return Response.json({\n success: false,\n error: error instanceof Error ? error.message : 'Invalid token',\n }, { status: 401 })\n }\n\n const data = await req.json()\n const { name, locale, emailPreferences } = data as UpdatePreferencesRequestData\n\n // Prepare update data\n const updateData: Partial<Subscriber> = {}\n \n if (name !== undefined) {\n updateData.name = name\n }\n \n if (locale !== undefined) {\n updateData.locale = locale\n }\n \n if (emailPreferences !== undefined) {\n updateData.emailPreferences = emailPreferences\n }\n\n // Update subscriber - use synthetic user to ensure only updating own data\n const subscriber = await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n data: updateData,\n overrideAccess: false,\n user: {\n collection: 'subscribers',\n id: payload.subscriberId,\n email: payload.email,\n },\n })\n\n return Response.json({\n success: true,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n name: subscriber.name,\n locale: subscriber.locale,\n emailPreferences: subscriber.emailPreferences,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n })\n } catch (error: unknown) {\n console.error('Update preferences error:', error)\n return Response.json({\n success: false,\n error: 'Failed to update preferences',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig, UnsubscribeRequestData, ExtendedPayloadRequest } from '../types'\nimport { isValidEmail } from '../utils/validation'\n\nexport const createUnsubscribeEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/unsubscribe',\n method: 'post',\n handler: (async (req: ExtendedPayloadRequest) => {\n try {\n const data = await req.json()\n const { email, token } = data as UnsubscribeRequestData\n\n // Two methods: email or token\n if (!email && !token) {\n return Response.json({\n success: false,\n error: 'Email or token is required',\n }, { status: 400 })\n }\n\n let subscriber\n\n if (token) {\n // Token-based unsubscribe (from email link)\n try {\n const jwt = await import('jsonwebtoken')\n const payload = jwt.verify(\n token,\n process.env.JWT_SECRET || process.env.PAYLOAD_SECRET || ''\n ) as { type: string; subscriberId: string; email: string }\n\n if (payload.type !== 'unsubscribe') {\n throw new Error('Invalid token type')\n }\n\n // Token verified, so we can look up the subscriber\n // Using overrideAccess: true here is OK since we verified the token\n subscriber = await req.payload.findByID({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n })\n } catch {\n return Response.json({\n success: false,\n error: 'Invalid or expired unsubscribe link',\n }, { status: 401 })\n }\n } else {\n // Email-based unsubscribe\n if (!email || !isValidEmail(email)) {\n return Response.json({\n success: false,\n error: 'Invalid email format',\n }, { status: 400 })\n }\n\n const result = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n email: {\n equals: email!.toLowerCase(),\n },\n },\n })\n\n if (result.docs.length === 0) {\n // Don't reveal if email exists or not\n return Response.json({\n success: true,\n message: 'If this email was subscribed, it has been unsubscribed.',\n })\n }\n\n subscriber = result.docs[0]\n }\n\n if (!subscriber) {\n return Response.json({\n success: true,\n message: 'If this email was subscribed, it has been unsubscribed.',\n })\n }\n\n // Check if already unsubscribed\n if (subscriber.subscriptionStatus === 'unsubscribed') {\n return Response.json({\n success: true,\n message: 'Already unsubscribed',\n })\n }\n\n // Update subscription status - use synthetic user to ensure proper access\n await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: subscriber.id,\n data: {\n subscriptionStatus: 'unsubscribed',\n unsubscribedAt: new Date().toISOString(),\n },\n overrideAccess: false,\n user: {\n collection: 'subscribers',\n id: subscriber.id,\n email: subscriber.email,\n },\n })\n\n return Response.json({\n success: true,\n message: 'Successfully unsubscribed',\n })\n } catch (error: unknown) {\n console.error('Unsubscribe error:', error)\n return Response.json({\n success: false,\n error: 'Failed to unsubscribe. Please try again.',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","export interface RateLimiterOptions {\n maxAttempts: number\n windowMs: number\n prefix?: string\n}\n\nexport class RateLimiter {\n private attempts: Map<string, { count: number; resetTime: number }> = new Map()\n private options: RateLimiterOptions\n\n constructor(options: RateLimiterOptions) {\n this.options = options\n }\n\n async checkLimit(key: string): Promise<boolean> {\n const now = Date.now()\n const record = this.attempts.get(key)\n\n if (!record || record.resetTime < now) {\n this.attempts.set(key, {\n count: 1,\n resetTime: now + this.options.windowMs\n })\n return true\n }\n\n if (record.count >= this.options.maxAttempts) {\n return false\n }\n\n record.count++\n return true\n }\n\n async incrementAttempt(key: string): Promise<void> {\n const now = Date.now()\n const record = this.attempts.get(key)\n\n if (!record || record.resetTime < now) {\n this.attempts.set(key, {\n count: 1,\n resetTime: now + this.options.windowMs\n })\n } else {\n record.count++\n }\n }\n\n async reset(key: string): Promise<void> {\n this.attempts.delete(key)\n }\n\n async resetAll(): Promise<void> {\n this.attempts.clear()\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig, SigninRequestData, ExtendedPayloadRequest } from '../types'\nimport { validateSubscriberData } from '../utils/validation'\nimport { generateMagicLinkToken, generateMagicLinkURL } from '../utils/jwt'\nimport { renderEmail } from '../emails/render'\nimport { RateLimiter } from '../utils/rate-limiter'\n\n// Create rate limiter: 5 attempts per 15 minutes\nconst signinRateLimiter = new RateLimiter({\n maxAttempts: 5,\n windowMs: 15 * 60 * 1000, // 15 minutes\n prefix: 'signin',\n})\n\nexport const createSigninEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/signin',\n method: 'post',\n handler: (async (req: ExtendedPayloadRequest) => {\n try {\n const data = await req.json()\n const { email, redirectUrl } = data as SigninRequestData & { redirectUrl?: string }\n\n // Validate email\n const validation = validateSubscriberData({ email })\n if (!validation.valid) {\n return Response.json({\n success: false,\n errors: validation.errors,\n }, { status: 400 })\n }\n\n // Check rate limit (per email to prevent abuse)\n const rateLimitKey = `signin:${email.toLowerCase()}`\n const allowed = await signinRateLimiter.checkLimit(rateLimitKey)\n \n if (!allowed) {\n return Response.json({\n success: false,\n error: 'Too many sign-in attempts. Please try again later.',\n }, { status: 429 })\n }\n\n // Find existing subscriber (including unsubscribed)\n const result = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n email: { equals: email.toLowerCase() },\n },\n limit: 1,\n overrideAccess: true, // Need to check subscriber exists\n })\n\n if (result.docs.length === 0) {\n return Response.json({\n success: false,\n error: 'Email not found. Please subscribe first.',\n requiresSubscribe: true,\n }, { status: 404 })\n }\n\n const subscriber = result.docs[0]\n \n // Check if unsubscribed and whether we allow unsubscribed signin\n const allowUnsubscribed = config.auth?.allowUnsubscribedSignin ?? false\n \n if (subscriber.subscriptionStatus === 'unsubscribed' && !allowUnsubscribed) {\n return Response.json({\n success: false,\n error: 'Your subscription is inactive. Please resubscribe to sign in.',\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n requiresResubscribe: true,\n }, { status: 403 })\n }\n\n // Generate magic link token\n const token = generateMagicLinkToken(\n String(subscriber.id),\n subscriber.email,\n config\n )\n\n // Generate magic link URL\n const serverURL = req.payload.config.serverURL || process.env.PAYLOAD_PUBLIC_SERVER_URL || ''\n const magicLinkURL = generateMagicLinkURL(token, serverURL, config, redirectUrl)\n\n // Get email service\n const emailService = (req.payload as any).newsletterEmailService // TODO: Add proper type for newsletter email service\n\n if (emailService) {\n // Get settings for customization\n const settings = await req.payload.findGlobal({\n slug: config.settingsSlug || 'newsletter-settings',\n })\n\n // Render email - pass config to use custom templates\n const html = await renderEmail('signin', {\n magicLink: magicLinkURL,\n email: subscriber.email,\n siteName: settings?.brandSettings?.siteName || 'Newsletter',\n expiresIn: config.auth?.tokenExpiration || '7d',\n }, config)\n\n // Use magic link subject from settings if available\n const subject = settings?.emailTemplates?.magicLink?.subjectLine || \n (settings?.brandSettings?.siteName \n ? `Sign in to ${settings.brandSettings.siteName}` \n : 'Sign in to your account')\n\n // Send email\n await emailService.send({\n to: subscriber.email,\n subject,\n html,\n })\n\n // Sign-in email sent successfully\n } else {\n console.warn('Email service not initialized, cannot send sign-in link')\n }\n\n return Response.json({\n success: true,\n message: 'Check your email for the sign-in link',\n })\n } catch (error) {\n console.error('Sign-in error:', error)\n return Response.json({\n success: false,\n error: 'Failed to process sign-in request',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig, ExtendedPayloadRequest } from '../types'\nimport { verifySessionToken } from '../utils/jwt'\n\nexport const createMeEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/me',\n method: 'get',\n handler: (async (req: ExtendedPayloadRequest) => {\n try {\n // Get token from cookie header\n const cookieHeader = req.headers.get('cookie') || ''\n const cookies = Object.fromEntries(\n cookieHeader.split('; ').map(c => {\n const [key, ...value] = c.split('=')\n return [key, value.join('=')]\n })\n )\n const token = cookies['newsletter-auth']\n \n if (!token) {\n return Response.json({\n success: false,\n error: 'Not authenticated',\n }, { status: 401 })\n }\n\n // Verify the session token\n let payload\n try {\n payload = verifySessionToken(token)\n } catch {\n return Response.json({\n success: false,\n error: 'Invalid or expired session',\n }, { status: 401 })\n }\n\n // Get fresh subscriber data\n const subscriber = await req.payload.findByID({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n overrideAccess: true, // Need to get subscriber data\n })\n\n if (!subscriber || subscriber.subscriptionStatus !== 'active') {\n return Response.json({\n success: false,\n error: 'Not authenticated',\n }, { status: 401 })\n }\n\n return Response.json({\n success: true,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n name: subscriber.name,\n status: subscriber.subscriptionStatus,\n preferences: {\n frequency: subscriber.emailPreferences?.frequency,\n categories: subscriber.emailPreferences?.categories,\n },\n createdAt: subscriber.createdAt,\n updatedAt: subscriber.updatedAt,\n },\n })\n } catch (error) {\n console.error('Me endpoint error:', error)\n return Response.json({\n success: false,\n error: 'Internal server error',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig, ExtendedPayloadRequest } from '../types'\n\nexport const createSignoutEndpoint = (\n _config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/signout',\n method: 'post',\n handler: ((_req: ExtendedPayloadRequest) => {\n try {\n // In Payload v3, cookies are handled differently\n // The Response object doesn't have a clearCookie method\n // We'll need to set the cookie with an expired date\n const headers = new Headers()\n headers.append('Set-Cookie', `newsletter-auth=; HttpOnly; Secure=${process.env.NODE_ENV === 'production'}; SameSite=Lax; Path=/; Max-Age=0`)\n \n return Response.json({ \n success: true, \n message: 'Signed out successfully' \n }, { headers })\n } catch (error) {\n console.error('Signout error:', error)\n return Response.json({\n success: false,\n error: 'Failed to sign out',\n }, { status: 500 })\n }\n }) as PayloadHandler,\n }\n}","import type { Endpoint } from 'payload'\nimport type { NewsletterPluginConfig } from '../../types'\n\nexport const createBroadcastManagementEndpoints = (\n _config: NewsletterPluginConfig\n): Endpoint[] => {\n // Broadcast endpoints are now added directly to the broadcasts collection\n // This function is kept for backward compatibility but returns empty array\n return []\n}","import type { Endpoint } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { createSubscribeEndpoint } from './subscribe'\nimport { createVerifyMagicLinkEndpoint } from './verify-magic-link'\nimport { createPreferencesEndpoint, createUpdatePreferencesEndpoint } from './preferences'\nimport { createUnsubscribeEndpoint } from './unsubscribe'\nimport { createSigninEndpoint } from './signin'\nimport { createMeEndpoint } from './me'\nimport { createSignoutEndpoint } from './signout'\nimport { createBroadcastManagementEndpoints } from './broadcasts'\n\nexport function createNewsletterEndpoints(\n config: NewsletterPluginConfig\n): Endpoint[] {\n const endpoints: Endpoint[] = [\n createSubscribeEndpoint(config),\n createUnsubscribeEndpoint(config),\n ]\n\n // Add auth endpoints if enabled\n if (config.auth?.enabled !== false) {\n endpoints.push(\n createVerifyMagicLinkEndpoint(config),\n createPreferencesEndpoint(config),\n createUpdatePreferencesEndpoint(config),\n createSigninEndpoint(config),\n createMeEndpoint(config),\n createSignoutEndpoint(config)\n )\n }\n\n // Add broadcast management endpoints if enabled\n endpoints.push(...createBroadcastManagementEndpoints(config))\n\n return endpoints\n}","import type { Field } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\n\nexport function createNewsletterSchedulingFields(\n config: NewsletterPluginConfig\n): Field[] {\n const groupName = config.features?.newsletterScheduling?.fields?.groupName || 'newsletterScheduling'\n const contentField = config.features?.newsletterScheduling?.fields?.contentField || 'content'\n const createMarkdownField = config.features?.newsletterScheduling?.fields?.createMarkdownField !== false\n\n const fields: Field[] = [\n {\n name: groupName,\n type: 'group',\n label: 'Newsletter Scheduling',\n admin: {\n condition: (data, { user }) => user?.collection === 'users', // Only show for admin users\n },\n fields: [\n {\n name: 'scheduled',\n type: 'checkbox',\n label: 'Schedule for Newsletter',\n defaultValue: false,\n admin: {\n description: 'Schedule this content to be sent as a newsletter',\n },\n },\n {\n name: 'scheduledDate',\n type: 'date',\n label: 'Send Date',\n required: true,\n admin: {\n date: {\n pickerAppearance: 'dayAndTime',\n },\n condition: (data) => data?.[groupName]?.scheduled,\n description: 'When to send this newsletter',\n },\n },\n {\n name: 'sentDate',\n type: 'date',\n label: 'Sent Date',\n admin: {\n readOnly: true,\n condition: (data) => data?.[groupName]?.sendStatus === 'sent',\n description: 'When this newsletter was sent',\n },\n },\n {\n name: 'sendStatus',\n type: 'select',\n label: 'Status',\n options: [\n { label: 'Draft', value: 'draft' },\n { label: 'Scheduled', value: 'scheduled' },\n { label: 'Sending', value: 'sending' },\n { label: 'Sent', value: 'sent' },\n { label: 'Failed', value: 'failed' },\n ],\n defaultValue: 'draft',\n admin: {\n readOnly: true,\n description: 'Current send status',\n },\n },\n {\n name: 'emailSubject',\n type: 'text',\n label: 'Email Subject',\n required: true,\n admin: {\n condition: (data) => data?.[groupName]?.scheduled,\n description: 'Subject line for the newsletter email',\n },\n },\n {\n name: 'preheader',\n type: 'text',\n label: 'Email Preheader',\n admin: {\n condition: (data) => data?.[groupName]?.scheduled,\n description: 'Preview text that appears after the subject line',\n },\n },\n {\n name: 'segments',\n type: 'select',\n label: 'Target Segments',\n hasMany: true,\n options: [\n { label: 'All Subscribers', value: 'all' },\n ...(config.i18n?.locales?.map(locale => ({\n label: `${locale.toUpperCase()} Subscribers`,\n value: locale,\n })) || []),\n ],\n defaultValue: ['all'],\n admin: {\n condition: (data) => data?.[groupName]?.scheduled,\n description: 'Which subscriber segments to send to',\n },\n },\n {\n name: 'testEmails',\n type: 'array',\n label: 'Test Email Recipients',\n admin: {\n condition: (data) => data?.[groupName]?.scheduled && data?.[groupName]?.sendStatus === 'draft',\n description: 'Send test emails before scheduling',\n },\n fields: [\n {\n name: 'email',\n type: 'email',\n required: true,\n },\n ],\n },\n ],\n },\n ]\n\n // Add markdown companion field if requested\n if (createMarkdownField) {\n fields.push(createMarkdownFieldInternal({\n name: `${contentField}Markdown`,\n richTextField: contentField,\n label: 'Email Content (Markdown)',\n admin: {\n position: 'sidebar',\n condition: (data: any) => Boolean(data?.[contentField] && data?.[groupName]?.scheduled),\n description: 'Markdown version for email rendering',\n readOnly: true,\n },\n }))\n }\n\n return fields\n}\n\n/**\n * Create a markdown companion field for rich text\n * This creates a virtual field that converts rich text to markdown\n */\nfunction createMarkdownFieldInternal(config: {\n name: string\n richTextField: string\n label?: string\n admin?: any\n}): Field {\n return {\n name: config.name,\n type: 'textarea',\n label: config.label || 'Markdown',\n admin: {\n ...config.admin,\n description: config.admin?.description || 'Auto-generated from rich text content',\n },\n hooks: {\n afterRead: [\n async ({ data }) => {\n // Convert rich text to markdown on read\n if (data?.[config.richTextField]) {\n try {\n const { convertLexicalToMarkdown } = await import('@payloadcms/richtext-lexical')\n return convertLexicalToMarkdown({\n data: data[config.richTextField],\n } as any)\n } catch {\n return ''\n }\n }\n return ''\n },\n ],\n beforeChange: [\n () => {\n // Don't save markdown to database\n return null\n },\n ],\n },\n }\n}","import type { TaskConfig, PayloadRequest } from 'payload'\nimport type { NewsletterPluginConfig } from '../types/index'\n\nexport const createUnsubscribeSyncJob = (\n pluginConfig: NewsletterPluginConfig\n): TaskConfig => {\n return {\n slug: 'sync-unsubscribes',\n label: 'Sync Unsubscribes from Email Service',\n handler: async ({ req }: { req: PayloadRequest }) => {\n const subscribersSlug = pluginConfig.subscribersSlug || 'subscribers'\n const emailService = (req.payload as any).newsletterEmailService // TODO: Add proper type for newsletter email service\n \n if (!emailService) {\n console.error('Email service not configured')\n return {\n output: {\n syncedCount: 0\n }\n }\n }\n\n let syncedCount = 0\n \n try {\n // For Broadcast: Poll all subscribers\n if (emailService.getProvider() === 'broadcast') {\n console.warn('Starting Broadcast unsubscribe sync...')\n \n // Get Broadcast configuration\n const broadcastConfig = pluginConfig.providers?.broadcast\n if (!broadcastConfig) {\n throw new Error('Broadcast configuration not found')\n }\n\n const apiUrl = broadcastConfig.apiUrl.replace(/\\/$/, '')\n const token = broadcastConfig.token\n\n let page = 1\n let hasMore = true\n\n while (hasMore) {\n // Fetch subscribers from Broadcast\n const response = await fetch(\n `${apiUrl}/api/v1/subscribers.json?page=${page}`,\n {\n headers: {\n 'Authorization': `Bearer ${token}`,\n },\n }\n )\n\n if (!response.ok) {\n throw new Error(`Broadcast API error: ${response.status}`)\n }\n\n const data = await response.json()\n const broadcastSubscribers = data.subscribers || []\n \n // Process each subscriber\n for (const broadcastSub of broadcastSubscribers) {\n // Find corresponding subscriber in Payload\n const payloadSubscribers = await req.payload.find({\n collection: subscribersSlug,\n where: {\n email: {\n equals: broadcastSub.email,\n },\n },\n limit: 1,\n })\n\n if (payloadSubscribers.docs.length > 0) {\n const payloadSub = payloadSubscribers.docs[0]\n \n // Check if unsubscribe status differs\n const broadcastUnsubscribed = !broadcastSub.is_active || broadcastSub.unsubscribed_at\n const payloadUnsubscribed = payloadSub.subscriptionStatus === 'unsubscribed'\n \n if (broadcastUnsubscribed && !payloadUnsubscribed) {\n // Update Payload subscriber to unsubscribed\n await req.payload.update({\n collection: subscribersSlug,\n id: payloadSub.id,\n data: {\n subscriptionStatus: 'unsubscribed',\n unsubscribedAt: broadcastSub.unsubscribed_at || new Date().toISOString(),\n },\n })\n syncedCount++\n console.warn(`Unsubscribed: ${broadcastSub.email}`)\n }\n }\n }\n\n // Check pagination\n if (data.pagination && data.pagination.current < data.pagination.total_pages) {\n page++\n } else {\n hasMore = false\n }\n }\n\n console.warn(`Broadcast sync complete. Unsubscribed ${syncedCount} contacts.`)\n }\n\n // For Resend: Use Audiences API\n if (emailService.getProvider() === 'resend') {\n console.warn('Starting Resend unsubscribe sync...')\n \n // Note: Resend webhooks are preferred over polling\n // This is a fallback polling implementation\n \n // First, get all audiences\n const resendConfig = pluginConfig.providers?.resend\n if (!resendConfig) {\n throw new Error('Resend configuration not found')\n }\n\n // You would need to implement audience/contact polling here\n // Resend's API structure would require:\n // 1. List audiences\n // 2. For each audience, list contacts\n // 3. Check unsubscribed status\n \n console.warn('Resend polling implementation needed - webhooks recommended')\n }\n\n // Custom after sync hook\n if (pluginConfig.hooks?.afterUnsubscribeSync) {\n await pluginConfig.hooks.afterUnsubscribeSync({ \n req, \n syncedCount: syncedCount\n })\n }\n\n } catch (error) {\n console.error('Unsubscribe sync error:', error)\n throw error\n }\n \n return {\n output: {\n syncedCount\n }\n }\n },\n }\n}","import type { CollectionConfig } from 'payload'\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: 'providerData',\n type: 'json',\n admin: {\n readOnly: true,\n condition: () => false, // Hidden by default\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 // Handle create operation\n if (operation === 'create') {\n // Skip provider sync if essential fields are missing\n // Broadcast API requires both subject and body\n if (!doc.subject || !doc.contentSection?.content) {\n req.payload.logger.info('Skipping provider sync - broadcast has no subject or content yet')\n return doc\n }\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 // Populate media fields and convert rich text to HTML\n req.payload.logger.info('Populating media fields and converting content to HTML...')\n const populatedContent = await populateMediaFields(doc.contentSection?.content, req.payload, pluginConfig)\n const htmlContent = await convertToEmailSafeHtml(populatedContent, {\n customBlockConverter: pluginConfig.customizations?.broadcasts?.customBlockConverter\n })\n \n // Skip if content is empty after conversion\n if (!htmlContent || htmlContent.trim() === '') {\n req.payload.logger.info('Skipping provider sync - content is empty after conversion')\n return doc\n }\n \n // Log what we're about to send\n const createData = {\n name: doc.subject, // Use subject as name since we removed the name field\n subject: doc.subject,\n preheader: doc.contentSection?.preheader,\n content: htmlContent,\n trackOpens: doc.settings?.trackOpens,\n trackClicks: doc.settings?.trackClicks,\n replyTo: doc.settings?.replyTo || providerConfig.replyTo,\n audienceIds: doc.audienceIds?.map((a: any) => a.audienceId),\n }\n \n req.payload.logger.info('Creating broadcast with data:', {\n name: createData.name,\n subject: createData.subject,\n preheader: createData.preheader || 'NONE',\n contentLength: htmlContent ? htmlContent.length : 0,\n contentPreview: htmlContent ? htmlContent.substring(0, 100) + '...' : 'EMPTY',\n trackOpens: createData.trackOpens,\n trackClicks: createData.trackClicks,\n replyTo: createData.replyTo,\n audienceIds: createData.audienceIds || [],\n apiUrl: providerConfig.apiUrl,\n hasToken: !!providerConfig.token,\n })\n\n // Create broadcast in provider\n const providerBroadcast = await provider.create(createData)\n\n // Update with provider ID\n await req.payload.update({\n collection: 'broadcasts',\n id: doc.id,\n data: {\n providerId: providerBroadcast.id,\n providerData: providerBroadcast.providerData,\n },\n req,\n })\n\n return {\n ...doc,\n providerId: providerBroadcast.id,\n providerData: providerBroadcast.providerData,\n }\n } catch (error: unknown) {\n // Log the raw error first to see what we're dealing with\n req.payload.logger.error('Raw error from broadcast provider:')\n req.payload.logger.error(error)\n \n // Try different error formats\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 // If it's a BroadcastProviderError, it might have additional details\n ...(error as any).details,\n // Check if it's a fetch response error\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('Error is a string:', error)\n } else if (error && typeof error === 'object') {\n req.payload.logger.error('Error is an object:', JSON.stringify(error, null, 2))\n } else {\n req.payload.logger.error('Unknown error type:', typeof error)\n }\n \n // Also log the doc info for context\n req.payload.logger.error('Failed broadcast document:', {\n id: doc.id,\n subject: doc.subject,\n hasContent: !!doc.contentSection?.content,\n contentType: doc.contentSection?.content ? typeof doc.contentSection.content : 'none',\n })\n \n return doc\n }\n }\n \n // Handle update operation\n if (operation === 'update') {\n req.payload.logger.info('Broadcast afterChange update hook triggered', {\n operation,\n hasProviderId: !!doc.providerId,\n sendStatus: doc.sendStatus,\n publishStatus: doc._status\n })\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 exists yet, we need to create in provider first (deferred from initial create)\n if (!doc.providerId) {\n // Check if we have minimum required fields now\n if (!doc.subject || !doc.contentSection?.content) {\n req.payload.logger.info('Still missing required fields for provider sync')\n return doc\n }\n\n // Populate media fields and convert rich text to HTML\n req.payload.logger.info('Creating broadcast in provider (deferred from initial create)...')\n const populatedContent = await populateMediaFields(doc.contentSection?.content, req.payload, pluginConfig)\n const htmlContent = await convertToEmailSafeHtml(populatedContent, {\n customBlockConverter: pluginConfig.customizations?.broadcasts?.customBlockConverter\n })\n\n // Skip if content is empty after conversion\n if (!htmlContent || htmlContent.trim() === '') {\n req.payload.logger.info('Skipping provider sync - content is empty after conversion')\n return doc\n }\n\n // Create broadcast in provider\n const createData = {\n name: doc.subject,\n subject: doc.subject,\n preheader: doc.contentSection?.preheader,\n content: htmlContent,\n trackOpens: doc.settings?.trackOpens,\n trackClicks: doc.settings?.trackClicks,\n replyTo: doc.settings?.replyTo || providerConfig.replyTo,\n audienceIds: doc.audienceIds?.map((a: any) => a.audienceId),\n }\n\n req.payload.logger.info('Creating broadcast with data:', {\n name: createData.name,\n subject: createData.subject,\n preheader: createData.preheader || 'NONE',\n contentLength: htmlContent ? htmlContent.length : 0,\n contentPreview: htmlContent ? htmlContent.substring(0, 100) + '...' : 'EMPTY',\n apiUrl: providerConfig.apiUrl,\n hasToken: !!providerConfig.token,\n })\n\n const providerBroadcast = await provider.create(createData)\n\n // Update with provider ID\n await req.payload.update({\n collection: 'broadcasts',\n id: doc.id,\n data: {\n providerId: providerBroadcast.id,\n providerData: providerBroadcast.providerData,\n },\n req,\n })\n\n req.payload.logger.info(`Broadcast ${doc.id} created in provider successfully (deferred)`)\n\n return {\n ...doc,\n providerId: providerBroadcast.id,\n providerData: providerBroadcast.providerData,\n }\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)\n updates.content = await convertToEmailSafeHtml(populatedContent, {\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('Syncing broadcast updates to provider', {\n providerId: doc.providerId,\n updates\n })\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('Error is a string:', error)\n } else if (error && typeof error === 'object') {\n req.payload.logger.error('Error is an object:', JSON.stringify(error, null, 2))\n } else {\n req.payload.logger.error('Unknown error type:', typeof error)\n }\n \n req.payload.logger.error('Failed broadcast document (update operation):', {\n id: doc.id,\n subject: doc.subject,\n hasContent: !!doc.contentSection?.content,\n contentType: doc.contentSection?.content ? typeof doc.contentSection.content : 'none',\n })\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(`Failed to send broadcast ${doc.id}:`, error)\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('Failed to delete broadcast from provider:', error)\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 with enhanced configuration\n LinkFeature({\n fields: [\n {\n name: 'url',\n type: 'text',\n required: true,\n admin: {\n description: 'Enter the full URL (including https://)',\n },\n },\n {\n name: 'newTab',\n type: 'checkbox',\n label: 'Open in new tab',\n defaultValue: false,\n },\n ],\n }),\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 with enhanced configuration\n LinkFeature({\n fields: [\n {\n name: 'url',\n type: 'text',\n required: true,\n admin: {\n description: 'Enter the full URL (including https://)',\n },\n },\n {\n name: 'newTab',\n type: 'checkbox',\n label: 'Open in new tab',\n defaultValue: false,\n },\n ],\n }),\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 }) => string | Promise<string>\n subject?: string // Email subject 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 }))\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('Failed to get broadcast config from settings:', error)\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 { 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 { Endpoint, PayloadHandler, PayloadRequest, Payload } from 'payload'\nimport type { NewsletterPluginConfig } from '../../types'\nimport { convertToEmailSafeHtml } from '../../utils/emailSafeHtml'\n\n// Helper function to recursively find and populate media fields in content\nexport async function populateMediaFields(content: any, payload: Payload, config: NewsletterPluginConfig): Promise<any> {\n if (!content || typeof content !== 'object') return content\n \n // Handle Lexical editor state\n if (content.root?.children) {\n for (const child of content.root.children) {\n await populateBlockMediaFields(child, payload, config)\n }\n }\n \n return content\n}\n\n// Helper function to populate media fields in individual blocks\nasync function populateBlockMediaFields(node: any, payload: Payload, config: NewsletterPluginConfig): Promise<void> {\n // Check if this is a block node\n if (node.type === 'block' && node.fields) {\n const blockType = node.fields.blockType || node.fields.blockName\n \n // Get custom blocks configuration\n const customBlocks = config.customizations?.broadcasts?.customBlocks || []\n const blockConfig = customBlocks.find((b: any) => 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 && node.fields[field.name]) {\n const fieldValue = node.fields[field.name]\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: field.relationTo,\n id: fieldValue,\n depth: 0,\n })\n \n if (media) {\n node.fields[field.name] = media\n payload.logger?.info(`Populated ${field.name} for block ${blockType}:`, {\n mediaId: fieldValue,\n mediaUrl: media.url,\n filename: media.filename\n })\n }\n } catch (error) {\n payload.logger?.error(`Failed to populate ${field.name} for block ${blockType}:`, error)\n }\n }\n }\n \n // Also handle arrays of uploads\n if (field.type === 'array' && field.fields) {\n const arrayValue = node.fields[field.name]\n if (Array.isArray(arrayValue)) {\n for (const arrayItem of arrayValue) {\n if (arrayItem && typeof arrayItem === 'object') {\n // Recursively process array items for upload fields\n for (const arrayField of field.fields) {\n if (arrayField.type === 'upload' && arrayField.relationTo && arrayItem[arrayField.name]) {\n const arrayFieldValue = arrayItem[arrayField.name]\n \n if (typeof arrayFieldValue === 'string' && arrayFieldValue.match(/^[a-f0-9]{24}$/i)) {\n try {\n const media = await payload.findByID({\n collection: arrayField.relationTo,\n id: arrayFieldValue,\n depth: 0,\n })\n \n if (media) {\n arrayItem[arrayField.name] = media\n payload.logger?.info(`Populated array ${arrayField.name} for block ${blockType}:`, {\n mediaId: arrayFieldValue,\n mediaUrl: media.url,\n filename: media.filename\n })\n }\n } catch (error) {\n payload.logger?.error(`Failed to populate array ${arrayField.name} for block ${blockType}:`, error)\n }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n \n // Recursively process children\n if (node.children) {\n for (const child of node.children) {\n await populateBlockMediaFields(child, payload, config)\n }\n }\n}\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 } = 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, {\n wrapInTemplate: emailPreviewConfig?.wrapInTemplate ?? true,\n preheader: preheader,\n subject: subject,\n mediaUrl: mediaUrl,\n customBlockConverter: config.customizations?.broadcasts?.customBlockConverter,\n customWrapper: emailPreviewConfig?.customWrapper,\n })\n\n return Response.json({\n success: true,\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 { Resend } from 'resend'\nimport 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 { ResendProviderConfig } from '../../types'\n\n/**\n * Resend Broadcast Provider\n * \n * IMPORTANT LIMITATIONS:\n * - Resend's Broadcast API is not fully documented publicly\n * - Many operations may not be available via API\n * - Broadcasts created via API can only be edited via API (not in dashboard)\n * - Channel management maps to Resend's Audience API\n * - Some methods below are marked as TODO pending official API documentation\n */\nexport class ResendBroadcastProvider extends BaseBroadcastProvider {\n readonly name = 'resend'\n private client: Resend\n private audienceIds: ResendProviderConfig['audienceIds']\n private isDevelopment: boolean\n\n constructor(config: ResendProviderConfig) {\n super(config)\n this.client = new Resend(config.apiKey)\n this.audienceIds = config.audienceIds || {}\n this.isDevelopment = process.env.NODE_ENV !== 'production'\n \n if (!config.apiKey) {\n throw new BroadcastProviderError(\n 'Resend API key is required',\n BroadcastErrorCode.CONFIGURATION_ERROR,\n this.name\n )\n }\n }\n\n\n // Broadcast Management Methods\n async list(_options?: ListBroadcastOptions): Promise<ListBroadcastResponse<Broadcast>> {\n // TODO: Resend broadcast list API is not documented\n // The SDK may have undocumented methods we could explore\n // For now, we throw a not supported error\n throw new BroadcastProviderError(\n 'Listing broadcasts is not currently supported by Resend API. ' +\n 'This feature may be available in the dashboard only.',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\n }\n\n async get(_id: string): Promise<Broadcast> {\n // TODO: Resend broadcast get API is not documented\n // We would need to explore if the SDK has undocumented methods\n throw new BroadcastProviderError(\n 'Getting individual broadcasts is not currently supported by Resend API. ' +\n 'This feature may be available in the dashboard only.',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\n }\n\n async create(data: CreateBroadcastInput): Promise<Broadcast> {\n try {\n this.validateRequiredFields(data, ['name', 'subject', 'content'])\n\n // Get the appropriate audience ID\n const locale = 'en' // TODO: Make this configurable\n const audienceConfig = this.audienceIds?.[locale]\n const audienceId = this.isDevelopment \n ? audienceConfig?.development || audienceConfig?.production\n : audienceConfig?.production || audienceConfig?.development\n\n if (!audienceId && data.audienceIds?.length) {\n // Use provided audience ID if no default configured\n // Note: Resend might only support one audience per broadcast\n }\n\n // TODO: The exact Resend broadcast creation API is not documented\n // Based on their blog posts, it seems broadcasts can be created via API\n // but the exact endpoint/method is unclear\n \n // Attempt to use broadcasts if available in SDK\n const resendClient = this.client as any\n if (resendClient.broadcasts?.create) {\n const broadcast = await resendClient.broadcasts.create({\n name: data.name,\n subject: data.subject,\n from: `${(this.config as ResendProviderConfig).fromName || 'Newsletter'} <${(this.config as ResendProviderConfig).fromEmail || 'noreply@example.com'}>`,\n reply_to: data.replyTo,\n audience_id: audienceId || data.audienceIds?.[0],\n content: {\n html: data.content,\n // TODO: Handle plain text version\n }\n })\n\n // Transform to our Broadcast type\n return this.transformResendToBroadcast(broadcast)\n }\n\n // If broadcasts API not available, throw error\n throw new BroadcastProviderError(\n 'Creating broadcasts via API is not currently supported. ' +\n 'Please check if Resend has released their Broadcasts API.',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\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 // TODO: Resend broadcast update API is not documented\n // Important: Resend has restrictions where broadcasts created via API\n // can only be edited via API (not in dashboard)\n throw new BroadcastProviderError(\n 'Updating broadcasts is not currently supported by Resend API. ' +\n 'Note: Resend broadcasts can only be edited where they were created.',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\n }\n\n async delete(_id: string): Promise<void> {\n // TODO: Resend broadcast delete API is not documented\n throw new BroadcastProviderError(\n 'Deleting broadcasts is not currently supported by Resend API.',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\n }\n\n async send(id: string, options?: SendBroadcastOptions): Promise<Broadcast> {\n try {\n // TODO: The exact Resend broadcast send API is not documented\n // Based on their features, sending broadcasts is supported\n \n const resendClient = this.client as any\n if (resendClient.broadcasts?.send) {\n await resendClient.broadcasts.send(id, {\n audience_id: options?.audienceIds?.[0],\n // TODO: Handle test mode if supported\n })\n\n // We can't get the updated broadcast, so return a mock\n return {\n id,\n name: 'Unknown',\n subject: 'Unknown',\n content: '',\n sendStatus: BroadcastStatus.SENDING,\n trackOpens: true,\n trackClicks: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n providerType: 'resend'\n } as Broadcast\n }\n\n throw new BroadcastProviderError(\n 'Sending broadcasts via API is not currently supported. ' +\n 'Please check if Resend has released their Broadcasts API.',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\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 // Scheduling is not supported according to our research\n throw new BroadcastProviderError(\n 'Scheduling broadcasts is not supported by Resend',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\n }\n\n async getAnalytics(_id: string): Promise<BroadcastAnalytics> {\n // TODO: Resend does support analytics, but the API is not documented\n // They have dashboard analytics for broadcasts\n throw new BroadcastProviderError(\n 'Getting broadcast analytics via API is not currently supported. ' +\n 'Analytics may be available in the Resend dashboard.',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\n }\n\n getCapabilities(): BroadcastProviderCapabilities {\n return {\n supportsScheduling: false, // Not documented\n supportsSegmentation: true, // Via Audiences\n supportsAnalytics: true, // Available in dashboard, API unclear\n supportsABTesting: false,\n supportsTemplates: false, // Not clear from docs\n supportsPersonalization: true, // Via merge tags\n supportsMultipleChannels: false,\n supportsChannelSegmentation: false,\n editableStatuses: [], // Unclear which statuses can be edited\n supportedContentTypes: ['html'] // React components via SDK\n }\n }\n\n async validateConfiguration(): Promise<boolean> {\n try {\n // Try to use the API key to validate it works\n // We can try to list audiences as a validation check\n const resendClient = this.client as any\n if (resendClient.audiences?.list) {\n await resendClient.audiences.list({ limit: 1 })\n return true\n }\n \n // Fallback: try to send a test email to validate API key\n await this.client.emails.send({\n from: 'onboarding@resend.dev',\n to: 'delivered@resend.dev',\n subject: 'Configuration Test',\n html: '<p>Testing configuration</p>'\n })\n return true\n } catch {\n return false\n }\n }\n\n /**\n * Transform Resend broadcast to our Broadcast type\n * NOTE: This is speculative based on what the API might return\n */\n private transformResendToBroadcast(broadcast: any): Broadcast {\n return {\n id: broadcast.id,\n name: broadcast.name || 'Untitled',\n subject: broadcast.subject,\n preheader: broadcast.preheader,\n content: broadcast.content?.html || broadcast.html || '',\n sendStatus: this.mapResendStatus(broadcast.status),\n trackOpens: true, // Resend tracks by default\n trackClicks: true, // Resend tracks by default\n replyTo: broadcast.reply_to,\n recipientCount: broadcast.recipient_count,\n sentAt: broadcast.sent_at ? new Date(broadcast.sent_at) : undefined,\n scheduledAt: broadcast.scheduled_at ? new Date(broadcast.scheduled_at) : undefined,\n createdAt: new Date(broadcast.created_at || Date.now()),\n updatedAt: new Date(broadcast.updated_at || Date.now()),\n providerData: { broadcast },\n providerId: broadcast.id,\n providerType: 'resend'\n }\n }\n\n private mapResendStatus(status?: string): BroadcastStatus {\n if (!status) return BroadcastStatus.DRAFT\n \n // NOTE: Resend statuses are not documented, these are guesses\n const statusMap: Record<string, BroadcastStatus> = {\n 'draft': BroadcastStatus.DRAFT,\n 'scheduled': BroadcastStatus.SCHEDULED,\n 'sending': BroadcastStatus.SENDING,\n 'sent': BroadcastStatus.SENT,\n 'failed': BroadcastStatus.FAILED\n }\n return statusMap[status.toLowerCase()] || BroadcastStatus.DRAFT\n }\n}\n\n/**\n * IMPLEMENTATION NOTES:\n * \n * 1. Most methods throw NOT_SUPPORTED errors because Resend's Broadcast API\n * is not publicly documented\n * \n * 2. The SDK might have undocumented methods (broadcasts.create, broadcasts.send, etc.)\n * that we attempt to use, but we can't guarantee they exist\n * \n * 3. Important limitation: Broadcasts created via API can only be edited via API,\n * not in the Resend dashboard\n * \n * 4. Resend uses \"Audiences\" instead of \"Segments\" for targeting\n * \n * 5. Analytics are available in the dashboard but API access is unclear\n * \n * FUTURE IMPROVEMENTS:\n * - Monitor Resend's documentation for Broadcast API updates\n * - Explore SDK source code for undocumented methods\n * - Consider using Resend's email API to simulate broadcasts\n * - Add webhook support for delivery/open/click tracking\n */","import type { PayloadRequest } from 'payload'\nimport jwt from 'jsonwebtoken'\n\n// Next.js types - these are optional and only used when Next.js is available\ninterface NextApiRequest {\n cookies?: { [key: string]: string }\n headers?: { [key: string]: string | string[] | undefined }\n [key: string]: any\n}\n\ninterface GetServerSidePropsContext {\n req: {\n cookies?: { [key: string]: string }\n headers?: { [key: string]: string | string[] | undefined }\n [key: string]: any\n }\n [key: string]: any\n}\n\ninterface TokenPayload {\n id: string\n email: string\n type?: string\n iat?: number\n exp?: number\n}\n\n/**\n * Extract token from request cookies\n */\nexport const getTokenFromRequest = (\n req: NextApiRequest | GetServerSidePropsContext['req'] | PayloadRequest\n): string | null => {\n // Handle different request types\n const cookies = (req as any).cookies || (req as any).headers?.cookie\n \n if (!cookies) return null\n \n // Parse cookies if it's a string\n if (typeof cookies === 'string') {\n const parsed = cookies.split(';').reduce((acc, cookie) => {\n const [key, value] = cookie.trim().split('=')\n acc[key] = value\n return acc\n }, {} as Record<string, string>)\n return parsed['newsletter-auth'] || null\n }\n \n // Direct cookie object\n return cookies['newsletter-auth'] || null\n}\n\n/**\n * Verify JWT token\n */\nexport const verifyToken = (\n token: string, \n secret: string\n): TokenPayload | null => {\n try {\n const decoded = jwt.verify(token, secret) as TokenPayload\n return decoded\n } catch {\n return null\n }\n}\n\n/**\n * Get authentication state for server-side rendering\n */\nexport const getServerSideAuth = async (\n context: GetServerSidePropsContext,\n secret?: string\n): Promise<{ subscriber: TokenPayload | null; isAuthenticated: boolean }> => {\n const token = getTokenFromRequest(context.req)\n \n if (!token) {\n return { subscriber: null, isAuthenticated: false }\n }\n \n const payloadSecret = secret || process.env.PAYLOAD_SECRET\n if (!payloadSecret) {\n console.error('No secret provided for token verification')\n return { subscriber: null, isAuthenticated: false }\n }\n \n const decoded = verifyToken(token, payloadSecret)\n \n if (!decoded) {\n return { subscriber: null, isAuthenticated: false }\n }\n \n return {\n subscriber: decoded,\n isAuthenticated: true,\n }\n}\n\n/**\n * Higher-order function for protecting pages\n */\nexport const requireAuth = <P extends { [key: string]: any }>(\n gssp?: (context: GetServerSidePropsContext) => Promise<{ props: P }>\n) => {\n return async (context: GetServerSidePropsContext) => {\n const { isAuthenticated, subscriber } = await getServerSideAuth(context)\n \n if (!isAuthenticated) {\n return {\n redirect: {\n destination: '/auth/signin',\n permanent: false,\n },\n }\n }\n \n // If there's a custom getServerSideProps, run it\n if (gssp) {\n const result = await gssp(context)\n return {\n ...result,\n props: {\n ...result.props,\n subscriber,\n },\n }\n }\n \n // Otherwise just return the subscriber\n return {\n props: {\n subscriber,\n } as any as P,\n }\n }\n}\n\n/**\n * Check if request has valid authentication\n */\nexport const isAuthenticated = (\n req: PayloadRequest | NextApiRequest,\n secret: string\n): boolean => {\n const token = getTokenFromRequest(req)\n if (!token) return false\n \n const decoded = verifyToken(token, secret)\n return !!decoded\n}","'use client'\n\nimport React, { createContext, useContext } from 'react'\nimport type { NewsletterPluginConfig } from '../types'\n\nconst PluginConfigContext = createContext<NewsletterPluginConfig | null>(null)\n\nexport const PluginConfigProvider: React.FC<{\n config: NewsletterPluginConfig\n children: React.ReactNode\n}> = ({ config, children }) => {\n return (\n <PluginConfigContext.Provider value={config}>\n {children}\n </PluginConfigContext.Provider>\n )\n}\n\nexport const usePluginConfig = () => {\n const config = useContext(PluginConfigContext)\n if (!config) {\n throw new Error('usePluginConfig must be used within PluginConfigProvider')\n }\n return config\n}\n\n/**\n * Hook to safely access plugin config without throwing if context is not available\n * This is useful for components that might be used outside of the plugin context\n */\nexport const usePluginConfigOptional = () => {\n return useContext(PluginConfigContext)\n}"],"mappings":"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","names":["init_broadcast","import_components","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","DOMPurify","jwt","subscriber","settings","jwt","import_isomorphic_dompurify","DOMPurify","styles","BroadcastApiProvider","BroadcastApiProvider","BroadcastApiProvider","init_broadcast","import_resend","import_jsonwebtoken","jwt","isAuthenticated","import_jsx_runtime"]}
|