payload-plugin-newsletter 0.9.2 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -65,13 +65,6 @@ var init_broadcast = __esm({
65
65
  }
66
66
  });
67
67
 
68
- // src/types/channel.ts
69
- var init_channel = __esm({
70
- "src/types/channel.ts"() {
71
- "use strict";
72
- }
73
- });
74
-
75
68
  // src/types/providers.ts
76
69
  var BaseBroadcastProvider;
77
70
  var init_providers = __esm({
@@ -176,7 +169,6 @@ var init_types = __esm({
176
169
  "src/types/index.ts"() {
177
170
  "use strict";
178
171
  init_broadcast();
179
- init_channel();
180
172
  init_providers();
181
173
  init_newsletter();
182
174
  }
@@ -197,8 +189,7 @@ var init_broadcast2 = __esm({
197
189
  super(config);
198
190
  this.name = "broadcast";
199
191
  this.apiUrl = config.apiUrl.replace(/\/$/, "");
200
- this.isDevelopment = process.env.NODE_ENV !== "production";
201
- this.token = this.isDevelopment ? config.tokens.development || config.tokens.production || "" : config.tokens.production || config.tokens.development || "";
192
+ this.token = config.token;
202
193
  if (!this.token) {
203
194
  throw new BroadcastProviderError(
204
195
  "Broadcast API token is required",
@@ -207,158 +198,6 @@ var init_broadcast2 = __esm({
207
198
  );
208
199
  }
209
200
  }
210
- // Channel Management Methods
211
- async listChannels(options) {
212
- try {
213
- const params = new URLSearchParams();
214
- if (options?.limit) params.append("limit", options.limit.toString());
215
- if (options?.offset) params.append("offset", options.offset.toString());
216
- const response = await fetch(`${this.apiUrl}/api/v1/channels?${params}`, {
217
- method: "GET",
218
- headers: {
219
- "Authorization": `Bearer ${this.token}`,
220
- "Content-Type": "application/json"
221
- }
222
- });
223
- if (!response.ok) {
224
- const error = await response.text();
225
- throw new Error(`Broadcast API error: ${response.status} - ${error}`);
226
- }
227
- const data = await response.json();
228
- const channels = data.data.map((channel) => this.transformChannelFromApi(channel));
229
- return {
230
- channels,
231
- total: data.total || channels.length,
232
- limit: options?.limit || 20,
233
- offset: options?.offset || 0
234
- };
235
- } catch (error) {
236
- throw new BroadcastProviderError(
237
- `Failed to list channels: ${error instanceof Error ? error.message : "Unknown error"}`,
238
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
239
- this.name,
240
- error
241
- );
242
- }
243
- }
244
- async getChannel(id) {
245
- try {
246
- const response = await fetch(`${this.apiUrl}/api/v1/channels/${id}`, {
247
- method: "GET",
248
- headers: {
249
- "Authorization": `Bearer ${this.token}`,
250
- "Content-Type": "application/json"
251
- }
252
- });
253
- if (!response.ok) {
254
- if (response.status === 404) {
255
- throw new BroadcastProviderError(
256
- `Channel not found: ${id}`,
257
- "CHANNEL_NOT_FOUND" /* CHANNEL_NOT_FOUND */,
258
- this.name
259
- );
260
- }
261
- const error = await response.text();
262
- throw new Error(`Broadcast API error: ${response.status} - ${error}`);
263
- }
264
- const channel = await response.json();
265
- return this.transformChannelFromApi(channel);
266
- } catch (error) {
267
- if (error instanceof BroadcastProviderError) throw error;
268
- throw new BroadcastProviderError(
269
- `Failed to get channel: ${error instanceof Error ? error.message : "Unknown error"}`,
270
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
271
- this.name,
272
- error
273
- );
274
- }
275
- }
276
- async createChannel(data) {
277
- try {
278
- const response = await fetch(`${this.apiUrl}/api/v1/channels`, {
279
- method: "POST",
280
- headers: {
281
- "Authorization": `Bearer ${this.token}`,
282
- "Content-Type": "application/json"
283
- },
284
- body: JSON.stringify({
285
- channel: {
286
- name: data.name,
287
- description: data.description,
288
- from: data.fromName,
289
- address: data.fromEmail,
290
- reply_to: data.replyTo
291
- }
292
- })
293
- });
294
- if (!response.ok) {
295
- const error = await response.text();
296
- throw new Error(`Broadcast API error: ${response.status} - ${error}`);
297
- }
298
- const channel = await response.json();
299
- return this.transformChannelFromApi(channel);
300
- } catch (error) {
301
- throw new BroadcastProviderError(
302
- `Failed to create channel: ${error instanceof Error ? error.message : "Unknown error"}`,
303
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
304
- this.name,
305
- error
306
- );
307
- }
308
- }
309
- async updateChannel(id, data) {
310
- try {
311
- const updateData = { channel: {} };
312
- if (data.name !== void 0) updateData.channel.name = data.name;
313
- if (data.description !== void 0) updateData.channel.description = data.description;
314
- if (data.fromName !== void 0) updateData.channel.from = data.fromName;
315
- if (data.fromEmail !== void 0) updateData.channel.address = data.fromEmail;
316
- if (data.replyTo !== void 0) updateData.channel.reply_to = data.replyTo;
317
- const response = await fetch(`${this.apiUrl}/api/v1/channels/${id}`, {
318
- method: "PATCH",
319
- headers: {
320
- "Authorization": `Bearer ${this.token}`,
321
- "Content-Type": "application/json"
322
- },
323
- body: JSON.stringify(updateData)
324
- });
325
- if (!response.ok) {
326
- const error = await response.text();
327
- throw new Error(`Broadcast API error: ${response.status} - ${error}`);
328
- }
329
- const channel = await response.json();
330
- return this.transformChannelFromApi(channel);
331
- } catch (error) {
332
- throw new BroadcastProviderError(
333
- `Failed to update channel: ${error instanceof Error ? error.message : "Unknown error"}`,
334
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
335
- this.name,
336
- error
337
- );
338
- }
339
- }
340
- async deleteChannel(id) {
341
- try {
342
- const response = await fetch(`${this.apiUrl}/api/v1/channels/${id}`, {
343
- method: "DELETE",
344
- headers: {
345
- "Authorization": `Bearer ${this.token}`,
346
- "Content-Type": "application/json"
347
- }
348
- });
349
- if (!response.ok) {
350
- const error = await response.text();
351
- throw new Error(`Broadcast API error: ${response.status} - ${error}`);
352
- }
353
- } catch (error) {
354
- throw new BroadcastProviderError(
355
- `Failed to delete channel: ${error instanceof Error ? error.message : "Unknown error"}`,
356
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
357
- this.name,
358
- error
359
- );
360
- }
361
- }
362
201
  // Broadcast Management Methods
363
202
  async list(options) {
364
203
  try {
@@ -422,7 +261,7 @@ var init_broadcast2 = __esm({
422
261
  }
423
262
  async create(data) {
424
263
  try {
425
- this.validateRequiredFields(data, ["channelId", "name", "subject", "content"]);
264
+ this.validateRequiredFields(data, ["name", "subject", "content"]);
426
265
  const response = await fetch(`${this.apiUrl}/api/v1/broadcasts`, {
427
266
  method: "POST",
428
267
  headers: {
@@ -431,8 +270,6 @@ var init_broadcast2 = __esm({
431
270
  },
432
271
  body: JSON.stringify({
433
272
  broadcast: {
434
- channel_id: parseInt(data.channelId),
435
- // Broadcast API uses numeric IDs
436
273
  name: data.name,
437
274
  subject: data.subject,
438
275
  preheader: data.preheader,
@@ -649,8 +486,8 @@ var init_broadcast2 = __esm({
649
486
  supportsABTesting: false,
650
487
  supportsTemplates: false,
651
488
  supportsPersonalization: true,
652
- supportsMultipleChannels: true,
653
- supportsChannelSegmentation: true,
489
+ supportsMultipleChannels: false,
490
+ supportsChannelSegmentation: false,
654
491
  editableStatuses: ["draft" /* DRAFT */, "scheduled" /* SCHEDULED */],
655
492
  supportedContentTypes: ["html", "text"]
656
493
  };
@@ -666,406 +503,37 @@ var init_broadcast2 = __esm({
666
503
  transformBroadcastFromApi(broadcast) {
667
504
  return {
668
505
  id: broadcast.id.toString(),
669
- channelId: "1",
670
- // TODO: Get from API response when available
671
506
  name: broadcast.name,
672
507
  subject: broadcast.subject,
673
508
  preheader: broadcast.preheader,
674
509
  content: broadcast.body,
675
- status: this.mapBroadcastStatus(broadcast.status),
676
- trackOpens: broadcast.track_opens,
677
- trackClicks: broadcast.track_clicks,
678
- replyTo: broadcast.reply_to,
679
- recipientCount: broadcast.total_recipients,
680
- sentAt: broadcast.sent_at ? new Date(broadcast.sent_at) : void 0,
681
- scheduledAt: broadcast.scheduled_send_at ? new Date(broadcast.scheduled_send_at) : void 0,
682
- createdAt: new Date(broadcast.created_at),
683
- updatedAt: new Date(broadcast.updated_at),
684
- providerData: { broadcast },
685
- providerId: broadcast.id.toString(),
686
- providerType: "broadcast"
687
- };
688
- }
689
- transformChannelFromApi(channel) {
690
- return {
691
- id: channel.id.toString(),
692
- name: channel.name,
693
- description: channel.description,
694
- fromName: channel.from,
695
- fromEmail: channel.address,
696
- replyTo: channel.reply_to,
697
- providerId: channel.id.toString(),
698
- providerType: "broadcast",
699
- subscriberCount: channel.total_active_subscribers,
700
- active: true,
701
- // Broadcast API doesn't have an active field
702
- createdAt: new Date(channel.created_at),
703
- updatedAt: new Date(channel.updated_at)
704
- };
705
- }
706
- mapBroadcastStatus(status) {
707
- const statusMap = {
708
- "draft": "draft" /* DRAFT */,
709
- "scheduled": "scheduled" /* SCHEDULED */,
710
- "queueing": "sending" /* SENDING */,
711
- "sending": "sending" /* SENDING */,
712
- "sent": "sent" /* SENT */,
713
- "failed": "failed" /* FAILED */,
714
- "partial_failure": "failed" /* FAILED */,
715
- "paused": "paused" /* PAUSED */,
716
- "aborted": "canceled" /* CANCELED */
717
- };
718
- return statusMap[status] || "draft" /* DRAFT */;
719
- }
720
- };
721
- }
722
- });
723
-
724
- // src/providers/resend/broadcast.ts
725
- var broadcast_exports2 = {};
726
- __export(broadcast_exports2, {
727
- ResendBroadcastProvider: () => ResendBroadcastProvider
728
- });
729
- var import_resend3, ResendBroadcastProvider;
730
- var init_broadcast3 = __esm({
731
- "src/providers/resend/broadcast.ts"() {
732
- "use strict";
733
- import_resend3 = require("resend");
734
- init_types();
735
- ResendBroadcastProvider = class extends BaseBroadcastProvider {
736
- constructor(config) {
737
- super(config);
738
- this.name = "resend";
739
- this.client = new import_resend3.Resend(config.apiKey);
740
- this.audienceIds = config.audienceIds || {};
741
- this.isDevelopment = process.env.NODE_ENV !== "production";
742
- if (!config.apiKey) {
743
- throw new BroadcastProviderError(
744
- "Resend API key is required",
745
- "CONFIGURATION_ERROR" /* CONFIGURATION_ERROR */,
746
- this.name
747
- );
748
- }
749
- }
750
- // Channel Management Methods (map to Resend Audiences)
751
- async listChannels(options) {
752
- try {
753
- const response = await this.client.audiences.list();
754
- const channels = response.data?.data?.map((audience) => ({
755
- id: audience.id,
756
- name: audience.name,
757
- description: void 0,
758
- // Resend doesn't have description
759
- fromName: this.config.fromName || "",
760
- fromEmail: this.config.fromEmail || "",
761
- replyTo: this.config.replyTo,
762
- providerId: audience.id,
763
- providerType: "resend",
764
- subscriberCount: void 0,
765
- // Not available in list API
766
- active: true,
767
- createdAt: new Date(audience.created_at),
768
- updatedAt: new Date(audience.created_at)
769
- // No updated_at in Resend
770
- })) || [];
771
- return {
772
- channels,
773
- total: channels.length,
774
- limit: options?.limit || 100,
775
- offset: options?.offset || 0
776
- };
777
- } catch (error) {
778
- throw new BroadcastProviderError(
779
- `Failed to list channels (audiences): ${error instanceof Error ? error.message : "Unknown error"}`,
780
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
781
- this.name,
782
- error
783
- );
784
- }
785
- }
786
- async getChannel(id) {
787
- try {
788
- const response = await this.client.audiences.get(id);
789
- if (!response.data) {
790
- throw new BroadcastProviderError(
791
- `Channel (audience) not found: ${id}`,
792
- "CHANNEL_NOT_FOUND" /* CHANNEL_NOT_FOUND */,
793
- this.name
794
- );
795
- }
796
- return {
797
- id: response.data.id,
798
- name: response.data.name,
799
- description: void 0,
800
- fromName: this.config.fromName || "",
801
- fromEmail: this.config.fromEmail || "",
802
- replyTo: this.config.replyTo,
803
- providerId: response.data.id,
804
- providerType: "resend",
805
- subscriberCount: void 0,
806
- // Not available
807
- active: true,
808
- createdAt: new Date(response.data.created_at),
809
- updatedAt: new Date(response.data.created_at)
810
- };
811
- } catch (error) {
812
- if (error instanceof BroadcastProviderError) throw error;
813
- throw new BroadcastProviderError(
814
- `Failed to get channel (audience): ${error instanceof Error ? error.message : "Unknown error"}`,
815
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
816
- this.name,
817
- error
818
- );
819
- }
820
- }
821
- async createChannel(data) {
822
- try {
823
- const response = await this.client.audiences.create({
824
- name: data.name
825
- });
826
- if (!response.data) {
827
- throw new Error("Failed to create audience");
828
- }
829
- return {
830
- id: response.data.id,
831
- name: response.data.name,
832
- description: data.description,
833
- fromName: data.fromName,
834
- fromEmail: data.fromEmail,
835
- replyTo: data.replyTo,
836
- providerId: response.data.id,
837
- providerType: "resend",
838
- subscriberCount: 0,
839
- active: true,
840
- createdAt: /* @__PURE__ */ new Date(),
841
- updatedAt: /* @__PURE__ */ new Date()
842
- };
843
- } catch (error) {
844
- throw new BroadcastProviderError(
845
- `Failed to create channel (audience): ${error instanceof Error ? error.message : "Unknown error"}`,
846
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
847
- this.name,
848
- error
849
- );
850
- }
851
- }
852
- async updateChannel(_id, _data) {
853
- throw new BroadcastProviderError(
854
- "Updating channels (audiences) is not supported by Resend API",
855
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
856
- this.name
857
- );
858
- }
859
- async deleteChannel(id) {
860
- try {
861
- await this.client.audiences.remove(id);
862
- } catch (error) {
863
- throw new BroadcastProviderError(
864
- `Failed to delete channel (audience): ${error instanceof Error ? error.message : "Unknown error"}`,
865
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
866
- this.name,
867
- error
868
- );
869
- }
870
- }
871
- // Broadcast Management Methods
872
- async list(_options) {
873
- throw new BroadcastProviderError(
874
- "Listing broadcasts is not currently supported by Resend API. This feature may be available in the dashboard only.",
875
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
876
- this.name
877
- );
878
- }
879
- async get(_id) {
880
- throw new BroadcastProviderError(
881
- "Getting individual broadcasts is not currently supported by Resend API. This feature may be available in the dashboard only.",
882
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
883
- this.name
884
- );
885
- }
886
- async create(data) {
887
- try {
888
- this.validateRequiredFields(data, ["channelId", "name", "subject", "content"]);
889
- const locale = "en";
890
- const audienceConfig = this.audienceIds?.[locale];
891
- const audienceId = this.isDevelopment ? audienceConfig?.development || audienceConfig?.production : audienceConfig?.production || audienceConfig?.development;
892
- if (!audienceId && data.audienceIds?.length) {
893
- }
894
- const resendClient = this.client;
895
- if (resendClient.broadcasts?.create) {
896
- const broadcast = await resendClient.broadcasts.create({
897
- name: data.name,
898
- subject: data.subject,
899
- from: `${this.config.fromName || "Newsletter"} <${this.config.fromEmail || "noreply@example.com"}>`,
900
- reply_to: data.replyTo,
901
- audience_id: audienceId || data.audienceIds?.[0],
902
- content: {
903
- html: data.content
904
- // TODO: Handle plain text version
905
- }
906
- });
907
- return this.transformResendToBroadcast(broadcast);
908
- }
909
- throw new BroadcastProviderError(
910
- "Creating broadcasts via API is not currently supported. Please check if Resend has released their Broadcasts API.",
911
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
912
- this.name
913
- );
914
- } catch (error) {
915
- if (error instanceof BroadcastProviderError) throw error;
916
- throw new BroadcastProviderError(
917
- `Failed to create broadcast: ${error instanceof Error ? error.message : "Unknown error"}`,
918
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
919
- this.name,
920
- error
921
- );
922
- }
923
- }
924
- async update(_id, _data) {
925
- throw new BroadcastProviderError(
926
- "Updating broadcasts is not currently supported by Resend API. Note: Resend broadcasts can only be edited where they were created.",
927
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
928
- this.name
929
- );
930
- }
931
- async delete(_id) {
932
- throw new BroadcastProviderError(
933
- "Deleting broadcasts is not currently supported by Resend API.",
934
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
935
- this.name
936
- );
937
- }
938
- async send(id, options) {
939
- try {
940
- const resendClient = this.client;
941
- if (resendClient.broadcasts?.send) {
942
- await resendClient.broadcasts.send(id, {
943
- audience_id: options?.audienceIds?.[0]
944
- // TODO: Handle test mode if supported
945
- });
946
- return {
947
- id,
948
- channelId: options?.audienceIds?.[0] || "1",
949
- name: "Unknown",
950
- subject: "Unknown",
951
- content: "",
952
- status: "sending" /* SENDING */,
953
- trackOpens: true,
954
- trackClicks: true,
955
- createdAt: /* @__PURE__ */ new Date(),
956
- updatedAt: /* @__PURE__ */ new Date(),
957
- providerType: "resend"
958
- };
959
- }
960
- throw new BroadcastProviderError(
961
- "Sending broadcasts via API is not currently supported. Please check if Resend has released their Broadcasts API.",
962
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
963
- this.name
964
- );
965
- } catch (error) {
966
- if (error instanceof BroadcastProviderError) throw error;
967
- throw new BroadcastProviderError(
968
- `Failed to send broadcast: ${error instanceof Error ? error.message : "Unknown error"}`,
969
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
970
- this.name,
971
- error
972
- );
973
- }
974
- }
975
- async schedule(_id, _scheduledAt) {
976
- throw new BroadcastProviderError(
977
- "Scheduling broadcasts is not supported by Resend",
978
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
979
- this.name
980
- );
981
- }
982
- async getAnalytics(_id) {
983
- throw new BroadcastProviderError(
984
- "Getting broadcast analytics via API is not currently supported. Analytics may be available in the Resend dashboard.",
985
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
986
- this.name
987
- );
988
- }
989
- getCapabilities() {
990
- return {
991
- supportsScheduling: false,
992
- // Not documented
993
- supportsSegmentation: true,
994
- // Via Audiences
995
- supportsAnalytics: true,
996
- // Available in dashboard, API unclear
997
- supportsABTesting: false,
998
- supportsTemplates: false,
999
- // Not clear from docs
1000
- supportsPersonalization: true,
1001
- // Via merge tags
1002
- supportsMultipleChannels: true,
1003
- // Via multiple audiences
1004
- supportsChannelSegmentation: false,
1005
- // Not within a single audience
1006
- editableStatuses: [],
1007
- // Unclear which statuses can be edited
1008
- supportedContentTypes: ["html"]
1009
- // React components via SDK
1010
- };
1011
- }
1012
- async validateConfiguration() {
1013
- try {
1014
- const resendClient = this.client;
1015
- if (resendClient.audiences?.list) {
1016
- await resendClient.audiences.list({ limit: 1 });
1017
- return true;
1018
- }
1019
- await this.client.emails.send({
1020
- from: "onboarding@resend.dev",
1021
- to: "delivered@resend.dev",
1022
- subject: "Configuration Test",
1023
- html: "<p>Testing configuration</p>"
1024
- });
1025
- return true;
1026
- } catch {
1027
- return false;
1028
- }
1029
- }
1030
- /**
1031
- * Transform Resend broadcast to our Broadcast type
1032
- * NOTE: This is speculative based on what the API might return
1033
- */
1034
- transformResendToBroadcast(broadcast) {
1035
- return {
1036
- id: broadcast.id,
1037
- channelId: broadcast.audience_id || "1",
1038
- // Map audience_id to channelId
1039
- name: broadcast.name || "Untitled",
1040
- subject: broadcast.subject,
1041
- preheader: broadcast.preheader,
1042
- content: broadcast.content?.html || broadcast.html || "",
1043
- status: this.mapResendStatus(broadcast.status),
1044
- trackOpens: true,
1045
- // Resend tracks by default
1046
- trackClicks: true,
1047
- // Resend tracks by default
510
+ status: this.mapBroadcastStatus(broadcast.status),
511
+ trackOpens: broadcast.track_opens,
512
+ trackClicks: broadcast.track_clicks,
1048
513
  replyTo: broadcast.reply_to,
1049
- recipientCount: broadcast.recipient_count,
514
+ recipientCount: broadcast.total_recipients,
1050
515
  sentAt: broadcast.sent_at ? new Date(broadcast.sent_at) : void 0,
1051
- scheduledAt: broadcast.scheduled_at ? new Date(broadcast.scheduled_at) : void 0,
1052
- createdAt: new Date(broadcast.created_at || Date.now()),
1053
- updatedAt: new Date(broadcast.updated_at || Date.now()),
516
+ scheduledAt: broadcast.scheduled_send_at ? new Date(broadcast.scheduled_send_at) : void 0,
517
+ createdAt: new Date(broadcast.created_at),
518
+ updatedAt: new Date(broadcast.updated_at),
1054
519
  providerData: { broadcast },
1055
- providerId: broadcast.id,
1056
- providerType: "resend"
520
+ providerId: broadcast.id.toString(),
521
+ providerType: "broadcast"
1057
522
  };
1058
523
  }
1059
- mapResendStatus(status) {
1060
- if (!status) return "draft" /* DRAFT */;
524
+ mapBroadcastStatus(status) {
1061
525
  const statusMap = {
1062
526
  "draft": "draft" /* DRAFT */,
1063
527
  "scheduled": "scheduled" /* SCHEDULED */,
528
+ "queueing": "sending" /* SENDING */,
1064
529
  "sending": "sending" /* SENDING */,
1065
530
  "sent": "sent" /* SENT */,
1066
- "failed": "failed" /* FAILED */
531
+ "failed": "failed" /* FAILED */,
532
+ "partial_failure": "failed" /* FAILED */,
533
+ "paused": "paused" /* PAUSED */,
534
+ "aborted": "canceled" /* CANCELED */
1067
535
  };
1068
- return statusMap[status.toLowerCase()] || "draft" /* DRAFT */;
536
+ return statusMap[status] || "draft" /* DRAFT */;
1069
537
  }
1070
538
  };
1071
539
  }
@@ -1752,19 +1220,12 @@ var createNewsletterSettingsGlobal = (pluginConfig) => {
1752
1220
  }
1753
1221
  },
1754
1222
  {
1755
- name: "productionToken",
1756
- type: "text",
1757
- label: "Production Token",
1758
- admin: {
1759
- description: "Token for production environment"
1760
- }
1761
- },
1762
- {
1763
- name: "developmentToken",
1223
+ name: "token",
1764
1224
  type: "text",
1765
- label: "Development Token",
1225
+ label: "API Token",
1226
+ required: true,
1766
1227
  admin: {
1767
- description: "Token for development environment"
1228
+ description: "Your Broadcast API token"
1768
1229
  }
1769
1230
  }
1770
1231
  ]
@@ -2090,10 +1551,10 @@ var ResendProvider = class {
2090
1551
  var BroadcastProvider = class {
2091
1552
  constructor(config) {
2092
1553
  this.apiUrl = config.apiUrl.replace(/\/$/, "");
2093
- this.isDevelopment = process.env.NODE_ENV !== "production";
2094
- this.token = this.isDevelopment ? config.tokens.development || config.tokens.production || "" : config.tokens.production || config.tokens.development || "";
1554
+ this.token = config.token;
2095
1555
  this.fromAddress = config.fromAddress;
2096
1556
  this.fromName = config.fromName;
1557
+ this.replyTo = config.replyTo;
2097
1558
  }
2098
1559
  getProvider() {
2099
1560
  return "broadcast";
@@ -2116,7 +1577,7 @@ var BroadcastProvider = class {
2116
1577
  // Broadcast API expects a single recipient for transactional emails
2117
1578
  subject: params.subject,
2118
1579
  body: params.html || params.text || "",
2119
- reply_to: params.replyTo || from.email
1580
+ reply_to: params.replyTo || this.replyTo || from.email
2120
1581
  })
2121
1582
  });
2122
1583
  if (!response.ok) {
@@ -3293,8 +2754,7 @@ var createSendBroadcastEndpoint = (config, collectionSlug) => {
3293
2754
  error: auth.error
3294
2755
  }, { status: 401 });
3295
2756
  }
3296
- const broadcastProvider = req.payload.newsletterProvider;
3297
- if (!broadcastProvider) {
2757
+ if (!config.features?.newsletterManagement?.enabled) {
3298
2758
  return Response.json({
3299
2759
  success: false,
3300
2760
  error: "Broadcast management is not enabled"
@@ -3321,7 +2781,16 @@ var createSendBroadcastEndpoint = (config, collectionSlug) => {
3321
2781
  error: "Broadcast not found or not synced with provider"
3322
2782
  }, { status: 404 });
3323
2783
  }
3324
- const broadcast = await broadcastProvider.send(broadcastDoc.providerId, data);
2784
+ const providerConfig = config.providers?.broadcast;
2785
+ if (!providerConfig) {
2786
+ return Response.json({
2787
+ success: false,
2788
+ error: "Broadcast provider not configured"
2789
+ }, { status: 500 });
2790
+ }
2791
+ const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
2792
+ const provider = new BroadcastApiProvider2(providerConfig);
2793
+ const broadcast = await provider.send(broadcastDoc.providerId, data);
3325
2794
  await req.payload.update({
3326
2795
  collection: collectionSlug,
3327
2796
  id,
@@ -3369,8 +2838,7 @@ var createScheduleBroadcastEndpoint = (config, collectionSlug) => {
3369
2838
  error: auth.error
3370
2839
  }, { status: 401 });
3371
2840
  }
3372
- const broadcastProvider = req.payload.newsletterProvider;
3373
- if (!broadcastProvider) {
2841
+ if (!config.features?.newsletterManagement?.enabled) {
3374
2842
  return Response.json({
3375
2843
  success: false,
3376
2844
  error: "Broadcast management is not enabled"
@@ -3417,7 +2885,16 @@ var createScheduleBroadcastEndpoint = (config, collectionSlug) => {
3417
2885
  error: "Broadcast not found or not synced with provider"
3418
2886
  }, { status: 404 });
3419
2887
  }
3420
- const broadcast = await broadcastProvider.schedule(broadcastDoc.providerId, scheduledDate);
2888
+ const providerConfig = config.providers?.broadcast;
2889
+ if (!providerConfig) {
2890
+ return Response.json({
2891
+ success: false,
2892
+ error: "Broadcast provider not configured"
2893
+ }, { status: 500 });
2894
+ }
2895
+ const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
2896
+ const provider = new BroadcastApiProvider2(providerConfig);
2897
+ const broadcast = await provider.schedule(broadcastDoc.providerId, scheduledDate);
3421
2898
  await req.payload.update({
3422
2899
  collection: collectionSlug,
3423
2900
  id,
@@ -3696,11 +3173,6 @@ var createTestBroadcastEndpoint = (config, collectionSlug) => {
3696
3173
  error: "Broadcast not found"
3697
3174
  }, { status: 404 });
3698
3175
  }
3699
- const channel = await req.payload.findByID({
3700
- collection: "channels",
3701
- id: typeof broadcast.channel === "string" ? broadcast.channel : broadcast.channel.id,
3702
- user: auth.user
3703
- });
3704
3176
  const htmlContent = await convertToEmailSafeHtml(broadcast.content, {
3705
3177
  wrapInTemplate: true,
3706
3178
  preheader: broadcast.preheader
@@ -3712,11 +3184,15 @@ var createTestBroadcastEndpoint = (config, collectionSlug) => {
3712
3184
  error: "Email service is not configured"
3713
3185
  }, { status: 500 });
3714
3186
  }
3187
+ const providerConfig = config.providers.default === "resend" ? config.providers.resend : config.providers.broadcast;
3188
+ const fromEmail = providerConfig?.fromAddress || providerConfig?.fromEmail || "noreply@example.com";
3189
+ const fromName = providerConfig?.fromName || "Newsletter";
3190
+ const replyTo = broadcast.settings?.replyTo || providerConfig?.replyTo;
3715
3191
  await emailService.send({
3716
3192
  to: testEmail,
3717
- from: channel?.fromEmail || config.providers.resend?.fromAddress || "noreply@example.com",
3718
- fromName: channel?.fromName || config.providers.resend?.fromName || "Newsletter",
3719
- replyTo: broadcast.settings?.replyTo || channel?.replyTo,
3193
+ from: fromEmail,
3194
+ fromName,
3195
+ replyTo,
3720
3196
  subject: `[TEST] ${broadcast.subject}`,
3721
3197
  html: htmlContent,
3722
3198
  trackOpens: false,
@@ -3964,7 +3440,7 @@ var createUnsubscribeSyncJob = (pluginConfig) => {
3964
3440
  throw new Error("Broadcast configuration not found");
3965
3441
  }
3966
3442
  const apiUrl = broadcastConfig.apiUrl.replace(/\/$/, "");
3967
- const token = process.env.NODE_ENV === "production" ? broadcastConfig.tokens.production : broadcastConfig.tokens.development;
3443
+ const token = broadcastConfig.token;
3968
3444
  let page = 1;
3969
3445
  let hasMore = true;
3970
3446
  while (hasMore) {
@@ -4044,216 +3520,6 @@ var createUnsubscribeSyncJob = (pluginConfig) => {
4044
3520
  };
4045
3521
  };
4046
3522
 
4047
- // src/collections/Channels.ts
4048
- var createChannelsCollection = (pluginConfig) => {
4049
- const hasProviders = !!(pluginConfig.providers?.broadcast || pluginConfig.providers?.resend);
4050
- return {
4051
- slug: "channels",
4052
- labels: {
4053
- singular: "Channel",
4054
- plural: "Channels"
4055
- },
4056
- admin: {
4057
- useAsTitle: "name",
4058
- description: "Newsletter channels/publications that can send broadcasts",
4059
- defaultColumns: ["name", "fromEmail", "subscriberCount", "active"]
4060
- },
4061
- fields: [
4062
- {
4063
- name: "name",
4064
- type: "text",
4065
- required: true,
4066
- admin: {
4067
- description: "The name of this newsletter channel"
4068
- }
4069
- },
4070
- {
4071
- name: "description",
4072
- type: "textarea",
4073
- admin: {
4074
- description: "A brief description of what this channel is about"
4075
- }
4076
- },
4077
- {
4078
- name: "fromName",
4079
- type: "text",
4080
- required: true,
4081
- admin: {
4082
- description: "The sender name that appears in emails"
4083
- }
4084
- },
4085
- {
4086
- name: "fromEmail",
4087
- type: "email",
4088
- required: true,
4089
- admin: {
4090
- description: "The sender email address"
4091
- }
4092
- },
4093
- {
4094
- name: "replyTo",
4095
- type: "email",
4096
- admin: {
4097
- description: "Reply-to email address (optional)"
4098
- }
4099
- },
4100
- {
4101
- name: "providerType",
4102
- type: "select",
4103
- required: true,
4104
- options: [
4105
- ...pluginConfig.providers?.broadcast ? [{ label: "Broadcast", value: "broadcast" }] : [],
4106
- ...pluginConfig.providers?.resend ? [{ label: "Resend", value: "resend" }] : []
4107
- ],
4108
- admin: {
4109
- description: "Which email provider manages this channel"
4110
- }
4111
- },
4112
- {
4113
- name: "providerId",
4114
- type: "text",
4115
- admin: {
4116
- readOnly: true,
4117
- description: "ID from the email provider",
4118
- condition: (data) => hasProviders && data?.providerId
4119
- }
4120
- },
4121
- {
4122
- name: "subscriberCount",
4123
- type: "number",
4124
- admin: {
4125
- readOnly: true,
4126
- description: "Number of active subscribers"
4127
- },
4128
- defaultValue: 0
4129
- },
4130
- {
4131
- name: "active",
4132
- type: "checkbox",
4133
- defaultValue: true,
4134
- admin: {
4135
- description: "Whether this channel is currently active"
4136
- }
4137
- },
4138
- {
4139
- name: "settings",
4140
- type: "group",
4141
- fields: [
4142
- {
4143
- name: "defaultTrackOpens",
4144
- type: "checkbox",
4145
- defaultValue: true,
4146
- admin: {
4147
- description: "Track email opens by default for broadcasts in this channel"
4148
- }
4149
- },
4150
- {
4151
- name: "defaultTrackClicks",
4152
- type: "checkbox",
4153
- defaultValue: true,
4154
- admin: {
4155
- description: "Track link clicks by default for broadcasts in this channel"
4156
- }
4157
- },
4158
- {
4159
- name: "requireDoubleOptIn",
4160
- type: "checkbox",
4161
- defaultValue: false,
4162
- admin: {
4163
- description: "Require double opt-in for new subscribers"
4164
- }
4165
- }
4166
- ]
4167
- }
4168
- ],
4169
- hooks: {
4170
- // Sync with provider on create
4171
- afterChange: [
4172
- async ({ doc, operation, req }) => {
4173
- if (!hasProviders || operation !== "create") return doc;
4174
- try {
4175
- const provider = await getProvider(doc.providerType, pluginConfig);
4176
- if (!provider) return doc;
4177
- const providerChannel = await provider.createChannel({
4178
- name: doc.name,
4179
- description: doc.description,
4180
- fromName: doc.fromName,
4181
- fromEmail: doc.fromEmail,
4182
- replyTo: doc.replyTo
4183
- });
4184
- await req.payload.update({
4185
- collection: "channels",
4186
- id: doc.id,
4187
- data: {
4188
- providerId: providerChannel.id,
4189
- subscriberCount: providerChannel.subscriberCount || 0
4190
- },
4191
- req
4192
- });
4193
- return {
4194
- ...doc,
4195
- providerId: providerChannel.id,
4196
- subscriberCount: providerChannel.subscriberCount || 0
4197
- };
4198
- } catch (error) {
4199
- req.payload.logger.error("Failed to create channel in provider:", error);
4200
- return doc;
4201
- }
4202
- }
4203
- ],
4204
- // Sync updates with provider
4205
- beforeChange: [
4206
- async ({ data, originalDoc, operation, req }) => {
4207
- if (!hasProviders || !originalDoc?.providerId || operation !== "update") return data;
4208
- try {
4209
- const provider = await getProvider(originalDoc.providerType, pluginConfig);
4210
- if (!provider) return data;
4211
- const updates = {};
4212
- if (data.name !== originalDoc.name) updates.name = data.name;
4213
- if (data.description !== originalDoc.description) updates.description = data.description;
4214
- if (data.fromName !== originalDoc.fromName) updates.fromName = data.fromName;
4215
- if (data.fromEmail !== originalDoc.fromEmail) updates.fromEmail = data.fromEmail;
4216
- if (data.replyTo !== originalDoc.replyTo) updates.replyTo = data.replyTo;
4217
- if (Object.keys(updates).length > 0) {
4218
- await provider.updateChannel(originalDoc.providerId, updates);
4219
- }
4220
- } catch (error) {
4221
- req.payload.logger.error("Failed to update channel in provider:", error);
4222
- }
4223
- return data;
4224
- }
4225
- ],
4226
- // Handle deletion
4227
- afterDelete: [
4228
- async ({ doc, req }) => {
4229
- if (!hasProviders || !doc?.providerId) return doc;
4230
- try {
4231
- const provider = await getProvider(doc.providerType, pluginConfig);
4232
- if (!provider) return doc;
4233
- await provider.deleteChannel(doc.providerId);
4234
- } catch (error) {
4235
- req.payload.logger.error("Failed to delete channel from provider:", error);
4236
- }
4237
- return doc;
4238
- }
4239
- ]
4240
- }
4241
- };
4242
- };
4243
- async function getProvider(providerType, config) {
4244
- if (providerType === "broadcast") {
4245
- const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
4246
- const providerConfig = config.providers?.broadcast;
4247
- return providerConfig ? new BroadcastApiProvider2(providerConfig) : null;
4248
- }
4249
- if (providerType === "resend") {
4250
- const { ResendBroadcastProvider: ResendBroadcastProvider2 } = await Promise.resolve().then(() => (init_broadcast3(), broadcast_exports2));
4251
- const providerConfig = config.providers?.resend;
4252
- return providerConfig ? new ResendBroadcastProvider2(providerConfig) : null;
4253
- }
4254
- return null;
4255
- }
4256
-
4257
3523
  // src/collections/Broadcasts.ts
4258
3524
  init_types();
4259
3525
 
@@ -4317,18 +3583,9 @@ var createBroadcastsCollection = (pluginConfig) => {
4317
3583
  admin: {
4318
3584
  useAsTitle: "name",
4319
3585
  description: "Individual email campaigns sent to subscribers",
4320
- defaultColumns: ["name", "subject", "status", "channel", "sentAt", "actions"]
3586
+ defaultColumns: ["name", "subject", "status", "sentAt", "actions"]
4321
3587
  },
4322
3588
  fields: [
4323
- {
4324
- name: "channel",
4325
- type: "relationship",
4326
- relationTo: "channels",
4327
- required: true,
4328
- admin: {
4329
- description: "The channel this broadcast belongs to"
4330
- }
4331
- },
4332
3589
  {
4333
3590
  name: "name",
4334
3591
  type: "text",
@@ -4540,23 +3797,22 @@ var createBroadcastsCollection = (pluginConfig) => {
4540
3797
  async ({ doc, operation, req }) => {
4541
3798
  if (!hasProviders || operation !== "create") return doc;
4542
3799
  try {
4543
- const channel = await req.payload.findByID({
4544
- collection: "channels",
4545
- id: typeof doc.channel === "string" ? doc.channel : doc.channel.id,
4546
- req
4547
- });
4548
- const provider = await getProvider2(channel.providerType, pluginConfig);
4549
- if (!provider) return doc;
3800
+ const providerConfig = pluginConfig.providers?.broadcast;
3801
+ if (!providerConfig) {
3802
+ req.payload.logger.error("Broadcast provider not configured");
3803
+ return doc;
3804
+ }
3805
+ const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
3806
+ const provider = new BroadcastApiProvider2(providerConfig);
4550
3807
  const htmlContent = await convertToEmailSafeHtml(doc.content);
4551
3808
  const providerBroadcast = await provider.create({
4552
- channelId: channel.providerId || channel.id,
4553
3809
  name: doc.name,
4554
3810
  subject: doc.subject,
4555
3811
  preheader: doc.preheader,
4556
3812
  content: htmlContent,
4557
3813
  trackOpens: doc.settings?.trackOpens,
4558
3814
  trackClicks: doc.settings?.trackClicks,
4559
- replyTo: doc.settings?.replyTo,
3815
+ replyTo: doc.settings?.replyTo || providerConfig.replyTo,
4560
3816
  audienceIds: doc.audienceIds?.map((a) => a.audienceId)
4561
3817
  });
4562
3818
  await req.payload.update({
@@ -4584,14 +3840,13 @@ var createBroadcastsCollection = (pluginConfig) => {
4584
3840
  async ({ data, originalDoc, operation, req }) => {
4585
3841
  if (!hasProviders || !originalDoc?.providerId || operation !== "update") return data;
4586
3842
  try {
4587
- const channelId = data.channel || originalDoc.channel;
4588
- const channel = await req.payload.findByID({
4589
- collection: "channels",
4590
- id: typeof channelId === "string" ? channelId : channelId.id,
4591
- req
4592
- });
4593
- const provider = await getProvider2(channel.providerType, pluginConfig);
4594
- if (!provider) return data;
3843
+ const providerConfig = pluginConfig.providers?.broadcast;
3844
+ if (!providerConfig) {
3845
+ req.payload.logger.error("Broadcast provider not configured");
3846
+ return data;
3847
+ }
3848
+ const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
3849
+ const provider = new BroadcastApiProvider2(providerConfig);
4595
3850
  const capabilities = provider.getCapabilities();
4596
3851
  if (!capabilities.editableStatuses.includes(originalDoc.status)) {
4597
3852
  return data;
@@ -4610,7 +3865,7 @@ var createBroadcastsCollection = (pluginConfig) => {
4610
3865
  updates.trackClicks = data.settings.trackClicks;
4611
3866
  }
4612
3867
  if (data.settings?.replyTo !== originalDoc.settings?.replyTo) {
4613
- updates.replyTo = data.settings.replyTo;
3868
+ updates.replyTo = data.settings.replyTo || providerConfig.replyTo;
4614
3869
  }
4615
3870
  if (JSON.stringify(data.audienceIds) !== JSON.stringify(originalDoc.audienceIds)) {
4616
3871
  updates.audienceIds = data.audienceIds?.map((a) => a.audienceId);
@@ -4629,13 +3884,13 @@ var createBroadcastsCollection = (pluginConfig) => {
4629
3884
  async ({ doc, req }) => {
4630
3885
  if (!hasProviders || !doc?.providerId) return doc;
4631
3886
  try {
4632
- const channel = await req.payload.findByID({
4633
- collection: "channels",
4634
- id: typeof doc.channel === "string" ? doc.channel : doc.channel.id,
4635
- req
4636
- });
4637
- const provider = await getProvider2(channel.providerType, pluginConfig);
4638
- if (!provider) return doc;
3887
+ const providerConfig = pluginConfig.providers?.broadcast;
3888
+ if (!providerConfig) {
3889
+ req.payload.logger.error("Broadcast provider not configured");
3890
+ return doc;
3891
+ }
3892
+ const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
3893
+ const provider = new BroadcastApiProvider2(providerConfig);
4639
3894
  const capabilities = provider.getCapabilities();
4640
3895
  if (capabilities.editableStatuses.includes(doc.status)) {
4641
3896
  await provider.delete(doc.providerId);
@@ -4649,23 +3904,223 @@ var createBroadcastsCollection = (pluginConfig) => {
4649
3904
  }
4650
3905
  };
4651
3906
  };
4652
- async function getProvider2(providerType, config) {
4653
- if (providerType === "broadcast") {
4654
- const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
4655
- const providerConfig = config.providers?.broadcast;
4656
- return providerConfig ? new BroadcastApiProvider2(providerConfig) : null;
4657
- }
4658
- if (providerType === "resend") {
4659
- const { ResendBroadcastProvider: ResendBroadcastProvider2 } = await Promise.resolve().then(() => (init_broadcast3(), broadcast_exports2));
4660
- const providerConfig = config.providers?.resend;
4661
- return providerConfig ? new ResendBroadcastProvider2(providerConfig) : null;
4662
- }
4663
- return null;
4664
- }
4665
3907
 
4666
3908
  // src/index.ts
4667
3909
  init_broadcast2();
4668
- init_broadcast3();
3910
+
3911
+ // src/providers/resend/broadcast.ts
3912
+ var import_resend3 = require("resend");
3913
+ init_types();
3914
+ var ResendBroadcastProvider = class extends BaseBroadcastProvider {
3915
+ constructor(config) {
3916
+ super(config);
3917
+ this.name = "resend";
3918
+ this.client = new import_resend3.Resend(config.apiKey);
3919
+ this.audienceIds = config.audienceIds || {};
3920
+ this.isDevelopment = process.env.NODE_ENV !== "production";
3921
+ if (!config.apiKey) {
3922
+ throw new BroadcastProviderError(
3923
+ "Resend API key is required",
3924
+ "CONFIGURATION_ERROR" /* CONFIGURATION_ERROR */,
3925
+ this.name
3926
+ );
3927
+ }
3928
+ }
3929
+ // Broadcast Management Methods
3930
+ async list(_options) {
3931
+ throw new BroadcastProviderError(
3932
+ "Listing broadcasts is not currently supported by Resend API. This feature may be available in the dashboard only.",
3933
+ "NOT_SUPPORTED" /* NOT_SUPPORTED */,
3934
+ this.name
3935
+ );
3936
+ }
3937
+ async get(_id) {
3938
+ throw new BroadcastProviderError(
3939
+ "Getting individual broadcasts is not currently supported by Resend API. This feature may be available in the dashboard only.",
3940
+ "NOT_SUPPORTED" /* NOT_SUPPORTED */,
3941
+ this.name
3942
+ );
3943
+ }
3944
+ async create(data) {
3945
+ try {
3946
+ this.validateRequiredFields(data, ["name", "subject", "content"]);
3947
+ const locale = "en";
3948
+ const audienceConfig = this.audienceIds?.[locale];
3949
+ const audienceId = this.isDevelopment ? audienceConfig?.development || audienceConfig?.production : audienceConfig?.production || audienceConfig?.development;
3950
+ if (!audienceId && data.audienceIds?.length) {
3951
+ }
3952
+ const resendClient = this.client;
3953
+ if (resendClient.broadcasts?.create) {
3954
+ const broadcast = await resendClient.broadcasts.create({
3955
+ name: data.name,
3956
+ subject: data.subject,
3957
+ from: `${this.config.fromName || "Newsletter"} <${this.config.fromEmail || "noreply@example.com"}>`,
3958
+ reply_to: data.replyTo,
3959
+ audience_id: audienceId || data.audienceIds?.[0],
3960
+ content: {
3961
+ html: data.content
3962
+ // TODO: Handle plain text version
3963
+ }
3964
+ });
3965
+ return this.transformResendToBroadcast(broadcast);
3966
+ }
3967
+ throw new BroadcastProviderError(
3968
+ "Creating broadcasts via API is not currently supported. Please check if Resend has released their Broadcasts API.",
3969
+ "NOT_SUPPORTED" /* NOT_SUPPORTED */,
3970
+ this.name
3971
+ );
3972
+ } catch (error) {
3973
+ if (error instanceof BroadcastProviderError) throw error;
3974
+ throw new BroadcastProviderError(
3975
+ `Failed to create broadcast: ${error instanceof Error ? error.message : "Unknown error"}`,
3976
+ "PROVIDER_ERROR" /* PROVIDER_ERROR */,
3977
+ this.name,
3978
+ error
3979
+ );
3980
+ }
3981
+ }
3982
+ async update(_id, _data) {
3983
+ throw new BroadcastProviderError(
3984
+ "Updating broadcasts is not currently supported by Resend API. Note: Resend broadcasts can only be edited where they were created.",
3985
+ "NOT_SUPPORTED" /* NOT_SUPPORTED */,
3986
+ this.name
3987
+ );
3988
+ }
3989
+ async delete(_id) {
3990
+ throw new BroadcastProviderError(
3991
+ "Deleting broadcasts is not currently supported by Resend API.",
3992
+ "NOT_SUPPORTED" /* NOT_SUPPORTED */,
3993
+ this.name
3994
+ );
3995
+ }
3996
+ async send(id, options) {
3997
+ try {
3998
+ const resendClient = this.client;
3999
+ if (resendClient.broadcasts?.send) {
4000
+ await resendClient.broadcasts.send(id, {
4001
+ audience_id: options?.audienceIds?.[0]
4002
+ // TODO: Handle test mode if supported
4003
+ });
4004
+ return {
4005
+ id,
4006
+ name: "Unknown",
4007
+ subject: "Unknown",
4008
+ content: "",
4009
+ status: "sending" /* SENDING */,
4010
+ trackOpens: true,
4011
+ trackClicks: true,
4012
+ createdAt: /* @__PURE__ */ new Date(),
4013
+ updatedAt: /* @__PURE__ */ new Date(),
4014
+ providerType: "resend"
4015
+ };
4016
+ }
4017
+ throw new BroadcastProviderError(
4018
+ "Sending broadcasts via API is not currently supported. Please check if Resend has released their Broadcasts API.",
4019
+ "NOT_SUPPORTED" /* NOT_SUPPORTED */,
4020
+ this.name
4021
+ );
4022
+ } catch (error) {
4023
+ if (error instanceof BroadcastProviderError) throw error;
4024
+ throw new BroadcastProviderError(
4025
+ `Failed to send broadcast: ${error instanceof Error ? error.message : "Unknown error"}`,
4026
+ "PROVIDER_ERROR" /* PROVIDER_ERROR */,
4027
+ this.name,
4028
+ error
4029
+ );
4030
+ }
4031
+ }
4032
+ async schedule(_id, _scheduledAt) {
4033
+ throw new BroadcastProviderError(
4034
+ "Scheduling broadcasts is not supported by Resend",
4035
+ "NOT_SUPPORTED" /* NOT_SUPPORTED */,
4036
+ this.name
4037
+ );
4038
+ }
4039
+ async getAnalytics(_id) {
4040
+ throw new BroadcastProviderError(
4041
+ "Getting broadcast analytics via API is not currently supported. Analytics may be available in the Resend dashboard.",
4042
+ "NOT_SUPPORTED" /* NOT_SUPPORTED */,
4043
+ this.name
4044
+ );
4045
+ }
4046
+ getCapabilities() {
4047
+ return {
4048
+ supportsScheduling: false,
4049
+ // Not documented
4050
+ supportsSegmentation: true,
4051
+ // Via Audiences
4052
+ supportsAnalytics: true,
4053
+ // Available in dashboard, API unclear
4054
+ supportsABTesting: false,
4055
+ supportsTemplates: false,
4056
+ // Not clear from docs
4057
+ supportsPersonalization: true,
4058
+ // Via merge tags
4059
+ supportsMultipleChannels: false,
4060
+ supportsChannelSegmentation: false,
4061
+ editableStatuses: [],
4062
+ // Unclear which statuses can be edited
4063
+ supportedContentTypes: ["html"]
4064
+ // React components via SDK
4065
+ };
4066
+ }
4067
+ async validateConfiguration() {
4068
+ try {
4069
+ const resendClient = this.client;
4070
+ if (resendClient.audiences?.list) {
4071
+ await resendClient.audiences.list({ limit: 1 });
4072
+ return true;
4073
+ }
4074
+ await this.client.emails.send({
4075
+ from: "onboarding@resend.dev",
4076
+ to: "delivered@resend.dev",
4077
+ subject: "Configuration Test",
4078
+ html: "<p>Testing configuration</p>"
4079
+ });
4080
+ return true;
4081
+ } catch {
4082
+ return false;
4083
+ }
4084
+ }
4085
+ /**
4086
+ * Transform Resend broadcast to our Broadcast type
4087
+ * NOTE: This is speculative based on what the API might return
4088
+ */
4089
+ transformResendToBroadcast(broadcast) {
4090
+ return {
4091
+ id: broadcast.id,
4092
+ name: broadcast.name || "Untitled",
4093
+ subject: broadcast.subject,
4094
+ preheader: broadcast.preheader,
4095
+ content: broadcast.content?.html || broadcast.html || "",
4096
+ status: this.mapResendStatus(broadcast.status),
4097
+ trackOpens: true,
4098
+ // Resend tracks by default
4099
+ trackClicks: true,
4100
+ // Resend tracks by default
4101
+ replyTo: broadcast.reply_to,
4102
+ recipientCount: broadcast.recipient_count,
4103
+ sentAt: broadcast.sent_at ? new Date(broadcast.sent_at) : void 0,
4104
+ scheduledAt: broadcast.scheduled_at ? new Date(broadcast.scheduled_at) : void 0,
4105
+ createdAt: new Date(broadcast.created_at || Date.now()),
4106
+ updatedAt: new Date(broadcast.updated_at || Date.now()),
4107
+ providerData: { broadcast },
4108
+ providerId: broadcast.id,
4109
+ providerType: "resend"
4110
+ };
4111
+ }
4112
+ mapResendStatus(status) {
4113
+ if (!status) return "draft" /* DRAFT */;
4114
+ const statusMap = {
4115
+ "draft": "draft" /* DRAFT */,
4116
+ "scheduled": "scheduled" /* SCHEDULED */,
4117
+ "sending": "sending" /* SENDING */,
4118
+ "sent": "sent" /* SENT */,
4119
+ "failed": "failed" /* FAILED */
4120
+ };
4121
+ return statusMap[status.toLowerCase()] || "draft" /* DRAFT */;
4122
+ }
4123
+ };
4669
4124
 
4670
4125
  // src/utilities/session.ts
4671
4126
  var import_jsonwebtoken2 = __toESM(require("jsonwebtoken"), 1);
@@ -4765,9 +4220,8 @@ var newsletterPlugin = (pluginConfig) => (incomingConfig) => {
4765
4220
  const settingsGlobal = createNewsletterSettingsGlobal(config);
4766
4221
  let collections = [...incomingConfig.collections || [], subscribersCollection];
4767
4222
  if (config.features?.newsletterManagement?.enabled) {
4768
- const channelsCollection = createChannelsCollection(config);
4769
4223
  const broadcastsCollection = createBroadcastsCollection(config);
4770
- collections.push(channelsCollection, broadcastsCollection);
4224
+ collections.push(broadcastsCollection);
4771
4225
  }
4772
4226
  if (config.features?.newsletterScheduling?.enabled) {
4773
4227
  const targetCollections = config.features.newsletterScheduling.collections || "articles";
@@ -4848,10 +4302,10 @@ var newsletterPlugin = (pluginConfig) => (incomingConfig) => {
4848
4302
  } : config.providers.resend,
4849
4303
  broadcast: settings.provider === "broadcast" ? {
4850
4304
  apiUrl: settings.broadcastSettings?.apiUrl || config.providers.broadcast?.apiUrl || "",
4851
- tokens: {
4852
- production: settings.broadcastSettings?.productionToken || config.providers.broadcast?.tokens.production,
4853
- development: settings.broadcastSettings?.developmentToken || config.providers.broadcast?.tokens.development
4854
- }
4305
+ token: settings.broadcastSettings?.token || config.providers.broadcast?.token || "",
4306
+ fromAddress: settings.fromAddress || config.providers.broadcast?.fromAddress,
4307
+ fromName: settings.fromName || config.providers.broadcast?.fromName,
4308
+ replyTo: settings.replyTo || config.providers.broadcast?.replyTo
4855
4309
  } : config.providers.broadcast
4856
4310
  };
4857
4311
  } else {