payload-plugin-newsletter 0.16.3 → 0.16.5
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 +41 -0
- package/dist/collections.cjs +46 -14
- package/dist/collections.cjs.map +1 -1
- package/dist/collections.js +46 -14
- package/dist/collections.js.map +1 -1
- package/dist/index.cjs +50 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +50 -18
- package/dist/index.js.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/plugin-api-key-recommendations.md +117 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,44 @@
|
|
|
1
|
+
## [0.16.5] - 2025-07-29
|
|
2
|
+
|
|
3
|
+
### Breaking Changes
|
|
4
|
+
- **Field Renaming** - Renamed `status` field to `sendStatus` throughout the codebase
|
|
5
|
+
- This avoids confusion with Payload's built-in `_status` field (draft/published)
|
|
6
|
+
- Database field is now `sendStatus` for email send status (draft, scheduled, sending, sent, etc.)
|
|
7
|
+
- All references in providers, endpoints, and types have been updated
|
|
8
|
+
- If you have existing broadcast data with a `status` field, you'll need to migrate it to `sendStatus`
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Update Sync** - Fixed issue where broadcast updates made in Payload weren't syncing to the Broadcast provider
|
|
12
|
+
- The update hook now correctly checks `sendStatus` instead of the non-existent `status` field
|
|
13
|
+
- Provider can now properly determine if a broadcast is editable based on its send status
|
|
14
|
+
|
|
15
|
+
### Technical
|
|
16
|
+
- Updated `Broadcast` type interface to use `sendStatus` property
|
|
17
|
+
- Updated all provider implementations (Broadcast and Resend) to use `sendStatus`
|
|
18
|
+
- Updated send and schedule endpoints to set `sendStatus` field
|
|
19
|
+
- All TypeScript errors resolved
|
|
20
|
+
|
|
21
|
+
## [0.16.4] - 2025-07-27
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
- **Access Control for Broadcasts** - Added proper access control to the Broadcasts collection
|
|
25
|
+
- Public read access for all users
|
|
26
|
+
- Create, update, and delete operations require authenticated users
|
|
27
|
+
- Prevents unauthorized modifications to broadcast content
|
|
28
|
+
- Follows Payload's standard access control patterns
|
|
29
|
+
|
|
30
|
+
### Improved
|
|
31
|
+
- **Enhanced Update Sync Debugging** - Added detailed logging for broadcast update synchronization
|
|
32
|
+
- Logs when update hooks are triggered with operation details
|
|
33
|
+
- Shows what fields are being synced to the provider
|
|
34
|
+
- Helps diagnose why updates might not be syncing
|
|
35
|
+
- Added info logging for skipped updates due to status restrictions
|
|
36
|
+
- **Clearer Field Naming** - Renamed `status` field to `sendStatus` to avoid confusion with Payload's `_status`
|
|
37
|
+
- Database field is now `sendStatus` (draft, scheduled, sending, sent, etc.)
|
|
38
|
+
- Payload's versioning field remains `_status` (draft, published)
|
|
39
|
+
- Added virtual `status` field for API backward compatibility
|
|
40
|
+
- Makes it clear which status controls email sending vs content publishing
|
|
41
|
+
|
|
1
42
|
## [0.16.3] - 2025-07-27
|
|
2
43
|
|
|
3
44
|
### Improved
|
package/dist/collections.cjs
CHANGED
|
@@ -291,9 +291,9 @@ var init_broadcast2 = __esm({
|
|
|
291
291
|
async update(id, data) {
|
|
292
292
|
try {
|
|
293
293
|
const existing = await this.get(id);
|
|
294
|
-
if (!this.canEditInStatus(existing.
|
|
294
|
+
if (!this.canEditInStatus(existing.sendStatus)) {
|
|
295
295
|
throw new BroadcastProviderError(
|
|
296
|
-
`Cannot update broadcast in status: ${existing.
|
|
296
|
+
`Cannot update broadcast in status: ${existing.sendStatus}`,
|
|
297
297
|
"INVALID_STATUS" /* INVALID_STATUS */,
|
|
298
298
|
this.name
|
|
299
299
|
);
|
|
@@ -336,9 +336,9 @@ var init_broadcast2 = __esm({
|
|
|
336
336
|
async delete(id) {
|
|
337
337
|
try {
|
|
338
338
|
const existing = await this.get(id);
|
|
339
|
-
if (!this.canEditInStatus(existing.
|
|
339
|
+
if (!this.canEditInStatus(existing.sendStatus)) {
|
|
340
340
|
throw new BroadcastProviderError(
|
|
341
|
-
`Cannot delete broadcast in status: ${existing.
|
|
341
|
+
`Cannot delete broadcast in status: ${existing.sendStatus}`,
|
|
342
342
|
"INVALID_STATUS" /* INVALID_STATUS */,
|
|
343
343
|
this.name
|
|
344
344
|
);
|
|
@@ -497,7 +497,7 @@ var init_broadcast2 = __esm({
|
|
|
497
497
|
subject: broadcast.subject,
|
|
498
498
|
preheader: broadcast.preheader,
|
|
499
499
|
content: broadcast.body,
|
|
500
|
-
|
|
500
|
+
sendStatus: this.mapBroadcastStatus(broadcast.status),
|
|
501
501
|
trackOpens: broadcast.track_opens,
|
|
502
502
|
trackClicks: broadcast.track_clicks,
|
|
503
503
|
replyTo: broadcast.reply_to,
|
|
@@ -1191,6 +1191,19 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
1191
1191
|
const customizations = pluginConfig.customizations?.broadcasts;
|
|
1192
1192
|
return {
|
|
1193
1193
|
slug: "broadcasts",
|
|
1194
|
+
access: {
|
|
1195
|
+
read: () => true,
|
|
1196
|
+
// Public read access
|
|
1197
|
+
create: ({ req: { user } }) => {
|
|
1198
|
+
return Boolean(user);
|
|
1199
|
+
},
|
|
1200
|
+
update: ({ req: { user } }) => {
|
|
1201
|
+
return Boolean(user);
|
|
1202
|
+
},
|
|
1203
|
+
delete: ({ req: { user } }) => {
|
|
1204
|
+
return Boolean(user);
|
|
1205
|
+
}
|
|
1206
|
+
},
|
|
1194
1207
|
versions: {
|
|
1195
1208
|
drafts: {
|
|
1196
1209
|
autosave: true,
|
|
@@ -1204,7 +1217,7 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
1204
1217
|
admin: {
|
|
1205
1218
|
useAsTitle: "subject",
|
|
1206
1219
|
description: "Individual email campaigns sent to subscribers",
|
|
1207
|
-
defaultColumns: ["subject", "_status", "
|
|
1220
|
+
defaultColumns: ["subject", "_status", "sendStatus", "sentAt", "recipientCount"]
|
|
1208
1221
|
},
|
|
1209
1222
|
fields: [
|
|
1210
1223
|
{
|
|
@@ -1264,8 +1277,9 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
1264
1277
|
]
|
|
1265
1278
|
},
|
|
1266
1279
|
{
|
|
1267
|
-
name: "
|
|
1280
|
+
name: "sendStatus",
|
|
1268
1281
|
type: "select",
|
|
1282
|
+
label: "Send Status",
|
|
1269
1283
|
required: true,
|
|
1270
1284
|
defaultValue: "draft" /* DRAFT */,
|
|
1271
1285
|
options: [
|
|
@@ -1279,6 +1293,7 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
1279
1293
|
],
|
|
1280
1294
|
admin: {
|
|
1281
1295
|
readOnly: true,
|
|
1296
|
+
description: "The status of the email send operation",
|
|
1282
1297
|
components: {
|
|
1283
1298
|
Cell: "payload-plugin-newsletter/components#StatusBadge"
|
|
1284
1299
|
}
|
|
@@ -1335,7 +1350,7 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
1335
1350
|
type: "group",
|
|
1336
1351
|
admin: {
|
|
1337
1352
|
readOnly: true,
|
|
1338
|
-
condition: (data) => data?.
|
|
1353
|
+
condition: (data) => data?.sendStatus === "sent" /* SENT */
|
|
1339
1354
|
},
|
|
1340
1355
|
fields: [
|
|
1341
1356
|
{
|
|
@@ -1394,7 +1409,7 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
1394
1409
|
name: "scheduledAt",
|
|
1395
1410
|
type: "date",
|
|
1396
1411
|
admin: {
|
|
1397
|
-
condition: (data) => data?.
|
|
1412
|
+
condition: (data) => data?.sendStatus === "scheduled" /* SCHEDULED */,
|
|
1398
1413
|
date: {
|
|
1399
1414
|
displayFormat: "MMM d, yyyy h:mm a"
|
|
1400
1415
|
}
|
|
@@ -1479,7 +1494,7 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
1479
1494
|
const wasUnpublished = !previousDoc?._status || previousDoc._status === "draft";
|
|
1480
1495
|
const isNowPublished = doc._status === "published";
|
|
1481
1496
|
if (wasUnpublished && isNowPublished && doc.providerId) {
|
|
1482
|
-
if (doc.
|
|
1497
|
+
if (doc.sendStatus === "sent" /* SENT */ || doc.sendStatus === "sending" /* SENDING */) {
|
|
1483
1498
|
return doc;
|
|
1484
1499
|
}
|
|
1485
1500
|
try {
|
|
@@ -1498,7 +1513,7 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
1498
1513
|
collection: "broadcasts",
|
|
1499
1514
|
id: doc.id,
|
|
1500
1515
|
data: {
|
|
1501
|
-
|
|
1516
|
+
sendStatus: "sending" /* SENDING */,
|
|
1502
1517
|
sentAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1503
1518
|
},
|
|
1504
1519
|
req
|
|
@@ -1520,7 +1535,7 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
1520
1535
|
collection: "broadcasts",
|
|
1521
1536
|
id: doc.id,
|
|
1522
1537
|
data: {
|
|
1523
|
-
|
|
1538
|
+
sendStatus: "failed" /* FAILED */
|
|
1524
1539
|
},
|
|
1525
1540
|
req
|
|
1526
1541
|
});
|
|
@@ -1533,6 +1548,14 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
1533
1548
|
beforeChange: [
|
|
1534
1549
|
async ({ data, originalDoc, operation, req }) => {
|
|
1535
1550
|
if (!hasProviders || !originalDoc?.providerId || operation !== "update") return data;
|
|
1551
|
+
req.payload.logger.info("Broadcast beforeChange update hook triggered", {
|
|
1552
|
+
operation,
|
|
1553
|
+
hasProviderId: !!originalDoc?.providerId,
|
|
1554
|
+
originalSendStatus: originalDoc?.sendStatus,
|
|
1555
|
+
originalPublishStatus: originalDoc?._status,
|
|
1556
|
+
newSendStatus: data?.sendStatus,
|
|
1557
|
+
newPublishStatus: data?._status
|
|
1558
|
+
});
|
|
1536
1559
|
try {
|
|
1537
1560
|
const providerConfig = await getBroadcastConfig(req, pluginConfig);
|
|
1538
1561
|
if (!providerConfig || !providerConfig.token) {
|
|
@@ -1542,7 +1565,9 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
1542
1565
|
const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
|
|
1543
1566
|
const provider = new BroadcastApiProvider2(providerConfig);
|
|
1544
1567
|
const capabilities = provider.getCapabilities();
|
|
1545
|
-
|
|
1568
|
+
const sendStatus = originalDoc.sendStatus || "draft" /* DRAFT */;
|
|
1569
|
+
if (!capabilities.editableStatuses.includes(sendStatus)) {
|
|
1570
|
+
req.payload.logger.info(`Skipping sync for broadcast in status: ${sendStatus}`);
|
|
1546
1571
|
return data;
|
|
1547
1572
|
}
|
|
1548
1573
|
const updates = {};
|
|
@@ -1567,7 +1592,14 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
1567
1592
|
updates.audienceIds = data.audienceIds?.map((a) => a.audienceId);
|
|
1568
1593
|
}
|
|
1569
1594
|
if (Object.keys(updates).length > 0) {
|
|
1595
|
+
req.payload.logger.info("Syncing broadcast updates to provider", {
|
|
1596
|
+
providerId: originalDoc.providerId,
|
|
1597
|
+
updates
|
|
1598
|
+
});
|
|
1570
1599
|
await provider.update(originalDoc.providerId, updates);
|
|
1600
|
+
req.payload.logger.info("Successfully synced broadcast updates to provider");
|
|
1601
|
+
} else {
|
|
1602
|
+
req.payload.logger.info("No broadcast updates to sync to provider");
|
|
1571
1603
|
}
|
|
1572
1604
|
} catch (error) {
|
|
1573
1605
|
if (error instanceof Error) {
|
|
@@ -1598,7 +1630,7 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
1598
1630
|
const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
|
|
1599
1631
|
const provider = new BroadcastApiProvider2(providerConfig);
|
|
1600
1632
|
const capabilities = provider.getCapabilities();
|
|
1601
|
-
if (capabilities.editableStatuses.includes(doc.
|
|
1633
|
+
if (capabilities.editableStatuses.includes(doc.sendStatus)) {
|
|
1602
1634
|
await provider.delete(doc.providerId);
|
|
1603
1635
|
}
|
|
1604
1636
|
} catch (error) {
|