@infuro/cms-core 1.0.63 → 1.0.65

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.
Files changed (50) hide show
  1. package/dist/admin.cjs +183 -65
  2. package/dist/admin.js +183 -65
  3. package/dist/api.cjs +40 -40
  4. package/dist/api.d.cts +2 -0
  5. package/dist/api.d.ts +2 -0
  6. package/dist/api.js +8 -8
  7. package/dist/{chunk-KAOHOHCA.js → chunk-6YOQ7G5O.js} +92 -51
  8. package/dist/{chunk-BWOITUNI.js → chunk-ACBN6UWZ.js} +320 -81
  9. package/dist/chunk-BXAKL2TF.cjs +84 -0
  10. package/dist/{chunk-7L556RGL.cjs → chunk-GLD263KW.cjs} +3 -3
  11. package/dist/{chunk-EWXG4E74.cjs → chunk-NIRYYJIJ.cjs} +330 -91
  12. package/dist/{chunk-MWEK7N3F.js → chunk-OPJEV44S.js} +2 -2
  13. package/dist/{chunk-DTUL3Q5L.js → chunk-RDEVZMO5.js} +36 -20
  14. package/dist/{chunk-77YWLP4X.js → chunk-SANKKGB3.js} +68 -32
  15. package/dist/chunk-THL5JDWJ.cjs +101 -0
  16. package/dist/{chunk-RXTUSF3R.js → chunk-TU23GJPJ.js} +2 -2
  17. package/dist/{chunk-JLDHK2QE.cjs → chunk-TZEMLHSP.cjs} +20 -14
  18. package/dist/{chunk-RHYVNRYG.cjs → chunk-V6EYAC7X.cjs} +38 -22
  19. package/dist/{chunk-YVP4NQII.cjs → chunk-VM6OVUUM.cjs} +93 -52
  20. package/dist/{chunk-MXABMVF7.cjs → chunk-XFDIIVZB.cjs} +4 -4
  21. package/dist/chunk-XJNNOSJR.js +98 -0
  22. package/dist/chunk-YEAXE4U2.js +77 -0
  23. package/dist/{chunk-CJEOH6QC.cjs → chunk-YHEITFHR.cjs} +112 -76
  24. package/dist/{chunk-3VZAAQUV.js → chunk-YRCKEGL2.js} +20 -14
  25. package/dist/{email-queue-VTYL2KFA.cjs → email-queue-4OY45JIU.cjs} +7 -7
  26. package/dist/{email-queue-YPRSVG56.js → email-queue-HGXB2FIS.js} +3 -3
  27. package/dist/{email-service-ATCPJFWG.cjs → email-service-5O24BSFR.cjs} +7 -7
  28. package/dist/{email-service-DPKVQOKP.js → email-service-ADDF52PJ.js} +2 -2
  29. package/dist/{emit-order-notification-trigger-WI4HGMKH.cjs → emit-order-notification-trigger-DR74TQXN.cjs} +4 -4
  30. package/dist/{emit-order-notification-trigger-XVG2B5ZF.js → emit-order-notification-trigger-UCKJHDQK.js} +2 -2
  31. package/dist/{erp-order-invoice-3UGWLICU.js → erp-order-invoice-H6HCJ7YS.js} +2 -2
  32. package/dist/{erp-order-invoice-KJYJNWMG.cjs → erp-order-invoice-YUSPZ7CE.cjs} +6 -6
  33. package/dist/index.cjs +279 -265
  34. package/dist/index.d.cts +46 -22
  35. package/dist/index.d.ts +46 -22
  36. package/dist/index.js +43 -29
  37. package/dist/migrations/1783000000000-AddOrderPendingProcessingCompletedTriggers.ts +15 -39
  38. package/dist/migrations/1783300000000-SeedOrderNotificationTriggersAndTemplates.ts +155 -0
  39. package/dist/{order-completion-otp-handlers-WGM7HWG4.js → order-completion-otp-handlers-CH22ZRAI.js} +5 -5
  40. package/dist/{order-completion-otp-handlers-IMMQGHDR.cjs → order-completion-otp-handlers-RW5RSXH3.cjs} +7 -7
  41. package/dist/{order-notification-dispatcher-JKFQJYGG.js → order-notification-dispatcher-3TXUAJ7L.js} +6 -6
  42. package/dist/{order-notification-dispatcher-5TUFCDU7.cjs → order-notification-dispatcher-Y7NZAALH.cjs} +11 -11
  43. package/dist/{pg-boss-service-L6MTF4EQ.cjs → pg-boss-service-BDGOKM2T.cjs} +3 -3
  44. package/dist/pg-boss-service-WCBJD4JB.js +2 -0
  45. package/package.json +1 -1
  46. package/dist/chunk-AYWDQFJZ.js +0 -27
  47. package/dist/chunk-GO7PPYNU.js +0 -76
  48. package/dist/chunk-UEE4PTTB.cjs +0 -30
  49. package/dist/chunk-XQ3QUHWR.cjs +0 -83
  50. package/dist/pg-boss-service-4XF2TQ2E.js +0 -2
@@ -1,26 +1,23 @@
1
1
  'use strict';
2
2
 
3
- var chunkUEE4PTTB_cjs = require('./chunk-UEE4PTTB.cjs');
3
+ var chunkBXAKL2TF_cjs = require('./chunk-BXAKL2TF.cjs');
4
4
  var chunkUSNT2KNT_cjs = require('./chunk-USNT2KNT.cjs');
5
5
 
6
6
  // src/lib/emit-order-notification-trigger.ts
7
- function maskPhone(raw) {
8
- const digits = String(raw ?? "").replace(/\D/g, "");
9
- if (digits.length <= 4) return "(none)";
10
- return `***${digits.slice(-4)}`;
11
- }
12
- chunkUSNT2KNT_cjs.__name(maskPhone, "maskPhone");
13
7
  async function emitOrderNotificationTrigger(triggerKey, orderId, deps, extra) {
14
8
  if (!deps.entityMap.orders) {
15
- console.warn("[notification-triggers] skip emit: orders entity missing from entityMap", {
9
+ chunkBXAKL2TF_cjs.notifyLog.skip("TRIGGER", "orders entity missing from entityMap", {
16
10
  triggerKey,
17
11
  orderId
18
12
  });
19
13
  return;
20
14
  }
21
- const listenerCount = chunkUEE4PTTB_cjs.notificationTriggerEmitter.listenerCount("__any__");
15
+ const listenerCount = chunkBXAKL2TF_cjs.notificationTriggerEmitter.listenerCount("__any__");
22
16
  if (listenerCount === 0) {
23
- console.warn("[notification-triggers] no WhatsApp dispatcher listener \u2014 ensure createCmsApiHandler passes getCms (initWhatsappTriggerDispatcher)");
17
+ chunkBXAKL2TF_cjs.notifyLog.skip("TRIGGER", "no dispatcher listener \u2014 will try direct dispatch (pass getCms to createCmsApiHandler)", {
18
+ triggerKey,
19
+ orderId
20
+ });
24
21
  }
25
22
  const orderRepo = deps.dataSource.getRepository(deps.entityMap.orders);
26
23
  const fullOrder = await orderRepo.findOne({
@@ -33,7 +30,7 @@ async function emitOrderNotificationTrigger(triggerKey, orderId, deps, extra) {
33
30
  ]
34
31
  });
35
32
  if (!fullOrder) {
36
- console.warn("[notification-triggers] skip emit: order not found", {
33
+ chunkBXAKL2TF_cjs.notifyLog.skip("TRIGGER", "order not found", {
37
34
  triggerKey,
38
35
  orderId
39
36
  });
@@ -41,15 +38,18 @@ async function emitOrderNotificationTrigger(triggerKey, orderId, deps, extra) {
41
38
  }
42
39
  const fo = fullOrder;
43
40
  const phone = fo.contact?.phone ?? null;
44
- console.log("[notification-triggers] emit", {
41
+ chunkBXAKL2TF_cjs.notifyLog.trigger("emit", {
45
42
  triggerKey,
46
43
  orderId,
47
44
  orderNumber: fo.orderNumber ?? null,
48
- phone: maskPhone(phone),
49
- listeners: listenerCount
45
+ phone: chunkBXAKL2TF_cjs.maskNotifyPhone(phone),
46
+ listeners: listenerCount,
47
+ vendorId: fo.vendorId ?? null,
48
+ source: extra?.source ?? "api"
50
49
  });
51
50
  if (!phone?.trim()) {
52
- console.warn("[notification-triggers] order contact has no phone \u2014 WhatsApp will be skipped", {
51
+ chunkBXAKL2TF_cjs.notifyLog.skip("WHATSAPP", "order contact has no phone", {
52
+ triggerKey,
53
53
  orderId
54
54
  });
55
55
  }
@@ -91,28 +91,44 @@ async function emitOrderNotificationTrigger(triggerKey, orderId, deps, extra) {
91
91
  refundAmount: resolvedRefundAmount
92
92
  };
93
93
  if (listenerCount === 0) {
94
+ chunkBXAKL2TF_cjs.notifyLog.trigger("direct dispatch (no in-process listener)", {
95
+ triggerKey,
96
+ orderId
97
+ });
94
98
  try {
95
- const { dispatchOrderNotificationDirectly } = await import('./order-notification-dispatcher-5TUFCDU7.cjs');
99
+ const { dispatchOrderNotificationDirectly } = await import('./order-notification-dispatcher-Y7NZAALH.cjs');
96
100
  await dispatchOrderNotificationDirectly(triggerKey, triggerPayload, deps.dataSource, deps.entityMap);
97
101
  } catch (err) {
98
- console.error("[notification-triggers] direct dispatch failed", {
102
+ chunkBXAKL2TF_cjs.notifyLog.error("TRIGGER", "direct dispatch failed", {
99
103
  triggerKey,
100
104
  orderId,
101
- err
105
+ error: err instanceof Error ? err.message : String(err),
106
+ stack: err instanceof Error ? err.stack : void 0
102
107
  });
103
108
  }
104
109
  } else {
105
- chunkUEE4PTTB_cjs.notificationTriggerEmitter.emitTrigger(triggerKey, triggerPayload);
110
+ chunkBXAKL2TF_cjs.notifyLog.trigger("emit to dispatcher listener", {
111
+ triggerKey,
112
+ orderId,
113
+ listeners: listenerCount
114
+ });
115
+ chunkBXAKL2TF_cjs.notificationTriggerEmitter.emitTrigger(triggerKey, triggerPayload);
106
116
  }
107
117
  }
108
118
  chunkUSNT2KNT_cjs.__name(emitOrderNotificationTrigger, "emitOrderNotificationTrigger");
109
119
  function fireOrderNotificationTrigger(triggerKey, orderId, deps, extra) {
110
- console.log("[notification-triggers] fire", {
120
+ chunkBXAKL2TF_cjs.notifyLog.trigger("FIRE", {
111
121
  triggerKey,
112
- orderId
122
+ orderId,
123
+ source: extra?.source ?? "api"
113
124
  });
114
125
  void emitOrderNotificationTrigger(triggerKey, orderId, deps, extra).catch((err) => {
115
- console.error("[notification-triggers]", triggerKey, orderId, err);
126
+ chunkBXAKL2TF_cjs.notifyLog.error("TRIGGER", "fire failed", {
127
+ triggerKey,
128
+ orderId,
129
+ error: err instanceof Error ? err.message : String(err),
130
+ stack: err instanceof Error ? err.stack : void 0
131
+ });
116
132
  });
117
133
  }
118
134
  chunkUSNT2KNT_cjs.__name(fireOrderNotificationTrigger, "fireOrderNotificationTrigger");
@@ -17,41 +17,65 @@ function escapeHtml(s) {
17
17
  chunkUSNT2KNT_cjs.__name(escapeHtml, "escapeHtml");
18
18
  function socialLinkInnerHtml(s) {
19
19
  if (s.iconUrl?.trim()) {
20
- return `<img src="${escapeHtml(s.iconUrl.trim())}" alt="" width="20" height="20" style="display:inline-block;vertical-align:middle;border:0;" />`;
20
+ return `<img src="${escapeHtml(s.iconUrl.trim())}" alt="" width="22" height="22" style="display:block;border:0;border-radius:4px;" />`;
21
21
  }
22
- const label = s.icon && s.icon.trim() || "\u{1F517}";
23
- return escapeHtml(label);
22
+ const label = s.icon && s.icon.trim() || "\u2022";
23
+ return `<span style="display:inline-block;width:28px;height:28px;line-height:28px;text-align:center;border-radius:999px;background:#ffffff;color:#1e293b;font-size:14px;">${escapeHtml(label)}</span>`;
24
24
  }
25
25
  chunkUSNT2KNT_cjs.__name(socialLinkInnerHtml, "socialLinkInnerHtml");
26
- function supportLinesHtml(supportEmail, supportPhone) {
27
- const parts = [];
28
- if (supportEmail) {
29
- parts.push(`<a href="mailto:${escapeHtml(supportEmail)}" style="color:#6b7280;text-decoration:none;font-size:13px;">${escapeHtml(supportEmail)}</a>`);
30
- }
31
- if (supportPhone) {
32
- parts.push(`<span style="color:#6b7280;font-size:13px;">${escapeHtml(supportPhone)}</span>`);
33
- }
34
- return parts.join('<span style="color:#d1d5db;padding:0 8px;">\xB7</span>');
35
- }
36
- chunkUSNT2KNT_cjs.__name(supportLinesHtml, "supportLinesHtml");
37
26
  function renderLayout(options) {
38
27
  const { bodyHtml, companyDetails } = options;
39
- const { logoUrl, companyName, supportEmail, supportPhone, socialLinks, footerDisclaimer, followUsTitle = "Follow Us" } = companyDetails;
28
+ const { logoUrl, companyName, supportEmail, supportPhone, companyAddress, socialLinks, footerDisclaimer, followUsTitle = "Follow Us" } = companyDetails;
40
29
  const brand = (companyName || "Store").trim();
30
+ const year = (/* @__PURE__ */ new Date()).getFullYear();
31
+ const slate = "#0f172a";
32
+ const slateSoft = "#1e293b";
41
33
  const accent = "#ea580c";
42
- const logoHtml = logoUrl ? `<img src="${escapeHtml(logoUrl)}" alt="${escapeHtml(brand)}" width="160" style="max-height:56px;max-width:180px;height:auto;width:auto;display:block;border:0;margin:0 auto;" />` : `<div style="font-size:22px;font-weight:700;letter-spacing:-0.02em;color:#111827;">${escapeHtml(brand)}</div>`;
34
+ const accentSoft = "#ffedd5";
35
+ const pageBg = "#eef2f7";
36
+ const muted = "#64748b";
37
+ const border = "#e2e8f0";
38
+ const logoBlock = logoUrl ? `<table role="presentation" cellpadding="0" cellspacing="0" style="margin:0 auto;border-collapse:collapse;">
39
+ <tr>
40
+ <td align="center" style="background:#ffffff;border-radius:14px;padding:14px 22px;box-shadow:0 8px 24px rgba(15,23,42,0.18);">
41
+ <img src="${escapeHtml(logoUrl)}" alt="${escapeHtml(brand)}" width="148" style="max-height:52px;max-width:148px;height:auto;width:auto;display:block;border:0;margin:0 auto;" />
42
+ </td>
43
+ </tr>
44
+ </table>` : `<div style="font-family:Georgia,'Times New Roman',serif;font-size:26px;font-weight:700;letter-spacing:-0.02em;color:#ffffff;">${escapeHtml(brand)}</div>`;
43
45
  const hasSocial = Boolean(socialLinks?.length);
44
- const socialRowHtml = hasSocial && socialLinks ? `<div style="margin-top:12px;text-align:center;font-size:0;line-height:0;">${socialLinks.map((s) => `<a href="${escapeHtml(s.url)}" style="display:inline-block;margin:0 8px;text-decoration:none;color:#374151;font-size:18px;line-height:1;vertical-align:middle;">${socialLinkInnerHtml(s)}</a>`).join("")}</div>` : "";
45
- const followTitleHtml = hasSocial && followUsTitle ? `<div style="font-size:12px;font-weight:600;color:#9ca3af;text-transform:uppercase;letter-spacing:0.06em;margin:0 0 4px 0;">${escapeHtml(followUsTitle)}</div>` : "";
46
- const supportHtml = supportLinesHtml(supportEmail, supportPhone);
47
- const disclaimerBlock = footerDisclaimer ? `<div style="margin-top:16px;font-size:11px;line-height:1.5;color:#9ca3af;">${escapeHtml(footerDisclaimer).replace(/\n/g, "<br/>")}</div>` : "";
46
+ const socialRowHtml = hasSocial && socialLinks ? `<table role="presentation" cellpadding="0" cellspacing="0" style="margin:14px auto 0 auto;border-collapse:collapse;">
47
+ <tr>
48
+ ${socialLinks.map((s) => `<td style="padding:0 6px;">
49
+ <a href="${escapeHtml(s.url)}" style="display:inline-block;text-decoration:none;border:1px solid ${border};border-radius:999px;padding:6px;background:#ffffff;">
50
+ ${socialLinkInnerHtml(s)}
51
+ </a>
52
+ </td>`).join("")}
53
+ </tr>
54
+ </table>` : "";
55
+ const followTitleHtml = hasSocial && followUsTitle ? `<div style="font-size:11px;font-weight:700;color:${muted};text-transform:uppercase;letter-spacing:0.08em;margin:0;">${escapeHtml(followUsTitle)}</div>` : "";
56
+ const contactRows = [];
57
+ if (supportEmail) {
58
+ contactRows.push(`<a href="mailto:${escapeHtml(supportEmail)}" style="color:${slateSoft};text-decoration:none;font-size:13px;font-weight:500;">${escapeHtml(supportEmail)}</a>`);
59
+ }
60
+ if (supportPhone) {
61
+ contactRows.push(`<span style="color:${muted};font-size:13px;">${escapeHtml(supportPhone)}</span>`);
62
+ }
63
+ if (companyAddress?.trim()) {
64
+ contactRows.push(`<span style="color:${muted};font-size:12px;line-height:1.5;display:inline-block;max-width:360px;">${escapeHtml(companyAddress.trim()).replace(/\n/g, "<br/>")}</span>`);
65
+ }
66
+ const contactHtml = contactRows.length ? `<div style="margin-top:12px;line-height:1.7;">${contactRows.join("<br/>")}</div>` : "";
67
+ const disclaimerBlock = footerDisclaimer ? `<div style="margin-top:14px;font-size:11px;line-height:1.55;color:#94a3b8;max-width:420px;margin-left:auto;margin-right:auto;">${escapeHtml(footerDisclaimer).replace(/\n/g, "<br/>")}</div>` : "";
48
68
  const responsiveCss = `
49
69
  @media only screen and (max-width: 620px) {
50
- .email-shell { padding: 16px 10px !important; }
51
- .email-card { border-radius: 12px !important; }
52
- .email-body { padding: 24px 18px !important; }
53
- .email-header { padding: 20px 18px !important; }
54
- }
70
+ .email-shell { padding: 12px 8px !important; }
71
+ .email-header { padding: 28px 18px 24px 18px !important; }
72
+ .email-body { padding: 26px 18px 8px 18px !important; }
73
+ .email-footer { padding: 22px 18px 28px 18px !important; }
74
+ .email-accent-label { display: none !important; }
75
+ }
76
+ .email-body p { margin: 0 0 14px 0 !important; }
77
+ .email-body h1, .email-body h2, .email-body h3 { margin: 0 0 12px 0 !important; color: ${slate} !important; }
78
+ .email-body a { color: ${accent} !important; }
55
79
  `;
56
80
  return `<!DOCTYPE html>
57
81
  <html lang="en">
@@ -60,39 +84,56 @@ function renderLayout(options) {
60
84
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
61
85
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
62
86
  <title>${escapeHtml(brand)}</title>
87
+ <!--[if mso]>
88
+ <style type="text/css">
89
+ body, table, td { font-family: Arial, Helvetica, sans-serif !important; }
90
+ </style>
91
+ <![endif]-->
63
92
  <style type="text/css">${responsiveCss}</style>
64
93
  </head>
65
- <body style="margin:0;padding:0;background:#f3f4f6;-webkit-font-smoothing:antialiased;">
66
- <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background:#f3f4f6;border-collapse:collapse;">
94
+ <body style="margin:0;padding:0;background:${pageBg};-webkit-font-smoothing:antialiased;">
95
+ <div style="display:none;max-height:0;overflow:hidden;opacity:0;color:transparent;mso-hide:all;">
96
+ Update from ${escapeHtml(brand)}
97
+ </div>
98
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background:${pageBg};border-collapse:collapse;">
67
99
  <tr>
68
- <td class="email-shell" align="center" style="padding:32px 16px;">
69
- <table role="presentation" class="email-card" width="100%" cellpadding="0" cellspacing="0" style="max-width:600px;background:#ffffff;border-radius:16px;overflow:hidden;border:1px solid #e5e7eb;border-collapse:collapse;">
70
- <tr>
71
- <td class="email-header" align="center" style="padding:28px 32px 20px 32px;background:#ffffff;">
72
- ${logoHtml}
73
- ${logoUrl && companyName ? `<div style="margin-top:10px;font-size:13px;color:#6b7280;">${escapeHtml(companyName)}</div>` : ""}
74
- </td>
75
- </tr>
76
- <tr>
77
- <td style="height:4px;line-height:4px;font-size:0;background:${accent};">&nbsp;</td>
78
- </tr>
79
- <tr>
80
- <td class="email-body" style="padding:28px 32px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:15px;line-height:1.65;color:#1f2937;">
81
- ${bodyHtml}
82
- </td>
83
- </tr>
100
+ <td class="email-shell" align="center" style="padding:40px 16px;">
101
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="max-width:600px;border-collapse:collapse;">
84
102
  <tr>
85
- <td style="padding:0 32px;">
86
- <div style="border-top:1px solid #e5e7eb;line-height:0;font-size:0;">&nbsp;</div>
103
+ <td style="background:#ffffff;border-radius:18px;overflow:hidden;border:1px solid ${border};box-shadow:0 12px 40px rgba(15,23,42,0.08);">
104
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="border-collapse:collapse;">
105
+ <tr>
106
+ <td class="email-header" align="center" style="padding:36px 32px 30px 32px;background:linear-gradient(165deg, ${slate} 0%, ${slateSoft} 100%);background-color:${slate};">
107
+ <div class="email-accent-label" style="display:inline-block;margin:0 0 18px 0;padding:5px 12px;border-radius:999px;background:rgba(234,88,12,0.18);border:1px solid rgba(251,146,60,0.35);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:11px;font-weight:600;letter-spacing:0.06em;text-transform:uppercase;color:${accentSoft};">
108
+ ${escapeHtml(brand)}
109
+ </div>
110
+ ${logoBlock}
111
+ ${logoUrl ? `<div style="margin-top:16px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:13px;color:#94a3b8;">${escapeHtml(brand)}</div>` : ""}
112
+ </td>
113
+ </tr>
114
+ <tr>
115
+ <td style="height:5px;line-height:5px;font-size:0;background:linear-gradient(90deg, ${accent} 0%, #f59e0b 55%, #fb923c 100%);background-color:${accent};">&nbsp;</td>
116
+ </tr>
117
+ <tr>
118
+ <td class="email-body" style="padding:32px 36px 12px 36px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:15px;line-height:1.7;color:#334155;background:#ffffff;">
119
+ ${bodyHtml}
120
+ </td>
121
+ </tr>
122
+ <tr>
123
+ <td class="email-footer" align="center" style="padding:24px 32px 32px 32px;background:#f8fafc;border-top:1px solid ${border};font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;">
124
+ ${followTitleHtml}
125
+ ${socialRowHtml}
126
+ ${contactHtml}
127
+ <div style="margin-top:18px;font-size:12px;color:#94a3b8;">\xA9 ${year} ${escapeHtml(brand)}. All rights reserved.</div>
128
+ ${disclaimerBlock}
129
+ </td>
130
+ </tr>
131
+ </table>
87
132
  </td>
88
133
  </tr>
89
134
  <tr>
90
- <td align="center" style="padding:20px 32px 28px 32px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;">
91
- ${followTitleHtml}
92
- ${socialRowHtml}
93
- ${supportHtml ? `<div style="margin-top:14px;">${supportHtml}</div>` : ""}
94
- <div style="margin-top:12px;font-size:12px;color:#9ca3af;">\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} ${escapeHtml(brand)}</div>
95
- ${disclaimerBlock}
135
+ <td align="center" style="padding:18px 8px 0 8px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:11px;line-height:1.5;color:#94a3b8;">
136
+ You\u2019re receiving this because of activity on your ${escapeHtml(brand)} account.
96
137
  </td>
97
138
  </tr>
98
139
  </table>
@@ -700,7 +741,7 @@ function renderEmail(templateName, ctx, options) {
700
741
  chunkUSNT2KNT_cjs.__name(renderEmail, "renderEmail");
701
742
 
702
743
  // src/plugins/email/email-service.ts
703
- var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-YVP4NQII.cjs', document.baseURI).href)));
744
+ var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-VM6OVUUM.cjs', document.baseURI).href)));
704
745
  var MailComposer = require2("nodemailer/lib/mail-composer");
705
746
  var SES_REGIONS_WITHOUT_SMTP = /* @__PURE__ */ new Set([
706
747
  "af-south-1",
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk7L556RGL_cjs = require('./chunk-7L556RGL.cjs');
3
+ var chunkGLD263KW_cjs = require('./chunk-GLD263KW.cjs');
4
4
  var chunkUSNT2KNT_cjs = require('./chunk-USNT2KNT.cjs');
5
5
 
6
6
  // src/plugins/email/email-queue.ts
@@ -50,13 +50,13 @@ async function resolveInvoiceAttachmentForJob(cms, payload, options) {
50
50
  invoiceAttached: false
51
51
  };
52
52
  const o = order;
53
- if (!chunk7L556RGL_cjs.isOrderEligibleForInvoiceEmail(o.status, o.orderKind)) {
53
+ if (!chunkGLD263KW_cjs.isOrderEligibleForInvoiceEmail(o.status, o.orderKind)) {
54
54
  return {
55
55
  attachments: payload.attachments,
56
56
  invoiceAttached: false
57
57
  };
58
58
  }
59
- const resolved = await chunk7L556RGL_cjs.resolveOrderInvoicePdfBytes(cms, dataSource, entityMap, payload.orderId);
59
+ const resolved = await chunkGLD263KW_cjs.resolveOrderInvoicePdfBytes(cms, dataSource, entityMap, payload.orderId);
60
60
  if ("error" in resolved) {
61
61
  console.warn("[email] order invoice attach failed", {
62
62
  orderId: payload.orderId,
@@ -133,7 +133,7 @@ async function queueEmail(cms, payload) {
133
133
  let email = cms && typeof cms.getPlugin === "function" ? cms.getPlugin("email") : void 0;
134
134
  if (!email) {
135
135
  try {
136
- const { EmailService } = await import('./email-service-ATCPJFWG.cjs');
136
+ const { EmailService } = await import('./email-service-5O24BSFR.cjs');
137
137
  const env = typeof process !== "undefined" && process.env ? process.env : {};
138
138
  const type = String(env.SMTP_TYPE || "SMTP").toUpperCase();
139
139
  const port = env.SMTP_PORT ? parseInt(env.SMTP_PORT, 10) : void 0;
@@ -0,0 +1,98 @@
1
+ import { __name } from './chunk-SHUYVCID.js';
2
+
3
+ // src/plugins/pg-boss/pg-boss-service.ts
4
+ var JOB_RUNNER_QUEUE = "job-runner";
5
+ var PgBossService = class {
6
+ static {
7
+ __name(this, "PgBossService");
8
+ }
9
+ connectionString;
10
+ schema;
11
+ boss = null;
12
+ bossPromise = null;
13
+ started = false;
14
+ workRegistered = /* @__PURE__ */ new Set();
15
+ constructor(connectionString, schema) {
16
+ this.connectionString = connectionString;
17
+ this.schema = schema?.trim() ? schema.trim() : void 0;
18
+ }
19
+ async getBoss() {
20
+ if (this.boss) return this.boss;
21
+ if (this.bossPromise) return this.bossPromise;
22
+ this.bossPromise = (async () => {
23
+ const mod = await import('pg-boss');
24
+ const PgBossClass = mod?.PgBoss ?? mod?.default ?? mod;
25
+ const instance = new PgBossClass({
26
+ connectionString: this.connectionString,
27
+ ...this.schema ? {
28
+ schema: this.schema
29
+ } : {},
30
+ schedule: true
31
+ });
32
+ instance.on("error", (err) => {
33
+ console.error("[pg-boss]", err);
34
+ });
35
+ this.boss = instance;
36
+ return instance;
37
+ })();
38
+ return this.bossPromise;
39
+ }
40
+ async start() {
41
+ if (this.started) return;
42
+ const boss = await this.getBoss();
43
+ await boss.start();
44
+ await this.ensureQueue(JOB_RUNNER_QUEUE);
45
+ this.started = true;
46
+ }
47
+ async stop() {
48
+ if (!this.started || !this.boss) return;
49
+ await this.boss.stop({
50
+ graceful: true,
51
+ timeout: 1e4
52
+ });
53
+ this.started = false;
54
+ this.workRegistered.clear();
55
+ }
56
+ get raw() {
57
+ return this.boss;
58
+ }
59
+ async ensureQueue(name) {
60
+ const boss = await this.getBoss();
61
+ const existing = await boss.getQueue(name);
62
+ if (!existing) {
63
+ await boss.createQueue(name);
64
+ }
65
+ }
66
+ async send(queue, data) {
67
+ await this.ensureQueue(queue);
68
+ const boss = await this.getBoss();
69
+ return boss.send(queue, data, {
70
+ retryLimit: 2
71
+ });
72
+ }
73
+ async schedule(name, cron, data, options) {
74
+ await this.ensureQueue(name);
75
+ const boss = await this.getBoss();
76
+ await boss.schedule(name, cron, data, options);
77
+ }
78
+ async unschedule(name) {
79
+ try {
80
+ const boss = await this.getBoss();
81
+ await boss.unschedule(name);
82
+ } catch {
83
+ }
84
+ }
85
+ async registerWork(queue, handler) {
86
+ if (this.workRegistered.has(queue)) return;
87
+ await this.ensureQueue(queue);
88
+ const boss = await this.getBoss();
89
+ await boss.work(queue, async (jobs) => {
90
+ for (const job of jobs) {
91
+ await handler(job.data);
92
+ }
93
+ });
94
+ this.workRegistered.add(queue);
95
+ }
96
+ };
97
+
98
+ export { JOB_RUNNER_QUEUE, PgBossService };
@@ -0,0 +1,77 @@
1
+ import { __name } from './chunk-SHUYVCID.js';
2
+ import { EventEmitter } from 'events';
3
+
4
+ var KNOWN_NOTIFICATION_TRIGGERS = {
5
+ ORDER_PENDING: "order_pending",
6
+ ORDER_PROCESSING: "order_processing",
7
+ ORDER_COMPLETED: "order_completed",
8
+ ORDER_PLACED: "order_placed",
9
+ ORDER_CANCELLED: "order_cancelled",
10
+ PAYMENT_SUCCESS: "payment_success",
11
+ PAYMENT_FAILED: "payment_failed",
12
+ PAYMENT_REFUND_INITIATED: "payment_refund_initiated"
13
+ };
14
+ var NotificationTriggerEmitter = class NotificationTriggerEmitter2 extends EventEmitter {
15
+ static {
16
+ __name(this, "NotificationTriggerEmitter");
17
+ }
18
+ emitTrigger(triggerKey, payload) {
19
+ this.emit("__any__", triggerKey, payload);
20
+ }
21
+ onAnyTrigger(listener) {
22
+ this.on("__any__", listener);
23
+ }
24
+ };
25
+ var notificationTriggerEmitter = new NotificationTriggerEmitter();
26
+
27
+ // src/lib/notify-log.ts
28
+ function maskTail(raw, keep = 6) {
29
+ const s = String(raw ?? "").trim();
30
+ if (!s) return "(none)";
31
+ if (s.length <= keep) return "***";
32
+ return `***${s.slice(-keep)}`;
33
+ }
34
+ __name(maskTail, "maskTail");
35
+ function maskNotifyPhone(raw) {
36
+ const digits = String(raw ?? "").replace(/\D/g, "");
37
+ if (digits.length <= 4) return "(none)";
38
+ return `***${digits.slice(-4)}`;
39
+ }
40
+ __name(maskNotifyPhone, "maskNotifyPhone");
41
+ function maskNotifyEmail(raw) {
42
+ const e = String(raw ?? "").trim();
43
+ if (!e || !e.includes("@")) return "(none)";
44
+ const [user, domain] = e.split("@");
45
+ const u = user.length <= 2 ? "**" : `${user.slice(0, 2)}***`;
46
+ return `${u}@${domain}`;
47
+ }
48
+ __name(maskNotifyEmail, "maskNotifyEmail");
49
+ function maskNotifyToken(raw) {
50
+ return maskTail(raw, 8);
51
+ }
52
+ __name(maskNotifyToken, "maskNotifyToken");
53
+ function write(level, channel, message, data) {
54
+ const banner = `========== [NOTIFY] ${channel} | ${message} ==========`;
55
+ const payload = data ?? {};
56
+ if (level === "error") {
57
+ console.error(`
58
+ ${banner}`, payload);
59
+ } else if (level === "warn") {
60
+ console.warn(`
61
+ ${banner}`, payload);
62
+ } else {
63
+ console.info(`
64
+ ${banner}`, payload);
65
+ }
66
+ }
67
+ __name(write, "write");
68
+ var notifyLog = {
69
+ trigger: /* @__PURE__ */ __name((message, data) => write("info", "TRIGGER", message, data), "trigger"),
70
+ email: /* @__PURE__ */ __name((message, data) => write("info", "EMAIL", message, data), "email"),
71
+ whatsapp: /* @__PURE__ */ __name((message, data) => write("info", "WHATSAPP", message, data), "whatsapp"),
72
+ push: /* @__PURE__ */ __name((message, data) => write("info", "PUSH", message, data), "push"),
73
+ skip: /* @__PURE__ */ __name((channel, message, data) => write("warn", `SKIP ${channel}`, message, data), "skip"),
74
+ error: /* @__PURE__ */ __name((channel, message, data) => write("error", channel, message, data), "error")
75
+ };
76
+
77
+ export { KNOWN_NOTIFICATION_TRIGGERS, maskNotifyEmail, maskNotifyPhone, maskNotifyToken, notificationTriggerEmitter, notifyLog };