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.js CHANGED
@@ -43,13 +43,6 @@ var init_broadcast = __esm({
43
43
  }
44
44
  });
45
45
 
46
- // src/types/channel.ts
47
- var init_channel = __esm({
48
- "src/types/channel.ts"() {
49
- "use strict";
50
- }
51
- });
52
-
53
46
  // src/types/providers.ts
54
47
  var BaseBroadcastProvider;
55
48
  var init_providers = __esm({
@@ -154,7 +147,6 @@ var init_types = __esm({
154
147
  "src/types/index.ts"() {
155
148
  "use strict";
156
149
  init_broadcast();
157
- init_channel();
158
150
  init_providers();
159
151
  init_newsletter();
160
152
  }
@@ -175,8 +167,7 @@ var init_broadcast2 = __esm({
175
167
  super(config);
176
168
  this.name = "broadcast";
177
169
  this.apiUrl = config.apiUrl.replace(/\/$/, "");
178
- this.isDevelopment = process.env.NODE_ENV !== "production";
179
- this.token = this.isDevelopment ? config.tokens.development || config.tokens.production || "" : config.tokens.production || config.tokens.development || "";
170
+ this.token = config.token;
180
171
  if (!this.token) {
181
172
  throw new BroadcastProviderError(
182
173
  "Broadcast API token is required",
@@ -185,158 +176,6 @@ var init_broadcast2 = __esm({
185
176
  );
186
177
  }
187
178
  }
188
- // Channel Management Methods
189
- async listChannels(options) {
190
- try {
191
- const params = new URLSearchParams();
192
- if (options?.limit) params.append("limit", options.limit.toString());
193
- if (options?.offset) params.append("offset", options.offset.toString());
194
- const response = await fetch(`${this.apiUrl}/api/v1/channels?${params}`, {
195
- method: "GET",
196
- headers: {
197
- "Authorization": `Bearer ${this.token}`,
198
- "Content-Type": "application/json"
199
- }
200
- });
201
- if (!response.ok) {
202
- const error = await response.text();
203
- throw new Error(`Broadcast API error: ${response.status} - ${error}`);
204
- }
205
- const data = await response.json();
206
- const channels = data.data.map((channel) => this.transformChannelFromApi(channel));
207
- return {
208
- channels,
209
- total: data.total || channels.length,
210
- limit: options?.limit || 20,
211
- offset: options?.offset || 0
212
- };
213
- } catch (error) {
214
- throw new BroadcastProviderError(
215
- `Failed to list channels: ${error instanceof Error ? error.message : "Unknown error"}`,
216
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
217
- this.name,
218
- error
219
- );
220
- }
221
- }
222
- async getChannel(id) {
223
- try {
224
- const response = await fetch(`${this.apiUrl}/api/v1/channels/${id}`, {
225
- method: "GET",
226
- headers: {
227
- "Authorization": `Bearer ${this.token}`,
228
- "Content-Type": "application/json"
229
- }
230
- });
231
- if (!response.ok) {
232
- if (response.status === 404) {
233
- throw new BroadcastProviderError(
234
- `Channel not found: ${id}`,
235
- "CHANNEL_NOT_FOUND" /* CHANNEL_NOT_FOUND */,
236
- this.name
237
- );
238
- }
239
- const error = await response.text();
240
- throw new Error(`Broadcast API error: ${response.status} - ${error}`);
241
- }
242
- const channel = await response.json();
243
- return this.transformChannelFromApi(channel);
244
- } catch (error) {
245
- if (error instanceof BroadcastProviderError) throw error;
246
- throw new BroadcastProviderError(
247
- `Failed to get channel: ${error instanceof Error ? error.message : "Unknown error"}`,
248
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
249
- this.name,
250
- error
251
- );
252
- }
253
- }
254
- async createChannel(data) {
255
- try {
256
- const response = await fetch(`${this.apiUrl}/api/v1/channels`, {
257
- method: "POST",
258
- headers: {
259
- "Authorization": `Bearer ${this.token}`,
260
- "Content-Type": "application/json"
261
- },
262
- body: JSON.stringify({
263
- channel: {
264
- name: data.name,
265
- description: data.description,
266
- from: data.fromName,
267
- address: data.fromEmail,
268
- reply_to: data.replyTo
269
- }
270
- })
271
- });
272
- if (!response.ok) {
273
- const error = await response.text();
274
- throw new Error(`Broadcast API error: ${response.status} - ${error}`);
275
- }
276
- const channel = await response.json();
277
- return this.transformChannelFromApi(channel);
278
- } catch (error) {
279
- throw new BroadcastProviderError(
280
- `Failed to create channel: ${error instanceof Error ? error.message : "Unknown error"}`,
281
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
282
- this.name,
283
- error
284
- );
285
- }
286
- }
287
- async updateChannel(id, data) {
288
- try {
289
- const updateData = { channel: {} };
290
- if (data.name !== void 0) updateData.channel.name = data.name;
291
- if (data.description !== void 0) updateData.channel.description = data.description;
292
- if (data.fromName !== void 0) updateData.channel.from = data.fromName;
293
- if (data.fromEmail !== void 0) updateData.channel.address = data.fromEmail;
294
- if (data.replyTo !== void 0) updateData.channel.reply_to = data.replyTo;
295
- const response = await fetch(`${this.apiUrl}/api/v1/channels/${id}`, {
296
- method: "PATCH",
297
- headers: {
298
- "Authorization": `Bearer ${this.token}`,
299
- "Content-Type": "application/json"
300
- },
301
- body: JSON.stringify(updateData)
302
- });
303
- if (!response.ok) {
304
- const error = await response.text();
305
- throw new Error(`Broadcast API error: ${response.status} - ${error}`);
306
- }
307
- const channel = await response.json();
308
- return this.transformChannelFromApi(channel);
309
- } catch (error) {
310
- throw new BroadcastProviderError(
311
- `Failed to update channel: ${error instanceof Error ? error.message : "Unknown error"}`,
312
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
313
- this.name,
314
- error
315
- );
316
- }
317
- }
318
- async deleteChannel(id) {
319
- try {
320
- const response = await fetch(`${this.apiUrl}/api/v1/channels/${id}`, {
321
- method: "DELETE",
322
- headers: {
323
- "Authorization": `Bearer ${this.token}`,
324
- "Content-Type": "application/json"
325
- }
326
- });
327
- if (!response.ok) {
328
- const error = await response.text();
329
- throw new Error(`Broadcast API error: ${response.status} - ${error}`);
330
- }
331
- } catch (error) {
332
- throw new BroadcastProviderError(
333
- `Failed to delete channel: ${error instanceof Error ? error.message : "Unknown error"}`,
334
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
335
- this.name,
336
- error
337
- );
338
- }
339
- }
340
179
  // Broadcast Management Methods
341
180
  async list(options) {
342
181
  try {
@@ -400,7 +239,7 @@ var init_broadcast2 = __esm({
400
239
  }
401
240
  async create(data) {
402
241
  try {
403
- this.validateRequiredFields(data, ["channelId", "name", "subject", "content"]);
242
+ this.validateRequiredFields(data, ["name", "subject", "content"]);
404
243
  const response = await fetch(`${this.apiUrl}/api/v1/broadcasts`, {
405
244
  method: "POST",
406
245
  headers: {
@@ -409,8 +248,6 @@ var init_broadcast2 = __esm({
409
248
  },
410
249
  body: JSON.stringify({
411
250
  broadcast: {
412
- channel_id: parseInt(data.channelId),
413
- // Broadcast API uses numeric IDs
414
251
  name: data.name,
415
252
  subject: data.subject,
416
253
  preheader: data.preheader,
@@ -627,8 +464,8 @@ var init_broadcast2 = __esm({
627
464
  supportsABTesting: false,
628
465
  supportsTemplates: false,
629
466
  supportsPersonalization: true,
630
- supportsMultipleChannels: true,
631
- supportsChannelSegmentation: true,
467
+ supportsMultipleChannels: false,
468
+ supportsChannelSegmentation: false,
632
469
  editableStatuses: ["draft" /* DRAFT */, "scheduled" /* SCHEDULED */],
633
470
  supportedContentTypes: ["html", "text"]
634
471
  };
@@ -644,406 +481,37 @@ var init_broadcast2 = __esm({
644
481
  transformBroadcastFromApi(broadcast) {
645
482
  return {
646
483
  id: broadcast.id.toString(),
647
- channelId: "1",
648
- // TODO: Get from API response when available
649
484
  name: broadcast.name,
650
485
  subject: broadcast.subject,
651
486
  preheader: broadcast.preheader,
652
487
  content: broadcast.body,
653
488
  status: this.mapBroadcastStatus(broadcast.status),
654
- trackOpens: broadcast.track_opens,
655
- trackClicks: broadcast.track_clicks,
656
- replyTo: broadcast.reply_to,
657
- recipientCount: broadcast.total_recipients,
658
- sentAt: broadcast.sent_at ? new Date(broadcast.sent_at) : void 0,
659
- scheduledAt: broadcast.scheduled_send_at ? new Date(broadcast.scheduled_send_at) : void 0,
660
- createdAt: new Date(broadcast.created_at),
661
- updatedAt: new Date(broadcast.updated_at),
662
- providerData: { broadcast },
663
- providerId: broadcast.id.toString(),
664
- providerType: "broadcast"
665
- };
666
- }
667
- transformChannelFromApi(channel) {
668
- return {
669
- id: channel.id.toString(),
670
- name: channel.name,
671
- description: channel.description,
672
- fromName: channel.from,
673
- fromEmail: channel.address,
674
- replyTo: channel.reply_to,
675
- providerId: channel.id.toString(),
676
- providerType: "broadcast",
677
- subscriberCount: channel.total_active_subscribers,
678
- active: true,
679
- // Broadcast API doesn't have an active field
680
- createdAt: new Date(channel.created_at),
681
- updatedAt: new Date(channel.updated_at)
682
- };
683
- }
684
- mapBroadcastStatus(status) {
685
- const statusMap = {
686
- "draft": "draft" /* DRAFT */,
687
- "scheduled": "scheduled" /* SCHEDULED */,
688
- "queueing": "sending" /* SENDING */,
689
- "sending": "sending" /* SENDING */,
690
- "sent": "sent" /* SENT */,
691
- "failed": "failed" /* FAILED */,
692
- "partial_failure": "failed" /* FAILED */,
693
- "paused": "paused" /* PAUSED */,
694
- "aborted": "canceled" /* CANCELED */
695
- };
696
- return statusMap[status] || "draft" /* DRAFT */;
697
- }
698
- };
699
- }
700
- });
701
-
702
- // src/providers/resend/broadcast.ts
703
- var broadcast_exports2 = {};
704
- __export(broadcast_exports2, {
705
- ResendBroadcastProvider: () => ResendBroadcastProvider
706
- });
707
- import { Resend as Resend2 } from "resend";
708
- var ResendBroadcastProvider;
709
- var init_broadcast3 = __esm({
710
- "src/providers/resend/broadcast.ts"() {
711
- "use strict";
712
- init_types();
713
- ResendBroadcastProvider = class extends BaseBroadcastProvider {
714
- constructor(config) {
715
- super(config);
716
- this.name = "resend";
717
- this.client = new Resend2(config.apiKey);
718
- this.audienceIds = config.audienceIds || {};
719
- this.isDevelopment = process.env.NODE_ENV !== "production";
720
- if (!config.apiKey) {
721
- throw new BroadcastProviderError(
722
- "Resend API key is required",
723
- "CONFIGURATION_ERROR" /* CONFIGURATION_ERROR */,
724
- this.name
725
- );
726
- }
727
- }
728
- // Channel Management Methods (map to Resend Audiences)
729
- async listChannels(options) {
730
- try {
731
- const response = await this.client.audiences.list();
732
- const channels = response.data?.data?.map((audience) => ({
733
- id: audience.id,
734
- name: audience.name,
735
- description: void 0,
736
- // Resend doesn't have description
737
- fromName: this.config.fromName || "",
738
- fromEmail: this.config.fromEmail || "",
739
- replyTo: this.config.replyTo,
740
- providerId: audience.id,
741
- providerType: "resend",
742
- subscriberCount: void 0,
743
- // Not available in list API
744
- active: true,
745
- createdAt: new Date(audience.created_at),
746
- updatedAt: new Date(audience.created_at)
747
- // No updated_at in Resend
748
- })) || [];
749
- return {
750
- channels,
751
- total: channels.length,
752
- limit: options?.limit || 100,
753
- offset: options?.offset || 0
754
- };
755
- } catch (error) {
756
- throw new BroadcastProviderError(
757
- `Failed to list channels (audiences): ${error instanceof Error ? error.message : "Unknown error"}`,
758
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
759
- this.name,
760
- error
761
- );
762
- }
763
- }
764
- async getChannel(id) {
765
- try {
766
- const response = await this.client.audiences.get(id);
767
- if (!response.data) {
768
- throw new BroadcastProviderError(
769
- `Channel (audience) not found: ${id}`,
770
- "CHANNEL_NOT_FOUND" /* CHANNEL_NOT_FOUND */,
771
- this.name
772
- );
773
- }
774
- return {
775
- id: response.data.id,
776
- name: response.data.name,
777
- description: void 0,
778
- fromName: this.config.fromName || "",
779
- fromEmail: this.config.fromEmail || "",
780
- replyTo: this.config.replyTo,
781
- providerId: response.data.id,
782
- providerType: "resend",
783
- subscriberCount: void 0,
784
- // Not available
785
- active: true,
786
- createdAt: new Date(response.data.created_at),
787
- updatedAt: new Date(response.data.created_at)
788
- };
789
- } catch (error) {
790
- if (error instanceof BroadcastProviderError) throw error;
791
- throw new BroadcastProviderError(
792
- `Failed to get channel (audience): ${error instanceof Error ? error.message : "Unknown error"}`,
793
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
794
- this.name,
795
- error
796
- );
797
- }
798
- }
799
- async createChannel(data) {
800
- try {
801
- const response = await this.client.audiences.create({
802
- name: data.name
803
- });
804
- if (!response.data) {
805
- throw new Error("Failed to create audience");
806
- }
807
- return {
808
- id: response.data.id,
809
- name: response.data.name,
810
- description: data.description,
811
- fromName: data.fromName,
812
- fromEmail: data.fromEmail,
813
- replyTo: data.replyTo,
814
- providerId: response.data.id,
815
- providerType: "resend",
816
- subscriberCount: 0,
817
- active: true,
818
- createdAt: /* @__PURE__ */ new Date(),
819
- updatedAt: /* @__PURE__ */ new Date()
820
- };
821
- } catch (error) {
822
- throw new BroadcastProviderError(
823
- `Failed to create channel (audience): ${error instanceof Error ? error.message : "Unknown error"}`,
824
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
825
- this.name,
826
- error
827
- );
828
- }
829
- }
830
- async updateChannel(_id, _data) {
831
- throw new BroadcastProviderError(
832
- "Updating channels (audiences) is not supported by Resend API",
833
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
834
- this.name
835
- );
836
- }
837
- async deleteChannel(id) {
838
- try {
839
- await this.client.audiences.remove(id);
840
- } catch (error) {
841
- throw new BroadcastProviderError(
842
- `Failed to delete channel (audience): ${error instanceof Error ? error.message : "Unknown error"}`,
843
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
844
- this.name,
845
- error
846
- );
847
- }
848
- }
849
- // Broadcast Management Methods
850
- async list(_options) {
851
- throw new BroadcastProviderError(
852
- "Listing broadcasts is not currently supported by Resend API. This feature may be available in the dashboard only.",
853
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
854
- this.name
855
- );
856
- }
857
- async get(_id) {
858
- throw new BroadcastProviderError(
859
- "Getting individual broadcasts is not currently supported by Resend API. This feature may be available in the dashboard only.",
860
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
861
- this.name
862
- );
863
- }
864
- async create(data) {
865
- try {
866
- this.validateRequiredFields(data, ["channelId", "name", "subject", "content"]);
867
- const locale = "en";
868
- const audienceConfig = this.audienceIds?.[locale];
869
- const audienceId = this.isDevelopment ? audienceConfig?.development || audienceConfig?.production : audienceConfig?.production || audienceConfig?.development;
870
- if (!audienceId && data.audienceIds?.length) {
871
- }
872
- const resendClient = this.client;
873
- if (resendClient.broadcasts?.create) {
874
- const broadcast = await resendClient.broadcasts.create({
875
- name: data.name,
876
- subject: data.subject,
877
- from: `${this.config.fromName || "Newsletter"} <${this.config.fromEmail || "noreply@example.com"}>`,
878
- reply_to: data.replyTo,
879
- audience_id: audienceId || data.audienceIds?.[0],
880
- content: {
881
- html: data.content
882
- // TODO: Handle plain text version
883
- }
884
- });
885
- return this.transformResendToBroadcast(broadcast);
886
- }
887
- throw new BroadcastProviderError(
888
- "Creating broadcasts via API is not currently supported. Please check if Resend has released their Broadcasts API.",
889
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
890
- this.name
891
- );
892
- } catch (error) {
893
- if (error instanceof BroadcastProviderError) throw error;
894
- throw new BroadcastProviderError(
895
- `Failed to create broadcast: ${error instanceof Error ? error.message : "Unknown error"}`,
896
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
897
- this.name,
898
- error
899
- );
900
- }
901
- }
902
- async update(_id, _data) {
903
- throw new BroadcastProviderError(
904
- "Updating broadcasts is not currently supported by Resend API. Note: Resend broadcasts can only be edited where they were created.",
905
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
906
- this.name
907
- );
908
- }
909
- async delete(_id) {
910
- throw new BroadcastProviderError(
911
- "Deleting broadcasts is not currently supported by Resend API.",
912
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
913
- this.name
914
- );
915
- }
916
- async send(id, options) {
917
- try {
918
- const resendClient = this.client;
919
- if (resendClient.broadcasts?.send) {
920
- await resendClient.broadcasts.send(id, {
921
- audience_id: options?.audienceIds?.[0]
922
- // TODO: Handle test mode if supported
923
- });
924
- return {
925
- id,
926
- channelId: options?.audienceIds?.[0] || "1",
927
- name: "Unknown",
928
- subject: "Unknown",
929
- content: "",
930
- status: "sending" /* SENDING */,
931
- trackOpens: true,
932
- trackClicks: true,
933
- createdAt: /* @__PURE__ */ new Date(),
934
- updatedAt: /* @__PURE__ */ new Date(),
935
- providerType: "resend"
936
- };
937
- }
938
- throw new BroadcastProviderError(
939
- "Sending broadcasts via API is not currently supported. Please check if Resend has released their Broadcasts API.",
940
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
941
- this.name
942
- );
943
- } catch (error) {
944
- if (error instanceof BroadcastProviderError) throw error;
945
- throw new BroadcastProviderError(
946
- `Failed to send broadcast: ${error instanceof Error ? error.message : "Unknown error"}`,
947
- "PROVIDER_ERROR" /* PROVIDER_ERROR */,
948
- this.name,
949
- error
950
- );
951
- }
952
- }
953
- async schedule(_id, _scheduledAt) {
954
- throw new BroadcastProviderError(
955
- "Scheduling broadcasts is not supported by Resend",
956
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
957
- this.name
958
- );
959
- }
960
- async getAnalytics(_id) {
961
- throw new BroadcastProviderError(
962
- "Getting broadcast analytics via API is not currently supported. Analytics may be available in the Resend dashboard.",
963
- "NOT_SUPPORTED" /* NOT_SUPPORTED */,
964
- this.name
965
- );
966
- }
967
- getCapabilities() {
968
- return {
969
- supportsScheduling: false,
970
- // Not documented
971
- supportsSegmentation: true,
972
- // Via Audiences
973
- supportsAnalytics: true,
974
- // Available in dashboard, API unclear
975
- supportsABTesting: false,
976
- supportsTemplates: false,
977
- // Not clear from docs
978
- supportsPersonalization: true,
979
- // Via merge tags
980
- supportsMultipleChannels: true,
981
- // Via multiple audiences
982
- supportsChannelSegmentation: false,
983
- // Not within a single audience
984
- editableStatuses: [],
985
- // Unclear which statuses can be edited
986
- supportedContentTypes: ["html"]
987
- // React components via SDK
988
- };
989
- }
990
- async validateConfiguration() {
991
- try {
992
- const resendClient = this.client;
993
- if (resendClient.audiences?.list) {
994
- await resendClient.audiences.list({ limit: 1 });
995
- return true;
996
- }
997
- await this.client.emails.send({
998
- from: "onboarding@resend.dev",
999
- to: "delivered@resend.dev",
1000
- subject: "Configuration Test",
1001
- html: "<p>Testing configuration</p>"
1002
- });
1003
- return true;
1004
- } catch {
1005
- return false;
1006
- }
1007
- }
1008
- /**
1009
- * Transform Resend broadcast to our Broadcast type
1010
- * NOTE: This is speculative based on what the API might return
1011
- */
1012
- transformResendToBroadcast(broadcast) {
1013
- return {
1014
- id: broadcast.id,
1015
- channelId: broadcast.audience_id || "1",
1016
- // Map audience_id to channelId
1017
- name: broadcast.name || "Untitled",
1018
- subject: broadcast.subject,
1019
- preheader: broadcast.preheader,
1020
- content: broadcast.content?.html || broadcast.html || "",
1021
- status: this.mapResendStatus(broadcast.status),
1022
- trackOpens: true,
1023
- // Resend tracks by default
1024
- trackClicks: true,
1025
- // Resend tracks by default
489
+ trackOpens: broadcast.track_opens,
490
+ trackClicks: broadcast.track_clicks,
1026
491
  replyTo: broadcast.reply_to,
1027
- recipientCount: broadcast.recipient_count,
492
+ recipientCount: broadcast.total_recipients,
1028
493
  sentAt: broadcast.sent_at ? new Date(broadcast.sent_at) : void 0,
1029
- scheduledAt: broadcast.scheduled_at ? new Date(broadcast.scheduled_at) : void 0,
1030
- createdAt: new Date(broadcast.created_at || Date.now()),
1031
- updatedAt: new Date(broadcast.updated_at || Date.now()),
494
+ scheduledAt: broadcast.scheduled_send_at ? new Date(broadcast.scheduled_send_at) : void 0,
495
+ createdAt: new Date(broadcast.created_at),
496
+ updatedAt: new Date(broadcast.updated_at),
1032
497
  providerData: { broadcast },
1033
- providerId: broadcast.id,
1034
- providerType: "resend"
498
+ providerId: broadcast.id.toString(),
499
+ providerType: "broadcast"
1035
500
  };
1036
501
  }
1037
- mapResendStatus(status) {
1038
- if (!status) return "draft" /* DRAFT */;
502
+ mapBroadcastStatus(status) {
1039
503
  const statusMap = {
1040
504
  "draft": "draft" /* DRAFT */,
1041
505
  "scheduled": "scheduled" /* SCHEDULED */,
506
+ "queueing": "sending" /* SENDING */,
1042
507
  "sending": "sending" /* SENDING */,
1043
508
  "sent": "sent" /* SENT */,
1044
- "failed": "failed" /* FAILED */
509
+ "failed": "failed" /* FAILED */,
510
+ "partial_failure": "failed" /* FAILED */,
511
+ "paused": "paused" /* PAUSED */,
512
+ "aborted": "canceled" /* CANCELED */
1045
513
  };
1046
- return statusMap[status.toLowerCase()] || "draft" /* DRAFT */;
514
+ return statusMap[status] || "draft" /* DRAFT */;
1047
515
  }
1048
516
  };
1049
517
  }
@@ -1735,19 +1203,12 @@ var createNewsletterSettingsGlobal = (pluginConfig) => {
1735
1203
  }
1736
1204
  },
1737
1205
  {
1738
- name: "productionToken",
1206
+ name: "token",
1739
1207
  type: "text",
1740
- label: "Production Token",
1741
- admin: {
1742
- description: "Token for production environment"
1743
- }
1744
- },
1745
- {
1746
- name: "developmentToken",
1747
- type: "text",
1748
- label: "Development Token",
1208
+ label: "API Token",
1209
+ required: true,
1749
1210
  admin: {
1750
- description: "Token for development environment"
1211
+ description: "Your Broadcast API token"
1751
1212
  }
1752
1213
  }
1753
1214
  ]
@@ -2073,10 +1534,10 @@ var ResendProvider = class {
2073
1534
  var BroadcastProvider = class {
2074
1535
  constructor(config) {
2075
1536
  this.apiUrl = config.apiUrl.replace(/\/$/, "");
2076
- this.isDevelopment = process.env.NODE_ENV !== "production";
2077
- this.token = this.isDevelopment ? config.tokens.development || config.tokens.production || "" : config.tokens.production || config.tokens.development || "";
1537
+ this.token = config.token;
2078
1538
  this.fromAddress = config.fromAddress;
2079
1539
  this.fromName = config.fromName;
1540
+ this.replyTo = config.replyTo;
2080
1541
  }
2081
1542
  getProvider() {
2082
1543
  return "broadcast";
@@ -2099,7 +1560,7 @@ var BroadcastProvider = class {
2099
1560
  // Broadcast API expects a single recipient for transactional emails
2100
1561
  subject: params.subject,
2101
1562
  body: params.html || params.text || "",
2102
- reply_to: params.replyTo || from.email
1563
+ reply_to: params.replyTo || this.replyTo || from.email
2103
1564
  })
2104
1565
  });
2105
1566
  if (!response.ok) {
@@ -3276,8 +2737,7 @@ var createSendBroadcastEndpoint = (config, collectionSlug) => {
3276
2737
  error: auth.error
3277
2738
  }, { status: 401 });
3278
2739
  }
3279
- const broadcastProvider = req.payload.newsletterProvider;
3280
- if (!broadcastProvider) {
2740
+ if (!config.features?.newsletterManagement?.enabled) {
3281
2741
  return Response.json({
3282
2742
  success: false,
3283
2743
  error: "Broadcast management is not enabled"
@@ -3304,7 +2764,16 @@ var createSendBroadcastEndpoint = (config, collectionSlug) => {
3304
2764
  error: "Broadcast not found or not synced with provider"
3305
2765
  }, { status: 404 });
3306
2766
  }
3307
- const broadcast = await broadcastProvider.send(broadcastDoc.providerId, data);
2767
+ const providerConfig = config.providers?.broadcast;
2768
+ if (!providerConfig) {
2769
+ return Response.json({
2770
+ success: false,
2771
+ error: "Broadcast provider not configured"
2772
+ }, { status: 500 });
2773
+ }
2774
+ const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
2775
+ const provider = new BroadcastApiProvider2(providerConfig);
2776
+ const broadcast = await provider.send(broadcastDoc.providerId, data);
3308
2777
  await req.payload.update({
3309
2778
  collection: collectionSlug,
3310
2779
  id,
@@ -3352,8 +2821,7 @@ var createScheduleBroadcastEndpoint = (config, collectionSlug) => {
3352
2821
  error: auth.error
3353
2822
  }, { status: 401 });
3354
2823
  }
3355
- const broadcastProvider = req.payload.newsletterProvider;
3356
- if (!broadcastProvider) {
2824
+ if (!config.features?.newsletterManagement?.enabled) {
3357
2825
  return Response.json({
3358
2826
  success: false,
3359
2827
  error: "Broadcast management is not enabled"
@@ -3400,7 +2868,16 @@ var createScheduleBroadcastEndpoint = (config, collectionSlug) => {
3400
2868
  error: "Broadcast not found or not synced with provider"
3401
2869
  }, { status: 404 });
3402
2870
  }
3403
- const broadcast = await broadcastProvider.schedule(broadcastDoc.providerId, scheduledDate);
2871
+ const providerConfig = config.providers?.broadcast;
2872
+ if (!providerConfig) {
2873
+ return Response.json({
2874
+ success: false,
2875
+ error: "Broadcast provider not configured"
2876
+ }, { status: 500 });
2877
+ }
2878
+ const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
2879
+ const provider = new BroadcastApiProvider2(providerConfig);
2880
+ const broadcast = await provider.schedule(broadcastDoc.providerId, scheduledDate);
3404
2881
  await req.payload.update({
3405
2882
  collection: collectionSlug,
3406
2883
  id,
@@ -3679,11 +3156,6 @@ var createTestBroadcastEndpoint = (config, collectionSlug) => {
3679
3156
  error: "Broadcast not found"
3680
3157
  }, { status: 404 });
3681
3158
  }
3682
- const channel = await req.payload.findByID({
3683
- collection: "channels",
3684
- id: typeof broadcast.channel === "string" ? broadcast.channel : broadcast.channel.id,
3685
- user: auth.user
3686
- });
3687
3159
  const htmlContent = await convertToEmailSafeHtml(broadcast.content, {
3688
3160
  wrapInTemplate: true,
3689
3161
  preheader: broadcast.preheader
@@ -3695,11 +3167,15 @@ var createTestBroadcastEndpoint = (config, collectionSlug) => {
3695
3167
  error: "Email service is not configured"
3696
3168
  }, { status: 500 });
3697
3169
  }
3170
+ const providerConfig = config.providers.default === "resend" ? config.providers.resend : config.providers.broadcast;
3171
+ const fromEmail = providerConfig?.fromAddress || providerConfig?.fromEmail || "noreply@example.com";
3172
+ const fromName = providerConfig?.fromName || "Newsletter";
3173
+ const replyTo = broadcast.settings?.replyTo || providerConfig?.replyTo;
3698
3174
  await emailService.send({
3699
3175
  to: testEmail,
3700
- from: channel?.fromEmail || config.providers.resend?.fromAddress || "noreply@example.com",
3701
- fromName: channel?.fromName || config.providers.resend?.fromName || "Newsletter",
3702
- replyTo: broadcast.settings?.replyTo || channel?.replyTo,
3176
+ from: fromEmail,
3177
+ fromName,
3178
+ replyTo,
3703
3179
  subject: `[TEST] ${broadcast.subject}`,
3704
3180
  html: htmlContent,
3705
3181
  trackOpens: false,
@@ -3947,7 +3423,7 @@ var createUnsubscribeSyncJob = (pluginConfig) => {
3947
3423
  throw new Error("Broadcast configuration not found");
3948
3424
  }
3949
3425
  const apiUrl = broadcastConfig.apiUrl.replace(/\/$/, "");
3950
- const token = process.env.NODE_ENV === "production" ? broadcastConfig.tokens.production : broadcastConfig.tokens.development;
3426
+ const token = broadcastConfig.token;
3951
3427
  let page = 1;
3952
3428
  let hasMore = true;
3953
3429
  while (hasMore) {
@@ -4027,216 +3503,6 @@ var createUnsubscribeSyncJob = (pluginConfig) => {
4027
3503
  };
4028
3504
  };
4029
3505
 
4030
- // src/collections/Channels.ts
4031
- var createChannelsCollection = (pluginConfig) => {
4032
- const hasProviders = !!(pluginConfig.providers?.broadcast || pluginConfig.providers?.resend);
4033
- return {
4034
- slug: "channels",
4035
- labels: {
4036
- singular: "Channel",
4037
- plural: "Channels"
4038
- },
4039
- admin: {
4040
- useAsTitle: "name",
4041
- description: "Newsletter channels/publications that can send broadcasts",
4042
- defaultColumns: ["name", "fromEmail", "subscriberCount", "active"]
4043
- },
4044
- fields: [
4045
- {
4046
- name: "name",
4047
- type: "text",
4048
- required: true,
4049
- admin: {
4050
- description: "The name of this newsletter channel"
4051
- }
4052
- },
4053
- {
4054
- name: "description",
4055
- type: "textarea",
4056
- admin: {
4057
- description: "A brief description of what this channel is about"
4058
- }
4059
- },
4060
- {
4061
- name: "fromName",
4062
- type: "text",
4063
- required: true,
4064
- admin: {
4065
- description: "The sender name that appears in emails"
4066
- }
4067
- },
4068
- {
4069
- name: "fromEmail",
4070
- type: "email",
4071
- required: true,
4072
- admin: {
4073
- description: "The sender email address"
4074
- }
4075
- },
4076
- {
4077
- name: "replyTo",
4078
- type: "email",
4079
- admin: {
4080
- description: "Reply-to email address (optional)"
4081
- }
4082
- },
4083
- {
4084
- name: "providerType",
4085
- type: "select",
4086
- required: true,
4087
- options: [
4088
- ...pluginConfig.providers?.broadcast ? [{ label: "Broadcast", value: "broadcast" }] : [],
4089
- ...pluginConfig.providers?.resend ? [{ label: "Resend", value: "resend" }] : []
4090
- ],
4091
- admin: {
4092
- description: "Which email provider manages this channel"
4093
- }
4094
- },
4095
- {
4096
- name: "providerId",
4097
- type: "text",
4098
- admin: {
4099
- readOnly: true,
4100
- description: "ID from the email provider",
4101
- condition: (data) => hasProviders && data?.providerId
4102
- }
4103
- },
4104
- {
4105
- name: "subscriberCount",
4106
- type: "number",
4107
- admin: {
4108
- readOnly: true,
4109
- description: "Number of active subscribers"
4110
- },
4111
- defaultValue: 0
4112
- },
4113
- {
4114
- name: "active",
4115
- type: "checkbox",
4116
- defaultValue: true,
4117
- admin: {
4118
- description: "Whether this channel is currently active"
4119
- }
4120
- },
4121
- {
4122
- name: "settings",
4123
- type: "group",
4124
- fields: [
4125
- {
4126
- name: "defaultTrackOpens",
4127
- type: "checkbox",
4128
- defaultValue: true,
4129
- admin: {
4130
- description: "Track email opens by default for broadcasts in this channel"
4131
- }
4132
- },
4133
- {
4134
- name: "defaultTrackClicks",
4135
- type: "checkbox",
4136
- defaultValue: true,
4137
- admin: {
4138
- description: "Track link clicks by default for broadcasts in this channel"
4139
- }
4140
- },
4141
- {
4142
- name: "requireDoubleOptIn",
4143
- type: "checkbox",
4144
- defaultValue: false,
4145
- admin: {
4146
- description: "Require double opt-in for new subscribers"
4147
- }
4148
- }
4149
- ]
4150
- }
4151
- ],
4152
- hooks: {
4153
- // Sync with provider on create
4154
- afterChange: [
4155
- async ({ doc, operation, req }) => {
4156
- if (!hasProviders || operation !== "create") return doc;
4157
- try {
4158
- const provider = await getProvider(doc.providerType, pluginConfig);
4159
- if (!provider) return doc;
4160
- const providerChannel = await provider.createChannel({
4161
- name: doc.name,
4162
- description: doc.description,
4163
- fromName: doc.fromName,
4164
- fromEmail: doc.fromEmail,
4165
- replyTo: doc.replyTo
4166
- });
4167
- await req.payload.update({
4168
- collection: "channels",
4169
- id: doc.id,
4170
- data: {
4171
- providerId: providerChannel.id,
4172
- subscriberCount: providerChannel.subscriberCount || 0
4173
- },
4174
- req
4175
- });
4176
- return {
4177
- ...doc,
4178
- providerId: providerChannel.id,
4179
- subscriberCount: providerChannel.subscriberCount || 0
4180
- };
4181
- } catch (error) {
4182
- req.payload.logger.error("Failed to create channel in provider:", error);
4183
- return doc;
4184
- }
4185
- }
4186
- ],
4187
- // Sync updates with provider
4188
- beforeChange: [
4189
- async ({ data, originalDoc, operation, req }) => {
4190
- if (!hasProviders || !originalDoc?.providerId || operation !== "update") return data;
4191
- try {
4192
- const provider = await getProvider(originalDoc.providerType, pluginConfig);
4193
- if (!provider) return data;
4194
- const updates = {};
4195
- if (data.name !== originalDoc.name) updates.name = data.name;
4196
- if (data.description !== originalDoc.description) updates.description = data.description;
4197
- if (data.fromName !== originalDoc.fromName) updates.fromName = data.fromName;
4198
- if (data.fromEmail !== originalDoc.fromEmail) updates.fromEmail = data.fromEmail;
4199
- if (data.replyTo !== originalDoc.replyTo) updates.replyTo = data.replyTo;
4200
- if (Object.keys(updates).length > 0) {
4201
- await provider.updateChannel(originalDoc.providerId, updates);
4202
- }
4203
- } catch (error) {
4204
- req.payload.logger.error("Failed to update channel in provider:", error);
4205
- }
4206
- return data;
4207
- }
4208
- ],
4209
- // Handle deletion
4210
- afterDelete: [
4211
- async ({ doc, req }) => {
4212
- if (!hasProviders || !doc?.providerId) return doc;
4213
- try {
4214
- const provider = await getProvider(doc.providerType, pluginConfig);
4215
- if (!provider) return doc;
4216
- await provider.deleteChannel(doc.providerId);
4217
- } catch (error) {
4218
- req.payload.logger.error("Failed to delete channel from provider:", error);
4219
- }
4220
- return doc;
4221
- }
4222
- ]
4223
- }
4224
- };
4225
- };
4226
- async function getProvider(providerType, config) {
4227
- if (providerType === "broadcast") {
4228
- const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
4229
- const providerConfig = config.providers?.broadcast;
4230
- return providerConfig ? new BroadcastApiProvider2(providerConfig) : null;
4231
- }
4232
- if (providerType === "resend") {
4233
- const { ResendBroadcastProvider: ResendBroadcastProvider2 } = await Promise.resolve().then(() => (init_broadcast3(), broadcast_exports2));
4234
- const providerConfig = config.providers?.resend;
4235
- return providerConfig ? new ResendBroadcastProvider2(providerConfig) : null;
4236
- }
4237
- return null;
4238
- }
4239
-
4240
3506
  // src/collections/Broadcasts.ts
4241
3507
  init_types();
4242
3508
 
@@ -4313,18 +3579,9 @@ var createBroadcastsCollection = (pluginConfig) => {
4313
3579
  admin: {
4314
3580
  useAsTitle: "name",
4315
3581
  description: "Individual email campaigns sent to subscribers",
4316
- defaultColumns: ["name", "subject", "status", "channel", "sentAt", "actions"]
3582
+ defaultColumns: ["name", "subject", "status", "sentAt", "actions"]
4317
3583
  },
4318
3584
  fields: [
4319
- {
4320
- name: "channel",
4321
- type: "relationship",
4322
- relationTo: "channels",
4323
- required: true,
4324
- admin: {
4325
- description: "The channel this broadcast belongs to"
4326
- }
4327
- },
4328
3585
  {
4329
3586
  name: "name",
4330
3587
  type: "text",
@@ -4536,23 +3793,22 @@ var createBroadcastsCollection = (pluginConfig) => {
4536
3793
  async ({ doc, operation, req }) => {
4537
3794
  if (!hasProviders || operation !== "create") return doc;
4538
3795
  try {
4539
- const channel = await req.payload.findByID({
4540
- collection: "channels",
4541
- id: typeof doc.channel === "string" ? doc.channel : doc.channel.id,
4542
- req
4543
- });
4544
- const provider = await getProvider2(channel.providerType, pluginConfig);
4545
- if (!provider) return doc;
3796
+ const providerConfig = pluginConfig.providers?.broadcast;
3797
+ if (!providerConfig) {
3798
+ req.payload.logger.error("Broadcast provider not configured");
3799
+ return doc;
3800
+ }
3801
+ const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
3802
+ const provider = new BroadcastApiProvider2(providerConfig);
4546
3803
  const htmlContent = await convertToEmailSafeHtml(doc.content);
4547
3804
  const providerBroadcast = await provider.create({
4548
- channelId: channel.providerId || channel.id,
4549
3805
  name: doc.name,
4550
3806
  subject: doc.subject,
4551
3807
  preheader: doc.preheader,
4552
3808
  content: htmlContent,
4553
3809
  trackOpens: doc.settings?.trackOpens,
4554
3810
  trackClicks: doc.settings?.trackClicks,
4555
- replyTo: doc.settings?.replyTo,
3811
+ replyTo: doc.settings?.replyTo || providerConfig.replyTo,
4556
3812
  audienceIds: doc.audienceIds?.map((a) => a.audienceId)
4557
3813
  });
4558
3814
  await req.payload.update({
@@ -4580,14 +3836,13 @@ var createBroadcastsCollection = (pluginConfig) => {
4580
3836
  async ({ data, originalDoc, operation, req }) => {
4581
3837
  if (!hasProviders || !originalDoc?.providerId || operation !== "update") return data;
4582
3838
  try {
4583
- const channelId = data.channel || originalDoc.channel;
4584
- const channel = await req.payload.findByID({
4585
- collection: "channels",
4586
- id: typeof channelId === "string" ? channelId : channelId.id,
4587
- req
4588
- });
4589
- const provider = await getProvider2(channel.providerType, pluginConfig);
4590
- if (!provider) return data;
3839
+ const providerConfig = pluginConfig.providers?.broadcast;
3840
+ if (!providerConfig) {
3841
+ req.payload.logger.error("Broadcast provider not configured");
3842
+ return data;
3843
+ }
3844
+ const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
3845
+ const provider = new BroadcastApiProvider2(providerConfig);
4591
3846
  const capabilities = provider.getCapabilities();
4592
3847
  if (!capabilities.editableStatuses.includes(originalDoc.status)) {
4593
3848
  return data;
@@ -4606,7 +3861,7 @@ var createBroadcastsCollection = (pluginConfig) => {
4606
3861
  updates.trackClicks = data.settings.trackClicks;
4607
3862
  }
4608
3863
  if (data.settings?.replyTo !== originalDoc.settings?.replyTo) {
4609
- updates.replyTo = data.settings.replyTo;
3864
+ updates.replyTo = data.settings.replyTo || providerConfig.replyTo;
4610
3865
  }
4611
3866
  if (JSON.stringify(data.audienceIds) !== JSON.stringify(originalDoc.audienceIds)) {
4612
3867
  updates.audienceIds = data.audienceIds?.map((a) => a.audienceId);
@@ -4625,13 +3880,13 @@ var createBroadcastsCollection = (pluginConfig) => {
4625
3880
  async ({ doc, req }) => {
4626
3881
  if (!hasProviders || !doc?.providerId) return doc;
4627
3882
  try {
4628
- const channel = await req.payload.findByID({
4629
- collection: "channels",
4630
- id: typeof doc.channel === "string" ? doc.channel : doc.channel.id,
4631
- req
4632
- });
4633
- const provider = await getProvider2(channel.providerType, pluginConfig);
4634
- if (!provider) return doc;
3883
+ const providerConfig = pluginConfig.providers?.broadcast;
3884
+ if (!providerConfig) {
3885
+ req.payload.logger.error("Broadcast provider not configured");
3886
+ return doc;
3887
+ }
3888
+ const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
3889
+ const provider = new BroadcastApiProvider2(providerConfig);
4635
3890
  const capabilities = provider.getCapabilities();
4636
3891
  if (capabilities.editableStatuses.includes(doc.status)) {
4637
3892
  await provider.delete(doc.providerId);
@@ -4645,23 +3900,223 @@ var createBroadcastsCollection = (pluginConfig) => {
4645
3900
  }
4646
3901
  };
4647
3902
  };
4648
- async function getProvider2(providerType, config) {
4649
- if (providerType === "broadcast") {
4650
- const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
4651
- const providerConfig = config.providers?.broadcast;
4652
- return providerConfig ? new BroadcastApiProvider2(providerConfig) : null;
4653
- }
4654
- if (providerType === "resend") {
4655
- const { ResendBroadcastProvider: ResendBroadcastProvider2 } = await Promise.resolve().then(() => (init_broadcast3(), broadcast_exports2));
4656
- const providerConfig = config.providers?.resend;
4657
- return providerConfig ? new ResendBroadcastProvider2(providerConfig) : null;
4658
- }
4659
- return null;
4660
- }
4661
3903
 
4662
3904
  // src/index.ts
4663
3905
  init_broadcast2();
4664
- init_broadcast3();
3906
+
3907
+ // src/providers/resend/broadcast.ts
3908
+ init_types();
3909
+ import { Resend as Resend2 } from "resend";
3910
+ var ResendBroadcastProvider = class extends BaseBroadcastProvider {
3911
+ constructor(config) {
3912
+ super(config);
3913
+ this.name = "resend";
3914
+ this.client = new Resend2(config.apiKey);
3915
+ this.audienceIds = config.audienceIds || {};
3916
+ this.isDevelopment = process.env.NODE_ENV !== "production";
3917
+ if (!config.apiKey) {
3918
+ throw new BroadcastProviderError(
3919
+ "Resend API key is required",
3920
+ "CONFIGURATION_ERROR" /* CONFIGURATION_ERROR */,
3921
+ this.name
3922
+ );
3923
+ }
3924
+ }
3925
+ // Broadcast Management Methods
3926
+ async list(_options) {
3927
+ throw new BroadcastProviderError(
3928
+ "Listing broadcasts is not currently supported by Resend API. This feature may be available in the dashboard only.",
3929
+ "NOT_SUPPORTED" /* NOT_SUPPORTED */,
3930
+ this.name
3931
+ );
3932
+ }
3933
+ async get(_id) {
3934
+ throw new BroadcastProviderError(
3935
+ "Getting individual broadcasts is not currently supported by Resend API. This feature may be available in the dashboard only.",
3936
+ "NOT_SUPPORTED" /* NOT_SUPPORTED */,
3937
+ this.name
3938
+ );
3939
+ }
3940
+ async create(data) {
3941
+ try {
3942
+ this.validateRequiredFields(data, ["name", "subject", "content"]);
3943
+ const locale = "en";
3944
+ const audienceConfig = this.audienceIds?.[locale];
3945
+ const audienceId = this.isDevelopment ? audienceConfig?.development || audienceConfig?.production : audienceConfig?.production || audienceConfig?.development;
3946
+ if (!audienceId && data.audienceIds?.length) {
3947
+ }
3948
+ const resendClient = this.client;
3949
+ if (resendClient.broadcasts?.create) {
3950
+ const broadcast = await resendClient.broadcasts.create({
3951
+ name: data.name,
3952
+ subject: data.subject,
3953
+ from: `${this.config.fromName || "Newsletter"} <${this.config.fromEmail || "noreply@example.com"}>`,
3954
+ reply_to: data.replyTo,
3955
+ audience_id: audienceId || data.audienceIds?.[0],
3956
+ content: {
3957
+ html: data.content
3958
+ // TODO: Handle plain text version
3959
+ }
3960
+ });
3961
+ return this.transformResendToBroadcast(broadcast);
3962
+ }
3963
+ throw new BroadcastProviderError(
3964
+ "Creating broadcasts via API is not currently supported. Please check if Resend has released their Broadcasts API.",
3965
+ "NOT_SUPPORTED" /* NOT_SUPPORTED */,
3966
+ this.name
3967
+ );
3968
+ } catch (error) {
3969
+ if (error instanceof BroadcastProviderError) throw error;
3970
+ throw new BroadcastProviderError(
3971
+ `Failed to create broadcast: ${error instanceof Error ? error.message : "Unknown error"}`,
3972
+ "PROVIDER_ERROR" /* PROVIDER_ERROR */,
3973
+ this.name,
3974
+ error
3975
+ );
3976
+ }
3977
+ }
3978
+ async update(_id, _data) {
3979
+ throw new BroadcastProviderError(
3980
+ "Updating broadcasts is not currently supported by Resend API. Note: Resend broadcasts can only be edited where they were created.",
3981
+ "NOT_SUPPORTED" /* NOT_SUPPORTED */,
3982
+ this.name
3983
+ );
3984
+ }
3985
+ async delete(_id) {
3986
+ throw new BroadcastProviderError(
3987
+ "Deleting broadcasts is not currently supported by Resend API.",
3988
+ "NOT_SUPPORTED" /* NOT_SUPPORTED */,
3989
+ this.name
3990
+ );
3991
+ }
3992
+ async send(id, options) {
3993
+ try {
3994
+ const resendClient = this.client;
3995
+ if (resendClient.broadcasts?.send) {
3996
+ await resendClient.broadcasts.send(id, {
3997
+ audience_id: options?.audienceIds?.[0]
3998
+ // TODO: Handle test mode if supported
3999
+ });
4000
+ return {
4001
+ id,
4002
+ name: "Unknown",
4003
+ subject: "Unknown",
4004
+ content: "",
4005
+ status: "sending" /* SENDING */,
4006
+ trackOpens: true,
4007
+ trackClicks: true,
4008
+ createdAt: /* @__PURE__ */ new Date(),
4009
+ updatedAt: /* @__PURE__ */ new Date(),
4010
+ providerType: "resend"
4011
+ };
4012
+ }
4013
+ throw new BroadcastProviderError(
4014
+ "Sending broadcasts via API is not currently supported. Please check if Resend has released their Broadcasts API.",
4015
+ "NOT_SUPPORTED" /* NOT_SUPPORTED */,
4016
+ this.name
4017
+ );
4018
+ } catch (error) {
4019
+ if (error instanceof BroadcastProviderError) throw error;
4020
+ throw new BroadcastProviderError(
4021
+ `Failed to send broadcast: ${error instanceof Error ? error.message : "Unknown error"}`,
4022
+ "PROVIDER_ERROR" /* PROVIDER_ERROR */,
4023
+ this.name,
4024
+ error
4025
+ );
4026
+ }
4027
+ }
4028
+ async schedule(_id, _scheduledAt) {
4029
+ throw new BroadcastProviderError(
4030
+ "Scheduling broadcasts is not supported by Resend",
4031
+ "NOT_SUPPORTED" /* NOT_SUPPORTED */,
4032
+ this.name
4033
+ );
4034
+ }
4035
+ async getAnalytics(_id) {
4036
+ throw new BroadcastProviderError(
4037
+ "Getting broadcast analytics via API is not currently supported. Analytics may be available in the Resend dashboard.",
4038
+ "NOT_SUPPORTED" /* NOT_SUPPORTED */,
4039
+ this.name
4040
+ );
4041
+ }
4042
+ getCapabilities() {
4043
+ return {
4044
+ supportsScheduling: false,
4045
+ // Not documented
4046
+ supportsSegmentation: true,
4047
+ // Via Audiences
4048
+ supportsAnalytics: true,
4049
+ // Available in dashboard, API unclear
4050
+ supportsABTesting: false,
4051
+ supportsTemplates: false,
4052
+ // Not clear from docs
4053
+ supportsPersonalization: true,
4054
+ // Via merge tags
4055
+ supportsMultipleChannels: false,
4056
+ supportsChannelSegmentation: false,
4057
+ editableStatuses: [],
4058
+ // Unclear which statuses can be edited
4059
+ supportedContentTypes: ["html"]
4060
+ // React components via SDK
4061
+ };
4062
+ }
4063
+ async validateConfiguration() {
4064
+ try {
4065
+ const resendClient = this.client;
4066
+ if (resendClient.audiences?.list) {
4067
+ await resendClient.audiences.list({ limit: 1 });
4068
+ return true;
4069
+ }
4070
+ await this.client.emails.send({
4071
+ from: "onboarding@resend.dev",
4072
+ to: "delivered@resend.dev",
4073
+ subject: "Configuration Test",
4074
+ html: "<p>Testing configuration</p>"
4075
+ });
4076
+ return true;
4077
+ } catch {
4078
+ return false;
4079
+ }
4080
+ }
4081
+ /**
4082
+ * Transform Resend broadcast to our Broadcast type
4083
+ * NOTE: This is speculative based on what the API might return
4084
+ */
4085
+ transformResendToBroadcast(broadcast) {
4086
+ return {
4087
+ id: broadcast.id,
4088
+ name: broadcast.name || "Untitled",
4089
+ subject: broadcast.subject,
4090
+ preheader: broadcast.preheader,
4091
+ content: broadcast.content?.html || broadcast.html || "",
4092
+ status: this.mapResendStatus(broadcast.status),
4093
+ trackOpens: true,
4094
+ // Resend tracks by default
4095
+ trackClicks: true,
4096
+ // Resend tracks by default
4097
+ replyTo: broadcast.reply_to,
4098
+ recipientCount: broadcast.recipient_count,
4099
+ sentAt: broadcast.sent_at ? new Date(broadcast.sent_at) : void 0,
4100
+ scheduledAt: broadcast.scheduled_at ? new Date(broadcast.scheduled_at) : void 0,
4101
+ createdAt: new Date(broadcast.created_at || Date.now()),
4102
+ updatedAt: new Date(broadcast.updated_at || Date.now()),
4103
+ providerData: { broadcast },
4104
+ providerId: broadcast.id,
4105
+ providerType: "resend"
4106
+ };
4107
+ }
4108
+ mapResendStatus(status) {
4109
+ if (!status) return "draft" /* DRAFT */;
4110
+ const statusMap = {
4111
+ "draft": "draft" /* DRAFT */,
4112
+ "scheduled": "scheduled" /* SCHEDULED */,
4113
+ "sending": "sending" /* SENDING */,
4114
+ "sent": "sent" /* SENT */,
4115
+ "failed": "failed" /* FAILED */
4116
+ };
4117
+ return statusMap[status.toLowerCase()] || "draft" /* DRAFT */;
4118
+ }
4119
+ };
4665
4120
 
4666
4121
  // src/utilities/session.ts
4667
4122
  import jwt2 from "jsonwebtoken";
@@ -4761,9 +4216,8 @@ var newsletterPlugin = (pluginConfig) => (incomingConfig) => {
4761
4216
  const settingsGlobal = createNewsletterSettingsGlobal(config);
4762
4217
  let collections = [...incomingConfig.collections || [], subscribersCollection];
4763
4218
  if (config.features?.newsletterManagement?.enabled) {
4764
- const channelsCollection = createChannelsCollection(config);
4765
4219
  const broadcastsCollection = createBroadcastsCollection(config);
4766
- collections.push(channelsCollection, broadcastsCollection);
4220
+ collections.push(broadcastsCollection);
4767
4221
  }
4768
4222
  if (config.features?.newsletterScheduling?.enabled) {
4769
4223
  const targetCollections = config.features.newsletterScheduling.collections || "articles";
@@ -4844,10 +4298,10 @@ var newsletterPlugin = (pluginConfig) => (incomingConfig) => {
4844
4298
  } : config.providers.resend,
4845
4299
  broadcast: settings.provider === "broadcast" ? {
4846
4300
  apiUrl: settings.broadcastSettings?.apiUrl || config.providers.broadcast?.apiUrl || "",
4847
- tokens: {
4848
- production: settings.broadcastSettings?.productionToken || config.providers.broadcast?.tokens.production,
4849
- development: settings.broadcastSettings?.developmentToken || config.providers.broadcast?.tokens.development
4850
- }
4301
+ token: settings.broadcastSettings?.token || config.providers.broadcast?.token || "",
4302
+ fromAddress: settings.fromAddress || config.providers.broadcast?.fromAddress,
4303
+ fromName: settings.fromName || config.providers.broadcast?.fromName,
4304
+ replyTo: settings.replyTo || config.providers.broadcast?.replyTo
4851
4305
  } : config.providers.broadcast
4852
4306
  };
4853
4307
  } else {