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/CHANGELOG.md +43 -0
- package/README.md +6 -5
- package/dist/components.cjs +3 -7
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.cts +0 -2
- package/dist/components.d.ts +0 -2
- package/dist/components.js +3 -7
- package/dist/components.js.map +1 -1
- package/dist/index.cjs +300 -846
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +299 -845
- package/dist/index.js.map +1 -1
- package/dist/types.cjs +0 -2
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +3 -83
- package/dist/types.d.ts +3 -83
- package/dist/types.js +0 -2
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
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.
|
|
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, ["
|
|
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:
|
|
631
|
-
supportsChannelSegmentation:
|
|
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.
|
|
492
|
+
recipientCount: broadcast.total_recipients,
|
|
1028
493
|
sentAt: broadcast.sent_at ? new Date(broadcast.sent_at) : void 0,
|
|
1029
|
-
scheduledAt: broadcast.
|
|
1030
|
-
createdAt: new Date(broadcast.created_at
|
|
1031
|
-
updatedAt: new Date(broadcast.updated_at
|
|
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: "
|
|
498
|
+
providerId: broadcast.id.toString(),
|
|
499
|
+
providerType: "broadcast"
|
|
1035
500
|
};
|
|
1036
501
|
}
|
|
1037
|
-
|
|
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
|
|
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: "
|
|
1206
|
+
name: "token",
|
|
1739
1207
|
type: "text",
|
|
1740
|
-
label: "
|
|
1741
|
-
|
|
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: "
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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:
|
|
3701
|
-
fromName
|
|
3702
|
-
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 =
|
|
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", "
|
|
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
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
}
|
|
4544
|
-
const
|
|
4545
|
-
|
|
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
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
});
|
|
4589
|
-
const provider =
|
|
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
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
}
|
|
4633
|
-
const
|
|
4634
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
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 {
|