payload-plugin-newsletter 0.16.7 → 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.
@@ -947,6 +947,9 @@ var EMAIL_SAFE_CONFIG = {
947
947
  FORBID_ATTR: ["class", "id", "onclick", "onload", "onerror"]
948
948
  };
949
949
  async function convertToEmailSafeHtml(editorState, options) {
950
+ if (!editorState) {
951
+ return "";
952
+ }
950
953
  const rawHtml = await lexicalToEmailHtml(editorState, options?.mediaUrl);
951
954
  const sanitizedHtml = DOMPurify.sanitize(rawHtml, EMAIL_SAFE_CONFIG);
952
955
  if (options?.wrapInTemplate) {
@@ -1444,6 +1447,10 @@ var createBroadcastsCollection = (pluginConfig) => {
1444
1447
  async ({ doc, operation, req, previousDoc }) => {
1445
1448
  if (!hasProviders) return doc;
1446
1449
  if (operation === "create") {
1450
+ if (!doc.subject || !doc.contentSection?.content) {
1451
+ req.payload.logger.info("Skipping provider sync - broadcast has no subject or content yet");
1452
+ return doc;
1453
+ }
1447
1454
  try {
1448
1455
  const providerConfig = await getBroadcastConfig(req, pluginConfig);
1449
1456
  if (!providerConfig || !providerConfig.token) {
@@ -1454,6 +1461,10 @@ var createBroadcastsCollection = (pluginConfig) => {
1454
1461
  const provider = new BroadcastApiProvider2(providerConfig);
1455
1462
  req.payload.logger.info("Converting content to HTML...");
1456
1463
  const htmlContent = await convertToEmailSafeHtml(doc.contentSection?.content);
1464
+ if (!htmlContent || htmlContent.trim() === "") {
1465
+ req.payload.logger.info("Skipping provider sync - content is empty after conversion");
1466
+ return doc;
1467
+ }
1457
1468
  const createData = {
1458
1469
  name: doc.subject,
1459
1470
  // Use subject as name since we removed the name field
@@ -1525,7 +1536,7 @@ var createBroadcastsCollection = (pluginConfig) => {
1525
1536
  return doc;
1526
1537
  }
1527
1538
  }
1528
- if (operation === "update" && doc.providerId) {
1539
+ if (operation === "update") {
1529
1540
  req.payload.logger.info("Broadcast afterChange update hook triggered", {
1530
1541
  operation,
1531
1542
  hasProviderId: !!doc.providerId,
@@ -1540,57 +1551,135 @@ var createBroadcastsCollection = (pluginConfig) => {
1540
1551
  }
1541
1552
  const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
1542
1553
  const provider = new BroadcastApiProvider2(providerConfig);
1543
- const capabilities = provider.getCapabilities();
1544
- const sendStatus = doc.sendStatus || "draft" /* DRAFT */;
1545
- if (!capabilities.editableStatuses.includes(sendStatus)) {
1546
- req.payload.logger.info(`Skipping sync for broadcast in status: ${sendStatus}`);
1547
- return doc;
1548
- }
1549
- 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);
1550
- if (contentChanged) {
1551
- const updates = {};
1552
- if (doc.subject !== previousDoc?.subject) {
1553
- updates.name = doc.subject;
1554
- updates.subject = doc.subject;
1555
- }
1556
- if (doc.contentSection?.preheader !== previousDoc?.contentSection?.preheader) {
1557
- updates.preheader = doc.contentSection?.preheader;
1554
+ if (!doc.providerId) {
1555
+ if (!doc.subject || !doc.contentSection?.content) {
1556
+ req.payload.logger.info("Still missing required fields for provider sync");
1557
+ return doc;
1558
1558
  }
1559
- if (JSON.stringify(doc.contentSection?.content) !== JSON.stringify(previousDoc?.contentSection?.content)) {
1560
- updates.content = await convertToEmailSafeHtml(doc.contentSection?.content);
1561
- }
1562
- if (doc.settings?.trackOpens !== previousDoc?.settings?.trackOpens) {
1563
- updates.trackOpens = doc.settings.trackOpens;
1564
- }
1565
- if (doc.settings?.trackClicks !== previousDoc?.settings?.trackClicks) {
1566
- updates.trackClicks = doc.settings.trackClicks;
1559
+ try {
1560
+ req.payload.logger.info("Creating broadcast in provider (deferred from initial create)...");
1561
+ const htmlContent = await convertToEmailSafeHtml(doc.contentSection?.content);
1562
+ if (!htmlContent || htmlContent.trim() === "") {
1563
+ req.payload.logger.info("Skipping provider sync - content is empty after conversion");
1564
+ return doc;
1565
+ }
1566
+ const createData = {
1567
+ name: doc.subject,
1568
+ subject: doc.subject,
1569
+ preheader: doc.contentSection?.preheader,
1570
+ content: htmlContent,
1571
+ trackOpens: doc.settings?.trackOpens,
1572
+ trackClicks: doc.settings?.trackClicks,
1573
+ replyTo: doc.settings?.replyTo || providerConfig.replyTo,
1574
+ audienceIds: doc.audienceIds?.map((a) => a.audienceId)
1575
+ };
1576
+ req.payload.logger.info("Creating broadcast with data:", {
1577
+ name: createData.name,
1578
+ subject: createData.subject,
1579
+ preheader: createData.preheader || "NONE",
1580
+ contentLength: htmlContent ? htmlContent.length : 0,
1581
+ contentPreview: htmlContent ? htmlContent.substring(0, 100) + "..." : "EMPTY",
1582
+ apiUrl: providerConfig.apiUrl,
1583
+ hasToken: !!providerConfig.token
1584
+ });
1585
+ const providerBroadcast = await provider.create(createData);
1586
+ await req.payload.update({
1587
+ collection: "broadcasts",
1588
+ id: doc.id,
1589
+ data: {
1590
+ providerId: providerBroadcast.id,
1591
+ providerData: providerBroadcast.providerData
1592
+ },
1593
+ req
1594
+ });
1595
+ req.payload.logger.info(`Broadcast ${doc.id} created in provider successfully (deferred)`);
1596
+ return {
1597
+ ...doc,
1598
+ providerId: providerBroadcast.id,
1599
+ providerData: providerBroadcast.providerData
1600
+ };
1601
+ } catch (error) {
1602
+ req.payload.logger.error("Raw error from broadcast provider (deferred create):");
1603
+ req.payload.logger.error(error);
1604
+ if (error instanceof Error) {
1605
+ req.payload.logger.error("Error is instance of Error:", {
1606
+ message: error.message,
1607
+ stack: error.stack,
1608
+ name: error.name,
1609
+ ...error.details,
1610
+ ...error.response,
1611
+ ...error.data,
1612
+ ...error.status,
1613
+ ...error.statusText
1614
+ });
1615
+ } else if (typeof error === "string") {
1616
+ req.payload.logger.error("Error is a string:", error);
1617
+ } else if (error && typeof error === "object") {
1618
+ req.payload.logger.error("Error is an object:", JSON.stringify(error, null, 2));
1619
+ } else {
1620
+ req.payload.logger.error("Unknown error type:", typeof error);
1621
+ }
1622
+ req.payload.logger.error("Failed broadcast document (deferred create):", {
1623
+ id: doc.id,
1624
+ subject: doc.subject,
1625
+ hasContent: !!doc.contentSection?.content,
1626
+ contentType: doc.contentSection?.content ? typeof doc.contentSection.content : "none"
1627
+ });
1628
+ return doc;
1567
1629
  }
1568
- if (doc.settings?.replyTo !== previousDoc?.settings?.replyTo) {
1569
- updates.replyTo = doc.settings.replyTo || providerConfig.replyTo;
1630
+ }
1631
+ if (doc.providerId) {
1632
+ const capabilities = provider.getCapabilities();
1633
+ const sendStatus = doc.sendStatus || "draft" /* DRAFT */;
1634
+ if (!capabilities.editableStatuses.includes(sendStatus)) {
1635
+ req.payload.logger.info(`Skipping sync for broadcast in status: ${sendStatus}`);
1636
+ return doc;
1570
1637
  }
1571
- if (JSON.stringify(doc.audienceIds) !== JSON.stringify(previousDoc?.audienceIds)) {
1572
- updates.audienceIds = doc.audienceIds?.map((a) => a.audienceId);
1638
+ 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);
1639
+ if (contentChanged) {
1640
+ const updates = {};
1641
+ if (doc.subject !== previousDoc?.subject) {
1642
+ updates.name = doc.subject;
1643
+ updates.subject = doc.subject;
1644
+ }
1645
+ if (doc.contentSection?.preheader !== previousDoc?.contentSection?.preheader) {
1646
+ updates.preheader = doc.contentSection?.preheader;
1647
+ }
1648
+ if (JSON.stringify(doc.contentSection?.content) !== JSON.stringify(previousDoc?.contentSection?.content)) {
1649
+ updates.content = await convertToEmailSafeHtml(doc.contentSection?.content);
1650
+ }
1651
+ if (doc.settings?.trackOpens !== previousDoc?.settings?.trackOpens) {
1652
+ updates.trackOpens = doc.settings.trackOpens;
1653
+ }
1654
+ if (doc.settings?.trackClicks !== previousDoc?.settings?.trackClicks) {
1655
+ updates.trackClicks = doc.settings.trackClicks;
1656
+ }
1657
+ if (doc.settings?.replyTo !== previousDoc?.settings?.replyTo) {
1658
+ updates.replyTo = doc.settings.replyTo || providerConfig.replyTo;
1659
+ }
1660
+ if (JSON.stringify(doc.audienceIds) !== JSON.stringify(previousDoc?.audienceIds)) {
1661
+ updates.audienceIds = doc.audienceIds?.map((a) => a.audienceId);
1662
+ }
1663
+ req.payload.logger.info("Syncing broadcast updates to provider", {
1664
+ providerId: doc.providerId,
1665
+ updates
1666
+ });
1667
+ await provider.update(doc.providerId, updates);
1668
+ req.payload.logger.info(`Broadcast ${doc.id} synced to provider successfully`);
1669
+ } else {
1670
+ req.payload.logger.info("No content changes to sync to provider");
1573
1671
  }
1574
- req.payload.logger.info("Syncing broadcast updates to provider", {
1575
- providerId: doc.providerId,
1576
- updates
1577
- });
1578
- await provider.update(doc.providerId, updates);
1579
- req.payload.logger.info(`Broadcast ${doc.id} synced to provider successfully`);
1580
- } else {
1581
- req.payload.logger.info("No content changes to sync to provider");
1582
1672
  }
1583
1673
  } catch (error) {
1584
1674
  if (error instanceof Error) {
1585
- req.payload.logger.error("Failed to sync broadcast update to provider:", {
1675
+ req.payload.logger.error("Failed to handle broadcast update operation:", {
1586
1676
  message: error.message,
1587
1677
  stack: error.stack,
1588
1678
  name: error.name,
1589
- // If it's a BroadcastProviderError, it might have additional details
1590
1679
  ...error.details
1591
1680
  });
1592
1681
  } else {
1593
- req.payload.logger.error("Failed to sync broadcast update to provider:", error);
1682
+ req.payload.logger.error("Failed to handle broadcast update operation:", error);
1594
1683
  }
1595
1684
  }
1596
1685
  }