payload-plugin-newsletter 0.20.2 → 0.20.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "payload-plugin-newsletter",
3
- "version": "0.20.2",
3
+ "version": "0.20.3",
4
4
  "description": "Complete newsletter management plugin for Payload CMS with subscriber management, magic link authentication, and email service integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -85,7 +85,8 @@
85
85
  "test:coverage": "bunx vitest run --coverage",
86
86
  "test:ui": "bunx vitest --ui",
87
87
  "generate:types": "tsc --emitDeclarationOnly --outDir dist",
88
- "prepublishOnly": "bun run clean && bun run build",
88
+ "validate:bundles": "node scripts/validate-bundles.cjs",
89
+ "prepublishOnly": "bun run clean && bun run build && bun run validate:bundles",
89
90
  "release:patch": "./scripts/release.sh patch",
90
91
  "release:minor": "./scripts/release.sh minor",
91
92
  "release:major": "./scripts/release.sh major"
package/dist/admin.d.ts DELETED
@@ -1,706 +0,0 @@
1
- import React$1 from 'react';
2
- import { DefaultCellComponentProps, Field, Block, RichTextField } from 'payload';
3
- import { SerializedEditorState } from 'lexical';
4
-
5
- declare const BroadcastInlinePreview: React$1.FC;
6
-
7
- declare const StatusBadge: React$1.FC<DefaultCellComponentProps>;
8
-
9
- /**
10
- * Core types for broadcast management functionality
11
- */
12
- /**
13
- * Represents a broadcast (individual email campaign) in the system
14
- */
15
- interface Broadcast {
16
- id: string;
17
- name: string;
18
- subject: string;
19
- preheader?: string;
20
- content: string;
21
- sendStatus: BroadcastStatus;
22
- trackOpens: boolean;
23
- trackClicks: boolean;
24
- replyTo?: string;
25
- recipientCount?: number;
26
- sentAt?: Date;
27
- scheduledAt?: Date;
28
- createdAt: Date;
29
- updatedAt: Date;
30
- providerData?: Record<string, any>;
31
- providerId?: string;
32
- providerType?: 'broadcast' | 'resend';
33
- }
34
- /**
35
- * Possible statuses for a broadcast
36
- */
37
- declare enum BroadcastStatus {
38
- DRAFT = "draft",
39
- SCHEDULED = "scheduled",
40
- SENDING = "sending",
41
- SENT = "sent",
42
- FAILED = "failed",
43
- PAUSED = "paused",
44
- CANCELED = "canceled"
45
- }
46
- /**
47
- * Options for listing broadcasts
48
- */
49
- interface ListBroadcastOptions {
50
- limit?: number;
51
- offset?: number;
52
- status?: BroadcastStatus;
53
- sortBy?: 'createdAt' | 'updatedAt' | 'sentAt' | 'name';
54
- sortOrder?: 'asc' | 'desc';
55
- }
56
- /**
57
- * Response from listing broadcasts
58
- */
59
- interface ListBroadcastResponse<T = Broadcast> {
60
- items: T[];
61
- total: number;
62
- limit: number;
63
- offset: number;
64
- hasMore: boolean;
65
- }
66
- /**
67
- * Input for creating a new broadcast
68
- */
69
- interface CreateBroadcastInput {
70
- name: string;
71
- subject: string;
72
- preheader?: string;
73
- content: string;
74
- trackOpens?: boolean;
75
- trackClicks?: boolean;
76
- replyTo?: string;
77
- audienceIds?: string[];
78
- }
79
- /**
80
- * Input for updating an existing broadcast
81
- */
82
- interface UpdateBroadcastInput {
83
- name?: string;
84
- subject?: string;
85
- preheader?: string;
86
- content?: string;
87
- trackOpens?: boolean;
88
- trackClicks?: boolean;
89
- replyTo?: string;
90
- audienceIds?: string[];
91
- }
92
- /**
93
- * Options for sending a broadcast
94
- */
95
- interface SendBroadcastOptions {
96
- audienceIds?: string[];
97
- testMode?: boolean;
98
- testRecipients?: string[];
99
- }
100
- /**
101
- * Analytics data for a broadcast
102
- */
103
- interface BroadcastAnalytics {
104
- sent: number;
105
- delivered: number;
106
- opened: number;
107
- clicked: number;
108
- bounced: number;
109
- complained: number;
110
- unsubscribed: number;
111
- deliveryRate?: number;
112
- openRate?: number;
113
- clickRate?: number;
114
- bounceRate?: number;
115
- }
116
- /**
117
- * Capabilities that a broadcast provider supports
118
- */
119
- interface BroadcastProviderCapabilities {
120
- supportsScheduling: boolean;
121
- supportsSegmentation: boolean;
122
- supportsAnalytics: boolean;
123
- supportsABTesting: boolean;
124
- supportsTemplates: boolean;
125
- supportsPersonalization: boolean;
126
- maxRecipientsPerSend?: number;
127
- editableStatuses: BroadcastStatus[];
128
- supportedContentTypes: ('html' | 'text' | 'react')[];
129
- supportsMultipleChannels: boolean;
130
- supportsChannelSegmentation: boolean;
131
- }
132
-
133
- /**
134
- * Provider interfaces for broadcast management
135
- */
136
-
137
- /**
138
- * Main interface for broadcast providers
139
- */
140
- interface BroadcastProvider {
141
- /**
142
- * Get the provider name
143
- */
144
- readonly name: string;
145
- /**
146
- * List broadcasts with pagination
147
- */
148
- list(options?: ListBroadcastOptions): Promise<ListBroadcastResponse<Broadcast>>;
149
- /**
150
- * Get a specific broadcast by ID
151
- */
152
- get(id: string): Promise<Broadcast>;
153
- /**
154
- * Create a new broadcast
155
- */
156
- create(data: CreateBroadcastInput): Promise<Broadcast>;
157
- /**
158
- * Update an existing broadcast
159
- */
160
- update(id: string, data: UpdateBroadcastInput): Promise<Broadcast>;
161
- /**
162
- * Delete a broadcast
163
- */
164
- delete(id: string): Promise<void>;
165
- /**
166
- * Send a broadcast immediately or to test recipients
167
- */
168
- send(id: string, options?: SendBroadcastOptions): Promise<Broadcast>;
169
- /**
170
- * Schedule a broadcast for future sending
171
- */
172
- schedule(id: string, scheduledAt: Date): Promise<Broadcast>;
173
- /**
174
- * Cancel a scheduled broadcast
175
- */
176
- cancelSchedule(id: string): Promise<Broadcast>;
177
- /**
178
- * Get analytics for a broadcast
179
- */
180
- getAnalytics(id: string): Promise<BroadcastAnalytics>;
181
- /**
182
- * Get provider capabilities
183
- */
184
- getCapabilities(): BroadcastProviderCapabilities;
185
- /**
186
- * Validate that the provider is properly configured
187
- */
188
- validateConfiguration(): Promise<boolean>;
189
- }
190
-
191
- interface BroadcastCustomizations {
192
- additionalFields?: Field[];
193
- customBlocks?: Block[];
194
- fieldOverrides?: {
195
- content?: (defaultField: RichTextField) => RichTextField;
196
- };
197
- /**
198
- * Custom block email converter
199
- * @param node - The block node from Lexical editor state
200
- * @param mediaUrl - Base URL for media files
201
- * @returns Promise<string> - The email-safe HTML for the block
202
- */
203
- customBlockConverter?: (node: any, mediaUrl?: string) => Promise<string>;
204
- /**
205
- * Fields to populate in custom blocks before email conversion
206
- * Can be an array of field names or a function that returns field names based on block type
207
- * This is useful for upload fields that need to be populated with full media objects
208
- *
209
- * @example
210
- * // Array of field names to always populate
211
- * populateFields: ['bannerImage', 'sponsorLogo']
212
- *
213
- * @example
214
- * // Function to return fields based on block type
215
- * populateFields: (blockType) => {
216
- * if (blockType === 'newsletter-hero') return ['bannerImage', 'sponsorLogo']
217
- * if (blockType === 'content-section') return ['featuredImage']
218
- * return []
219
- * }
220
- */
221
- populateFields?: string[] | ((blockType: string) => string[]);
222
- /**
223
- * Email preview customization options
224
- */
225
- emailPreview?: {
226
- /**
227
- * Whether to wrap preview content in default email template
228
- * @default true
229
- */
230
- wrapInTemplate?: boolean;
231
- /**
232
- * Custom wrapper function for preview content
233
- * Receives the converted HTML and should return wrapped HTML
234
- */
235
- customWrapper?: (content: string, options?: {
236
- subject?: string;
237
- preheader?: string;
238
- }) => string | Promise<string>;
239
- /**
240
- * Custom preview component to replace the default one entirely
241
- * If provided, this component will be used instead of the default EmailPreview
242
- */
243
- customPreviewComponent?: string;
244
- };
245
- }
246
- interface NewsletterPluginConfig {
247
- /**
248
- * Enable or disable the plugin
249
- * @default true
250
- */
251
- enabled?: boolean;
252
- /**
253
- * Slug for the subscribers collection
254
- * @default 'subscribers'
255
- */
256
- subscribersSlug?: string;
257
- /**
258
- * Slug for the newsletter settings global
259
- * @default 'newsletter-settings'
260
- */
261
- settingsSlug?: string;
262
- /**
263
- * Authentication configuration for magic links
264
- */
265
- auth?: {
266
- /**
267
- * Enable magic link authentication
268
- * @default true
269
- */
270
- enabled?: boolean;
271
- /**
272
- * Token expiration time
273
- * @default '7d'
274
- */
275
- tokenExpiration?: string;
276
- /**
277
- * Path where magic link redirects
278
- * @default '/newsletter/verify'
279
- */
280
- magicLinkPath?: string;
281
- /**
282
- * Allow unsubscribed users to sign in
283
- * @default false
284
- */
285
- allowUnsubscribedSignin?: boolean;
286
- /**
287
- * Allow unsubscribed users to resubscribe
288
- * @default false
289
- */
290
- allowResubscribe?: boolean;
291
- };
292
- /**
293
- * Access control configuration
294
- */
295
- access?: {
296
- /**
297
- * Custom function to determine if a user is an admin
298
- * @param user - The authenticated user object
299
- * @returns true if the user should have admin access
300
- */
301
- isAdmin?: (user: any) => boolean;
302
- };
303
- /**
304
- * Email provider configuration
305
- */
306
- providers: {
307
- /**
308
- * Default provider to use
309
- */
310
- default: 'resend' | 'broadcast' | string;
311
- /**
312
- * Resend provider configuration
313
- */
314
- resend?: ResendProviderConfig;
315
- /**
316
- * Broadcast provider configuration
317
- */
318
- broadcast?: BroadcastProviderConfig;
319
- };
320
- /**
321
- * Field customization options
322
- */
323
- fields?: {
324
- /**
325
- * Override default fields
326
- */
327
- overrides?: (args: {
328
- defaultFields: Field[];
329
- }) => Field[];
330
- /**
331
- * Additional custom fields
332
- */
333
- additional?: Field[];
334
- };
335
- /**
336
- * Email template components
337
- */
338
- templates?: {
339
- /**
340
- * Welcome email template
341
- */
342
- welcome?: React.ComponentType<WelcomeEmailProps>;
343
- /**
344
- * Magic link email template
345
- */
346
- magicLink?: React.ComponentType<MagicLinkEmailProps>;
347
- };
348
- /**
349
- * Plugin hooks
350
- */
351
- hooks?: {
352
- beforeSubscribe?: (args: BeforeSubscribeArgs) => void | Promise<void>;
353
- afterSubscribe?: (args: AfterSubscribeArgs) => void | Promise<void>;
354
- beforeUnsubscribe?: (args: BeforeUnsubscribeArgs) => void | Promise<void>;
355
- afterUnsubscribe?: (args: AfterUnsubscribeArgs) => void | Promise<void>;
356
- afterUnsubscribeSync?: (args: AfterUnsubscribeSyncArgs) => void | Promise<void>;
357
- };
358
- /**
359
- * UI component overrides
360
- */
361
- components?: {
362
- signupForm?: React.ComponentType<SignupFormProps>;
363
- preferencesForm?: React.ComponentType<PreferencesFormProps>;
364
- };
365
- /**
366
- * Feature flags
367
- */
368
- features?: {
369
- /**
370
- * Lead magnet configuration
371
- */
372
- leadMagnets?: {
373
- enabled?: boolean;
374
- collection?: string;
375
- };
376
- /**
377
- * Post-signup survey configuration
378
- */
379
- surveys?: {
380
- enabled?: boolean;
381
- questions?: SurveyQuestion[];
382
- };
383
- /**
384
- * UTM tracking configuration
385
- */
386
- utmTracking?: {
387
- enabled?: boolean;
388
- fields?: string[];
389
- };
390
- /**
391
- * Newsletter scheduling configuration
392
- */
393
- newsletterScheduling?: {
394
- enabled?: boolean;
395
- /**
396
- * Collections to add newsletter fields to
397
- * Can be a string for single collection or array for multiple
398
- * @example 'articles' or ['articles', 'posts', 'updates']
399
- */
400
- collections?: string | string[];
401
- /**
402
- * Field configuration
403
- */
404
- fields?: {
405
- /**
406
- * Group name for newsletter fields
407
- * @default 'newsletterScheduling'
408
- */
409
- groupName?: string;
410
- /**
411
- * Rich text field name to use for content
412
- * @default 'content'
413
- */
414
- contentField?: string;
415
- /**
416
- * Whether to create a markdown companion field
417
- * @default true
418
- */
419
- createMarkdownField?: boolean;
420
- };
421
- };
422
- /**
423
- * Unsubscribe sync configuration
424
- */
425
- unsubscribeSync?: {
426
- /**
427
- * Enable sync of unsubscribes from email service to Payload
428
- * @default false
429
- */
430
- enabled?: boolean;
431
- /**
432
- * Cron schedule for sync job (e.g., '0 * * * *' for hourly)
433
- * If not provided, job must be triggered manually
434
- */
435
- schedule?: string;
436
- /**
437
- * Queue name for the sync job
438
- * @default 'newsletter-sync'
439
- */
440
- queue?: string;
441
- };
442
- /**
443
- * Newsletter management configuration
444
- */
445
- newsletterManagement?: {
446
- /**
447
- * Enable newsletter management features
448
- * @default false
449
- */
450
- enabled?: boolean;
451
- /**
452
- * Collection names for broadcast management
453
- */
454
- collections?: {
455
- /**
456
- * Broadcasts collection slug
457
- * @default 'broadcasts'
458
- */
459
- broadcasts?: string;
460
- };
461
- /**
462
- * Optional: Custom broadcast provider implementation
463
- * If not provided, will use the default email provider
464
- */
465
- provider?: BroadcastProvider;
466
- };
467
- };
468
- /**
469
- * Internationalization configuration
470
- */
471
- i18n?: {
472
- defaultLocale?: string;
473
- locales?: string[];
474
- };
475
- /**
476
- * Custom email templates
477
- */
478
- customTemplates?: {
479
- [key: string]: React.ComponentType<any>;
480
- };
481
- /**
482
- * Customization options for plugin collections
483
- */
484
- customizations?: {
485
- broadcasts?: BroadcastCustomizations;
486
- };
487
- }
488
- interface ResendProviderConfig {
489
- apiKey: string;
490
- fromEmail?: string;
491
- fromAddress?: string;
492
- fromName?: string;
493
- replyTo?: string;
494
- audienceIds?: {
495
- [locale: string]: {
496
- production?: string;
497
- development?: string;
498
- };
499
- };
500
- }
501
- interface BroadcastProviderConfig {
502
- apiUrl: string;
503
- token: string;
504
- fromEmail?: string;
505
- fromAddress?: string;
506
- fromName?: string;
507
- replyTo?: string;
508
- }
509
- interface Subscriber {
510
- id: string;
511
- email: string;
512
- name?: string;
513
- locale?: string;
514
- subscriptionStatus: 'active' | 'unsubscribed' | 'pending';
515
- emailPreferences?: {
516
- newsletter?: boolean;
517
- announcements?: boolean;
518
- [key: string]: boolean | undefined;
519
- };
520
- source?: string;
521
- utmParameters?: {
522
- source?: string;
523
- medium?: string;
524
- campaign?: string;
525
- content?: string;
526
- term?: string;
527
- };
528
- signupMetadata?: {
529
- ipAddress?: string;
530
- userAgent?: string;
531
- referrer?: string;
532
- signupPage?: string;
533
- };
534
- leadMagnet?: string;
535
- unsubscribedAt?: string;
536
- magicLinkToken?: string;
537
- magicLinkTokenExpiry?: string;
538
- createdAt: string;
539
- updatedAt: string;
540
- }
541
- interface WelcomeEmailProps {
542
- subscriber: Subscriber;
543
- unsubscribeUrl: string;
544
- preferencesUrl: string;
545
- }
546
- interface MagicLinkEmailProps {
547
- magicLinkUrl: string;
548
- subscriber: Subscriber;
549
- }
550
- interface SignupFormProps {
551
- onSuccess?: (subscriber: Subscriber) => void;
552
- onError?: (error: Error) => void;
553
- showName?: boolean;
554
- showPreferences?: boolean;
555
- leadMagnet?: {
556
- id: string;
557
- title: string;
558
- description?: string;
559
- };
560
- className?: string;
561
- styles?: {
562
- form?: React.CSSProperties;
563
- inputGroup?: React.CSSProperties;
564
- label?: React.CSSProperties;
565
- input?: React.CSSProperties;
566
- button?: React.CSSProperties;
567
- buttonDisabled?: React.CSSProperties;
568
- error?: React.CSSProperties;
569
- success?: React.CSSProperties;
570
- checkbox?: React.CSSProperties;
571
- checkboxInput?: React.CSSProperties;
572
- checkboxLabel?: React.CSSProperties;
573
- };
574
- apiEndpoint?: string;
575
- buttonText?: string;
576
- loadingText?: string;
577
- successMessage?: string;
578
- placeholders?: {
579
- email?: string;
580
- name?: string;
581
- };
582
- labels?: {
583
- email?: string;
584
- name?: string;
585
- newsletter?: string;
586
- announcements?: string;
587
- };
588
- }
589
- interface PreferencesFormProps {
590
- subscriber?: Subscriber;
591
- onSuccess?: (subscriber: Subscriber) => void;
592
- onError?: (error: Error) => void;
593
- className?: string;
594
- styles?: {
595
- container?: React.CSSProperties;
596
- heading?: React.CSSProperties;
597
- form?: React.CSSProperties;
598
- section?: React.CSSProperties;
599
- sectionTitle?: React.CSSProperties;
600
- inputGroup?: React.CSSProperties;
601
- label?: React.CSSProperties;
602
- input?: React.CSSProperties;
603
- select?: React.CSSProperties;
604
- checkbox?: React.CSSProperties;
605
- checkboxInput?: React.CSSProperties;
606
- checkboxLabel?: React.CSSProperties;
607
- buttonGroup?: React.CSSProperties;
608
- button?: React.CSSProperties;
609
- primaryButton?: React.CSSProperties;
610
- secondaryButton?: React.CSSProperties;
611
- dangerButton?: React.CSSProperties;
612
- error?: React.CSSProperties;
613
- success?: React.CSSProperties;
614
- info?: React.CSSProperties;
615
- };
616
- sessionToken?: string;
617
- apiEndpoint?: string;
618
- showUnsubscribe?: boolean;
619
- locales?: string[];
620
- labels?: {
621
- title?: string;
622
- personalInfo?: string;
623
- emailPreferences?: string;
624
- name?: string;
625
- language?: string;
626
- newsletter?: string;
627
- announcements?: string;
628
- saveButton?: string;
629
- unsubscribeButton?: string;
630
- saving?: string;
631
- saved?: string;
632
- unsubscribeConfirm?: string;
633
- };
634
- }
635
- interface BeforeSubscribeArgs {
636
- data: Partial<Subscriber>;
637
- req: any;
638
- }
639
- interface AfterSubscribeArgs {
640
- doc: Subscriber;
641
- req: any;
642
- }
643
- interface BeforeUnsubscribeArgs {
644
- email: string;
645
- req: any;
646
- }
647
- interface AfterUnsubscribeArgs {
648
- doc: Subscriber;
649
- req: any;
650
- }
651
- interface AfterUnsubscribeSyncArgs {
652
- req: any;
653
- syncedCount: number;
654
- }
655
- interface SurveyQuestion {
656
- id: string;
657
- question: string;
658
- type: 'text' | 'select' | 'multiselect' | 'radio';
659
- options?: string[];
660
- required?: boolean;
661
- }
662
-
663
- interface EmailPreviewProps {
664
- content: SerializedEditorState | null;
665
- subject: string;
666
- preheader?: string;
667
- mode?: 'desktop' | 'mobile';
668
- onValidation?: (result: {
669
- valid: boolean;
670
- warnings: string[];
671
- errors: string[];
672
- }) => void;
673
- pluginConfig?: NewsletterPluginConfig;
674
- }
675
- declare const EmailPreview: React$1.FC<EmailPreviewProps>;
676
-
677
- interface BroadcastEditorProps {
678
- field: RichTextField;
679
- path: string;
680
- }
681
- declare const BroadcastEditor: React$1.FC<BroadcastEditorProps>;
682
-
683
- declare const EmailPreviewField: React$1.FC;
684
-
685
- declare const BroadcastPreviewField: React$1.FC;
686
-
687
- declare const PluginConfigProvider: React$1.FC<{
688
- config: NewsletterPluginConfig;
689
- children: React$1.ReactNode;
690
- }>;
691
- declare const usePluginConfig: () => NewsletterPluginConfig;
692
- declare const usePluginConfigOptional: () => NewsletterPluginConfig | null;
693
-
694
- declare const createBroadcastInlinePreviewField: () => Field;
695
-
696
- declare const createBroadcastPreviewField: () => Field;
697
-
698
- /**
699
- * Creates an email-safe rich text field configuration
700
- */
701
- declare const createEmailContentField: (overrides?: Partial<RichTextField> & {
702
- additionalBlocks?: Block[];
703
- editor?: any;
704
- }) => RichTextField;
705
-
706
- export { BroadcastEditor, BroadcastInlinePreview, BroadcastPreviewField, EmailPreview, EmailPreviewField, PluginConfigProvider, StatusBadge, createBroadcastInlinePreviewField, createBroadcastPreviewField, createEmailContentField, usePluginConfig, usePluginConfigOptional };