av6-core 1.5.6 → 1.5.7
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/dist/index.js +172 -79
- package/dist/index.mjs +172 -79
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2546,72 +2546,6 @@ var SmsProvider = class {
|
|
|
2546
2546
|
|
|
2547
2547
|
// src/providers/whatsapp.provider.ts
|
|
2548
2548
|
var import_axios2 = __toESM(require("axios"));
|
|
2549
|
-
var WhatsAppProvider = class {
|
|
2550
|
-
constructor(args, logger) {
|
|
2551
|
-
this.args = args;
|
|
2552
|
-
this.logger = logger;
|
|
2553
|
-
this.logger.info(`[NotificationService] args for whatsapp : ${JSON.stringify(args)}`);
|
|
2554
|
-
this.apiUrl = args.apiUrl || "https://api.interakt.ai/v1/public/message/";
|
|
2555
|
-
this.apiKey = "RW9FTlFWM3h3aTdGbmJhVFFRU0RQdzVUdERyQl84VkU2RFRJWVdhcW8xZzo=";
|
|
2556
|
-
}
|
|
2557
|
-
apiKey;
|
|
2558
|
-
apiUrl;
|
|
2559
|
-
async send(inp) {
|
|
2560
|
-
const to = inp.recipient;
|
|
2561
|
-
if (!to) {
|
|
2562
|
-
return {
|
|
2563
|
-
ok: false,
|
|
2564
|
-
provider: "WHATSAPP" /* WHATSAPP */,
|
|
2565
|
-
error: "Missing recipient.whatsapp/phone"
|
|
2566
|
-
};
|
|
2567
|
-
}
|
|
2568
|
-
const allRecipients = [to];
|
|
2569
|
-
if (this.args.masterNumber) {
|
|
2570
|
-
allRecipients.push(this.args.masterNumber);
|
|
2571
|
-
}
|
|
2572
|
-
try {
|
|
2573
|
-
for (const recipient of allRecipients) {
|
|
2574
|
-
const requestBody = {
|
|
2575
|
-
countryCode: this.args.countryCode ?? "+233",
|
|
2576
|
-
phoneNumber: recipient.replace(this.args.countryCode ?? "+233", ""),
|
|
2577
|
-
callbackData: this.args.callbackData || "default-callback",
|
|
2578
|
-
type: "Template",
|
|
2579
|
-
template: {
|
|
2580
|
-
name: this.args.templateName,
|
|
2581
|
-
languageCode: this.args.languageCode,
|
|
2582
|
-
bodyValues: inp.bodyValues ?? []
|
|
2583
|
-
}
|
|
2584
|
-
};
|
|
2585
|
-
if (inp.fileUrl) {
|
|
2586
|
-
requestBody.template.headerValues = [inp.fileUrl];
|
|
2587
|
-
if (inp.fileName) requestBody.template.fileName = inp.fileName;
|
|
2588
|
-
}
|
|
2589
|
-
const headers = {
|
|
2590
|
-
Authorization: `Basic ${this.apiKey}`,
|
|
2591
|
-
"Content-Type": "application/json"
|
|
2592
|
-
};
|
|
2593
|
-
const response = await import_axios2.default.post(this.apiUrl, requestBody, { headers });
|
|
2594
|
-
const data = response.data;
|
|
2595
|
-
return {
|
|
2596
|
-
ok: true,
|
|
2597
|
-
provider: "WHATSAPP" /* WHATSAPP */,
|
|
2598
|
-
externalId: data?.message_id || "unknown",
|
|
2599
|
-
meta: data
|
|
2600
|
-
};
|
|
2601
|
-
}
|
|
2602
|
-
return {
|
|
2603
|
-
ok: true,
|
|
2604
|
-
provider: "WHATSAPP" /* WHATSAPP */
|
|
2605
|
-
};
|
|
2606
|
-
} catch (err) {
|
|
2607
|
-
return {
|
|
2608
|
-
ok: false,
|
|
2609
|
-
provider: "WHATSAPP" /* WHATSAPP */,
|
|
2610
|
-
error: err?.response?.data || err?.message || String(err)
|
|
2611
|
-
};
|
|
2612
|
-
}
|
|
2613
|
-
}
|
|
2614
|
-
};
|
|
2615
2549
|
|
|
2616
2550
|
// src/utils/notification.utils.ts
|
|
2617
2551
|
function defaultValueField(t) {
|
|
@@ -2884,6 +2818,177 @@ async function resolveAllRecipients(args) {
|
|
|
2884
2818
|
}
|
|
2885
2819
|
return res;
|
|
2886
2820
|
}
|
|
2821
|
+
async function mapWithConcurrency(items, limit, fn) {
|
|
2822
|
+
const results = new Array(items.length);
|
|
2823
|
+
let idx = 0;
|
|
2824
|
+
const workers = new Array(limit).fill(null).map(async () => {
|
|
2825
|
+
while (idx < items.length) {
|
|
2826
|
+
const cur = idx++;
|
|
2827
|
+
results[cur] = await fn(items[cur]);
|
|
2828
|
+
}
|
|
2829
|
+
});
|
|
2830
|
+
await Promise.all(workers);
|
|
2831
|
+
return results;
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
// src/providers/whatsapp.provider.ts
|
|
2835
|
+
var WhatsAppProvider = class {
|
|
2836
|
+
constructor(args, logger) {
|
|
2837
|
+
this.args = args;
|
|
2838
|
+
this.logger = logger;
|
|
2839
|
+
const safeArgs = { ...args, apiKey: args.apiKey ? "***" : "" };
|
|
2840
|
+
this.logger.info(`[NotificationService] args for whatsapp : ${JSON.stringify(safeArgs)}`);
|
|
2841
|
+
this.apiUrl = args.apiUrl ?? "";
|
|
2842
|
+
this.apiKey = args.apiKey;
|
|
2843
|
+
}
|
|
2844
|
+
apiKey;
|
|
2845
|
+
apiUrl;
|
|
2846
|
+
/**
|
|
2847
|
+
* Existing single-recipient send (kept as-is, but fixed phone normalization a bit).
|
|
2848
|
+
* NOTE: This method sends to inp.recipient ONLY (no master). sendBulk handles master inclusion.
|
|
2849
|
+
*/
|
|
2850
|
+
async send(inp) {
|
|
2851
|
+
const to = inp.recipient;
|
|
2852
|
+
if (!to) {
|
|
2853
|
+
return { ok: false, provider: "WHATSAPP" /* WHATSAPP */, error: "Missing recipient" };
|
|
2854
|
+
}
|
|
2855
|
+
if (!this.apiUrl) {
|
|
2856
|
+
return { ok: false, provider: "WHATSAPP" /* WHATSAPP */, error: "Missing WhatsApp apiUrl" };
|
|
2857
|
+
}
|
|
2858
|
+
if (!this.apiKey) {
|
|
2859
|
+
return { ok: false, provider: "WHATSAPP" /* WHATSAPP */, error: "Missing WhatsApp apiKey" };
|
|
2860
|
+
}
|
|
2861
|
+
try {
|
|
2862
|
+
const { requestBody, headers } = this.buildRequest(to, inp);
|
|
2863
|
+
const response = await import_axios2.default.post(this.apiUrl, requestBody, { headers });
|
|
2864
|
+
const data = response.data;
|
|
2865
|
+
return {
|
|
2866
|
+
ok: true,
|
|
2867
|
+
provider: "WHATSAPP" /* WHATSAPP */,
|
|
2868
|
+
externalId: data?.message_id || "unknown",
|
|
2869
|
+
meta: data
|
|
2870
|
+
};
|
|
2871
|
+
} catch (err) {
|
|
2872
|
+
return {
|
|
2873
|
+
ok: false,
|
|
2874
|
+
provider: "WHATSAPP" /* WHATSAPP */,
|
|
2875
|
+
error: err?.response?.data || err?.message || String(err)
|
|
2876
|
+
};
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2879
|
+
/**
|
|
2880
|
+
* Proper bulk send:
|
|
2881
|
+
* - Accepts list of recipients
|
|
2882
|
+
* - Optionally includes masterNumber
|
|
2883
|
+
* - Dedupe recipients
|
|
2884
|
+
* - Concurrency-limited sending
|
|
2885
|
+
* - Returns per-recipient results + overall ok
|
|
2886
|
+
*/
|
|
2887
|
+
async sendBulk(args) {
|
|
2888
|
+
if (!this.apiUrl) {
|
|
2889
|
+
return {
|
|
2890
|
+
ok: false,
|
|
2891
|
+
provider: "WHATSAPP" /* WHATSAPP */,
|
|
2892
|
+
items: [{ recipient: "", ok: false, error: "Missing WhatsApp apiUrl" }]
|
|
2893
|
+
};
|
|
2894
|
+
}
|
|
2895
|
+
if (!this.apiKey) {
|
|
2896
|
+
return {
|
|
2897
|
+
ok: false,
|
|
2898
|
+
provider: "WHATSAPP" /* WHATSAPP */,
|
|
2899
|
+
items: [{ recipient: "", ok: false, error: "Missing WhatsApp apiKey" }]
|
|
2900
|
+
};
|
|
2901
|
+
}
|
|
2902
|
+
const includeMaster = args.includeMaster ?? true;
|
|
2903
|
+
const concurrency = Math.max(1, Math.min(args.concurrency ?? 5, 25));
|
|
2904
|
+
const cleaned = (args.recipients ?? []).map((x) => String(x ?? "").trim()).filter(Boolean);
|
|
2905
|
+
const uniq = new Set(cleaned);
|
|
2906
|
+
if (includeMaster && this.args.masterNumber) {
|
|
2907
|
+
uniq.add(String(this.args.masterNumber).trim());
|
|
2908
|
+
}
|
|
2909
|
+
const recipients = Array.from(uniq);
|
|
2910
|
+
if (!recipients.length) {
|
|
2911
|
+
return { ok: true, provider: "WHATSAPP" /* WHATSAPP */, items: [] };
|
|
2912
|
+
}
|
|
2913
|
+
const baseInp = {
|
|
2914
|
+
bodyValues: args.bodyValues ?? [],
|
|
2915
|
+
fileUrl: args.fileUrl,
|
|
2916
|
+
fileName: args.fileName
|
|
2917
|
+
};
|
|
2918
|
+
const items = await mapWithConcurrency(recipients, concurrency, async (recipient) => {
|
|
2919
|
+
try {
|
|
2920
|
+
const { requestBody, headers } = this.buildRequest(recipient, baseInp);
|
|
2921
|
+
const response = await import_axios2.default.post(this.apiUrl, requestBody, { headers });
|
|
2922
|
+
const data = response.data;
|
|
2923
|
+
return {
|
|
2924
|
+
recipient,
|
|
2925
|
+
ok: true,
|
|
2926
|
+
externalId: data?.message_id || "unknown",
|
|
2927
|
+
meta: data
|
|
2928
|
+
};
|
|
2929
|
+
} catch (err) {
|
|
2930
|
+
const errorPayload = err?.response?.data || err?.message || String(err);
|
|
2931
|
+
return {
|
|
2932
|
+
recipient,
|
|
2933
|
+
ok: false,
|
|
2934
|
+
error: typeof errorPayload === "string" ? errorPayload : JSON.stringify(errorPayload),
|
|
2935
|
+
meta: err?.response?.data
|
|
2936
|
+
};
|
|
2937
|
+
}
|
|
2938
|
+
});
|
|
2939
|
+
const ok = items.every((x) => x.ok);
|
|
2940
|
+
return {
|
|
2941
|
+
ok,
|
|
2942
|
+
provider: "WHATSAPP" /* WHATSAPP */,
|
|
2943
|
+
items
|
|
2944
|
+
};
|
|
2945
|
+
}
|
|
2946
|
+
// ------------------------- helpers -------------------------
|
|
2947
|
+
buildRequest(recipient, inp) {
|
|
2948
|
+
const countryCode = (this.args.countryCode ?? "+233").trim();
|
|
2949
|
+
const languageCode = (this.args.languageCode ?? "en").trim();
|
|
2950
|
+
const callbackData = (this.args.callbackData ?? "default-callback").trim();
|
|
2951
|
+
const phoneNumber = this.normalizePhoneNumber(recipient, countryCode);
|
|
2952
|
+
const requestBody = {
|
|
2953
|
+
countryCode,
|
|
2954
|
+
phoneNumber,
|
|
2955
|
+
callbackData,
|
|
2956
|
+
type: "Template",
|
|
2957
|
+
template: {
|
|
2958
|
+
name: this.args.templateName,
|
|
2959
|
+
languageCode,
|
|
2960
|
+
bodyValues: inp.bodyValues ?? []
|
|
2961
|
+
}
|
|
2962
|
+
};
|
|
2963
|
+
if (inp.fileUrl) {
|
|
2964
|
+
requestBody.template.headerValues = [inp.fileUrl];
|
|
2965
|
+
if (inp.fileName) requestBody.template.fileName = inp.fileName;
|
|
2966
|
+
}
|
|
2967
|
+
const headers = {
|
|
2968
|
+
Authorization: `Basic ${this.apiKey}`,
|
|
2969
|
+
"Content-Type": "application/json"
|
|
2970
|
+
};
|
|
2971
|
+
return { requestBody, headers };
|
|
2972
|
+
}
|
|
2973
|
+
/**
|
|
2974
|
+
* Normalize a phone number into Interakt's expected format:
|
|
2975
|
+
* - requestBody.countryCode = "+91"
|
|
2976
|
+
* - requestBody.phoneNumber = "9883984351" (digits, without country code)
|
|
2977
|
+
*
|
|
2978
|
+
* Handles input formats:
|
|
2979
|
+
* - "9883984351"
|
|
2980
|
+
* - "+919883984351"
|
|
2981
|
+
* - "91 98839 84351"
|
|
2982
|
+
*/
|
|
2983
|
+
normalizePhoneNumber(input, countryCode) {
|
|
2984
|
+
const ccDigits = countryCode.replace(/[^\d]/g, "");
|
|
2985
|
+
const digits = String(input ?? "").replace(/[^\d]/g, "");
|
|
2986
|
+
if (ccDigits && digits.startsWith(ccDigits) && digits.length > ccDigits.length) {
|
|
2987
|
+
return digits.slice(ccDigits.length);
|
|
2988
|
+
}
|
|
2989
|
+
return digits;
|
|
2990
|
+
}
|
|
2991
|
+
};
|
|
2887
2992
|
|
|
2888
2993
|
// src/utils/renderer.ts
|
|
2889
2994
|
var import_handlebars = __toESM(require("handlebars"));
|
|
@@ -3249,7 +3354,7 @@ var NotificationService = class {
|
|
|
3249
3354
|
this.logger.error("[NotificationService] WhatsApp sendBulk failed, falling back", e);
|
|
3250
3355
|
}
|
|
3251
3356
|
}
|
|
3252
|
-
const items = await
|
|
3357
|
+
const items = await mapWithConcurrency(
|
|
3253
3358
|
uniq,
|
|
3254
3359
|
Math.max(1, args.concurrency),
|
|
3255
3360
|
async (recipient) => {
|
|
@@ -3271,18 +3376,6 @@ var NotificationService = class {
|
|
|
3271
3376
|
const ok = items.length > 0 && items.every((x) => x.ok);
|
|
3272
3377
|
return { ok, items };
|
|
3273
3378
|
}
|
|
3274
|
-
async mapWithConcurrency(items, limit, fn) {
|
|
3275
|
-
const results = new Array(items.length);
|
|
3276
|
-
let idx = 0;
|
|
3277
|
-
const workers = new Array(limit).fill(null).map(async () => {
|
|
3278
|
-
while (idx < items.length) {
|
|
3279
|
-
const cur = idx++;
|
|
3280
|
-
results[cur] = await fn(items[cur]);
|
|
3281
|
-
}
|
|
3282
|
-
});
|
|
3283
|
-
await Promise.all(workers);
|
|
3284
|
-
return results;
|
|
3285
|
-
}
|
|
3286
3379
|
};
|
|
3287
3380
|
|
|
3288
3381
|
// src/events/eventEmitter.ts
|
package/dist/index.mjs
CHANGED
|
@@ -2496,72 +2496,6 @@ var SmsProvider = class {
|
|
|
2496
2496
|
|
|
2497
2497
|
// src/providers/whatsapp.provider.ts
|
|
2498
2498
|
import axios2 from "axios";
|
|
2499
|
-
var WhatsAppProvider = class {
|
|
2500
|
-
constructor(args, logger) {
|
|
2501
|
-
this.args = args;
|
|
2502
|
-
this.logger = logger;
|
|
2503
|
-
this.logger.info(`[NotificationService] args for whatsapp : ${JSON.stringify(args)}`);
|
|
2504
|
-
this.apiUrl = args.apiUrl || "https://api.interakt.ai/v1/public/message/";
|
|
2505
|
-
this.apiKey = "RW9FTlFWM3h3aTdGbmJhVFFRU0RQdzVUdERyQl84VkU2RFRJWVdhcW8xZzo=";
|
|
2506
|
-
}
|
|
2507
|
-
apiKey;
|
|
2508
|
-
apiUrl;
|
|
2509
|
-
async send(inp) {
|
|
2510
|
-
const to = inp.recipient;
|
|
2511
|
-
if (!to) {
|
|
2512
|
-
return {
|
|
2513
|
-
ok: false,
|
|
2514
|
-
provider: "WHATSAPP" /* WHATSAPP */,
|
|
2515
|
-
error: "Missing recipient.whatsapp/phone"
|
|
2516
|
-
};
|
|
2517
|
-
}
|
|
2518
|
-
const allRecipients = [to];
|
|
2519
|
-
if (this.args.masterNumber) {
|
|
2520
|
-
allRecipients.push(this.args.masterNumber);
|
|
2521
|
-
}
|
|
2522
|
-
try {
|
|
2523
|
-
for (const recipient of allRecipients) {
|
|
2524
|
-
const requestBody = {
|
|
2525
|
-
countryCode: this.args.countryCode ?? "+233",
|
|
2526
|
-
phoneNumber: recipient.replace(this.args.countryCode ?? "+233", ""),
|
|
2527
|
-
callbackData: this.args.callbackData || "default-callback",
|
|
2528
|
-
type: "Template",
|
|
2529
|
-
template: {
|
|
2530
|
-
name: this.args.templateName,
|
|
2531
|
-
languageCode: this.args.languageCode,
|
|
2532
|
-
bodyValues: inp.bodyValues ?? []
|
|
2533
|
-
}
|
|
2534
|
-
};
|
|
2535
|
-
if (inp.fileUrl) {
|
|
2536
|
-
requestBody.template.headerValues = [inp.fileUrl];
|
|
2537
|
-
if (inp.fileName) requestBody.template.fileName = inp.fileName;
|
|
2538
|
-
}
|
|
2539
|
-
const headers = {
|
|
2540
|
-
Authorization: `Basic ${this.apiKey}`,
|
|
2541
|
-
"Content-Type": "application/json"
|
|
2542
|
-
};
|
|
2543
|
-
const response = await axios2.post(this.apiUrl, requestBody, { headers });
|
|
2544
|
-
const data = response.data;
|
|
2545
|
-
return {
|
|
2546
|
-
ok: true,
|
|
2547
|
-
provider: "WHATSAPP" /* WHATSAPP */,
|
|
2548
|
-
externalId: data?.message_id || "unknown",
|
|
2549
|
-
meta: data
|
|
2550
|
-
};
|
|
2551
|
-
}
|
|
2552
|
-
return {
|
|
2553
|
-
ok: true,
|
|
2554
|
-
provider: "WHATSAPP" /* WHATSAPP */
|
|
2555
|
-
};
|
|
2556
|
-
} catch (err) {
|
|
2557
|
-
return {
|
|
2558
|
-
ok: false,
|
|
2559
|
-
provider: "WHATSAPP" /* WHATSAPP */,
|
|
2560
|
-
error: err?.response?.data || err?.message || String(err)
|
|
2561
|
-
};
|
|
2562
|
-
}
|
|
2563
|
-
}
|
|
2564
|
-
};
|
|
2565
2499
|
|
|
2566
2500
|
// src/utils/notification.utils.ts
|
|
2567
2501
|
function defaultValueField(t) {
|
|
@@ -2834,6 +2768,177 @@ async function resolveAllRecipients(args) {
|
|
|
2834
2768
|
}
|
|
2835
2769
|
return res;
|
|
2836
2770
|
}
|
|
2771
|
+
async function mapWithConcurrency(items, limit, fn) {
|
|
2772
|
+
const results = new Array(items.length);
|
|
2773
|
+
let idx = 0;
|
|
2774
|
+
const workers = new Array(limit).fill(null).map(async () => {
|
|
2775
|
+
while (idx < items.length) {
|
|
2776
|
+
const cur = idx++;
|
|
2777
|
+
results[cur] = await fn(items[cur]);
|
|
2778
|
+
}
|
|
2779
|
+
});
|
|
2780
|
+
await Promise.all(workers);
|
|
2781
|
+
return results;
|
|
2782
|
+
}
|
|
2783
|
+
|
|
2784
|
+
// src/providers/whatsapp.provider.ts
|
|
2785
|
+
var WhatsAppProvider = class {
|
|
2786
|
+
constructor(args, logger) {
|
|
2787
|
+
this.args = args;
|
|
2788
|
+
this.logger = logger;
|
|
2789
|
+
const safeArgs = { ...args, apiKey: args.apiKey ? "***" : "" };
|
|
2790
|
+
this.logger.info(`[NotificationService] args for whatsapp : ${JSON.stringify(safeArgs)}`);
|
|
2791
|
+
this.apiUrl = args.apiUrl ?? "";
|
|
2792
|
+
this.apiKey = args.apiKey;
|
|
2793
|
+
}
|
|
2794
|
+
apiKey;
|
|
2795
|
+
apiUrl;
|
|
2796
|
+
/**
|
|
2797
|
+
* Existing single-recipient send (kept as-is, but fixed phone normalization a bit).
|
|
2798
|
+
* NOTE: This method sends to inp.recipient ONLY (no master). sendBulk handles master inclusion.
|
|
2799
|
+
*/
|
|
2800
|
+
async send(inp) {
|
|
2801
|
+
const to = inp.recipient;
|
|
2802
|
+
if (!to) {
|
|
2803
|
+
return { ok: false, provider: "WHATSAPP" /* WHATSAPP */, error: "Missing recipient" };
|
|
2804
|
+
}
|
|
2805
|
+
if (!this.apiUrl) {
|
|
2806
|
+
return { ok: false, provider: "WHATSAPP" /* WHATSAPP */, error: "Missing WhatsApp apiUrl" };
|
|
2807
|
+
}
|
|
2808
|
+
if (!this.apiKey) {
|
|
2809
|
+
return { ok: false, provider: "WHATSAPP" /* WHATSAPP */, error: "Missing WhatsApp apiKey" };
|
|
2810
|
+
}
|
|
2811
|
+
try {
|
|
2812
|
+
const { requestBody, headers } = this.buildRequest(to, inp);
|
|
2813
|
+
const response = await axios2.post(this.apiUrl, requestBody, { headers });
|
|
2814
|
+
const data = response.data;
|
|
2815
|
+
return {
|
|
2816
|
+
ok: true,
|
|
2817
|
+
provider: "WHATSAPP" /* WHATSAPP */,
|
|
2818
|
+
externalId: data?.message_id || "unknown",
|
|
2819
|
+
meta: data
|
|
2820
|
+
};
|
|
2821
|
+
} catch (err) {
|
|
2822
|
+
return {
|
|
2823
|
+
ok: false,
|
|
2824
|
+
provider: "WHATSAPP" /* WHATSAPP */,
|
|
2825
|
+
error: err?.response?.data || err?.message || String(err)
|
|
2826
|
+
};
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
/**
|
|
2830
|
+
* Proper bulk send:
|
|
2831
|
+
* - Accepts list of recipients
|
|
2832
|
+
* - Optionally includes masterNumber
|
|
2833
|
+
* - Dedupe recipients
|
|
2834
|
+
* - Concurrency-limited sending
|
|
2835
|
+
* - Returns per-recipient results + overall ok
|
|
2836
|
+
*/
|
|
2837
|
+
async sendBulk(args) {
|
|
2838
|
+
if (!this.apiUrl) {
|
|
2839
|
+
return {
|
|
2840
|
+
ok: false,
|
|
2841
|
+
provider: "WHATSAPP" /* WHATSAPP */,
|
|
2842
|
+
items: [{ recipient: "", ok: false, error: "Missing WhatsApp apiUrl" }]
|
|
2843
|
+
};
|
|
2844
|
+
}
|
|
2845
|
+
if (!this.apiKey) {
|
|
2846
|
+
return {
|
|
2847
|
+
ok: false,
|
|
2848
|
+
provider: "WHATSAPP" /* WHATSAPP */,
|
|
2849
|
+
items: [{ recipient: "", ok: false, error: "Missing WhatsApp apiKey" }]
|
|
2850
|
+
};
|
|
2851
|
+
}
|
|
2852
|
+
const includeMaster = args.includeMaster ?? true;
|
|
2853
|
+
const concurrency = Math.max(1, Math.min(args.concurrency ?? 5, 25));
|
|
2854
|
+
const cleaned = (args.recipients ?? []).map((x) => String(x ?? "").trim()).filter(Boolean);
|
|
2855
|
+
const uniq = new Set(cleaned);
|
|
2856
|
+
if (includeMaster && this.args.masterNumber) {
|
|
2857
|
+
uniq.add(String(this.args.masterNumber).trim());
|
|
2858
|
+
}
|
|
2859
|
+
const recipients = Array.from(uniq);
|
|
2860
|
+
if (!recipients.length) {
|
|
2861
|
+
return { ok: true, provider: "WHATSAPP" /* WHATSAPP */, items: [] };
|
|
2862
|
+
}
|
|
2863
|
+
const baseInp = {
|
|
2864
|
+
bodyValues: args.bodyValues ?? [],
|
|
2865
|
+
fileUrl: args.fileUrl,
|
|
2866
|
+
fileName: args.fileName
|
|
2867
|
+
};
|
|
2868
|
+
const items = await mapWithConcurrency(recipients, concurrency, async (recipient) => {
|
|
2869
|
+
try {
|
|
2870
|
+
const { requestBody, headers } = this.buildRequest(recipient, baseInp);
|
|
2871
|
+
const response = await axios2.post(this.apiUrl, requestBody, { headers });
|
|
2872
|
+
const data = response.data;
|
|
2873
|
+
return {
|
|
2874
|
+
recipient,
|
|
2875
|
+
ok: true,
|
|
2876
|
+
externalId: data?.message_id || "unknown",
|
|
2877
|
+
meta: data
|
|
2878
|
+
};
|
|
2879
|
+
} catch (err) {
|
|
2880
|
+
const errorPayload = err?.response?.data || err?.message || String(err);
|
|
2881
|
+
return {
|
|
2882
|
+
recipient,
|
|
2883
|
+
ok: false,
|
|
2884
|
+
error: typeof errorPayload === "string" ? errorPayload : JSON.stringify(errorPayload),
|
|
2885
|
+
meta: err?.response?.data
|
|
2886
|
+
};
|
|
2887
|
+
}
|
|
2888
|
+
});
|
|
2889
|
+
const ok = items.every((x) => x.ok);
|
|
2890
|
+
return {
|
|
2891
|
+
ok,
|
|
2892
|
+
provider: "WHATSAPP" /* WHATSAPP */,
|
|
2893
|
+
items
|
|
2894
|
+
};
|
|
2895
|
+
}
|
|
2896
|
+
// ------------------------- helpers -------------------------
|
|
2897
|
+
buildRequest(recipient, inp) {
|
|
2898
|
+
const countryCode = (this.args.countryCode ?? "+233").trim();
|
|
2899
|
+
const languageCode = (this.args.languageCode ?? "en").trim();
|
|
2900
|
+
const callbackData = (this.args.callbackData ?? "default-callback").trim();
|
|
2901
|
+
const phoneNumber = this.normalizePhoneNumber(recipient, countryCode);
|
|
2902
|
+
const requestBody = {
|
|
2903
|
+
countryCode,
|
|
2904
|
+
phoneNumber,
|
|
2905
|
+
callbackData,
|
|
2906
|
+
type: "Template",
|
|
2907
|
+
template: {
|
|
2908
|
+
name: this.args.templateName,
|
|
2909
|
+
languageCode,
|
|
2910
|
+
bodyValues: inp.bodyValues ?? []
|
|
2911
|
+
}
|
|
2912
|
+
};
|
|
2913
|
+
if (inp.fileUrl) {
|
|
2914
|
+
requestBody.template.headerValues = [inp.fileUrl];
|
|
2915
|
+
if (inp.fileName) requestBody.template.fileName = inp.fileName;
|
|
2916
|
+
}
|
|
2917
|
+
const headers = {
|
|
2918
|
+
Authorization: `Basic ${this.apiKey}`,
|
|
2919
|
+
"Content-Type": "application/json"
|
|
2920
|
+
};
|
|
2921
|
+
return { requestBody, headers };
|
|
2922
|
+
}
|
|
2923
|
+
/**
|
|
2924
|
+
* Normalize a phone number into Interakt's expected format:
|
|
2925
|
+
* - requestBody.countryCode = "+91"
|
|
2926
|
+
* - requestBody.phoneNumber = "9883984351" (digits, without country code)
|
|
2927
|
+
*
|
|
2928
|
+
* Handles input formats:
|
|
2929
|
+
* - "9883984351"
|
|
2930
|
+
* - "+919883984351"
|
|
2931
|
+
* - "91 98839 84351"
|
|
2932
|
+
*/
|
|
2933
|
+
normalizePhoneNumber(input, countryCode) {
|
|
2934
|
+
const ccDigits = countryCode.replace(/[^\d]/g, "");
|
|
2935
|
+
const digits = String(input ?? "").replace(/[^\d]/g, "");
|
|
2936
|
+
if (ccDigits && digits.startsWith(ccDigits) && digits.length > ccDigits.length) {
|
|
2937
|
+
return digits.slice(ccDigits.length);
|
|
2938
|
+
}
|
|
2939
|
+
return digits;
|
|
2940
|
+
}
|
|
2941
|
+
};
|
|
2837
2942
|
|
|
2838
2943
|
// src/utils/renderer.ts
|
|
2839
2944
|
import Handlebars from "handlebars";
|
|
@@ -3199,7 +3304,7 @@ var NotificationService = class {
|
|
|
3199
3304
|
this.logger.error("[NotificationService] WhatsApp sendBulk failed, falling back", e);
|
|
3200
3305
|
}
|
|
3201
3306
|
}
|
|
3202
|
-
const items = await
|
|
3307
|
+
const items = await mapWithConcurrency(
|
|
3203
3308
|
uniq,
|
|
3204
3309
|
Math.max(1, args.concurrency),
|
|
3205
3310
|
async (recipient) => {
|
|
@@ -3221,18 +3326,6 @@ var NotificationService = class {
|
|
|
3221
3326
|
const ok = items.length > 0 && items.every((x) => x.ok);
|
|
3222
3327
|
return { ok, items };
|
|
3223
3328
|
}
|
|
3224
|
-
async mapWithConcurrency(items, limit, fn) {
|
|
3225
|
-
const results = new Array(items.length);
|
|
3226
|
-
let idx = 0;
|
|
3227
|
-
const workers = new Array(limit).fill(null).map(async () => {
|
|
3228
|
-
while (idx < items.length) {
|
|
3229
|
-
const cur = idx++;
|
|
3230
|
-
results[cur] = await fn(items[cur]);
|
|
3231
|
-
}
|
|
3232
|
-
});
|
|
3233
|
-
await Promise.all(workers);
|
|
3234
|
-
return results;
|
|
3235
|
-
}
|
|
3236
3329
|
};
|
|
3237
3330
|
|
|
3238
3331
|
// src/events/eventEmitter.ts
|