payload-plugin-newsletter 0.16.8 → 0.16.9

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 CHANGED
@@ -1,3 +1,18 @@
1
+ ## [0.16.9] - 2025-01-29
2
+
3
+ ### Fixed
4
+ - **Deferred Provider Sync for Empty Broadcasts** - Fixed issue where broadcasts created empty were never synced to provider
5
+ - Update operation now handles "deferred create" scenario when providerId is missing
6
+ - When a broadcast has subject and content but no providerId, it creates the broadcast in the provider
7
+ - Normal update sync works for broadcasts that already exist in the provider
8
+ - Resolves workflow: create empty → add content → save → now syncs to provider
9
+
10
+ ### Technical
11
+ - Modified update operation handler to check for missing providerId
12
+ - Added deferred create logic in update afterChange hook
13
+ - Separated normal update logic to only run when providerId exists
14
+ - Added comprehensive error handling for both deferred create and normal update scenarios
15
+
1
16
  ## [0.16.8] - 2025-01-29
2
17
 
3
18
  ### Fixed
@@ -1549,7 +1549,7 @@ var createBroadcastsCollection = (pluginConfig) => {
1549
1549
  return doc;
1550
1550
  }
1551
1551
  }
1552
- if (operation === "update" && doc.providerId) {
1552
+ if (operation === "update") {
1553
1553
  req.payload.logger.info("Broadcast afterChange update hook triggered", {
1554
1554
  operation,
1555
1555
  hasProviderId: !!doc.providerId,
@@ -1564,57 +1564,135 @@ var createBroadcastsCollection = (pluginConfig) => {
1564
1564
  }
1565
1565
  const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
1566
1566
  const provider = new BroadcastApiProvider2(providerConfig);
1567
- const capabilities = provider.getCapabilities();
1568
- const sendStatus = doc.sendStatus || "draft" /* DRAFT */;
1569
- if (!capabilities.editableStatuses.includes(sendStatus)) {
1570
- req.payload.logger.info(`Skipping sync for broadcast in status: ${sendStatus}`);
1571
- return doc;
1572
- }
1573
- const contentChanged = doc.subject !== previousDoc?.subject || doc.contentSection?.preheader !== previousDoc?.contentSection?.preheader || JSON.stringify(doc.contentSection?.content) !== JSON.stringify(previousDoc?.contentSection?.content) || doc.settings?.trackOpens !== previousDoc?.settings?.trackOpens || doc.settings?.trackClicks !== previousDoc?.settings?.trackClicks || doc.settings?.replyTo !== previousDoc?.settings?.replyTo || JSON.stringify(doc.audienceIds) !== JSON.stringify(previousDoc?.audienceIds);
1574
- if (contentChanged) {
1575
- const updates = {};
1576
- if (doc.subject !== previousDoc?.subject) {
1577
- updates.name = doc.subject;
1578
- updates.subject = doc.subject;
1579
- }
1580
- if (doc.contentSection?.preheader !== previousDoc?.contentSection?.preheader) {
1581
- updates.preheader = doc.contentSection?.preheader;
1567
+ if (!doc.providerId) {
1568
+ if (!doc.subject || !doc.contentSection?.content) {
1569
+ req.payload.logger.info("Still missing required fields for provider sync");
1570
+ return doc;
1582
1571
  }
1583
- if (JSON.stringify(doc.contentSection?.content) !== JSON.stringify(previousDoc?.contentSection?.content)) {
1584
- updates.content = await convertToEmailSafeHtml(doc.contentSection?.content);
1585
- }
1586
- if (doc.settings?.trackOpens !== previousDoc?.settings?.trackOpens) {
1587
- updates.trackOpens = doc.settings.trackOpens;
1588
- }
1589
- if (doc.settings?.trackClicks !== previousDoc?.settings?.trackClicks) {
1590
- updates.trackClicks = doc.settings.trackClicks;
1572
+ try {
1573
+ req.payload.logger.info("Creating broadcast in provider (deferred from initial create)...");
1574
+ const htmlContent = await convertToEmailSafeHtml(doc.contentSection?.content);
1575
+ if (!htmlContent || htmlContent.trim() === "") {
1576
+ req.payload.logger.info("Skipping provider sync - content is empty after conversion");
1577
+ return doc;
1578
+ }
1579
+ const createData = {
1580
+ name: doc.subject,
1581
+ subject: doc.subject,
1582
+ preheader: doc.contentSection?.preheader,
1583
+ content: htmlContent,
1584
+ trackOpens: doc.settings?.trackOpens,
1585
+ trackClicks: doc.settings?.trackClicks,
1586
+ replyTo: doc.settings?.replyTo || providerConfig.replyTo,
1587
+ audienceIds: doc.audienceIds?.map((a) => a.audienceId)
1588
+ };
1589
+ req.payload.logger.info("Creating broadcast with data:", {
1590
+ name: createData.name,
1591
+ subject: createData.subject,
1592
+ preheader: createData.preheader || "NONE",
1593
+ contentLength: htmlContent ? htmlContent.length : 0,
1594
+ contentPreview: htmlContent ? htmlContent.substring(0, 100) + "..." : "EMPTY",
1595
+ apiUrl: providerConfig.apiUrl,
1596
+ hasToken: !!providerConfig.token
1597
+ });
1598
+ const providerBroadcast = await provider.create(createData);
1599
+ await req.payload.update({
1600
+ collection: "broadcasts",
1601
+ id: doc.id,
1602
+ data: {
1603
+ providerId: providerBroadcast.id,
1604
+ providerData: providerBroadcast.providerData
1605
+ },
1606
+ req
1607
+ });
1608
+ req.payload.logger.info(`Broadcast ${doc.id} created in provider successfully (deferred)`);
1609
+ return {
1610
+ ...doc,
1611
+ providerId: providerBroadcast.id,
1612
+ providerData: providerBroadcast.providerData
1613
+ };
1614
+ } catch (error) {
1615
+ req.payload.logger.error("Raw error from broadcast provider (deferred create):");
1616
+ req.payload.logger.error(error);
1617
+ if (error instanceof Error) {
1618
+ req.payload.logger.error("Error is instance of Error:", {
1619
+ message: error.message,
1620
+ stack: error.stack,
1621
+ name: error.name,
1622
+ ...error.details,
1623
+ ...error.response,
1624
+ ...error.data,
1625
+ ...error.status,
1626
+ ...error.statusText
1627
+ });
1628
+ } else if (typeof error === "string") {
1629
+ req.payload.logger.error("Error is a string:", error);
1630
+ } else if (error && typeof error === "object") {
1631
+ req.payload.logger.error("Error is an object:", JSON.stringify(error, null, 2));
1632
+ } else {
1633
+ req.payload.logger.error("Unknown error type:", typeof error);
1634
+ }
1635
+ req.payload.logger.error("Failed broadcast document (deferred create):", {
1636
+ id: doc.id,
1637
+ subject: doc.subject,
1638
+ hasContent: !!doc.contentSection?.content,
1639
+ contentType: doc.contentSection?.content ? typeof doc.contentSection.content : "none"
1640
+ });
1641
+ return doc;
1591
1642
  }
1592
- if (doc.settings?.replyTo !== previousDoc?.settings?.replyTo) {
1593
- updates.replyTo = doc.settings.replyTo || providerConfig.replyTo;
1643
+ }
1644
+ if (doc.providerId) {
1645
+ const capabilities = provider.getCapabilities();
1646
+ const sendStatus = doc.sendStatus || "draft" /* DRAFT */;
1647
+ if (!capabilities.editableStatuses.includes(sendStatus)) {
1648
+ req.payload.logger.info(`Skipping sync for broadcast in status: ${sendStatus}`);
1649
+ return doc;
1594
1650
  }
1595
- if (JSON.stringify(doc.audienceIds) !== JSON.stringify(previousDoc?.audienceIds)) {
1596
- updates.audienceIds = doc.audienceIds?.map((a) => a.audienceId);
1651
+ const contentChanged = doc.subject !== previousDoc?.subject || doc.contentSection?.preheader !== previousDoc?.contentSection?.preheader || JSON.stringify(doc.contentSection?.content) !== JSON.stringify(previousDoc?.contentSection?.content) || doc.settings?.trackOpens !== previousDoc?.settings?.trackOpens || doc.settings?.trackClicks !== previousDoc?.settings?.trackClicks || doc.settings?.replyTo !== previousDoc?.settings?.replyTo || JSON.stringify(doc.audienceIds) !== JSON.stringify(previousDoc?.audienceIds);
1652
+ if (contentChanged) {
1653
+ const updates = {};
1654
+ if (doc.subject !== previousDoc?.subject) {
1655
+ updates.name = doc.subject;
1656
+ updates.subject = doc.subject;
1657
+ }
1658
+ if (doc.contentSection?.preheader !== previousDoc?.contentSection?.preheader) {
1659
+ updates.preheader = doc.contentSection?.preheader;
1660
+ }
1661
+ if (JSON.stringify(doc.contentSection?.content) !== JSON.stringify(previousDoc?.contentSection?.content)) {
1662
+ updates.content = await convertToEmailSafeHtml(doc.contentSection?.content);
1663
+ }
1664
+ if (doc.settings?.trackOpens !== previousDoc?.settings?.trackOpens) {
1665
+ updates.trackOpens = doc.settings.trackOpens;
1666
+ }
1667
+ if (doc.settings?.trackClicks !== previousDoc?.settings?.trackClicks) {
1668
+ updates.trackClicks = doc.settings.trackClicks;
1669
+ }
1670
+ if (doc.settings?.replyTo !== previousDoc?.settings?.replyTo) {
1671
+ updates.replyTo = doc.settings.replyTo || providerConfig.replyTo;
1672
+ }
1673
+ if (JSON.stringify(doc.audienceIds) !== JSON.stringify(previousDoc?.audienceIds)) {
1674
+ updates.audienceIds = doc.audienceIds?.map((a) => a.audienceId);
1675
+ }
1676
+ req.payload.logger.info("Syncing broadcast updates to provider", {
1677
+ providerId: doc.providerId,
1678
+ updates
1679
+ });
1680
+ await provider.update(doc.providerId, updates);
1681
+ req.payload.logger.info(`Broadcast ${doc.id} synced to provider successfully`);
1682
+ } else {
1683
+ req.payload.logger.info("No content changes to sync to provider");
1597
1684
  }
1598
- req.payload.logger.info("Syncing broadcast updates to provider", {
1599
- providerId: doc.providerId,
1600
- updates
1601
- });
1602
- await provider.update(doc.providerId, updates);
1603
- req.payload.logger.info(`Broadcast ${doc.id} synced to provider successfully`);
1604
- } else {
1605
- req.payload.logger.info("No content changes to sync to provider");
1606
1685
  }
1607
1686
  } catch (error) {
1608
1687
  if (error instanceof Error) {
1609
- req.payload.logger.error("Failed to sync broadcast update to provider:", {
1688
+ req.payload.logger.error("Failed to handle broadcast update operation:", {
1610
1689
  message: error.message,
1611
1690
  stack: error.stack,
1612
1691
  name: error.name,
1613
- // If it's a BroadcastProviderError, it might have additional details
1614
1692
  ...error.details
1615
1693
  });
1616
1694
  } else {
1617
- req.payload.logger.error("Failed to sync broadcast update to provider:", error);
1695
+ req.payload.logger.error("Failed to handle broadcast update operation:", error);
1618
1696
  }
1619
1697
  }
1620
1698
  }