@infuro/cms-core 1.0.44 → 1.0.46
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/README.md +19 -2
- package/dist/admin.cjs +1413 -620
- package/dist/admin.d.cts +8 -2
- package/dist/admin.d.ts +8 -2
- package/dist/admin.js +1414 -621
- package/dist/api.cjs +40 -37
- package/dist/api.d.cts +3 -1
- package/dist/api.d.ts +3 -1
- package/dist/api.js +8 -5
- package/dist/auth.cjs +23 -23
- package/dist/auth.d.cts +1 -0
- package/dist/auth.d.ts +1 -0
- package/dist/auth.js +2 -2
- package/dist/chunk-2KUCQVAQ.js +936 -0
- package/dist/chunk-3K5AIEIZ.js +256 -0
- package/dist/{chunk-I6NH72MO.js → chunk-57O3HZPG.js} +9 -1
- package/dist/chunk-7PMHZRF3.cjs +872 -0
- package/dist/chunk-BXYZDMTZ.cjs +953 -0
- package/dist/chunk-CQHXW4TR.js +107 -0
- package/dist/{chunk-NNQBWDCI.js → chunk-CRYKVJTO.js} +55 -959
- package/dist/chunk-DBPSJYLZ.js +47 -0
- package/dist/{chunk-TAHX46EI.cjs → chunk-FBKDMRQL.cjs} +9 -1
- package/dist/chunk-GUSHM5HN.js +862 -0
- package/dist/chunk-HY3AXLOI.cjs +265 -0
- package/dist/chunk-L3525VXI.js +243 -0
- package/dist/{chunk-ZMRQ72F6.cjs → chunk-NBY4NVTY.cjs} +3 -3
- package/dist/chunk-OY2YTBMP.cjs +50 -0
- package/dist/{chunk-BLR6H5GL.js → chunk-SF2XKMCI.js} +3 -3
- package/dist/{chunk-22FFHLTO.cjs → chunk-TCSGFAWB.cjs} +56 -970
- package/dist/{chunk-P2IWWBJV.cjs → chunk-UDVLFVEC.cjs} +1314 -601
- package/dist/{chunk-SQGBHYJF.js → chunk-UKC3HYXI.js} +1245 -548
- package/dist/chunk-V25RDUOU.cjs +248 -0
- package/dist/chunk-XMRMZ6NQ.cjs +109 -0
- package/dist/cli.cjs +9 -4
- package/dist/cli.js +9 -4
- package/dist/{email-queue-TPZWLTIV.cjs → email-queue-6NJY6HNM.cjs} +7 -5
- package/dist/email-queue-OI2HSCGE.js +4 -0
- package/dist/erp-order-invoice-3GXDE443.js +3 -0
- package/dist/erp-order-invoice-EYYNR526.cjs +24 -0
- package/dist/index.cjs +426 -359
- package/dist/index.d.cts +308 -20
- package/dist/index.d.ts +308 -20
- package/dist/index.js +31 -110
- package/dist/migrations/1781800000000-CustomerPhoneNullable.ts +53 -0
- package/dist/migrations/1781810000000-OrderItemsVariantId.ts +44 -0
- package/dist/migrations/1781900000000-UserInviteStatusToken.ts +46 -0
- package/dist/migrations/1782000000000-ComboSlug.ts +58 -0
- package/dist/migrations/1782100000000-DiscountDeviceType.ts +20 -0
- package/dist/order-inventory-2MYRKEPC.cjs +39 -0
- package/dist/order-inventory-76V4XIGW.js +2 -0
- package/dist/order-notification-dispatcher-SBQAMM5V.cjs +21 -0
- package/dist/{order-notification-dispatcher-XWIJYDGA.js → order-notification-dispatcher-ZJZB2HUN.js} +5 -2
- package/dist/retire-soft-deleted-unique-5VXBA5XX.cjs +15 -0
- package/dist/retire-soft-deleted-unique-NXQIH4BC.js +2 -0
- package/dist/send-order-placed-emails-B5ZVJT7T.cjs +15 -0
- package/dist/send-order-placed-emails-WPI37KRZ.js +6 -0
- package/package.json +5 -4
- package/src/admin/admin.css +27 -24
- package/dist/chunk-5ELSW2UP.js +0 -150
- package/dist/chunk-PNOKNSG2.cjs +0 -222
- package/dist/chunk-WEMDMVHQ.js +0 -216
- package/dist/chunk-XW5ATPRW.cjs +0 -155
- package/dist/email-queue-CGZBVVAS.js +0 -2
- package/dist/erp-order-invoice-3YISSOWW.js +0 -3
- package/dist/erp-order-invoice-ZR5F2KTA.cjs +0 -12
- package/dist/order-notification-dispatcher-RU7BTGGX.cjs +0 -18
|
@@ -1,581 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var chunkOOTLNH63_cjs = require('./chunk-OOTLNH63.cjs');
|
|
3
|
+
var chunkV25RDUOU_cjs = require('./chunk-V25RDUOU.cjs');
|
|
4
|
+
var chunkBXYZDMTZ_cjs = require('./chunk-BXYZDMTZ.cjs');
|
|
6
5
|
var chunkUSNT2KNT_cjs = require('./chunk-USNT2KNT.cjs');
|
|
7
6
|
var clientSes = require('@aws-sdk/client-ses');
|
|
7
|
+
var module$1 = require('module');
|
|
8
8
|
var nodemailer = require('nodemailer');
|
|
9
9
|
|
|
10
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
10
11
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
12
|
|
|
12
13
|
var nodemailer__default = /*#__PURE__*/_interopDefault(nodemailer);
|
|
13
14
|
|
|
14
|
-
// src/lib/event-order-template-context.ts
|
|
15
|
-
function resolvePublicSiteUrl() {
|
|
16
|
-
if (typeof process !== "undefined") {
|
|
17
|
-
const u = (process.env.CMS_PUBLIC_URL || process.env.NEXT_PUBLIC_SITE_URL || "").trim();
|
|
18
|
-
if (u) return u.replace(/\/+$/, "");
|
|
19
|
-
const v = (process.env.VERCEL_URL || "").trim();
|
|
20
|
-
if (v) return v.startsWith("http") ? v.replace(/\/+$/, "") : `https://${v.replace(/\/+$/, "")}`;
|
|
21
|
-
}
|
|
22
|
-
return "";
|
|
23
|
-
}
|
|
24
|
-
chunkUSNT2KNT_cjs.__name(resolvePublicSiteUrl, "resolvePublicSiteUrl");
|
|
25
|
-
function buildOrderTrackUrl(qrToken, siteUrl) {
|
|
26
|
-
const token = qrToken?.trim();
|
|
27
|
-
if (!token) return "";
|
|
28
|
-
const base = (siteUrl ?? resolvePublicSiteUrl()).replace(/\/+$/, "");
|
|
29
|
-
if (!base) return `/track/${token}`;
|
|
30
|
-
return `${base}/track/${token}`;
|
|
31
|
-
}
|
|
32
|
-
chunkUSNT2KNT_cjs.__name(buildOrderTrackUrl, "buildOrderTrackUrl");
|
|
33
|
-
function buildOrderQrImageUrl(trackUrl, size = 200) {
|
|
34
|
-
if (!trackUrl.trim()) return "";
|
|
35
|
-
return `https://api.qrserver.com/v1/create-qr-code/?size=${size}x${size}&data=${encodeURIComponent(trackUrl)}`;
|
|
36
|
-
}
|
|
37
|
-
chunkUSNT2KNT_cjs.__name(buildOrderQrImageUrl, "buildOrderQrImageUrl");
|
|
38
|
-
function formatOrderDetailsText(input) {
|
|
39
|
-
const { orderNumber, total, currency, lines } = input;
|
|
40
|
-
const header = `Order: ${orderNumber}
|
|
41
|
-
Total: ${total} ${currency}`;
|
|
42
|
-
if (!lines.length) return header;
|
|
43
|
-
const items = lines.map((line) => `- ${line.name} \xD7 ${line.quantity} (${line.total} ${line.currency})`).join("\n");
|
|
44
|
-
return `${header}
|
|
45
|
-
|
|
46
|
-
Items:
|
|
47
|
-
${items}`;
|
|
48
|
-
}
|
|
49
|
-
chunkUSNT2KNT_cjs.__name(formatOrderDetailsText, "formatOrderDetailsText");
|
|
50
|
-
function formatOrderDetailsHtml(input) {
|
|
51
|
-
const text = formatOrderDetailsText(input);
|
|
52
|
-
const escaped = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
53
|
-
return `<pre style="font-family:inherit;white-space:pre-wrap;margin:0">${escaped}</pre>`;
|
|
54
|
-
}
|
|
55
|
-
chunkUSNT2KNT_cjs.__name(formatOrderDetailsHtml, "formatOrderDetailsHtml");
|
|
56
|
-
function buildEventOrderTemplateVariables(input) {
|
|
57
|
-
const { event, order, contact, productNames, orderLines = [], siteUrl } = input;
|
|
58
|
-
const trackUrl = buildOrderTrackUrl(order.qrToken, siteUrl);
|
|
59
|
-
const qrImageUrl = buildOrderQrImageUrl(trackUrl);
|
|
60
|
-
const orderDetailsPayload = {
|
|
61
|
-
orderNumber: String(order.orderNumber ?? ""),
|
|
62
|
-
total: String(order.total ?? ""),
|
|
63
|
-
currency: String(order.currency ?? "INR"),
|
|
64
|
-
lines: orderLines
|
|
65
|
-
};
|
|
66
|
-
return {
|
|
67
|
-
eventName: event.name ?? "",
|
|
68
|
-
eventSlug: event.slug ?? "",
|
|
69
|
-
venue: event.venue ?? "",
|
|
70
|
-
startDate: formatEventDate(event.startDate),
|
|
71
|
-
orderNumber: String(order.orderNumber ?? ""),
|
|
72
|
-
orderTotal: String(order.total ?? ""),
|
|
73
|
-
currency: String(order.currency ?? "INR"),
|
|
74
|
-
customerName: contact.name?.trim() || contact.email?.split("@")[0] || "Guest",
|
|
75
|
-
customerEmail: contact.email?.trim() || "",
|
|
76
|
-
customerPhone: contact.phone?.trim() || "",
|
|
77
|
-
productNames,
|
|
78
|
-
trackUrl,
|
|
79
|
-
qrImageUrl,
|
|
80
|
-
orderDetails: formatOrderDetailsText(orderDetailsPayload),
|
|
81
|
-
orderDetailsHtml: formatOrderDetailsHtml(orderDetailsPayload)
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
chunkUSNT2KNT_cjs.__name(buildEventOrderTemplateVariables, "buildEventOrderTemplateVariables");
|
|
85
|
-
function formatEventDate(d) {
|
|
86
|
-
if (!d) return "";
|
|
87
|
-
try {
|
|
88
|
-
return new Date(d).toLocaleString(void 0, {
|
|
89
|
-
dateStyle: "medium",
|
|
90
|
-
timeStyle: "short"
|
|
91
|
-
});
|
|
92
|
-
} catch {
|
|
93
|
-
return String(d);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
chunkUSNT2KNT_cjs.__name(formatEventDate, "formatEventDate");
|
|
97
|
-
|
|
98
|
-
// src/lib/order-notification-context.ts
|
|
99
|
-
async function loadOrderLines(dataSource, entityMap, orderId, currency) {
|
|
100
|
-
if (!entityMap.order_items) return [];
|
|
101
|
-
const itemRows = await dataSource.getRepository(entityMap.order_items).find({
|
|
102
|
-
where: {
|
|
103
|
-
orderId
|
|
104
|
-
},
|
|
105
|
-
relations: [
|
|
106
|
-
"product"
|
|
107
|
-
],
|
|
108
|
-
order: {
|
|
109
|
-
id: "ASC"
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
return itemRows.map((item) => {
|
|
113
|
-
const row = item;
|
|
114
|
-
const name = row.product?.name || row.product?.title || `Product #${row.productId}`;
|
|
115
|
-
return {
|
|
116
|
-
name: String(name),
|
|
117
|
-
quantity: Number(row.quantity) || 1,
|
|
118
|
-
total: row.total,
|
|
119
|
-
currency
|
|
120
|
-
};
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
chunkUSNT2KNT_cjs.__name(loadOrderLines, "loadOrderLines");
|
|
124
|
-
async function loadPrimaryEvent(dataSource, entityMap, itemRows) {
|
|
125
|
-
if (!entityMap.event_products || !entityMap.events) {
|
|
126
|
-
return {
|
|
127
|
-
productNames: []
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
const epRepo = dataSource.getRepository(entityMap.event_products);
|
|
131
|
-
const eventRepo = dataSource.getRepository(entityMap.events);
|
|
132
|
-
const eventMap = /* @__PURE__ */ new Map();
|
|
133
|
-
for (const item of itemRows) {
|
|
134
|
-
const productId = item.productId;
|
|
135
|
-
const productName = item.product?.name || item.product?.title || `Product #${productId}`;
|
|
136
|
-
const eps = await epRepo.find({
|
|
137
|
-
where: {
|
|
138
|
-
productId,
|
|
139
|
-
isActive: true
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
for (const ep of eps) {
|
|
143
|
-
const eventId = ep.eventId;
|
|
144
|
-
const existing = eventMap.get(eventId);
|
|
145
|
-
if (existing) {
|
|
146
|
-
if (!existing.productNames.includes(String(productName))) {
|
|
147
|
-
existing.productNames.push(String(productName));
|
|
148
|
-
}
|
|
149
|
-
} else {
|
|
150
|
-
const event = await eventRepo.findOne({
|
|
151
|
-
where: {
|
|
152
|
-
id: eventId,
|
|
153
|
-
deleted: false
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
if (event) {
|
|
157
|
-
eventMap.set(eventId, {
|
|
158
|
-
event,
|
|
159
|
-
productNames: [
|
|
160
|
-
String(productName)
|
|
161
|
-
]
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
const first = eventMap.values().next().value;
|
|
168
|
-
if (!first) return {
|
|
169
|
-
productNames: []
|
|
170
|
-
};
|
|
171
|
-
return {
|
|
172
|
-
event: first.event,
|
|
173
|
-
productNames: first.productNames
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
chunkUSNT2KNT_cjs.__name(loadPrimaryEvent, "loadPrimaryEvent");
|
|
177
|
-
async function loadOrderNotificationContexts(orderId, deps) {
|
|
178
|
-
if (!deps.entityMap.orders) return null;
|
|
179
|
-
const order = await deps.dataSource.getRepository(deps.entityMap.orders).findOne({
|
|
180
|
-
where: {
|
|
181
|
-
id: orderId,
|
|
182
|
-
deleted: false
|
|
183
|
-
},
|
|
184
|
-
relations: [
|
|
185
|
-
"contact"
|
|
186
|
-
]
|
|
187
|
-
});
|
|
188
|
-
if (!order) return null;
|
|
189
|
-
const o = order;
|
|
190
|
-
const contact = o.contact ?? {};
|
|
191
|
-
const currency = String(o.currency ?? "INR");
|
|
192
|
-
const siteUrl = resolvePublicSiteUrl();
|
|
193
|
-
const itemRows = await deps.dataSource.getRepository(deps.entityMap.order_items).find({
|
|
194
|
-
where: {
|
|
195
|
-
orderId
|
|
196
|
-
},
|
|
197
|
-
relations: [
|
|
198
|
-
"product"
|
|
199
|
-
],
|
|
200
|
-
order: {
|
|
201
|
-
id: "ASC"
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
const orderLines = await loadOrderLines(deps.dataSource, deps.entityMap, orderId, currency);
|
|
205
|
-
const { event, productNames: eventProductNames } = await loadPrimaryEvent(deps.dataSource, deps.entityMap, itemRows);
|
|
206
|
-
const allProductNames = orderLines.map((line) => line.name);
|
|
207
|
-
const productNames = eventProductNames.length > 0 ? eventProductNames.join(", ") : allProductNames.join(", ");
|
|
208
|
-
const variables = event ? buildEventOrderTemplateVariables({
|
|
209
|
-
event,
|
|
210
|
-
order: {
|
|
211
|
-
orderNumber: o.orderNumber,
|
|
212
|
-
total: o.total,
|
|
213
|
-
currency,
|
|
214
|
-
qrToken: o.qrToken
|
|
215
|
-
},
|
|
216
|
-
contact,
|
|
217
|
-
productNames,
|
|
218
|
-
orderLines,
|
|
219
|
-
siteUrl
|
|
220
|
-
}) : buildEventOrderTemplateVariables({
|
|
221
|
-
event: {
|
|
222
|
-
name: productNames || "Your order",
|
|
223
|
-
slug: "",
|
|
224
|
-
venue: "",
|
|
225
|
-
startDate: null
|
|
226
|
-
},
|
|
227
|
-
order: {
|
|
228
|
-
orderNumber: o.orderNumber,
|
|
229
|
-
total: o.total,
|
|
230
|
-
currency,
|
|
231
|
-
qrToken: o.qrToken
|
|
232
|
-
},
|
|
233
|
-
contact,
|
|
234
|
-
productNames,
|
|
235
|
-
orderLines,
|
|
236
|
-
siteUrl
|
|
237
|
-
});
|
|
238
|
-
return {
|
|
239
|
-
order: {
|
|
240
|
-
id: o.id,
|
|
241
|
-
orderNumber: String(o.orderNumber ?? ""),
|
|
242
|
-
total: o.total,
|
|
243
|
-
currency,
|
|
244
|
-
qrToken: o.qrToken
|
|
245
|
-
},
|
|
246
|
-
contact,
|
|
247
|
-
orderLines,
|
|
248
|
-
productNames,
|
|
249
|
-
event,
|
|
250
|
-
variables
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
chunkUSNT2KNT_cjs.__name(loadOrderNotificationContexts, "loadOrderNotificationContexts");
|
|
254
|
-
|
|
255
|
-
// src/plugins/whatsapp/whatsapp-queue.ts
|
|
256
|
-
var WHATSAPP_QUEUE_NAME = "whatsapp";
|
|
257
|
-
function maskPhone(raw) {
|
|
258
|
-
const digits = raw.replace(/\D/g, "");
|
|
259
|
-
if (digits.length <= 4) return "****";
|
|
260
|
-
return `${"*".repeat(Math.max(0, digits.length - 4))}${digits.slice(-4)}`;
|
|
261
|
-
}
|
|
262
|
-
chunkUSNT2KNT_cjs.__name(maskPhone, "maskPhone");
|
|
263
|
-
function registerWhatsAppQueueProcessor(cms) {
|
|
264
|
-
const queue = cms.getPlugin("queue");
|
|
265
|
-
const whatsapp = cms.getPlugin("whatsapp");
|
|
266
|
-
if (!queue) {
|
|
267
|
-
console.warn("[whatsapp] queue processor not registered: queue plugin missing");
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
if (!whatsapp || typeof whatsapp.send !== "function") {
|
|
271
|
-
console.warn("[whatsapp] queue processor not registered: whatsapp plugin missing or not configured");
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
queue.registerProcessor(WHATSAPP_QUEUE_NAME, async (data) => {
|
|
275
|
-
const payload = data;
|
|
276
|
-
if (!payload.to) {
|
|
277
|
-
console.warn("[whatsapp] queue job skipped: missing recipient");
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
console.log("[whatsapp] queue job processing", {
|
|
281
|
-
to: maskPhone(payload.to),
|
|
282
|
-
templateKey: payload.templateKey ?? null,
|
|
283
|
-
externalTemplateRef: payload.externalTemplateRef ?? null
|
|
284
|
-
});
|
|
285
|
-
try {
|
|
286
|
-
const ok = await whatsapp.send(payload);
|
|
287
|
-
if (ok) {
|
|
288
|
-
console.log("[whatsapp] queue job completed", {
|
|
289
|
-
to: maskPhone(payload.to),
|
|
290
|
-
sent: true
|
|
291
|
-
});
|
|
292
|
-
} else {
|
|
293
|
-
console.warn("[whatsapp] queue job completed without delivery", {
|
|
294
|
-
to: maskPhone(payload.to),
|
|
295
|
-
sent: false
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
} catch (err) {
|
|
299
|
-
console.error("[whatsapp] queue job failed", {
|
|
300
|
-
to: maskPhone(payload.to),
|
|
301
|
-
error: err instanceof Error ? err.message : String(err)
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
});
|
|
305
|
-
console.log("[whatsapp] queue processor registered", {
|
|
306
|
-
queue: WHATSAPP_QUEUE_NAME
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
chunkUSNT2KNT_cjs.__name(registerWhatsAppQueueProcessor, "registerWhatsAppQueueProcessor");
|
|
310
|
-
async function queueWhatsApp(cms, payload) {
|
|
311
|
-
const queue = cms.getPlugin("queue");
|
|
312
|
-
if (queue) {
|
|
313
|
-
console.log("[whatsapp] enqueue", {
|
|
314
|
-
to: maskPhone(payload.to),
|
|
315
|
-
templateKey: payload.templateKey ?? null,
|
|
316
|
-
externalTemplateRef: payload.externalTemplateRef ?? null
|
|
317
|
-
});
|
|
318
|
-
await queue.add(WHATSAPP_QUEUE_NAME, payload);
|
|
319
|
-
return true;
|
|
320
|
-
}
|
|
321
|
-
const whatsapp = cms.getPlugin("whatsapp");
|
|
322
|
-
if (whatsapp && typeof whatsapp.send === "function") {
|
|
323
|
-
console.log("[whatsapp] no queue plugin \u2014 sending immediately", {
|
|
324
|
-
to: maskPhone(payload.to)
|
|
325
|
-
});
|
|
326
|
-
return whatsapp.send(payload);
|
|
327
|
-
}
|
|
328
|
-
console.warn("[whatsapp] send skipped: neither queue nor whatsapp plugin available", {
|
|
329
|
-
to: maskPhone(payload.to)
|
|
330
|
-
});
|
|
331
|
-
return false;
|
|
332
|
-
}
|
|
333
|
-
chunkUSNT2KNT_cjs.__name(queueWhatsApp, "queueWhatsApp");
|
|
334
|
-
|
|
335
|
-
// src/plugins/whatsapp/whatsapp-service.ts
|
|
336
|
-
function norm(v) {
|
|
337
|
-
const t = v?.trim();
|
|
338
|
-
return t || void 0;
|
|
339
|
-
}
|
|
340
|
-
chunkUSNT2KNT_cjs.__name(norm, "norm");
|
|
341
|
-
function pick(plugin, db, env, ...keys) {
|
|
342
|
-
for (const key of keys) {
|
|
343
|
-
const pk = key;
|
|
344
|
-
if (pk in plugin && plugin[pk] !== void 0 && String(plugin[pk]).trim() !== "") {
|
|
345
|
-
const v = norm(String(plugin[pk]));
|
|
346
|
-
if (v) return v;
|
|
347
|
-
}
|
|
348
|
-
if (norm(db[key])) return norm(db[key]);
|
|
349
|
-
if (norm(env[key])) return norm(env[key]);
|
|
350
|
-
}
|
|
351
|
-
return void 0;
|
|
352
|
-
}
|
|
353
|
-
chunkUSNT2KNT_cjs.__name(pick, "pick");
|
|
354
|
-
function mergeWhatsAppConfigLayers(env, db, plugin) {
|
|
355
|
-
return {
|
|
356
|
-
accessToken: pick(plugin, db, env, "accessToken", "WHATSAPP_ACCESS_TOKEN"),
|
|
357
|
-
phoneNumberId: pick(plugin, db, env, "phoneNumberId", "WHATSAPP_PHONE_NUMBER_ID"),
|
|
358
|
-
apiVersion: pick(plugin, db, env, "apiVersion", "WHATSAPP_API_VERSION") ?? "v21.0"
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
chunkUSNT2KNT_cjs.__name(mergeWhatsAppConfigLayers, "mergeWhatsAppConfigLayers");
|
|
362
|
-
function isWhatsAppPluginEnabled(db) {
|
|
363
|
-
const v = (db.enabled ?? "true").toLowerCase();
|
|
364
|
-
return v !== "false" && v !== "0";
|
|
365
|
-
}
|
|
366
|
-
chunkUSNT2KNT_cjs.__name(isWhatsAppPluginEnabled, "isWhatsAppPluginEnabled");
|
|
367
|
-
function whatsAppConfigured(config) {
|
|
368
|
-
return Boolean(config.accessToken?.trim() && config.phoneNumberId?.trim());
|
|
369
|
-
}
|
|
370
|
-
chunkUSNT2KNT_cjs.__name(whatsAppConfigured, "whatsAppConfigured");
|
|
371
|
-
function normalizeWhatsAppRecipient(to) {
|
|
372
|
-
const digits = to.replace(/\D/g, "");
|
|
373
|
-
return digits;
|
|
374
|
-
}
|
|
375
|
-
chunkUSNT2KNT_cjs.__name(normalizeWhatsAppRecipient, "normalizeWhatsAppRecipient");
|
|
376
|
-
function resolveMetaWhatsAppTemplateName(opts) {
|
|
377
|
-
const ref = opts.externalTemplateRef?.trim();
|
|
378
|
-
const rowName = opts.name?.trim();
|
|
379
|
-
if (ref && !/^\d+$/.test(ref)) return ref;
|
|
380
|
-
if (rowName) return rowName;
|
|
381
|
-
return ref || void 0;
|
|
382
|
-
}
|
|
383
|
-
chunkUSNT2KNT_cjs.__name(resolveMetaWhatsAppTemplateName, "resolveMetaWhatsAppTemplateName");
|
|
384
|
-
function maskPhone2(digits) {
|
|
385
|
-
if (digits.length <= 4) return "****";
|
|
386
|
-
return `${"*".repeat(Math.max(0, digits.length - 4))}${digits.slice(-4)}`;
|
|
387
|
-
}
|
|
388
|
-
chunkUSNT2KNT_cjs.__name(maskPhone2, "maskPhone");
|
|
389
|
-
function logWhatsApp(level, message, extra) {
|
|
390
|
-
const line = extra ? `${message} ${JSON.stringify(extra)}` : message;
|
|
391
|
-
if (level === "info") console.log(`[whatsapp] ${line}`);
|
|
392
|
-
else if (level === "warn") console.warn(`[whatsapp] ${line}`);
|
|
393
|
-
else console.error(`[whatsapp] ${line}`);
|
|
394
|
-
}
|
|
395
|
-
chunkUSNT2KNT_cjs.__name(logWhatsApp, "logWhatsApp");
|
|
396
|
-
var WhatsAppService = class {
|
|
397
|
-
static {
|
|
398
|
-
chunkUSNT2KNT_cjs.__name(this, "WhatsAppService");
|
|
399
|
-
}
|
|
400
|
-
getWhatsAppSettings;
|
|
401
|
-
config;
|
|
402
|
-
getMessageTemplateRow;
|
|
403
|
-
constructor(env, plugin = {}, getWhatsAppSettings, getMessageTemplateRow) {
|
|
404
|
-
this.getWhatsAppSettings = getWhatsAppSettings;
|
|
405
|
-
this.getMessageTemplateRow = getMessageTemplateRow;
|
|
406
|
-
this.config = mergeWhatsAppConfigLayers(env, {}, plugin);
|
|
407
|
-
}
|
|
408
|
-
async mergedConfig() {
|
|
409
|
-
let db = {};
|
|
410
|
-
try {
|
|
411
|
-
db = await this.getWhatsAppSettings?.() ?? {};
|
|
412
|
-
} catch {
|
|
413
|
-
}
|
|
414
|
-
return mergeWhatsAppConfigLayers((typeof process !== "undefined" ? process.env : {}) ?? {}, db, this.config);
|
|
415
|
-
}
|
|
416
|
-
async send(opts) {
|
|
417
|
-
const cfg = await this.mergedConfig();
|
|
418
|
-
if (!whatsAppConfigured(cfg)) {
|
|
419
|
-
logWhatsApp("warn", "send skipped: not configured (Plugins \u2192 WhatsApp or WHATSAPP_ACCESS_TOKEN + WHATSAPP_PHONE_NUMBER_ID)");
|
|
420
|
-
return false;
|
|
421
|
-
}
|
|
422
|
-
const to = normalizeWhatsAppRecipient(opts.to);
|
|
423
|
-
if (!to) {
|
|
424
|
-
logWhatsApp("warn", "send skipped: invalid recipient", {
|
|
425
|
-
rawTo: opts.to
|
|
426
|
-
});
|
|
427
|
-
return false;
|
|
428
|
-
}
|
|
429
|
-
logWhatsApp("info", "send started", {
|
|
430
|
-
to: maskPhone2(to),
|
|
431
|
-
templateKey: opts.templateKey ?? null,
|
|
432
|
-
externalTemplateRef: opts.externalTemplateRef ?? null,
|
|
433
|
-
phoneNumberId: cfg.phoneNumberId
|
|
434
|
-
});
|
|
435
|
-
let templateName = resolveMetaWhatsAppTemplateName({
|
|
436
|
-
externalTemplateRef: opts.externalTemplateRef
|
|
437
|
-
});
|
|
438
|
-
let templateLanguage = opts.templateLanguage?.trim();
|
|
439
|
-
let body = opts.body?.trim() ?? "";
|
|
440
|
-
const variables = opts.variables ?? {};
|
|
441
|
-
if (opts.templateKey?.trim() && this.getMessageTemplateRow) {
|
|
442
|
-
const { resolveEventOrderTemplate, EVENT_ORDER_TEMPLATE_KEY } = await import('./event-order-defaults-EMWBIGL3.cjs');
|
|
443
|
-
if (opts.templateKey.trim() === EVENT_ORDER_TEMPLATE_KEY) {
|
|
444
|
-
const resolved = await resolveEventOrderTemplate("whatsapp", async (ch, key) => {
|
|
445
|
-
const row = await this.getMessageTemplateRow(ch, key);
|
|
446
|
-
if (!row) return null;
|
|
447
|
-
return {
|
|
448
|
-
subject: null,
|
|
449
|
-
body: row.body,
|
|
450
|
-
externalTemplateRef: row.externalTemplateRef,
|
|
451
|
-
enabled: row.enabled
|
|
452
|
-
};
|
|
453
|
-
});
|
|
454
|
-
if (resolved && !resolved.enabled) {
|
|
455
|
-
logWhatsApp("warn", "send skipped: template disabled in message_templates", {
|
|
456
|
-
templateKey: opts.templateKey
|
|
457
|
-
});
|
|
458
|
-
return false;
|
|
459
|
-
}
|
|
460
|
-
if (resolved) {
|
|
461
|
-
body = resolved.body;
|
|
462
|
-
if (resolved.externalTemplateRef) templateName = resolved.externalTemplateRef;
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
const { applyTemplateVars: applyTemplateVars2 } = await import('./interpolate-WAKPN56R.cjs');
|
|
467
|
-
if (body) body = applyTemplateVars2(body, variables);
|
|
468
|
-
if (templateName) {
|
|
469
|
-
const paramValues = opts.templateParamOrder?.length ? opts.templateParamOrder.map((key) => String(variables[key] ?? "").slice(0, 1024)) : Object.keys(variables).length ? Object.values(variables) : body ? [
|
|
470
|
-
body
|
|
471
|
-
] : [];
|
|
472
|
-
logWhatsApp("info", "sending template message", {
|
|
473
|
-
to: maskPhone2(to),
|
|
474
|
-
templateName,
|
|
475
|
-
paramCount: paramValues.length,
|
|
476
|
-
paramOrder: opts.templateParamOrder ?? null
|
|
477
|
-
});
|
|
478
|
-
return this.sendTemplateMessage(cfg, to, templateName, paramValues, templateLanguage);
|
|
479
|
-
}
|
|
480
|
-
if (!body) {
|
|
481
|
-
logWhatsApp("warn", "send skipped: no template name and empty body", {
|
|
482
|
-
to: maskPhone2(to)
|
|
483
|
-
});
|
|
484
|
-
return false;
|
|
485
|
-
}
|
|
486
|
-
logWhatsApp("info", "sending text message", {
|
|
487
|
-
to: maskPhone2(to),
|
|
488
|
-
bodyLength: body.length
|
|
489
|
-
});
|
|
490
|
-
return this.sendTextMessage(cfg, to, body);
|
|
491
|
-
}
|
|
492
|
-
async sendTextMessage(cfg, to, body) {
|
|
493
|
-
const url = `https://graph.facebook.com/${cfg.apiVersion}/${cfg.phoneNumberId}/messages`;
|
|
494
|
-
const res = await fetch(url, {
|
|
495
|
-
method: "POST",
|
|
496
|
-
headers: {
|
|
497
|
-
Authorization: `Bearer ${cfg.accessToken}`,
|
|
498
|
-
"Content-Type": "application/json"
|
|
499
|
-
},
|
|
500
|
-
body: JSON.stringify({
|
|
501
|
-
messaging_product: "whatsapp",
|
|
502
|
-
to,
|
|
503
|
-
type: "text",
|
|
504
|
-
text: {
|
|
505
|
-
body
|
|
506
|
-
}
|
|
507
|
-
})
|
|
508
|
-
});
|
|
509
|
-
if (!res.ok) {
|
|
510
|
-
const errText = await res.text().catch(() => "");
|
|
511
|
-
logWhatsApp("error", "text send failed", {
|
|
512
|
-
status: res.status,
|
|
513
|
-
to: maskPhone2(to),
|
|
514
|
-
error: errText
|
|
515
|
-
});
|
|
516
|
-
return false;
|
|
517
|
-
}
|
|
518
|
-
const data = await res.json().catch(() => ({}));
|
|
519
|
-
logWhatsApp("info", "text send succeeded", {
|
|
520
|
-
to: maskPhone2(to),
|
|
521
|
-
messageId: data.messages?.[0]?.id ?? null
|
|
522
|
-
});
|
|
523
|
-
return true;
|
|
524
|
-
}
|
|
525
|
-
async sendTemplateMessage(cfg, to, templateName, paramValues, templateLanguage) {
|
|
526
|
-
const components = paramValues.length > 0 ? [
|
|
527
|
-
{
|
|
528
|
-
type: "body",
|
|
529
|
-
parameters: paramValues.map((text) => ({
|
|
530
|
-
type: "text",
|
|
531
|
-
text: String(text).slice(0, 1024)
|
|
532
|
-
}))
|
|
533
|
-
}
|
|
534
|
-
] : void 0;
|
|
535
|
-
const url = `https://graph.facebook.com/${cfg.apiVersion}/${cfg.phoneNumberId}/messages`;
|
|
536
|
-
const payload = {
|
|
537
|
-
messaging_product: "whatsapp",
|
|
538
|
-
to,
|
|
539
|
-
type: "template",
|
|
540
|
-
template: {
|
|
541
|
-
name: templateName,
|
|
542
|
-
language: {
|
|
543
|
-
code: templateLanguage?.trim() || "en"
|
|
544
|
-
},
|
|
545
|
-
...components ? {
|
|
546
|
-
components
|
|
547
|
-
} : {}
|
|
548
|
-
}
|
|
549
|
-
};
|
|
550
|
-
const res = await fetch(url, {
|
|
551
|
-
method: "POST",
|
|
552
|
-
headers: {
|
|
553
|
-
Authorization: `Bearer ${cfg.accessToken}`,
|
|
554
|
-
"Content-Type": "application/json"
|
|
555
|
-
},
|
|
556
|
-
body: JSON.stringify(payload)
|
|
557
|
-
});
|
|
558
|
-
if (!res.ok) {
|
|
559
|
-
const errText = await res.text().catch(() => "");
|
|
560
|
-
logWhatsApp("error", "template send failed", {
|
|
561
|
-
status: res.status,
|
|
562
|
-
to: maskPhone2(to),
|
|
563
|
-
templateName,
|
|
564
|
-
paramCount: paramValues.length,
|
|
565
|
-
error: errText
|
|
566
|
-
});
|
|
567
|
-
return false;
|
|
568
|
-
}
|
|
569
|
-
const data = await res.json().catch(() => ({}));
|
|
570
|
-
logWhatsApp("info", "template send succeeded", {
|
|
571
|
-
to: maskPhone2(to),
|
|
572
|
-
templateName,
|
|
573
|
-
messageId: data.messages?.[0]?.id ?? null
|
|
574
|
-
});
|
|
575
|
-
return true;
|
|
576
|
-
}
|
|
577
|
-
};
|
|
578
|
-
|
|
579
15
|
// src/plugins/email/templates/layout.ts
|
|
580
16
|
function escapeHtml(s) {
|
|
581
17
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
@@ -655,96 +91,6 @@ function renderLayout(options) {
|
|
|
655
91
|
}
|
|
656
92
|
chunkUSNT2KNT_cjs.__name(renderLayout, "renderLayout");
|
|
657
93
|
|
|
658
|
-
// src/plugins/email/templates/types.ts
|
|
659
|
-
function normalizeSocialLinkItem(o) {
|
|
660
|
-
const url = String(o.url ?? "").trim();
|
|
661
|
-
if (!url) return null;
|
|
662
|
-
let iconUrl = String(o.iconUrl ?? o.icon_image ?? "").trim();
|
|
663
|
-
let icon = String(o.icon ?? "").trim();
|
|
664
|
-
if (!iconUrl && /^https?:\/\//i.test(icon)) {
|
|
665
|
-
iconUrl = icon;
|
|
666
|
-
icon = "";
|
|
667
|
-
}
|
|
668
|
-
const item = {
|
|
669
|
-
url
|
|
670
|
-
};
|
|
671
|
-
if (iconUrl) item.iconUrl = iconUrl;
|
|
672
|
-
if (icon) item.icon = icon;
|
|
673
|
-
return item;
|
|
674
|
-
}
|
|
675
|
-
chunkUSNT2KNT_cjs.__name(normalizeSocialLinkItem, "normalizeSocialLinkItem");
|
|
676
|
-
function parseSocialLinksJson(raw) {
|
|
677
|
-
if (raw == null || raw.trim() === "") return void 0;
|
|
678
|
-
try {
|
|
679
|
-
const parsed = JSON.parse(raw);
|
|
680
|
-
if (!Array.isArray(parsed)) return void 0;
|
|
681
|
-
const out = [];
|
|
682
|
-
for (const item of parsed) {
|
|
683
|
-
if (item && typeof item === "object" && "url" in item) {
|
|
684
|
-
const n = normalizeSocialLinkItem(item);
|
|
685
|
-
if (n) out.push(n);
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
return out.length ? out : void 0;
|
|
689
|
-
} catch {
|
|
690
|
-
return void 0;
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
chunkUSNT2KNT_cjs.__name(parseSocialLinksJson, "parseSocialLinksJson");
|
|
694
|
-
function mergeEmailLayoutCompanyDetails(branding, emailSettings) {
|
|
695
|
-
const fromBranding = getCompanyDetailsFromSettings(branding);
|
|
696
|
-
const pick2 = /* @__PURE__ */ chunkUSNT2KNT_cjs.__name((emailVal, fallback) => {
|
|
697
|
-
const t = emailVal?.trim();
|
|
698
|
-
return t || fallback?.trim() || void 0;
|
|
699
|
-
}, "pick");
|
|
700
|
-
const logoUrl = pick2(emailSettings.logoUrl ?? emailSettings.emailLogoUrl, fromBranding.logoUrl);
|
|
701
|
-
const companyName = pick2(emailSettings.companyName ?? emailSettings.emailCompanyName, fromBranding.companyName);
|
|
702
|
-
const supportEmail = pick2(emailSettings.supportEmail ?? emailSettings.emailSupportEmail, fromBranding.supportEmail);
|
|
703
|
-
const supportPhone = pick2(emailSettings.supportPhone, void 0);
|
|
704
|
-
const footerDisclaimer = pick2(emailSettings.footerDisclaimer, void 0);
|
|
705
|
-
const followUsTitle = pick2(emailSettings.followUsTitle, "Follow Us") || "Follow Us";
|
|
706
|
-
const socialFromEmail = parseSocialLinksJson(emailSettings.socialLinks);
|
|
707
|
-
const socialLinks = socialFromEmail?.length ? socialFromEmail : fromBranding.socialLinks;
|
|
708
|
-
return {
|
|
709
|
-
logoUrl,
|
|
710
|
-
companyName,
|
|
711
|
-
supportEmail,
|
|
712
|
-
supportPhone,
|
|
713
|
-
socialLinks,
|
|
714
|
-
footerDisclaimer,
|
|
715
|
-
followUsTitle
|
|
716
|
-
};
|
|
717
|
-
}
|
|
718
|
-
chunkUSNT2KNT_cjs.__name(mergeEmailLayoutCompanyDetails, "mergeEmailLayoutCompanyDetails");
|
|
719
|
-
function getCompanyDetailsFromSettings(settingsGroup) {
|
|
720
|
-
const logoUrl = settingsGroup.logo ?? settingsGroup.logoUrl ?? "";
|
|
721
|
-
const companyName = settingsGroup.companyName ?? settingsGroup.company_name ?? "";
|
|
722
|
-
const supportEmail = settingsGroup.supportEmail ?? settingsGroup.support_email ?? "";
|
|
723
|
-
let socialLinks = [];
|
|
724
|
-
const raw = settingsGroup.socialLinks ?? settingsGroup.social_links;
|
|
725
|
-
if (typeof raw === "string") {
|
|
726
|
-
try {
|
|
727
|
-
const arr = JSON.parse(raw);
|
|
728
|
-
if (Array.isArray(arr)) {
|
|
729
|
-
for (const item of arr) {
|
|
730
|
-
if (item && typeof item === "object") {
|
|
731
|
-
const n = normalizeSocialLinkItem(item);
|
|
732
|
-
if (n) socialLinks.push(n);
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
} catch {
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
return {
|
|
740
|
-
logoUrl: logoUrl || void 0,
|
|
741
|
-
companyName: companyName || void 0,
|
|
742
|
-
supportEmail: supportEmail || void 0,
|
|
743
|
-
socialLinks: socialLinks.length ? socialLinks : void 0
|
|
744
|
-
};
|
|
745
|
-
}
|
|
746
|
-
chunkUSNT2KNT_cjs.__name(getCompanyDetailsFromSettings, "getCompanyDetailsFromSettings");
|
|
747
|
-
|
|
748
94
|
// src/plugins/email/templates/inline-cta.ts
|
|
749
95
|
function escapeHtml2(s) {
|
|
750
96
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
@@ -949,7 +295,7 @@ function renderAddressesText(billing, shipping) {
|
|
|
949
295
|
}
|
|
950
296
|
chunkUSNT2KNT_cjs.__name(renderAddressesText, "renderAddressesText");
|
|
951
297
|
function render4(ctx) {
|
|
952
|
-
const { orderNumber, total, subtotal, tax, currency, customerName, companyDetails, audience = "customer", internalCustomerEmail, lineItems = [], billingAddress, shippingAddress } = ctx;
|
|
298
|
+
const { orderNumber, total, subtotal, tax, currency, customerName, companyDetails, audience = "customer", internalCustomerEmail, lineItems = [], billingAddress, shippingAddress, invoiceAttached = false } = ctx;
|
|
953
299
|
const itemsHtml = renderLineItemsHtml(lineItems, currency);
|
|
954
300
|
const itemsText = renderLineItemsText(lineItems, currency);
|
|
955
301
|
const addrHtml = renderAddressesHtml(billingAddress, shippingAddress);
|
|
@@ -988,6 +334,7 @@ ${subtotalLine}${taxLine}${totalLine}`;
|
|
|
988
334
|
${addrHtml}
|
|
989
335
|
${itemsHtml}
|
|
990
336
|
${subtotalLine}${taxLine}${totalLine}
|
|
337
|
+
${invoiceAttached ? `<p style="margin:16px 0 0 0;font-size:14px;line-height:1.5;color:#333;">Your order invoice is attached as a PDF.</p>` : ""}
|
|
991
338
|
<p style="margin:16px 0 0 0;font-size:13px;line-height:1.5;color:#666;">If you have questions, reply to this email or contact us using the details below.</p>`;
|
|
992
339
|
text = [
|
|
993
340
|
`Order confirmed #${orderNumber}`,
|
|
@@ -998,6 +345,7 @@ ${subtotalLine}${taxLine}${totalLine}
|
|
|
998
345
|
subtotal != null ? `Subtotal: ${subtotal}${currency ? ` ${currency}` : ""}` : "",
|
|
999
346
|
tax != null && Number(tax) !== 0 ? `Tax: ${tax}${currency ? ` ${currency}` : ""}` : "",
|
|
1000
347
|
total != null ? `Order total: ${total}${currency ? ` ${currency}` : ""}` : "",
|
|
348
|
+
invoiceAttached ? "Your order invoice is attached as a PDF." : "",
|
|
1001
349
|
"",
|
|
1002
350
|
"We will process your order shortly."
|
|
1003
351
|
].filter((line, i, arr) => !(line === "" && arr[i - 1] === "")).join("\n");
|
|
@@ -1324,8 +672,8 @@ function renderEmail(templateName, ctx, options) {
|
|
|
1324
672
|
return render12(ctx);
|
|
1325
673
|
}
|
|
1326
674
|
chunkUSNT2KNT_cjs.__name(renderEmail, "renderEmail");
|
|
1327
|
-
|
|
1328
|
-
|
|
675
|
+
var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-TCSGFAWB.cjs', document.baseURI).href)));
|
|
676
|
+
var MailComposer = require2("nodemailer/lib/mail-composer");
|
|
1329
677
|
var SES_REGIONS_WITHOUT_SMTP = /* @__PURE__ */ new Set([
|
|
1330
678
|
"af-south-1",
|
|
1331
679
|
"ap-south-2",
|
|
@@ -1346,6 +694,10 @@ function sesRegionSupportsSmtp(region) {
|
|
|
1346
694
|
return !SES_REGIONS_WITHOUT_SMTP.has(region.trim());
|
|
1347
695
|
}
|
|
1348
696
|
chunkUSNT2KNT_cjs.__name(sesRegionSupportsSmtp, "sesRegionSupportsSmtp");
|
|
697
|
+
function toBuffer(content) {
|
|
698
|
+
return Buffer.isBuffer(content) ? content : Buffer.from(content);
|
|
699
|
+
}
|
|
700
|
+
chunkUSNT2KNT_cjs.__name(toBuffer, "toBuffer");
|
|
1349
701
|
var EmailService = class {
|
|
1350
702
|
static {
|
|
1351
703
|
chunkUSNT2KNT_cjs.__name(this, "EmailService");
|
|
@@ -1409,14 +761,47 @@ var EmailService = class {
|
|
|
1409
761
|
throw new Error(`Unsupported email type: ${config.type}`);
|
|
1410
762
|
}
|
|
1411
763
|
}
|
|
764
|
+
nodemailerAttachments(attachments) {
|
|
765
|
+
if (!attachments?.length) return void 0;
|
|
766
|
+
return attachments.map((a) => ({
|
|
767
|
+
filename: a.filename,
|
|
768
|
+
content: toBuffer(a.content),
|
|
769
|
+
contentType: a.contentType || "application/octet-stream"
|
|
770
|
+
}));
|
|
771
|
+
}
|
|
1412
772
|
async send(emailData) {
|
|
1413
773
|
try {
|
|
774
|
+
const from = emailData.from || this.config.from;
|
|
775
|
+
const to = emailData.to || this.config.to;
|
|
776
|
+
const attachments = this.nodemailerAttachments(emailData.attachments);
|
|
1414
777
|
if (this.config.type === "AWS" && this.sesClient) {
|
|
778
|
+
if (attachments?.length) {
|
|
779
|
+
const composer = new MailComposer({
|
|
780
|
+
from,
|
|
781
|
+
to,
|
|
782
|
+
subject: emailData.subject,
|
|
783
|
+
html: emailData.html,
|
|
784
|
+
text: emailData.text,
|
|
785
|
+
attachments
|
|
786
|
+
});
|
|
787
|
+
const raw = await new Promise((resolve, reject) => {
|
|
788
|
+
composer.compile().build((err, message) => {
|
|
789
|
+
if (err) reject(err);
|
|
790
|
+
else resolve(message);
|
|
791
|
+
});
|
|
792
|
+
});
|
|
793
|
+
await this.sesClient.send(new clientSes.SendRawEmailCommand({
|
|
794
|
+
RawMessage: {
|
|
795
|
+
Data: raw
|
|
796
|
+
}
|
|
797
|
+
}));
|
|
798
|
+
return true;
|
|
799
|
+
}
|
|
1415
800
|
await this.sesClient.send(new clientSes.SendEmailCommand({
|
|
1416
|
-
Source:
|
|
801
|
+
Source: from,
|
|
1417
802
|
Destination: {
|
|
1418
803
|
ToAddresses: [
|
|
1419
|
-
|
|
804
|
+
to
|
|
1420
805
|
]
|
|
1421
806
|
},
|
|
1422
807
|
Message: {
|
|
@@ -1442,11 +827,12 @@ var EmailService = class {
|
|
|
1442
827
|
}
|
|
1443
828
|
if (this.transporter && (this.config.type === "SMTP" || this.config.type === "GMAIL" || this.config.type === "AWS" && this.awsViaSmtp)) {
|
|
1444
829
|
await this.transporter.sendMail({
|
|
1445
|
-
from
|
|
1446
|
-
to
|
|
830
|
+
from,
|
|
831
|
+
to,
|
|
1447
832
|
subject: emailData.subject,
|
|
1448
833
|
html: emailData.html,
|
|
1449
|
-
text: emailData.text
|
|
834
|
+
text: emailData.text,
|
|
835
|
+
attachments
|
|
1450
836
|
});
|
|
1451
837
|
return true;
|
|
1452
838
|
}
|
|
@@ -1652,8 +1038,8 @@ function resolveChatEmailToolSettings(configMap, sources) {
|
|
|
1652
1038
|
chunkUSNT2KNT_cjs.__name(resolveChatEmailToolSettings, "resolveChatEmailToolSettings");
|
|
1653
1039
|
function intentByKey(intents, key) {
|
|
1654
1040
|
if (!key) return null;
|
|
1655
|
-
const
|
|
1656
|
-
return intents.find((i) => i.intent ===
|
|
1041
|
+
const norm = normalizeIntentKey(key);
|
|
1042
|
+
return intents.find((i) => i.intent === norm) ?? null;
|
|
1657
1043
|
}
|
|
1658
1044
|
chunkUSNT2KNT_cjs.__name(intentByKey, "intentByKey");
|
|
1659
1045
|
function buildIntentTableForPrompt(intents) {
|
|
@@ -1930,14 +1316,14 @@ async function sendChatLeadEmail(cms, emailSettings, brandingSettings, input) {
|
|
|
1930
1316
|
recipients,
|
|
1931
1317
|
source: input.recipients?.length ? "intent_email_to" : "crm_or_smtp_fallback"
|
|
1932
1318
|
});
|
|
1933
|
-
const companyDetails = mergeEmailLayoutCompanyDetails(brandingSettings, emailSettings);
|
|
1319
|
+
const companyDetails = chunkBXYZDMTZ_cjs.mergeEmailLayoutCompanyDetails(brandingSettings, emailSettings);
|
|
1934
1320
|
const ctx = {
|
|
1935
1321
|
...input,
|
|
1936
1322
|
companyDetails: input.companyDetails ?? companyDetails
|
|
1937
1323
|
};
|
|
1938
1324
|
let anySent = false;
|
|
1939
1325
|
for (const to of recipients) {
|
|
1940
|
-
await
|
|
1326
|
+
await chunkV25RDUOU_cjs.queueEmail(cms, {
|
|
1941
1327
|
to,
|
|
1942
1328
|
templateName: "chatLead",
|
|
1943
1329
|
ctx
|
|
@@ -2039,318 +1425,18 @@ function emailPlugin(config) {
|
|
|
2039
1425
|
}
|
|
2040
1426
|
chunkUSNT2KNT_cjs.__name(emailPlugin, "emailPlugin");
|
|
2041
1427
|
|
|
2042
|
-
// src/lib/order-notification-dispatcher.ts
|
|
2043
|
-
var initialized = false;
|
|
2044
|
-
function maskPhone3(raw) {
|
|
2045
|
-
const digits = String(raw ?? "").replace(/\D/g, "");
|
|
2046
|
-
if (digits.length <= 4) return "(none)";
|
|
2047
|
-
return `***${digits.slice(-4)}`;
|
|
2048
|
-
}
|
|
2049
|
-
chunkUSNT2KNT_cjs.__name(maskPhone3, "maskPhone");
|
|
2050
|
-
async function getSettingsGroup(dataSource, entityMap, group) {
|
|
2051
|
-
if (!entityMap.configs) return {};
|
|
2052
|
-
const rows = await dataSource.getRepository(entityMap.configs).find({
|
|
2053
|
-
where: {
|
|
2054
|
-
settings: group,
|
|
2055
|
-
deleted: false
|
|
2056
|
-
}
|
|
2057
|
-
});
|
|
2058
|
-
return Object.fromEntries(rows.map((r) => [
|
|
2059
|
-
r.key,
|
|
2060
|
-
r.value
|
|
2061
|
-
]));
|
|
2062
|
-
}
|
|
2063
|
-
chunkUSNT2KNT_cjs.__name(getSettingsGroup, "getSettingsGroup");
|
|
2064
|
-
async function isOrderNotificationsEnabled(dataSource, entityMap) {
|
|
2065
|
-
const settings = await getSettingsGroup(dataSource, entityMap, "event_notifications");
|
|
2066
|
-
return settings.enabled !== "false" && settings.enabled !== "0";
|
|
2067
|
-
}
|
|
2068
|
-
chunkUSNT2KNT_cjs.__name(isOrderNotificationsEnabled, "isOrderNotificationsEnabled");
|
|
2069
|
-
async function isTriggerCatalogEnabled(triggerKey, dataSource, entityMap) {
|
|
2070
|
-
if (!entityMap.order_notification_triggers) {
|
|
2071
|
-
console.warn("[order-notifications] order_notification_triggers missing \u2014 run migration 1781230000000-AddOrderNotificationTriggers");
|
|
2072
|
-
return false;
|
|
2073
|
-
}
|
|
2074
|
-
try {
|
|
2075
|
-
const row = await dataSource.getRepository(entityMap.order_notification_triggers).findOne({
|
|
2076
|
-
where: {
|
|
2077
|
-
triggerKey,
|
|
2078
|
-
enabled: true
|
|
2079
|
-
}
|
|
2080
|
-
});
|
|
2081
|
-
if (!row) {
|
|
2082
|
-
console.warn("[order-notifications] trigger disabled or not in DB", {
|
|
2083
|
-
triggerKey
|
|
2084
|
-
});
|
|
2085
|
-
}
|
|
2086
|
-
return Boolean(row);
|
|
2087
|
-
} catch (err) {
|
|
2088
|
-
console.error("[order-notifications] failed to load trigger catalog", {
|
|
2089
|
-
triggerKey,
|
|
2090
|
-
err
|
|
2091
|
-
});
|
|
2092
|
-
return false;
|
|
2093
|
-
}
|
|
2094
|
-
}
|
|
2095
|
-
chunkUSNT2KNT_cjs.__name(isTriggerCatalogEnabled, "isTriggerCatalogEnabled");
|
|
2096
|
-
async function loadBoundTemplate(triggerKey, channel, dataSource, entityMap) {
|
|
2097
|
-
if (!entityMap.order_notification_bindings || !entityMap.message_templates) {
|
|
2098
|
-
console.warn("[order-notifications] order_notification_bindings or message_templates missing from entityMap");
|
|
2099
|
-
return null;
|
|
2100
|
-
}
|
|
2101
|
-
const binding = await dataSource.getRepository(entityMap.order_notification_bindings).findOne({
|
|
2102
|
-
where: {
|
|
2103
|
-
triggerKey,
|
|
2104
|
-
channel,
|
|
2105
|
-
enabled: true
|
|
2106
|
-
}
|
|
2107
|
-
});
|
|
2108
|
-
if (!binding) {
|
|
2109
|
-
console.warn("[order-notifications] no order_notification_bindings row", {
|
|
2110
|
-
triggerKey,
|
|
2111
|
-
channel
|
|
2112
|
-
});
|
|
2113
|
-
return null;
|
|
2114
|
-
}
|
|
2115
|
-
const templateId = binding.messageTemplateId;
|
|
2116
|
-
if (templateId == null) {
|
|
2117
|
-
console.warn("[order-notifications] binding exists but no template selected", {
|
|
2118
|
-
triggerKey,
|
|
2119
|
-
channel
|
|
2120
|
-
});
|
|
2121
|
-
return null;
|
|
2122
|
-
}
|
|
2123
|
-
const template = await dataSource.getRepository(entityMap.message_templates).findOne({
|
|
2124
|
-
where: {
|
|
2125
|
-
id: templateId,
|
|
2126
|
-
channel,
|
|
2127
|
-
deleted: false,
|
|
2128
|
-
enabled: true
|
|
2129
|
-
}
|
|
2130
|
-
});
|
|
2131
|
-
if (!template) {
|
|
2132
|
-
console.warn("[order-notifications] bound template not found or disabled", {
|
|
2133
|
-
triggerKey,
|
|
2134
|
-
channel,
|
|
2135
|
-
templateId
|
|
2136
|
-
});
|
|
2137
|
-
return null;
|
|
2138
|
-
}
|
|
2139
|
-
return template;
|
|
2140
|
-
}
|
|
2141
|
-
chunkUSNT2KNT_cjs.__name(loadBoundTemplate, "loadBoundTemplate");
|
|
2142
|
-
function mergeTriggerVariables(payload, rich) {
|
|
2143
|
-
const basic = {
|
|
2144
|
-
orderId: String(payload.orderId ?? ""),
|
|
2145
|
-
orderNumber: payload.orderNumber,
|
|
2146
|
-
customerName: payload.customerName,
|
|
2147
|
-
customerPhone: payload.customerPhone ?? "",
|
|
2148
|
-
total: String(payload.total),
|
|
2149
|
-
orderTotal: String(payload.total),
|
|
2150
|
-
currency: payload.currency,
|
|
2151
|
-
vendorId: String(payload.vendorId ?? ""),
|
|
2152
|
-
...payload.refundAmount != null ? {
|
|
2153
|
-
refundAmount: String(payload.refundAmount)
|
|
2154
|
-
} : {}
|
|
2155
|
-
};
|
|
2156
|
-
return {
|
|
2157
|
-
...basic,
|
|
2158
|
-
...rich ?? {}
|
|
2159
|
-
};
|
|
2160
|
-
}
|
|
2161
|
-
chunkUSNT2KNT_cjs.__name(mergeTriggerVariables, "mergeTriggerVariables");
|
|
2162
|
-
async function sendEmailForTrigger(triggerKey, orderId, variables, contactEmail, dataSource, entityMap, getCms) {
|
|
2163
|
-
const template = await loadBoundTemplate(triggerKey, "email", dataSource, entityMap);
|
|
2164
|
-
if (!template) return;
|
|
2165
|
-
const [branding, emailSettings] = await Promise.all([
|
|
2166
|
-
getSettingsGroup(dataSource, entityMap, "branding"),
|
|
2167
|
-
getSettingsGroup(dataSource, entityMap, "email")
|
|
2168
|
-
]);
|
|
2169
|
-
const companyDetails = mergeEmailLayoutCompanyDetails(branding, emailSettings);
|
|
2170
|
-
const subject = chunkOOTLNH63_cjs.applyTemplateVars(template.subject ?? "Order update", variables);
|
|
2171
|
-
const bodyHtml = chunkOOTLNH63_cjs.applyTemplateVars(template.body, variables);
|
|
2172
|
-
const html = renderLayout({
|
|
2173
|
-
bodyHtml,
|
|
2174
|
-
companyDetails
|
|
2175
|
-
});
|
|
2176
|
-
const cms = await getCms();
|
|
2177
|
-
await chunkXW5ATPRW_cjs.queueEmail(cms, {
|
|
2178
|
-
to: contactEmail,
|
|
2179
|
-
subject,
|
|
2180
|
-
html,
|
|
2181
|
-
text: bodyHtml.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim()
|
|
2182
|
-
});
|
|
2183
|
-
console.log("[order-notifications] email queued", {
|
|
2184
|
-
triggerKey,
|
|
2185
|
-
orderId,
|
|
2186
|
-
to: contactEmail
|
|
2187
|
-
});
|
|
2188
|
-
}
|
|
2189
|
-
chunkUSNT2KNT_cjs.__name(sendEmailForTrigger, "sendEmailForTrigger");
|
|
2190
|
-
async function sendWhatsAppForTrigger(triggerKey, orderId, phone, variables, dataSource, entityMap, getCms) {
|
|
2191
|
-
const template = await loadBoundTemplate(triggerKey, "whatsapp", dataSource, entityMap);
|
|
2192
|
-
if (!template) return;
|
|
2193
|
-
const paramOrder = template.providerMeta?.paramOrder ?? [];
|
|
2194
|
-
if (paramOrder.length === 0) {
|
|
2195
|
-
console.warn("[order-notifications] WhatsApp template has no paramOrder set \u2014 variables may send blank/wrong", {
|
|
2196
|
-
triggerKey
|
|
2197
|
-
});
|
|
2198
|
-
}
|
|
2199
|
-
const cms = await getCms();
|
|
2200
|
-
const metaTemplateName = resolveMetaWhatsAppTemplateName({
|
|
2201
|
-
externalTemplateRef: template.externalTemplateRef,
|
|
2202
|
-
name: template.name
|
|
2203
|
-
});
|
|
2204
|
-
if (!metaTemplateName) {
|
|
2205
|
-
console.warn("[order-notifications] bound WhatsApp template has no Meta template name", {
|
|
2206
|
-
triggerKey,
|
|
2207
|
-
templateId: template.id
|
|
2208
|
-
});
|
|
2209
|
-
return;
|
|
2210
|
-
}
|
|
2211
|
-
const sent = await queueWhatsApp(cms, {
|
|
2212
|
-
to: phone.trim(),
|
|
2213
|
-
templateKey: triggerKey,
|
|
2214
|
-
externalTemplateRef: metaTemplateName,
|
|
2215
|
-
templateLanguage: template.providerMeta?.language ?? void 0,
|
|
2216
|
-
body: template.body,
|
|
2217
|
-
variables,
|
|
2218
|
-
templateParamOrder: paramOrder
|
|
2219
|
-
});
|
|
2220
|
-
if (!sent) {
|
|
2221
|
-
console.warn("[order-notifications] WhatsApp send failed", {
|
|
2222
|
-
triggerKey,
|
|
2223
|
-
orderId,
|
|
2224
|
-
hint: "Register whatsappPlugin() + queuePlugin() in getCms(), or set WHATSAPP_ACCESS_TOKEN and WHATSAPP_PHONE_NUMBER_ID"
|
|
2225
|
-
});
|
|
2226
|
-
} else {
|
|
2227
|
-
console.log("[order-notifications] WhatsApp queued/sent", {
|
|
2228
|
-
triggerKey,
|
|
2229
|
-
orderId,
|
|
2230
|
-
phone: maskPhone3(phone)
|
|
2231
|
-
});
|
|
2232
|
-
}
|
|
2233
|
-
}
|
|
2234
|
-
chunkUSNT2KNT_cjs.__name(sendWhatsAppForTrigger, "sendWhatsAppForTrigger");
|
|
2235
|
-
async function handleTrigger(triggerKey, payload, dataSource, entityMap, getCms) {
|
|
2236
|
-
console.log("[order-notifications] received", {
|
|
2237
|
-
triggerKey,
|
|
2238
|
-
orderId: payload.orderId,
|
|
2239
|
-
phone: maskPhone3(payload.customerPhone)
|
|
2240
|
-
});
|
|
2241
|
-
const pluginEnabled = await isOrderNotificationsEnabled(dataSource, entityMap);
|
|
2242
|
-
if (!pluginEnabled) {
|
|
2243
|
-
console.warn("[order-notifications] skip: Plugins \u2192 Order notifications disabled");
|
|
2244
|
-
return;
|
|
2245
|
-
}
|
|
2246
|
-
const triggerEnabled = await isTriggerCatalogEnabled(triggerKey, dataSource, entityMap);
|
|
2247
|
-
if (!triggerEnabled) return;
|
|
2248
|
-
const context = await loadOrderNotificationContexts(payload.orderId, {
|
|
2249
|
-
dataSource,
|
|
2250
|
-
entityMap
|
|
2251
|
-
});
|
|
2252
|
-
const variables = mergeTriggerVariables(payload, context?.variables);
|
|
2253
|
-
const contactEmail = context?.contact.email?.trim() || "";
|
|
2254
|
-
const contactPhone = context?.contact.phone?.trim() || payload.customerPhone?.trim() || "";
|
|
2255
|
-
if (contactEmail) {
|
|
2256
|
-
await sendEmailForTrigger(triggerKey, payload.orderId, variables, contactEmail, dataSource, entityMap, getCms);
|
|
2257
|
-
} else {
|
|
2258
|
-
console.warn("[order-notifications] skip email: no customer email", {
|
|
2259
|
-
triggerKey,
|
|
2260
|
-
orderId: payload.orderId
|
|
2261
|
-
});
|
|
2262
|
-
}
|
|
2263
|
-
if (contactPhone) {
|
|
2264
|
-
await sendWhatsAppForTrigger(triggerKey, payload.orderId, contactPhone, variables, dataSource, entityMap, getCms);
|
|
2265
|
-
} else {
|
|
2266
|
-
console.warn("[order-notifications] skip WhatsApp: no customer phone", {
|
|
2267
|
-
triggerKey,
|
|
2268
|
-
orderId: payload.orderId
|
|
2269
|
-
});
|
|
2270
|
-
}
|
|
2271
|
-
}
|
|
2272
|
-
chunkUSNT2KNT_cjs.__name(handleTrigger, "handleTrigger");
|
|
2273
|
-
function initWhatsappTriggerDispatcher(deps) {
|
|
2274
|
-
if (initialized) return;
|
|
2275
|
-
initialized = true;
|
|
2276
|
-
const { dataSource, entityMap, getCms } = deps;
|
|
2277
|
-
chunkUCKN4BBY_cjs.notificationTriggerEmitter.onAnyTrigger((triggerKey, payload) => {
|
|
2278
|
-
void handleTrigger(triggerKey, payload, dataSource, entityMap, getCms).catch((err) => {
|
|
2279
|
-
console.error("[order-notifications]", triggerKey, err);
|
|
2280
|
-
});
|
|
2281
|
-
});
|
|
2282
|
-
console.log("[order-notifications] dispatcher initialized (email + WhatsApp, unified via order_notification_bindings)");
|
|
2283
|
-
}
|
|
2284
|
-
chunkUSNT2KNT_cjs.__name(initWhatsappTriggerDispatcher, "initWhatsappTriggerDispatcher");
|
|
2285
|
-
async function resendOrderNotification(triggerKey, orderId, deps) {
|
|
2286
|
-
if (!deps.entityMap.orders) return {
|
|
2287
|
-
ok: false,
|
|
2288
|
-
error: "orders entity missing"
|
|
2289
|
-
};
|
|
2290
|
-
const pluginEnabled = await isOrderNotificationsEnabled(deps.dataSource, deps.entityMap);
|
|
2291
|
-
if (!pluginEnabled) return {
|
|
2292
|
-
ok: false,
|
|
2293
|
-
error: "Order notifications plugin is disabled"
|
|
2294
|
-
};
|
|
2295
|
-
const triggerEnabled = await isTriggerCatalogEnabled(triggerKey, deps.dataSource, deps.entityMap);
|
|
2296
|
-
if (!triggerEnabled) {
|
|
2297
|
-
return {
|
|
2298
|
-
ok: false,
|
|
2299
|
-
error: `Trigger "${triggerKey}" is disabled or migration 1781230000000 not applied`
|
|
2300
|
-
};
|
|
2301
|
-
}
|
|
2302
|
-
const order = await deps.dataSource.getRepository(deps.entityMap.orders).findOne({
|
|
2303
|
-
where: {
|
|
2304
|
-
id: orderId,
|
|
2305
|
-
deleted: false
|
|
2306
|
-
},
|
|
2307
|
-
relations: [
|
|
2308
|
-
"contact"
|
|
2309
|
-
]
|
|
2310
|
-
});
|
|
2311
|
-
if (!order) return {
|
|
2312
|
-
ok: false,
|
|
2313
|
-
error: "Order not found"
|
|
2314
|
-
};
|
|
2315
|
-
const o = order;
|
|
2316
|
-
await handleTrigger(triggerKey, {
|
|
2317
|
-
orderId,
|
|
2318
|
-
orderNumber: String(o.orderNumber ?? ""),
|
|
2319
|
-
customerName: o.contact?.name ?? "",
|
|
2320
|
-
customerPhone: o.contact?.phone ?? null,
|
|
2321
|
-
total: o.total ?? 0,
|
|
2322
|
-
currency: String(o.currency ?? "INR"),
|
|
2323
|
-
vendorId: o.vendorId ?? null
|
|
2324
|
-
}, deps.dataSource, deps.entityMap, deps.getCms);
|
|
2325
|
-
return {
|
|
2326
|
-
ok: true
|
|
2327
|
-
};
|
|
2328
|
-
}
|
|
2329
|
-
chunkUSNT2KNT_cjs.__name(resendOrderNotification, "resendOrderNotification");
|
|
2330
|
-
|
|
2331
1428
|
exports.CHAT_EMAIL_LOG = CHAT_EMAIL_LOG;
|
|
2332
1429
|
exports.EmailService = EmailService;
|
|
2333
|
-
exports.WhatsAppService = WhatsAppService;
|
|
2334
1430
|
exports.buildChatbotSystemPromptWithEmailTool = buildChatbotSystemPromptWithEmailTool;
|
|
2335
|
-
exports.buildEventOrderTemplateVariables = buildEventOrderTemplateVariables;
|
|
2336
1431
|
exports.buildTranscriptForLeadEmail = buildTranscriptForLeadEmail;
|
|
2337
1432
|
exports.detectChatLeadIntent = detectChatLeadIntent;
|
|
2338
1433
|
exports.emailPlugin = emailPlugin;
|
|
2339
1434
|
exports.emailTemplates = emailTemplates;
|
|
2340
|
-
exports.getCompanyDetailsFromSettings = getCompanyDetailsFromSettings;
|
|
2341
|
-
exports.initWhatsappTriggerDispatcher = initWhatsappTriggerDispatcher;
|
|
2342
|
-
exports.isWhatsAppPluginEnabled = isWhatsAppPluginEnabled;
|
|
2343
1435
|
exports.joinRecipientsForSend = joinRecipientsForSend;
|
|
2344
|
-
exports.mergeEmailLayoutCompanyDetails = mergeEmailLayoutCompanyDetails;
|
|
2345
|
-
exports.mergeWhatsAppConfigLayers = mergeWhatsAppConfigLayers;
|
|
2346
1436
|
exports.parseEmailRecipientsFromConfig = parseEmailRecipientsFromConfig;
|
|
2347
1437
|
exports.parseIntentRecipientEmails = parseIntentRecipientEmails;
|
|
2348
|
-
exports.queueWhatsApp = queueWhatsApp;
|
|
2349
|
-
exports.registerWhatsAppQueueProcessor = registerWhatsAppQueueProcessor;
|
|
2350
1438
|
exports.renderEmail = renderEmail;
|
|
2351
1439
|
exports.renderLayout = renderLayout;
|
|
2352
|
-
exports.resendOrderNotification = resendOrderNotification;
|
|
2353
1440
|
exports.resolveChatEmailToolSettings = resolveChatEmailToolSettings;
|
|
2354
1441
|
exports.sendChatLeadEmail = sendChatLeadEmail;
|
|
2355
1442
|
exports.serializeEmailRecipients = serializeEmailRecipients;
|
|
2356
|
-
exports.whatsAppConfigured = whatsAppConfigured;
|