payload-plugin-newsletter
Version:
Complete newsletter management plugin for Payload CMS with subscriber management, magic link authentication, and email service integration
1 lines • 322 kB
Source Map (JSON)
{"version":3,"sources":["../src/types/newsletter.ts","../src/types/broadcast.ts","../src/types/channel.ts","../src/types/providers.ts","../src/types/index.ts","../src/providers/broadcast/broadcast.ts","../src/providers/resend/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/send.ts","../src/utils/auth.ts","../src/endpoints/broadcasts/schedule.ts","../src/utils/emailSafeHtml.ts","../src/endpoints/broadcasts/test.ts","../src/endpoints/broadcasts/index.ts","../src/endpoints/index.ts","../src/fields/newsletterScheduling.ts","../src/jobs/sync-unsubscribes.ts","../src/collections/Channels.ts","../src/collections/Broadcasts.ts","../src/fields/emailContent.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 channelId: string; // Reference to the channel this broadcast belongs to\n name: string;\n subject: string;\n preheader?: string;\n content: string; // HTML content\n status: 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 channelId?: string; // Filter by channel\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 channelId: string; // Which channel to send to\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 within the channel\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 within the channel\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 // Channel-specific capabilities\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 CHANNEL_NOT_FOUND = 'CHANNEL_NOT_FOUND',\n INVALID_CHANNEL = 'INVALID_CHANNEL'\n}\n\n/**\n * Broadcast template for reusable content\n */\nexport interface BroadcastTemplate {\n id: string;\n channelId?: string; // Optional channel-specific template\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';","export interface Channel {\n id: string;\n name: string;\n description?: string;\n fromName: string;\n fromEmail: string;\n replyTo?: string;\n providerId: string;\n providerType: 'broadcast' | 'resend';\n subscriberCount?: number;\n active: boolean;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface CreateChannelInput {\n name: string;\n description?: string;\n fromName: string;\n fromEmail: string;\n replyTo?: string;\n}\n\nexport interface UpdateChannelInput {\n name?: string;\n description?: string;\n fromName?: string;\n fromEmail?: string;\n replyTo?: string;\n active?: boolean;\n}\n\nexport interface ListChannelsOptions {\n limit?: number;\n offset?: number;\n active?: boolean;\n}\n\nexport interface ListChannelsResponse {\n channels: Channel[];\n total: number;\n limit: number;\n offset: number;\n}","/**\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// Import channel types\nimport type {\n Channel,\n CreateChannelInput,\n UpdateChannelInput,\n ListChannelsOptions,\n ListChannelsResponse\n} from './channel'\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 // Channel management methods\n /**\n * List channels (newsletter types/publications)\n */\n listChannels(options?: ListChannelsOptions): Promise<ListChannelsResponse>;\n \n /**\n * Get a specific channel by ID\n */\n getChannel(id: string): Promise<Channel>;\n \n /**\n * Create a new channel\n */\n createChannel(data: CreateChannelInput): Promise<Channel>;\n \n /**\n * Update an existing channel\n */\n updateChannel(id: string, data: UpdateChannelInput): Promise<Channel>;\n \n /**\n * Delete a channel\n */\n deleteChannel(id: string): Promise<void>;\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 // Channel management - abstract methods\n abstract listChannels(options?: ListChannelsOptions): Promise<ListChannelsResponse>;\n abstract getChannel(id: string): Promise<Channel>;\n abstract createChannel(data: CreateChannelInput): Promise<Channel>;\n abstract updateChannel(id: string, data: UpdateChannelInput): Promise<Channel>;\n abstract deleteChannel(id: string): Promise<void>;\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 } from 'payload'\nimport type { BroadcastProvider } from './providers'\n\n// Export broadcast and channel types\nexport * from './broadcast'\nexport * from './channel'\nexport * from './providers'\n// Export legacy newsletter types for backwards compatibility\nexport * from './newsletter'\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 /**\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 * Channels collection slug\n * @default 'channels'\n */\n channels?: string\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\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 tokens: {\n production?: string\n development?: string\n }\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 Channel,\n CreateChannelInput,\n UpdateChannelInput,\n ListChannelsOptions,\n ListChannelsResponse\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// Channel API interfaces\ninterface BroadcastChannelApiResponse {\n id: number\n name: string\n description?: string\n address: string\n from: string\n reply_to?: string\n total_active_subscribers: number\n created_at: string\n updated_at: string\n}\n\nexport class BroadcastApiProvider extends BaseBroadcastProvider {\n readonly name = 'broadcast'\n private apiUrl: string\n private token: string\n private isDevelopment: boolean\n\n constructor(config: BroadcastProviderConfig) {\n super(config)\n this.apiUrl = config.apiUrl.replace(/\\/$/, '') // Remove trailing slash\n this.isDevelopment = process.env.NODE_ENV !== 'production'\n this.token = this.isDevelopment \n ? config.tokens.development || config.tokens.production || ''\n : config.tokens.production || config.tokens.development || ''\n \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 // Channel Management Methods\n async listChannels(options?: ListChannelsOptions): Promise<ListChannelsResponse> {\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/channels?${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 = await response.json()\n const channels = data.data.map((channel: BroadcastChannelApiResponse) => this.transformChannelFromApi(channel))\n \n return {\n channels,\n total: data.total || channels.length,\n limit: options?.limit || 20,\n offset: options?.offset || 0\n }\n } catch (error: unknown) {\n throw new BroadcastProviderError(\n `Failed to list channels: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async getChannel(id: string): Promise<Channel> {\n try {\n const response = await fetch(`${this.apiUrl}/api/v1/channels/${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 `Channel not found: ${id}`,\n BroadcastErrorCode.CHANNEL_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 channel: BroadcastChannelApiResponse = await response.json()\n return this.transformChannelFromApi(channel)\n } catch (error: unknown) {\n if (error instanceof BroadcastProviderError) throw error\n \n throw new BroadcastProviderError(\n `Failed to get channel: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async createChannel(data: CreateChannelInput): Promise<Channel> {\n try {\n const response = await fetch(`${this.apiUrl}/api/v1/channels`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n channel: {\n name: data.name,\n description: data.description,\n from: data.fromName,\n address: data.fromEmail,\n reply_to: data.replyTo\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 channel: BroadcastChannelApiResponse = await response.json()\n return this.transformChannelFromApi(channel)\n } catch (error: unknown) {\n throw new BroadcastProviderError(\n `Failed to create channel: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async updateChannel(id: string, data: UpdateChannelInput): Promise<Channel> {\n try {\n const updateData: any = { channel: {} }\n if (data.name !== undefined) updateData.channel.name = data.name\n if (data.description !== undefined) updateData.channel.description = data.description\n if (data.fromName !== undefined) updateData.channel.from = data.fromName\n if (data.fromEmail !== undefined) updateData.channel.address = data.fromEmail\n if (data.replyTo !== undefined) updateData.channel.reply_to = data.replyTo\n\n const response = await fetch(`${this.apiUrl}/api/v1/channels/${id}`, {\n method: 'PATCH',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(updateData)\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 channel: BroadcastChannelApiResponse = await response.json()\n return this.transformChannelFromApi(channel)\n } catch (error: unknown) {\n throw new BroadcastProviderError(\n `Failed to update channel: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async deleteChannel(id: string): Promise<void> {\n try {\n const response = await fetch(`${this.apiUrl}/api/v1/channels/${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 throw new BroadcastProviderError(\n `Failed to delete channel: ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\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, ['channelId', 'name', 'subject', 'content'])\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({\n broadcast: {\n channel_id: parseInt(data.channelId), // Broadcast API uses numeric IDs\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\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\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.status)) {\n throw new BroadcastProviderError(\n `Cannot update broadcast in status: ${existing.status}`,\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.status)) {\n throw new BroadcastProviderError(\n `Cannot delete broadcast in status: ${existing.status}`,\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: true,\n supportsChannelSegmentation: true,\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 // TODO: We need to get the channel_id from the broadcast API response\n // For now, we'll use a placeholder\n return {\n id: broadcast.id.toString(),\n channelId: '1', // TODO: Get from API response when available\n name: broadcast.name,\n subject: broadcast.subject,\n preheader: broadcast.preheader,\n content: broadcast.body,\n status: 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 transformChannelFromApi(channel: BroadcastChannelApiResponse): Channel {\n return {\n id: channel.id.toString(),\n name: channel.name,\n description: channel.description,\n fromName: channel.from,\n fromEmail: channel.address,\n replyTo: channel.reply_to,\n providerId: channel.id.toString(),\n providerType: 'broadcast',\n subscriberCount: channel.total_active_subscribers,\n active: true, // Broadcast API doesn't have an active field\n createdAt: new Date(channel.created_at),\n updatedAt: new Date(channel.updated_at)\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 { Resend } from 'resend'\nimport type { \n Broadcast,\n ListBroadcastOptions,\n ListBroadcastResponse,\n CreateBroadcastInput,\n UpdateBroadcastInput,\n SendBroadcastOptions,\n BroadcastAnalytics,\n BroadcastProviderCapabilities,\n Channel,\n CreateChannelInput,\n UpdateChannelInput,\n ListChannelsOptions,\n ListChannelsResponse\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 // Channel Management Methods (map to Resend Audiences)\n async listChannels(options?: ListChannelsOptions): Promise<ListChannelsResponse> {\n try {\n // Resend audiences API\n const response = await this.client.audiences.list()\n \n const channels: Channel[] = response.data?.data?.map(audience => ({\n id: audience.id,\n name: audience.name,\n description: undefined, // Resend doesn't have description\n fromName: (this.config as ResendProviderConfig).fromName || '',\n fromEmail: (this.config as ResendProviderConfig).fromEmail || '',\n replyTo: (this.config as ResendProviderConfig).replyTo,\n providerId: audience.id,\n providerType: 'resend' as const,\n subscriberCount: undefined, // Not available in list API\n active: true,\n createdAt: new Date(audience.created_at),\n updatedAt: new Date(audience.created_at) // No updated_at in Resend\n })) || []\n \n return {\n channels,\n total: channels.length,\n limit: options?.limit || 100,\n offset: options?.offset || 0\n }\n } catch (error: unknown) {\n throw new BroadcastProviderError(\n `Failed to list channels (audiences): ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async getChannel(id: string): Promise<Channel> {\n try {\n const response = await this.client.audiences.get(id)\n \n if (!response.data) {\n throw new BroadcastProviderError(\n `Channel (audience) not found: ${id}`,\n BroadcastErrorCode.CHANNEL_NOT_FOUND,\n this.name\n )\n }\n \n return {\n id: response.data.id,\n name: response.data.name,\n description: undefined,\n fromName: (this.config as ResendProviderConfig).fromName || '',\n fromEmail: (this.config as ResendProviderConfig).fromEmail || '',\n replyTo: (this.config as ResendProviderConfig).replyTo,\n providerId: response.data.id,\n providerType: 'resend',\n subscriberCount: undefined, // Not available\n active: true,\n createdAt: new Date(response.data.created_at),\n updatedAt: new Date(response.data.created_at)\n }\n } catch (error: unknown) {\n if (error instanceof BroadcastProviderError) throw error\n \n throw new BroadcastProviderError(\n `Failed to get channel (audience): ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async createChannel(data: CreateChannelInput): Promise<Channel> {\n try {\n const response = await this.client.audiences.create({\n name: data.name\n })\n \n if (!response.data) {\n throw new Error('Failed to create audience')\n }\n \n return {\n id: response.data.id,\n name: response.data.name,\n description: data.description,\n fromName: data.fromName,\n fromEmail: data.fromEmail,\n replyTo: data.replyTo,\n providerId: response.data.id,\n providerType: 'resend',\n subscriberCount: 0,\n active: true,\n createdAt: new Date(),\n updatedAt: new Date()\n }\n } catch (error: unknown) {\n throw new BroadcastProviderError(\n `Failed to create channel (audience): ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\n )\n }\n }\n\n async updateChannel(_id: string, _data: UpdateChannelInput): Promise<Channel> {\n // Resend doesn't support updating audiences via API\n throw new BroadcastProviderError(\n 'Updating channels (audiences) is not supported by Resend API',\n BroadcastErrorCode.NOT_SUPPORTED,\n this.name\n )\n }\n\n async deleteChannel(id: string): Promise<void> {\n try {\n await this.client.audiences.remove(id)\n } catch (error: unknown) {\n throw new BroadcastProviderError(\n `Failed to delete channel (audience): ${error instanceof Error ? error.message : 'Unknown error'}`,\n BroadcastErrorCode.PROVIDER_ERROR,\n this.name,\n error\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, ['channelId', '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 channelId: options?.audienceIds?.[0] || '1',\n name: 'Unknown',\n subject: 'Unknown',\n content: '',\n status: 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: true, // Via multiple audiences\n supportsChannelSegmentation: false, // Not within a single audience\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 channelId: broadcast.audience_id || '1', // Map audience_id to channelId\n name: broadcast.name || 'Untitled',\n subject: broadcast.subject,\n preheader: broadcast.preheader,\n content: broadcast.content?.html || broadcast.html || '',\n status: 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 { 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 { createChannelsCollection } from './collections/Channels'\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 collections if enabled\n if (config.features?.newsletterManagement?.enabled) {\n const channelsCollection = createChannelsCollection(config)\n const broadcastsCollection = createBroadcastsCollection(config)\n collections.push(channelsCollection, 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 let emailServiceConfig: any\n \n if (settings) {\n emailServiceConfig = {\n provider: settings.provider || config.providers.default,\n fromAddress: settings.fromAddress || config.providers.resend?.fromAddress || config.providers.broadcast?.fromAddress || 'noreply@example.com',\n fromName: settings.fromName || config.providers.resend?.fromName || config.providers.broadcast?.fromName || 'Newsletter',\n replyTo: settings.replyTo,\n resend: settings.provider === 'resend' ? {\n apiKey: settings.resendSettings?.apiKey || config.providers.resend?.apiKey || '',\n audienceIds: settings.resendSettings?.audienceIds?.reduce((acc: any, item: any) => {\n acc[item.locale] = {\n production: item.production,\n development: item.development,\n }\n return acc\n }, {}) || config.providers.resend?.audienceIds,\n } : config.providers.resend,\n broadcast: settings.provider === 'broadcast' ? {\n apiUrl: settings.broadcastSettings?.apiUrl || config.providers.broadcast?.apiUrl || '',\n tokens: {\n production: settings.broadcastSettings?.productionToken || config.providers.broadcast?.tokens.production,\n development: settings.broadcastSettings?.developmentToken || config.providers.broadcast?.tokens.development,\n },\n } : config.providers.broadcast,\n }\n } else {\n // Use config defaults\n emailServiceConfig = {\n provider: config.providers.default,\n fromAddress: config.providers.resend?.fromAddress || config.providers.broadcast?.fromAddress || 'noreply@example.com',\n fromName: config.providers.resend?.fromName || config.providers.broadcast?.fromName || 'Newsletter',\n resend: config.providers.resend,\n broadcast: config.providers.broadcast,\n }\n }\n\n (payload as any).newsletterEmailService = createEmailService(emailServiceConfig)\n\n console.warn('Newsletter plugin initialized with', (payload as any).newsletterEmailService.getProvider(), 'provider')\n \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'\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): Promise<string> {\n try {\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 if (emailService) {\n try {\n await emailService.addContact(doc)\n } catch {\n // Failed to add contact to email service\n }\n }\n\n // Send welcome email if active\n if (doc.subscriptionStatus === 'active' && emailService) {\n try {\n // 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 })\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 if (\n doc.subscriptionStatus !== previousDoc.subscriptionStatus &&\n emailService\n ) {\n try {\n await emailService.updateContact(doc)\n } catch {\n // Failed to update contact in email service\n }\n }\n\n // Handle unsubscribe\n if (\n doc.subscriptionStatus === 'unsubscribed' &&\n previousDoc.subscriptionStatus !== 'unsubscribed'\n ) {\n // Set unsubscribed timestamp\n doc.unsubscribedAt = new Date().toISOString()\n \n // Custom after unsubscribe hook\n if (pluginConfig.hooks?.afterUnsubscribe) {\n await pluginConfig.hooks.afterUnsubscribe({ doc, req })\n }\n }\n }\n },\n ] as CollectionAfterChangeHook[],\n beforeDelete: [\n async ({ id, req }) => {\n // Remove from email service\n const emailService = (req.payload as any).newsletterEmailService // 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: 'productionToken',\n type: 'text',\n label: 'Production Token',\n admin: {\n description: 'Token for production environment',\n },\n },\n {\n name: 'developmentToken',\n type: 'text',\n label: 'Development Token',\n admin: {\n description: 'Token for development environment',\n },\n },\n ],\n },\n {\n name: 'fromAddress',\n type: 'email',\n label: 'From Address',\n required: true,\n admin: {\n description: 'Default sender email address',\n },\n },\n {\n name: 'fromName',\n type: 'text',\n label: 'From Name',\n required: true,\n admin: {\n description: 'Default sender name',\n },\n },\n {\n name: 'replyTo',\n type: 'email',\n label: 'Reply-To Address',\n admin: {\n description: 'Optional reply-to email address',\n },\n },\n ],\n },\n {\n label: 'Email Templates',\n fields: [\n {\n name: 'emailTemplates',\n type: 'group',\n label: 'Email Templates',\n fields: [\n {\n name: 'welcome',\n type: 'group',\n label: 'Welcome Email',\n fields: [\n {\n name: 'enabled',\n type: 'checkbox',\n label: 'Send Welcome Email',\n defaultValue: true,\n },\n {\n name: 'subject',\n type: 'text',\n label: 'Subject Line',\n defaultValue: 'Welcome to {{fromName}}!',\n admin: {\n condition: (data) => data?.emailTemplates?.welcome?.enabled,\n },\n },\n {\n name: 'preheader',\n type: 'text',\n label: 'Preheader Text',\n admin: {\n condition: (data) => data?.emailTemplates?.welcome?.enabled,\n },\n },\n ],\n },\n {\n name: 'magicLink',\n type: 'group',\n label: 'Magic Link Email',\n fields: [\n {\n name: 'subject',\n type: 'text',\n label: 'Subject Line',\n defaultValue: 'Sign in to {{fromName}}',\n },\n {\n name: 'preheader',\n type: 'text',\n label: 'Preheader Text',\n defaultValue: 'Click the link to access your preferences',\n },\n {\n name: 'expirationTime',\n type: 'select',\n label: 'Link Expiration',\n defaultValue: '7d',\n options: [\n { label: '1 hour', value: '1h' },\n { label: '24 hours', value: '24h' },\n { label: '7 days', value: '7d' },\n { label: '30 days', value: '30d' },\n ],\n },\n ],\n },\n ],\n },\n ],\n },\n {\n label: 'Subscription Settings',\n fields: [\n {\n name: 'subscriptionSettings',\n type: 'group',\n label: 'Subscription Settings',\n fields: [\n {\n name: 'requireDoubleOptIn',\n type: 'checkbox',\n label: 'Require Double Opt-In',\n defaultValue: false,\n admin: {\n description: 'Require email confirmation before activating subscriptions',\n },\n },\n {\n name: 'allowedDomains',\n type: 'array',\n label: 'Allowed Email Domains',\n admin: {\n description: 'Leave empty to allow all domains',\n },\n fields: [\n {\n name: 'domain',\n type: 'text',\n label: 'Domain',\n required: true,\n admin: {\n placeholder: 'example.com',\n },\n },\n ],\n },\n {\n name: 'maxSubscribersPerIP',\n type: 'number',\n label: 'Max Subscribers per IP',\n defaultValue: 10,\n min: 1,\n admin: {\n description: 'Maximum number of subscriptions allowed from a single IP address',\n },\n },\n ],\n },\n ],\n },\n ],\n },\n ],\n hooks: {\n beforeChange: [\n async ({ data, req }) => {\n // Verify admin access for settings changes\n if (!req.user || req.user.collection !== 'users') {\n throw new Error('Only administrators can modify newsletter settings')\n }\n \n return data\n },\n ],\n afterChange: [\n async ({ doc, req }) => {\n // Reinitialize email service when settings change\n if ((req.payload as any).newsletterEmailService) {\n try {\n // TODO: Implement email service reinitialization\n console.warn('Newsletter settings updated, reinitializing service...')\n } catch {\n // Failed to reinitialize email service\n }\n }\n \n return doc\n },\n ],\n },\n access: {\n read: () => true, // Settings can be read publicly for validation\n update: adminOnly(pluginConfig),\n },\n }\n}","import { Resend } from 'resend'\nimport type { EmailProvider, SendEmailParams } from './types'\nimport { EmailProviderError } from './types'\nimport type { Subscriber, ResendProviderConfig } from '../types'\n\nexport class ResendProvider implements EmailProvider {\n private client: Resend\n private audienceIds: ResendProviderConfig['audienceIds']\n private fromAddress: string\n private fromName: string\n private isDevelopment: boolean\n\n constructor(config: ResendProviderConfig & { \n fromAddress: string\n fromName: string \n }) {\n this.client = new Resend(config.apiKey)\n this.audienceIds = config.audienceIds || {}\n this.fromAddress = config.fromAddress\n this.fromName = config.fromName\n this.isDevelopment = process.env.NODE_ENV !== 'production'\n }\n\n getProvider(): string {\n return 'resend'\n }\n\n async send(params: SendEmailParams): Promise<void> {\n try {\n const from = params.from || {\n email: this.fromAddress,\n name: this.fromName,\n }\n\n if (!params.html && !params.text) {\n throw new Error('Either html or text content is required')\n }\n\n await this.client.emails.send({\n from: `${from.name} <${from.email}>`,\n to: Array.isArray(params.to) ? params.to : [params.to],\n subject: params.subject,\n html: params.html || '',\n text: params.text,\n replyTo: params.replyTo,\n })\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to send email via Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n try {\n const audienceId = this.getAudienceId(contact.locale)\n if (!audienceId) {\n console.warn(`No audience ID configured for locale: ${contact.locale}`)\n return\n }\n\n await this.client.contacts.create({\n email: contact.email,\n firstName: contact.name?.split(' ')[0],\n lastName: contact.name?.split(' ').slice(1).join(' '),\n unsubscribed: contact.subscriptionStatus === 'unsubscribed',\n audienceId,\n })\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to add contact to Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n try {\n const audienceId = this.getAudienceId(contact.locale)\n if (!audienceId) {\n console.warn(`No audience ID configured for locale: ${contact.locale}`)\n return\n }\n\n // Resend requires finding the contact first\n const contacts = await this.client.contacts.list({ audienceId })\n const existingContact = contacts.data?.data?.find(c => c.email === contact.email)\n\n if (existingContact) {\n await this.client.contacts.update({\n id: existingContact.id,\n audienceId,\n firstName: contact.name?.split(' ')[0],\n lastName: contact.name?.split(' ').slice(1).join(' '),\n unsubscribed: contact.subscriptionStatus === 'unsubscribed',\n })\n } else {\n // If contact doesn't exist, add them\n await this.addContact(contact)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to update contact in Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async removeContact(email: string): Promise<void> {\n try {\n // Resend doesn't have a direct remove method, so we unsubscribe instead\n // First, we need to find the contact across all audiences\n for (const locale in this.audienceIds) {\n const audienceId = this.getAudienceId(locale)\n if (!audienceId) continue\n\n const contacts = await this.client.contacts.list({ audienceId })\n const contact = contacts.data?.data?.find(c => c.email === email)\n\n if (contact) {\n await this.client.contacts.update({\n id: contact.id,\n audienceId,\n unsubscribed: true,\n })\n break\n }\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to remove contact from Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n private getAudienceId(locale?: string): string | undefined {\n const localeKey = locale || 'en'\n if (!this.audienceIds) return undefined\n \n const localeConfig = this.audienceIds[localeKey]\n if (!localeConfig) return undefined\n\n const audienceId = this.isDevelopment \n ? (localeConfig.development || localeConfig.production)\n : (localeConfig.production || localeConfig.development)\n \n return audienceId\n }\n}","import type { Subscriber } from '../types'\n\nexport interface EmailProvider {\n send(params: SendEmailParams): Promise<void>\n addContact(contact: Subscriber): Promise<void>\n updateContact(contact: Subscriber): Promise<void>\n removeContact(email: string): Promise<void>\n getProvider(): string\n}\n\nexport interface SendEmailParams {\n to: string | string[]\n subject: string\n html?: string\n text?: string\n react?: React.ReactElement\n from?: {\n email: string\n name?: string\n }\n replyTo?: string\n}\n\nexport interface EmailServiceConfig {\n provider: 'resend' | 'broadcast' | string\n fromAddress: string\n fromName: string\n replyTo?: string\n resend?: {\n apiKey: string\n audienceIds?: Record<string, { production?: string; development?: string }>\n }\n broadcast?: {\n apiUrl: string\n tokens: {\n production?: string\n development?: string\n }\n }\n}\n\nexport class EmailProviderError extends Error {\n provider: string\n originalError?: any\n\n constructor(message: string, provider: string, originalError?: any) {\n super(message)\n this.name = 'EmailProviderError'\n this.provider = provider\n this.originalError = originalError\n }\n}","import type { EmailProvider, SendEmailParams } from './types'\nimport { EmailProviderError } from './types'\nimport type { Subscriber, BroadcastProviderConfig } from '../types'\n\nexport class BroadcastProvider implements EmailProvider {\n private apiUrl: string\n private token: string\n private fromAddress: string\n private fromName: string\n private isDevelopment: boolean\n\n constructor(config: BroadcastProviderConfig & { \n fromAddress: string\n fromName: string \n }) {\n this.apiUrl = config.apiUrl.replace(/\\/$/, '') // Remove trailing slash\n this.isDevelopment = process.env.NODE_ENV !== 'production'\n this.token = this.isDevelopment \n ? config.tokens.development || config.tokens.production || ''\n : config.tokens.production || config.tokens.development || ''\n this.fromAddress = config.fromAddress\n this.fromName = config.fromName\n }\n\n getProvider(): string {\n return 'broadcast'\n }\n\n async send(params: SendEmailParams): Promise<void> {\n try {\n const from = params.from || {\n email: this.fromAddress,\n name: this.fromName,\n }\n\n const recipients = Array.isArray(params.to) ? params.to : [params.to]\n \n // Broadcast expects a specific format\n const response = await fetch(`${this.apiUrl}/api/v1/emails`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n from_email: from.email,\n from_name: from.name,\n to: recipients,\n subject: params.subject,\n html_body: params.html,\n text_body: params.text,\n reply_to: params.replyTo,\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to send email via Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n try {\n const [firstName, ...lastNameParts] = (contact.name || '').split(' ')\n const lastName = lastNameParts.join(' ')\n\n const response = await fetch(`${this.apiUrl}/api/v1/subscribers.json`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n subscriber: {\n email: contact.email,\n first_name: firstName || undefined,\n last_name: lastName || undefined,\n tags: [`lang:${contact.locale || 'en'}`],\n is_active: contact.subscriptionStatus === 'active',\n source: contact.source,\n },\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to add contact to Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n try {\n // First, try to find the contact\n const searchResponse = await fetch(\n `${this.apiUrl}/api/v1/subscribers/find.json?email=${encodeURIComponent(contact.email)}`,\n {\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n },\n }\n )\n\n if (!searchResponse.ok) {\n // If contact doesn't exist, create it\n await this.addContact(contact)\n return\n }\n\n const existingContact = await searchResponse.json()\n\n if (!existingContact || !existingContact.id) {\n await this.addContact(contact)\n return\n }\n\n const [firstName, ...lastNameParts] = (contact.name || '').split(' ')\n const lastName = lastNameParts.join(' ')\n\n // Update existing contact\n const response = await fetch(`${this.apiUrl}/api/v1/subscribers.json`, {\n method: 'PATCH',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n email: contact.email,\n subscriber: {\n first_name: firstName || undefined,\n last_name: lastName || undefined,\n tags: [`lang:${contact.locale || 'en'}`],\n is_active: contact.subscriptionStatus === 'active',\n source: contact.source,\n },\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to update contact in Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async removeContact(email: string): Promise<void> {\n try {\n // First, find the contact\n const searchResponse = await fetch(\n `${this.apiUrl}/api/v1/subscribers/find.json?email=${encodeURIComponent(email)}`,\n {\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n },\n }\n )\n\n if (!searchResponse.ok) {\n // Contact doesn't exist, nothing to remove\n return\n }\n\n const contact = await searchResponse.json()\n\n if (!contact || !contact.id) {\n return\n }\n\n // Deactivate the contact\n const response = await fetch(`${this.apiUrl}/api/v1/subscribers/deactivate.json`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ email }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to remove contact from Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n}","import type { EmailProvider, EmailServiceConfig, SendEmailParams } from './types'\nimport type { Subscriber } from '../types'\nimport { ResendProvider } from './resend'\nimport { BroadcastProvider } from './broadcast'\n\nexport * from './types'\n\nexport class EmailService {\n private provider: EmailProvider\n\n constructor(config: EmailServiceConfig) {\n this.provider = this.createProvider(config)\n }\n\n private createProvider(config: EmailServiceConfig): EmailProvider {\n const baseConfig = {\n fromAddress: config.fromAddress,\n fromName: config.fromName,\n }\n\n switch (config.provider) {\n case 'resend':\n if (!config.resend) {\n throw new Error('Resend configuration is required when using Resend provider')\n }\n return new ResendProvider({\n ...config.resend,\n ...baseConfig,\n })\n\n case 'broadcast':\n if (!config.broadcast) {\n throw new Error('Broadcast configuration is required when using Broadcast provider')\n }\n return new BroadcastProvider({\n ...config.broadcast,\n ...baseConfig,\n })\n\n default:\n throw new Error(`Unknown email provider: ${config.provider}`)\n }\n }\n\n async send(params: SendEmailParams): Promise<void> {\n return this.provider.send(params)\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n return this.provider.addContact(contact)\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n return this.provider.updateContact(contact)\n }\n\n async removeContact(email: string): Promise<void> {\n return this.provider.removeContact(email)\n }\n\n getProvider(): string {\n return this.provider.getProvider()\n }\n\n /**\n * Update the provider configuration\n * Useful when settings are changed in the admin UI\n */\n updateConfig(config: EmailServiceConfig): void {\n this.provider = this.createProvider(config)\n }\n}\n\n/**\n * Create email service from plugin configuration\n */\nexport function createEmailService(config: EmailServiceConfig): EmailService {\n return new EmailService(config)\n}","import DOMPurify from 'isomorphic-dompurify'\n\n/**\n * Validate email address format\n */\nexport function isValidEmail(email: string): boolean {\n if (!email || typeof email !== 'string') return false\n \n // Trim whitespace\n const trimmed = email.trim()\n \n // Length limits\n if (trimmed.length > 255) return false\n \n // Check for dangerous patterns\n if (trimmed.includes('<') || trimmed.includes('>')) return false\n if (trimmed.includes('javascript:')) return false\n if (trimmed.includes('data:')) return false\n \n // Basic format validation with stricter regex\n const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/\n if (!emailRegex.test(trimmed)) return false\n \n // Additional validation rules\n const parts = trimmed.split('@')\n if (parts.length !== 2) return false\n \n const [localPart, domain] = parts\n \n // Check local part length\n if (localPart.length > 64 || localPart.length === 0) return false\n \n // Check for invalid patterns\n if (localPart.startsWith('.') || localPart.endsWith('.')) return false\n if (domain.startsWith('.') || domain.endsWith('.')) return false\n if (domain.includes('..')) return false\n if (localPart.includes('..')) return false\n \n return true\n}\n\n/**\n * Normalize email for rate limiting and deduplication\n */\nexport function normalizeEmail(email: string): string {\n if (!email || typeof email !== 'string') return ''\n \n const parts = email.toLowerCase().trim().split('@')\n if (parts.length !== 2) return email.toLowerCase().trim()\n \n let [localPart] = parts\n const [, domain] = parts\n \n // Remove dots from local part (Gmail-style)\n localPart = localPart.replace(/\\./g, '')\n \n // Remove everything after + (Gmail-style aliases)\n const plusIndex = localPart.indexOf('+')\n if (plusIndex > -1) {\n localPart = localPart.substring(0, plusIndex)\n }\n \n return `${localPart}@${domain}`\n}\n\n/**\n * Check if email domain is allowed\n */\nexport function isDomainAllowed(\n email: string,\n allowedDomains?: string[]\n): boolean {\n // Validate email format first\n if (!isValidEmail(email)) {\n return false\n }\n \n // If no domains specified, allow all valid emails\n if (!allowedDomains || allowedDomains.length === 0) {\n return true\n }\n\n const domain = email.split('@')[1]?.toLowerCase()\n if (!domain) return false\n\n return allowedDomains.some(\n allowedDomain => domain === allowedDomain.toLowerCase()\n )\n}\n\n/**\n * Sanitize user input to prevent XSS\n */\nexport function sanitizeInput(input: string): string {\n if (!input) return ''\n \n // First, remove all HTML tags and scripts\n let cleaned = DOMPurify.sanitize(input, { \n ALLOWED_TAGS: [],\n ALLOWED_ATTR: [],\n KEEP_CONTENT: true\n })\n \n // Additional security: remove dangerous patterns\n cleaned = cleaned\n .replace(/javascript:/gi, '')\n .replace(/data:/gi, '')\n .replace(/vbscript:/gi, '')\n .replace(/file:\\/\\//gi, '')\n .replace(/onload/gi, '')\n .replace(/onerror/gi, '')\n .replace(/onclick/gi, '')\n .replace(/onmouseover/gi, '')\n .replace(/alert\\(/gi, '')\n .replace(/prompt\\(/gi, '')\n .replace(/confirm\\(/gi, '')\n .replace(/\\|/g, '') // Remove pipe character (command injection)\n .replace(/;/g, '') // Remove semicolon (command chaining)\n .replace(/`/g, '') // Remove backticks (command substitution)\n .replace(/&&/g, '') // Remove command chaining\n .replace(/\\$\\(/g, '') // Remove command substitution pattern $()\n .replace(/\\.\\./g, '') // Remove directory traversal\n .replace(/\\/..\\//g, '') // Remove path traversal\n .replace(/\\0/g, '') // Remove null bytes\n \n return cleaned.trim()\n}\n\n/**\n * Extract UTM parameters from URL search params\n */\nexport function extractUTMParams(searchParams: URLSearchParams): Record<string, string> {\n const utmParams: Record<string, string> = {}\n const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']\n\n utmKeys.forEach(key => {\n const value = searchParams.get(key)\n if (value) {\n // Remove 'utm_' prefix for storage\n const shortKey = key.replace('utm_', '')\n utmParams[shortKey] = value\n }\n })\n\n return utmParams\n}\n\n/**\n * Validate source field - only allow predefined values\n */\nexport function isValidSource(source: string): boolean {\n if (!source || typeof source !== 'string') return false\n \n const allowedSources = [\n 'website',\n 'api',\n 'import',\n 'admin',\n 'signup-form',\n 'magic-link',\n 'preferences',\n 'external'\n ]\n \n return allowedSources.includes(source)\n}\n\n/**\n * Validate subscriber data before creation\n */\nexport interface ValidateSubscriberResult {\n valid: boolean\n errors: string[]\n}\n\nexport function validateSubscriberData(data: any): ValidateSubscriberResult {\n const errors: string[] = []\n\n // Email validation\n if (!data.email) {\n errors.push('Email is required')\n } else if (!isValidEmail(data.email)) {\n errors.push('Invalid email format')\n }\n\n // Name validation (optional but if provided, should be reasonable)\n if (data.name && data.name.length > 100) {\n errors.push('Name is too long (max 100 characters)')\n }\n\n // Source validation\n if (data.source !== undefined) {\n if (!data.source || data.source.length === 0) {\n errors.push('Source cannot be empty')\n } else if (data.source.length > 50) {\n errors.push('Source is too long (max 50 characters)')\n } else if (!isValidSource(data.source)) {\n errors.push('Invalid source value')\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n }\n}","import jwt from 'jsonwebtoken'\nimport type { NewsletterPluginConfig } from '../types'\n\nexport interface MagicLinkTokenPayload {\n subscriberId: string\n email: string\n type: 'magic-link'\n}\n\nexport interface SessionTokenPayload {\n subscriberId: string\n email: string\n type: 'session'\n}\n\n/**\n * Get JWT secret from environment or generate a warning\n */\nfunction getJWTSecret(): string {\n const secret = process.env.JWT_SECRET || process.env.PAYLOAD_SECRET\n\n if (!secret) {\n console.warn(\n 'WARNING: No JWT_SECRET or PAYLOAD_SECRET found in environment variables. ' +\n 'Magic link authentication will not work properly. ' +\n 'Please set JWT_SECRET in your environment.'\n )\n // Return a placeholder to prevent crashes during development\n return 'INSECURE_DEVELOPMENT_SECRET_PLEASE_SET_JWT_SECRET'\n }\n\n return secret\n}\n\n/**\n * Generate a magic link token for email authentication\n */\nexport function generateMagicLinkToken(\n subscriberId: string,\n email: string,\n config: NewsletterPluginConfig\n): string {\n const payload: MagicLinkTokenPayload = {\n subscriberId,\n email,\n type: 'magic-link',\n }\n\n const expiresIn = config.auth?.tokenExpiration || '7d'\n\n return jwt.sign(payload, getJWTSecret(), {\n expiresIn: expiresIn,\n issuer: 'payload-newsletter-plugin',\n } as jwt.SignOptions)\n}\n\n/**\n * Verify a magic link token\n */\nexport function verifyMagicLinkToken(token: string): MagicLinkTokenPayload {\n try {\n const payload = jwt.verify(token, getJWTSecret(), {\n issuer: 'payload-newsletter-plugin',\n }) as any\n\n if (payload.type !== 'magic-link') {\n throw new Error('Invalid token type')\n }\n\n return payload as MagicLinkTokenPayload\n } catch (error: unknown) {\n if (error instanceof Error && error.name === 'TokenExpiredError') {\n throw new Error('Magic link has expired. Please request a new one.')\n }\n if (error instanceof Error && error.name === 'JsonWebTokenError') {\n throw new Error('Invalid magic link token')\n }\n throw error\n }\n}\n\n/**\n * Generate a session token after successful magic link verification\n */\nexport function generateSessionToken(\n subscriberId: string,\n email: string\n): string {\n const payload: SessionTokenPayload = {\n subscriberId,\n email,\n type: 'session',\n }\n\n return jwt.sign(payload, getJWTSecret(), {\n expiresIn: '30d',\n issuer: 'payload-newsletter-plugin',\n })\n}\n\n/**\n * Verify a session token\n */\nexport function verifySessionToken(token: string): SessionTokenPayload {\n try {\n const payload = jwt.verify(token, getJWTSecret(), {\n issuer: 'payload-newsletter-plugin',\n }) as any\n\n if (payload.type !== 'session') {\n throw new Error('Invalid token type')\n }\n\n return payload as SessionTokenPayload\n } catch (error: unknown) {\n if (error instanceof Error && error.name === 'TokenExpiredError') {\n throw new Error('Session has expired. Please sign in again.')\n }\n if (error instanceof Error && error.name === 'JsonWebTokenError') {\n throw new Error('Invalid session token')\n }\n throw error\n }\n}\n\n/**\n * Generate a magic link URL\n */\nexport function generateMagicLinkURL(\n token: string,\n baseURL: string,\n config: NewsletterPluginConfig\n): string {\n const path = config.auth?.magicLinkPath || '/newsletter/verify'\n const url = new URL(path, baseURL)\n url.searchParams.set('token', token)\n return url.toString()\n}","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig, 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 // If unsubscribed, don't allow resubscription via API\n if (subscriber.subscriptionStatus === 'unsubscribed') {\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 return Response.json({\n success: false,\n error: 'Already subscribed',\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n }, { status: 400 })\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 })\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 })\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 } = data as SigninRequestData\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 active subscriber\n const result = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n email: { equals: email.toLowerCase() },\n subscriptionStatus: { equals: 'active' },\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 }, { status: 404 })\n }\n\n const subscriber = result.docs[0]\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)\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\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 })\n\n // Send email\n await emailService.send({\n to: subscriber.email,\n subject: settings?.brandSettings?.siteName \n ? `Sign in to ${settings.brandSettings.siteName}` \n : 'Sign in to your account',\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, PayloadHandler, PayloadRequest } from 'payload'\nimport type { NewsletterPluginConfig, SendBroadcastOptions } from '../../types'\nimport { NewsletterProviderError, NewsletterStatus } from '../../types'\nimport { requireAdmin } from '../../utils/auth'\n\nexport const createSendBroadcastEndpoint = (\n config: NewsletterPluginConfig,\n collectionSlug: string\n): Endpoint => {\n return {\n path: `/${collectionSlug}/: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 // Get broadcast provider\n const broadcastProvider = (req.payload as any).newsletterProvider\n if (!broadcastProvider) {\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 to get the provider ID\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 // Send broadcast using provider ID\n const broadcast = await broadcastProvider.send(broadcastDoc.providerId, data)\n\n // Update status in Payload collection\n await req.payload.update({\n collection: collectionSlug,\n id,\n data: {\n status: 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: `/${collectionSlug}/: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 // Get broadcast provider\n const broadcastProvider = (req.payload as any).newsletterProvider\n if (!broadcastProvider) {\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 to get the provider ID\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 // Schedule broadcast using provider ID\n const broadcast = await broadcastProvider.schedule(broadcastDoc.providerId, scheduledDate)\n\n // Update status in Payload collection\n await req.payload.update({\n collection: collectionSlug,\n id,\n data: {\n status: 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 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 ],\n ALLOWED_ATTR: ['href', 'style', 'target', 'rel', 'align'],\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,\n options?: {\n wrapInTemplate?: boolean\n preheader?: string\n }\n): Promise<string> {\n // First, convert Lexical state to HTML using custom converters\n const rawHtml = await lexicalToEmailHtml(editorState)\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(editorState: SerializedEditorState): Promise<string> {\n const { root } = editorState\n \n if (!root || !root.children) {\n return ''\n }\n \n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const html = root.children.map((node: any) => convertNode(node)).join('')\n return html\n}\n\n/**\n * Convert individual Lexical nodes to email-safe HTML\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction convertNode(node: any): string {\n switch (node.type) {\n case 'paragraph':\n return convertParagraph(node)\n case 'heading':\n return convertHeading(node)\n case 'list':\n return convertList(node)\n case 'listitem':\n return convertListItem(node)\n case 'blockquote':\n return convertBlockquote(node)\n case 'text':\n return convertText(node)\n case 'link':\n return convertLink(node)\n case 'linebreak':\n return '<br>'\n default:\n // Unknown node type - convert children if any\n if (node.children) {\n return node.children.map(convertNode).join('')\n }\n return ''\n }\n}\n\n/**\n * Convert paragraph node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction convertParagraph(node: any): string {\n const align = getAlignment(node.format)\n const children = node.children?.map(convertNode).join('') || ''\n \n if (!children.trim()) {\n return '<p style=\"margin: 0 0 16px 0; min-height: 1em;\"> </p>'\n }\n \n return `<p style=\"margin: 0 0 16px 0; text-align: ${align};\">${children}</p>`\n}\n\n/**\n * Convert heading node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction convertHeading(node: any): string {\n const tag = node.tag || 'h1'\n const align = getAlignment(node.format)\n const children = node.children?.map(convertNode).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 style = `${styles[tag] || styles.h3} text-align: ${align};`\n \n return `<${tag} style=\"${style}\">${children}</${tag}>`\n}\n\n/**\n * Convert list node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction convertList(node: any): string {\n const tag = node.listType === 'number' ? 'ol' : 'ul'\n const children = node.children?.map(convertNode).join('') || ''\n \n const style = tag === 'ul' \n ? 'margin: 0 0 16px 0; padding-left: 24px; list-style-type: disc;'\n : 'margin: 0 0 16px 0; padding-left: 24px; list-style-type: decimal;'\n \n return `<${tag} style=\"${style}\">${children}</${tag}>`\n}\n\n/**\n * Convert list item node\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction convertListItem(node: any): string {\n const children = node.children?.map(convertNode).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\nfunction convertBlockquote(node: any): string {\n const children = node.children?.map(convertNode).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\nfunction convertLink(node: any): string {\n const children = node.children?.map(convertNode).join('') || ''\n const url = node.fields?.url || '#'\n \n // Ensure links open in new tab and have security attributes\n return `<a href=\"${escapeHtml(url)}\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"color: #2563eb; text-decoration: underline;\">${children}</a>`\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 basic email template\n */\nfunction wrapInEmailTemplate(content: string, preheader?: string): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Email</title>\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</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: #333333; background-color: #f3f4f6;\">\n ${preheader ? `<div style=\"display: none; max-height: 0; overflow: hidden;\">${escapeHtml(preheader)}</div>` : ''}\n <table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" style=\"margin: 0; padding: 0;\">\n <tr>\n <td align=\"center\" style=\"padding: 20px 0;\">\n <table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" width=\"600\" style=\"margin: 0 auto; background-color: #ffffff; border-radius: 8px; overflow: hidden;\">\n <tr>\n <td style=\"padding: 40px 30px;\">\n ${content}\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 { 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: `/${collectionSlug}/: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 // Get the channel for sender info\n const channel = await req.payload.findByID({\n collection: 'channels',\n id: typeof broadcast.channel === 'string' ? broadcast.channel : broadcast.channel.id,\n user: auth.user,\n })\n\n // Convert content to email-safe HTML\n const htmlContent = await convertToEmailSafeHtml(broadcast.content, {\n wrapInTemplate: true,\n preheader: broadcast.preheader,\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 // Send test email\n await emailService.send({\n to: testEmail,\n from: channel?.fromEmail || config.providers.resend?.fromAddress || 'noreply@example.com',\n fromName: channel?.fromName || config.providers.resend?.fromName || 'Newsletter',\n replyTo: broadcast.settings?.replyTo || channel?.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 } from 'payload'\nimport type { NewsletterPluginConfig } from '../../types'\nimport { createSendBroadcastEndpoint } from './send'\nimport { createScheduleBroadcastEndpoint } from './schedule'\nimport { createTestBroadcastEndpoint } from './test'\n\nexport const createBroadcastManagementEndpoints = (\n config: NewsletterPluginConfig\n): Endpoint[] => {\n // Only create endpoints if broadcast management is enabled\n if (!config.features?.newsletterManagement?.enabled) {\n return []\n }\n\n // Only create custom action endpoints\n // CRUD operations are handled by Payload's automatic REST API\n const collectionSlug = config.features.newsletterManagement.collections?.broadcasts || 'broadcasts'\n \n return [\n createSendBroadcastEndpoint(config, collectionSlug),\n createScheduleBroadcastEndpoint(config, collectionSlug),\n createTestBroadcastEndpoint(config, collectionSlug),\n ]\n}","import type { Endpoint } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { createSubscribeEndpoint } from './subscribe'\nimport { createVerifyMagicLinkEndpoint } from './verify-magic-link'\nimport { createPreferencesEndpoint, createUpdatePreferencesEndpoint } from './preferences'\nimport { createUnsubscribeEndpoint } from './unsubscribe'\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 = process.env.NODE_ENV === 'production' \n ? broadcastConfig.tokens.production \n : broadcastConfig.tokens.development\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'\n\nexport const createChannelsCollection = (pluginConfig: NewsletterPluginConfig): CollectionConfig => {\n const hasProviders = !!(pluginConfig.providers?.broadcast || pluginConfig.providers?.resend)\n\n return {\n slug: 'channels',\n labels: {\n singular: 'Channel',\n plural: 'Channels',\n },\n admin: {\n useAsTitle: 'name',\n description: 'Newsletter channels/publications that can send broadcasts',\n defaultColumns: ['name', 'fromEmail', 'subscriberCount', 'active'],\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n required: true,\n admin: {\n description: 'The name of this newsletter channel'\n },\n },\n {\n name: 'description',\n type: 'textarea',\n admin: {\n description: 'A brief description of what this channel is about'\n },\n },\n {\n name: 'fromName',\n type: 'text',\n required: true,\n admin: {\n description: 'The sender name that appears in emails'\n },\n },\n {\n name: 'fromEmail',\n type: 'email',\n required: true,\n admin: {\n description: 'The sender email address'\n },\n },\n {\n name: 'replyTo',\n type: 'email',\n admin: {\n description: 'Reply-to email address (optional)'\n },\n },\n {\n name: 'providerType',\n type: 'select',\n required: true,\n options: [\n ...(pluginConfig.providers?.broadcast ? [{ label: 'Broadcast', value: 'broadcast' }] : []),\n ...(pluginConfig.providers?.resend ? [{ label: 'Resend', value: 'resend' }] : []),\n ],\n admin: {\n description: 'Which email provider manages this channel'\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: 'subscriberCount',\n type: 'number',\n admin: {\n readOnly: true,\n description: 'Number of active subscribers',\n },\n defaultValue: 0,\n },\n {\n name: 'active',\n type: 'checkbox',\n defaultValue: true,\n admin: {\n description: 'Whether this channel is currently active'\n },\n },\n {\n name: 'settings',\n type: 'group',\n fields: [\n {\n name: 'defaultTrackOpens',\n type: 'checkbox',\n defaultValue: true,\n admin: {\n description: 'Track email opens by default for broadcasts in this channel'\n },\n },\n {\n name: 'defaultTrackClicks',\n type: 'checkbox',\n defaultValue: true,\n admin: {\n description: 'Track link clicks by default for broadcasts in this channel'\n },\n },\n {\n name: 'requireDoubleOptIn',\n type: 'checkbox',\n defaultValue: false,\n admin: {\n description: 'Require double opt-in for new subscribers'\n },\n },\n ],\n },\n ],\n hooks: {\n // Sync with provider on create\n afterChange: [\n async ({ doc, operation, req }) => {\n if (!hasProviders || operation !== 'create') return doc\n\n try {\n const provider = await getProvider(doc.providerType, pluginConfig)\n if (!provider) return doc\n\n // Create channel in provider\n const providerChannel = await provider.createChannel({\n name: doc.name,\n description: doc.description,\n fromName: doc.fromName,\n fromEmail: doc.fromEmail,\n replyTo: doc.replyTo,\n })\n\n // Update with provider ID\n await req.payload.update({\n collection: 'channels',\n id: doc.id,\n data: {\n providerId: providerChannel.id,\n subscriberCount: providerChannel.subscriberCount || 0,\n },\n req,\n })\n\n return {\n ...doc,\n providerId: providerChannel.id,\n subscriberCount: providerChannel.subscriberCount || 0,\n }\n } catch (error) {\n req.payload.logger.error('Failed to create channel in provider:', error)\n return doc\n }\n },\n ],\n // Sync updates with provider\n beforeChange: [\n async ({ data, originalDoc, operation, req }) => {\n if (!hasProviders || !originalDoc?.providerId || operation !== 'update') return data\n\n try {\n const provider = await getProvider(originalDoc.providerType, pluginConfig)\n if (!provider) return data\n\n // Check what fields changed\n const updates: any = {}\n if (data.name !== originalDoc.name) updates.name = data.name\n if (data.description !== originalDoc.description) updates.description = data.description\n if (data.fromName !== originalDoc.fromName) updates.fromName = data.fromName\n if (data.fromEmail !== originalDoc.fromEmail) updates.fromEmail = data.fromEmail\n if (data.replyTo !== originalDoc.replyTo) updates.replyTo = data.replyTo\n\n if (Object.keys(updates).length > 0) {\n await provider.updateChannel(originalDoc.providerId, updates)\n }\n } catch (error) {\n req.payload.logger.error('Failed to update channel in provider:', error)\n // Continue with local update even if provider fails\n }\n\n return data\n },\n ],\n // Handle deletion\n afterDelete: [\n async ({ doc, req }) => {\n if (!hasProviders || !doc?.providerId) return doc\n\n try {\n const provider = await getProvider(doc.providerType, pluginConfig)\n if (!provider) return doc\n\n await provider.deleteChannel(doc.providerId)\n } catch (error) {\n req.payload.logger.error('Failed to delete channel from provider:', error)\n }\n\n return doc\n },\n ],\n },\n }\n}\n\n// Helper to get provider instance\nasync function getProvider(providerType: string, config: NewsletterPluginConfig): Promise<any> {\n if (providerType === 'broadcast') {\n const { BroadcastApiProvider } = await import('../providers/broadcast/broadcast')\n const providerConfig = config.providers?.broadcast\n return providerConfig ? new BroadcastApiProvider(providerConfig) : null\n }\n \n if (providerType === 'resend') {\n const { ResendBroadcastProvider } = await import('../providers/resend/broadcast')\n const providerConfig = config.providers?.resend\n return providerConfig ? new ResendBroadcastProvider(providerConfig) : null\n }\n\n return null\n}","import type { CollectionConfig } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { BroadcastStatus } from '../types'\nimport { createEmailContentField } from '../fields/emailContent'\nimport { convertToEmailSafeHtml } from '../utils/emailSafeHtml'\n\nexport const createBroadcastsCollection = (pluginConfig: NewsletterPluginConfig): CollectionConfig => {\n const hasProviders = !!(pluginConfig.providers?.broadcast || pluginConfig.providers?.resend)\n\n return {\n slug: 'broadcasts',\n labels: {\n singular: 'Broadcast',\n plural: 'Broadcasts',\n },\n admin: {\n useAsTitle: 'name',\n description: 'Individual email campaigns sent to subscribers',\n defaultColumns: ['name', 'subject', 'status', 'channel', 'sentAt', 'actions'],\n },\n fields: [\n {\n name: 'channel',\n type: 'relationship',\n relationTo: 'channels',\n required: true,\n admin: {\n description: 'The channel this broadcast belongs to'\n },\n },\n {\n name: 'name',\n type: 'text',\n required: true,\n admin: {\n description: 'Internal name for this broadcast'\n },\n },\n {\n name: 'subject',\n type: 'text',\n required: true,\n admin: {\n description: 'Email subject line'\n },\n },\n {\n name: 'preheader',\n type: 'text',\n admin: {\n description: 'Preview text shown in email clients'\n },\n },\n createEmailContentField({\n admin: {\n description: 'Email content',\n },\n }),\n {\n name: 'emailPreview',\n type: 'ui',\n admin: {\n components: {\n Field: '/src/components/Broadcasts/EmailPreviewField',\n },\n },\n },\n {\n name: 'status',\n type: 'select',\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 components: {\n Cell: '/src/components/Broadcasts/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?.status === 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?.status === 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 // UI Field for custom actions in list view\n {\n name: 'actions',\n type: 'ui',\n admin: {\n components: {\n Cell: '/src/components/Broadcasts/ActionsCell',\n Field: '/src/components/Broadcasts/EmptyField',\n },\n disableListColumn: false,\n },\n },\n ],\n hooks: {\n // Sync with provider on create\n afterChange: [\n async ({ doc, operation, req }) => {\n if (!hasProviders || operation !== 'create') return doc\n\n try {\n // Get the channel to determine provider\n const channel = await req.payload.findByID({\n collection: 'channels',\n id: typeof doc.channel === 'string' ? doc.channel : doc.channel.id,\n req,\n })\n\n const provider = await getProvider(channel.providerType, pluginConfig)\n if (!provider) return doc\n\n // Convert rich text to HTML\n const htmlContent = await convertToEmailSafeHtml(doc.content)\n\n // Create broadcast in provider\n const providerBroadcast = await provider.create({\n channelId: channel.providerId || channel.id,\n name: doc.name,\n subject: doc.subject,\n preheader: doc.preheader,\n content: htmlContent,\n trackOpens: doc.settings?.trackOpens,\n trackClicks: doc.settings?.trackClicks,\n replyTo: doc.settings?.replyTo,\n audienceIds: doc.audienceIds?.map((a: any) => a.audienceId),\n })\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) {\n req.payload.logger.error('Failed to create broadcast in provider:', error)\n return doc\n }\n },\n ],\n // Sync updates with provider\n beforeChange: [\n async ({ data, originalDoc, operation, req }) => {\n if (!hasProviders || !originalDoc?.providerId || operation !== 'update') return data\n\n try {\n // Get the channel to determine provider\n const channelId = data.channel || originalDoc.channel\n const channel = await req.payload.findByID({\n collection: 'channels',\n id: typeof channelId === 'string' ? channelId : channelId.id,\n req,\n })\n\n const provider = await getProvider(channel.providerType, pluginConfig)\n if (!provider) return data\n\n // Only sync if broadcast is still editable\n const capabilities = provider.getCapabilities()\n if (!capabilities.editableStatuses.includes(originalDoc.status)) {\n return data\n }\n\n // Build update data\n const updates: any = {}\n if (data.name !== originalDoc.name) updates.name = data.name\n if (data.subject !== originalDoc.subject) updates.subject = data.subject\n if (data.preheader !== originalDoc.preheader) updates.preheader = data.preheader\n if (data.content !== originalDoc.content) {\n updates.content = await convertToEmailSafeHtml(data.content)\n }\n if (data.settings?.trackOpens !== originalDoc.settings?.trackOpens) {\n updates.trackOpens = data.settings.trackOpens\n }\n if (data.settings?.trackClicks !== originalDoc.settings?.trackClicks) {\n updates.trackClicks = data.settings.trackClicks\n }\n if (data.settings?.replyTo !== originalDoc.settings?.replyTo) {\n updates.replyTo = data.settings.replyTo\n }\n if (JSON.stringify(data.audienceIds) !== JSON.stringify(originalDoc.audienceIds)) {\n updates.audienceIds = data.audienceIds?.map((a: any) => a.audienceId)\n }\n\n if (Object.keys(updates).length > 0) {\n await provider.update(originalDoc.providerId, updates)\n }\n } catch (error) {\n req.payload.logger.error('Failed to update broadcast in provider:', error)\n // Continue with local update even if provider fails\n }\n\n return data\n },\n ],\n // Handle deletion\n afterDelete: [\n async ({ doc, req }) => {\n if (!hasProviders || !doc?.providerId) return doc\n\n try {\n // Get the channel to determine provider\n const channel = await req.payload.findByID({\n collection: 'channels',\n id: typeof doc.channel === 'string' ? doc.channel : doc.channel.id,\n req,\n })\n\n const provider = await getProvider(channel.providerType, pluginConfig)\n if (!provider) return doc\n\n // Only delete if broadcast is still editable\n const capabilities = provider.getCapabilities()\n if (capabilities.editableStatuses.includes(doc.status)) {\n await provider.delete(doc.providerId)\n }\n } catch (error) {\n req.payload.logger.error('Failed to delete broadcast from provider:', error)\n }\n\n return doc\n },\n ],\n },\n }\n}\n\n// Helper to get provider instance\nasync function getProvider(providerType: string, config: NewsletterPluginConfig): Promise<any> {\n if (providerType === 'broadcast') {\n const { BroadcastApiProvider } = await import('../providers/broadcast/broadcast')\n const providerConfig = config.providers?.broadcast\n return providerConfig ? new BroadcastApiProvider(providerConfig) : null\n }\n \n if (providerType === 'resend') {\n const { ResendBroadcastProvider } = await import('../providers/resend/broadcast')\n const providerConfig = config.providers?.resend\n return providerConfig ? new ResendBroadcastProvider(providerConfig) : null\n }\n\n return null\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 lexicalEditor,\n} from '@payloadcms/richtext-lexical'\nimport type { RichTextField } from 'payload'\n\n/**\n * Email-safe features for Lexical editor\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 emailSafeFeatures: any[] = [\n // Basic text formatting\n BoldFeature(),\n ItalicFeature(),\n UnderlineFeature(),\n StrikethroughFeature(),\n \n // Links with simple configuration\n LinkFeature({\n fields: [{\n name: 'url',\n type: 'text',\n required: true,\n admin: {\n description: 'Enter the full URL (including https://)',\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\n/**\n * Creates an email-safe rich text field configuration\n */\nexport const createEmailContentField = (overrides?: Partial<RichTextField>): RichTextField => {\n return {\n name: 'content',\n type: 'richText',\n required: true,\n editor: lexicalEditor({\n features: emailSafeFeatures,\n }),\n admin: {\n description: 'Email content with limited formatting for compatibility',\n ...overrides?.admin,\n },\n ...overrides,\n }\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","broadcast_exports","import_resend","init_broadcast","import_components","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","DOMPurify","jwt","subscriber","jwt","import_isomorphic_dompurify","DOMPurify","styles","BroadcastApiProvider","ResendBroadcastProvider","getProvider","BroadcastApiProvider","ResendBroadcastProvider","init_broadcast","import_jsonwebtoken","jwt","isAuthenticated"]}