payload-plugin-newsletter 0.16.6 → 0.16.8

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,42 @@
1
+ ## [0.16.8] - 2025-01-29
2
+
3
+ ### Fixed
4
+ - **Handle Empty Content When Creating Broadcasts** - Fixed error when creating broadcasts without content
5
+ - Added null/undefined check in convertToEmailSafeHtml function
6
+ - Skip provider sync when subject or content is missing on create
7
+ - Skip provider sync when content is empty after conversion
8
+ - Prevents "Cannot destructure property 'root' of 'editorState'" error
9
+ - Broadcasts can now be created empty and synced later when content is added
10
+
11
+ ### Technical
12
+ - Updated convertToEmailSafeHtml to accept undefined/null editorState
13
+ - Added pre-sync validation in afterChange hook for create operations
14
+ - Empty broadcasts are saved in Payload but not synced to provider until content is added
15
+
16
+ ## [0.16.7] - 2025-07-29
17
+
18
+ ### Added
19
+ - **Comprehensive Diagnostic Logging** - Added extensive logging to diagnose broadcast sync issues
20
+ - Logs the HTML content conversion process
21
+ - Shows exactly what data is being sent to the Broadcast API (with preview)
22
+ - Displays request URL, method, and body structure
23
+ - Shows API response status and headers
24
+ - Captures and logs all error types (Error objects, strings, JSON responses)
25
+ - Logs raw errors to identify unexpected error formats
26
+
27
+ ### Improved
28
+ - **Better Error Visibility** - Enhanced error handling to capture more details
29
+ - Raw error logging to see the actual error structure
30
+ - Multiple error format handlers (Error, string, object, unknown)
31
+ - Response body parsing for API errors
32
+ - Document context logging when errors occur
33
+ - API request/response details in provider logs
34
+
35
+ ### Technical
36
+ - Added pre-API call logging in afterChange hook
37
+ - Added comprehensive error logging in BroadcastApiProvider
38
+ - Logs help identify if issues are with content, API format, or authentication
39
+
1
40
  ## [0.16.6] - 2025-07-29
2
41
 
3
42
  ### Fixed
@@ -252,29 +252,46 @@ var init_broadcast2 = __esm({
252
252
  async create(data) {
253
253
  try {
254
254
  this.validateRequiredFields(data, ["name", "subject", "content"]);
255
+ const requestBody = {
256
+ broadcast: {
257
+ name: data.name,
258
+ subject: data.subject,
259
+ preheader: data.preheader,
260
+ body: data.content,
261
+ html_body: true,
262
+ track_opens: data.trackOpens ?? true,
263
+ track_clicks: data.trackClicks ?? true,
264
+ reply_to: data.replyTo,
265
+ segment_ids: data.audienceIds
266
+ }
267
+ };
268
+ console.log("[BroadcastApiProvider] Creating broadcast:", {
269
+ url: `${this.apiUrl}/api/v1/broadcasts`,
270
+ method: "POST",
271
+ hasToken: !!this.token,
272
+ tokenLength: this.token?.length,
273
+ body: JSON.stringify(requestBody, null, 2)
274
+ });
255
275
  const response = await fetch(`${this.apiUrl}/api/v1/broadcasts`, {
256
276
  method: "POST",
257
277
  headers: {
258
278
  "Authorization": `Bearer ${this.token}`,
259
279
  "Content-Type": "application/json"
260
280
  },
261
- body: JSON.stringify({
262
- broadcast: {
263
- name: data.name,
264
- subject: data.subject,
265
- preheader: data.preheader,
266
- body: data.content,
267
- html_body: true,
268
- track_opens: data.trackOpens ?? true,
269
- track_clicks: data.trackClicks ?? true,
270
- reply_to: data.replyTo,
271
- segment_ids: data.audienceIds
272
- }
273
- })
281
+ body: JSON.stringify(requestBody)
274
282
  });
283
+ console.log("[BroadcastApiProvider] Response status:", response.status);
284
+ console.log("[BroadcastApiProvider] Response headers:", Object.fromEntries(response.headers.entries()));
275
285
  if (!response.ok) {
276
- const error = await response.text();
277
- throw new Error(`Broadcast API error: ${response.status} - ${error}`);
286
+ const errorText = await response.text();
287
+ console.error("[BroadcastApiProvider] Error response body:", errorText);
288
+ let errorDetails;
289
+ try {
290
+ errorDetails = JSON.parse(errorText);
291
+ console.error("[BroadcastApiProvider] Parsed error:", errorDetails);
292
+ } catch {
293
+ }
294
+ throw new Error(`Broadcast API error: ${response.status} - ${errorText}`);
278
295
  }
279
296
  const result = await response.json();
280
297
  return this.get(result.id.toString());
@@ -943,6 +960,9 @@ var EMAIL_SAFE_CONFIG = {
943
960
  FORBID_ATTR: ["class", "id", "onclick", "onload", "onerror"]
944
961
  };
945
962
  async function convertToEmailSafeHtml(editorState, options) {
963
+ if (!editorState) {
964
+ return "";
965
+ }
946
966
  const rawHtml = await lexicalToEmailHtml(editorState, options?.mediaUrl);
947
967
  const sanitizedHtml = import_isomorphic_dompurify.default.sanitize(rawHtml, EMAIL_SAFE_CONFIG);
948
968
  if (options?.wrapInTemplate) {
@@ -1440,6 +1460,10 @@ var createBroadcastsCollection = (pluginConfig) => {
1440
1460
  async ({ doc, operation, req, previousDoc }) => {
1441
1461
  if (!hasProviders) return doc;
1442
1462
  if (operation === "create") {
1463
+ if (!doc.subject || !doc.contentSection?.content) {
1464
+ req.payload.logger.info("Skipping provider sync - broadcast has no subject or content yet");
1465
+ return doc;
1466
+ }
1443
1467
  try {
1444
1468
  const providerConfig = await getBroadcastConfig(req, pluginConfig);
1445
1469
  if (!providerConfig || !providerConfig.token) {
@@ -1448,8 +1472,13 @@ var createBroadcastsCollection = (pluginConfig) => {
1448
1472
  }
1449
1473
  const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
1450
1474
  const provider = new BroadcastApiProvider2(providerConfig);
1475
+ req.payload.logger.info("Converting content to HTML...");
1451
1476
  const htmlContent = await convertToEmailSafeHtml(doc.contentSection?.content);
1452
- const providerBroadcast = await provider.create({
1477
+ if (!htmlContent || htmlContent.trim() === "") {
1478
+ req.payload.logger.info("Skipping provider sync - content is empty after conversion");
1479
+ return doc;
1480
+ }
1481
+ const createData = {
1453
1482
  name: doc.subject,
1454
1483
  // Use subject as name since we removed the name field
1455
1484
  subject: doc.subject,
@@ -1459,7 +1488,21 @@ var createBroadcastsCollection = (pluginConfig) => {
1459
1488
  trackClicks: doc.settings?.trackClicks,
1460
1489
  replyTo: doc.settings?.replyTo || providerConfig.replyTo,
1461
1490
  audienceIds: doc.audienceIds?.map((a) => a.audienceId)
1491
+ };
1492
+ req.payload.logger.info("Creating broadcast with data:", {
1493
+ name: createData.name,
1494
+ subject: createData.subject,
1495
+ preheader: createData.preheader || "NONE",
1496
+ contentLength: htmlContent ? htmlContent.length : 0,
1497
+ contentPreview: htmlContent ? htmlContent.substring(0, 100) + "..." : "EMPTY",
1498
+ trackOpens: createData.trackOpens,
1499
+ trackClicks: createData.trackClicks,
1500
+ replyTo: createData.replyTo,
1501
+ audienceIds: createData.audienceIds || [],
1502
+ apiUrl: providerConfig.apiUrl,
1503
+ hasToken: !!providerConfig.token
1462
1504
  });
1505
+ const providerBroadcast = await provider.create(createData);
1463
1506
  await req.payload.update({
1464
1507
  collection: "broadcasts",
1465
1508
  id: doc.id,
@@ -1475,17 +1518,34 @@ var createBroadcastsCollection = (pluginConfig) => {
1475
1518
  providerData: providerBroadcast.providerData
1476
1519
  };
1477
1520
  } catch (error) {
1521
+ req.payload.logger.error("Raw error from broadcast provider:");
1522
+ req.payload.logger.error(error);
1478
1523
  if (error instanceof Error) {
1479
- req.payload.logger.error("Failed to create broadcast in provider:", {
1524
+ req.payload.logger.error("Error is instance of Error:", {
1480
1525
  message: error.message,
1481
1526
  stack: error.stack,
1482
1527
  name: error.name,
1483
1528
  // If it's a BroadcastProviderError, it might have additional details
1484
- ...error.details
1529
+ ...error.details,
1530
+ // Check if it's a fetch response error
1531
+ ...error.response,
1532
+ ...error.data,
1533
+ ...error.status,
1534
+ ...error.statusText
1485
1535
  });
1536
+ } else if (typeof error === "string") {
1537
+ req.payload.logger.error("Error is a string:", error);
1538
+ } else if (error && typeof error === "object") {
1539
+ req.payload.logger.error("Error is an object:", JSON.stringify(error, null, 2));
1486
1540
  } else {
1487
- req.payload.logger.error("Failed to create broadcast in provider:", error);
1541
+ req.payload.logger.error("Unknown error type:", typeof error);
1488
1542
  }
1543
+ req.payload.logger.error("Failed broadcast document:", {
1544
+ id: doc.id,
1545
+ subject: doc.subject,
1546
+ hasContent: !!doc.contentSection?.content,
1547
+ contentType: doc.contentSection?.content ? typeof doc.contentSection.content : "none"
1548
+ });
1489
1549
  return doc;
1490
1550
  }
1491
1551
  }