av6-core 1.5.9 → 1.5.11
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 +107 -80
- package/dist/index.mjs +107 -80
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2447,31 +2447,47 @@ var EmailProvider = class {
|
|
|
2447
2447
|
};
|
|
2448
2448
|
|
|
2449
2449
|
// src/providers/sms.provider.ts
|
|
2450
|
+
var import_axios2 = __toESM(require("axios"));
|
|
2451
|
+
var import_node_https = __toESM(require("https"));
|
|
2452
|
+
var import_promises = __toESM(require("dns/promises"));
|
|
2453
|
+
var import_node_url = require("url");
|
|
2454
|
+
var DEFAULT_SMS_URL = "https://web.nsemfua.com/api/http/sms/send";
|
|
2455
|
+
var FALLBACK_SMS_IPS = [
|
|
2456
|
+
"185.38.109.200",
|
|
2457
|
+
"185.38.109.201",
|
|
2458
|
+
"185.38.109.202",
|
|
2459
|
+
"185.38.109.203",
|
|
2460
|
+
"185.38.109.204",
|
|
2461
|
+
"185.38.109.205",
|
|
2462
|
+
"185.38.109.206",
|
|
2463
|
+
"185.38.109.207",
|
|
2464
|
+
"185.38.109.208",
|
|
2465
|
+
"185.38.109.209"
|
|
2466
|
+
];
|
|
2467
|
+
var rr = 0;
|
|
2450
2468
|
var SmsProvider = class {
|
|
2451
2469
|
constructor(logger = console, args) {
|
|
2452
2470
|
this.logger = logger;
|
|
2453
2471
|
this.args = args;
|
|
2454
2472
|
const safeArgs = { ...args, apiKey: args.apiKey ? "***" : "" };
|
|
2455
2473
|
this.logger.info(`[NotificationService] args for sms : ${JSON.stringify(safeArgs)}`);
|
|
2456
|
-
this.url = args.apiUrl
|
|
2457
|
-
this.token = (args.apiKey
|
|
2458
|
-
this.sender = args.senderId
|
|
2459
|
-
this.countryCode = (args.countryCode
|
|
2474
|
+
this.url = this.normalizeUrl(args.apiUrl);
|
|
2475
|
+
this.token = (args.apiKey ?? "").trim();
|
|
2476
|
+
this.sender = (args.senderId ?? "AlmaMedLab").trim();
|
|
2477
|
+
this.countryCode = (args.countryCode ?? "+233").trim();
|
|
2478
|
+
this.masterNumber = args.masterNumber ?? void 0;
|
|
2460
2479
|
}
|
|
2461
2480
|
url;
|
|
2462
2481
|
token;
|
|
2463
2482
|
sender;
|
|
2464
2483
|
countryCode;
|
|
2484
|
+
masterNumber;
|
|
2465
2485
|
/**
|
|
2466
|
-
* Single
|
|
2486
|
+
* Single wrapper (still uses bulk API with one number)
|
|
2467
2487
|
*/
|
|
2468
2488
|
async send(args) {
|
|
2469
|
-
const phone = args?.recipient?.phone;
|
|
2470
|
-
if (!phone) {
|
|
2471
|
-
return { ok: false, provider: "SMS" /* SMS */, error: "Missing recipient.phone" };
|
|
2472
|
-
}
|
|
2473
2489
|
const bulk = await this.sendBulk({
|
|
2474
|
-
phones: [phone],
|
|
2490
|
+
phones: [args.phone],
|
|
2475
2491
|
message: args.body,
|
|
2476
2492
|
includeMaster: true
|
|
2477
2493
|
});
|
|
@@ -2481,38 +2497,31 @@ var SmsProvider = class {
|
|
|
2481
2497
|
return { ok: true, provider: "SMS" /* SMS */, externalId: bulk.externalId, meta: bulk.meta };
|
|
2482
2498
|
}
|
|
2483
2499
|
/**
|
|
2484
|
-
* ✅ Bulk SMS in ONE
|
|
2500
|
+
* ✅ Bulk SMS in ONE API call (recipient: "988..., 977...")
|
|
2485
2501
|
*/
|
|
2486
2502
|
async sendBulk(args) {
|
|
2487
|
-
if (!this.url) {
|
|
2488
|
-
return { ok: false, provider: "SMS" /* SMS */, recipients: [], error: "Missing sms apiUrl" };
|
|
2489
|
-
}
|
|
2490
2503
|
if (!this.token) {
|
|
2491
2504
|
return { ok: false, provider: "SMS" /* SMS */, recipients: [], error: "Missing sms apiKey" };
|
|
2492
2505
|
}
|
|
2493
2506
|
const includeMaster = args.includeMaster ?? true;
|
|
2494
2507
|
const phones = [...args.phones ?? []];
|
|
2495
|
-
if (includeMaster && this.
|
|
2508
|
+
if (includeMaster && this.masterNumber) phones.push(this.masterNumber);
|
|
2496
2509
|
const recipients = this.normalizePhones(phones);
|
|
2497
2510
|
if (!recipients.length) {
|
|
2498
2511
|
return { ok: false, provider: "SMS" /* SMS */, recipients: [], error: "No valid phone recipients" };
|
|
2499
2512
|
}
|
|
2500
|
-
const
|
|
2513
|
+
const payload = {
|
|
2514
|
+
api_token: this.token,
|
|
2515
|
+
recipient: recipients.join(", "),
|
|
2516
|
+
// PHP parity: comma-space separated
|
|
2517
|
+
sender_id: this.sender,
|
|
2518
|
+
type: "plain",
|
|
2519
|
+
message: this.cleanMessage(args.message)
|
|
2520
|
+
};
|
|
2501
2521
|
try {
|
|
2502
|
-
const
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
sender_id: this.sender,
|
|
2506
|
-
type: "plain",
|
|
2507
|
-
message: this.cleanMessage(args.message)
|
|
2508
|
-
};
|
|
2509
|
-
const res = await fetch(this.normalizeUrl(this.url), {
|
|
2510
|
-
method: "POST",
|
|
2511
|
-
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
2512
|
-
body: JSON.stringify(payload)
|
|
2513
|
-
});
|
|
2514
|
-
const data = await res.json().catch(() => ({}));
|
|
2515
|
-
const isError = !res.ok || data?.status === "error";
|
|
2522
|
+
const res = await this.postByIp(this.url, payload);
|
|
2523
|
+
const data = res.data ?? {};
|
|
2524
|
+
const isError = res.status >= 400 || data?.status === "error";
|
|
2516
2525
|
if (isError) {
|
|
2517
2526
|
return {
|
|
2518
2527
|
ok: false,
|
|
@@ -2522,7 +2531,7 @@ var SmsProvider = class {
|
|
|
2522
2531
|
meta: data
|
|
2523
2532
|
};
|
|
2524
2533
|
}
|
|
2525
|
-
const externalId = data?.id || data?.data?.id || data?.message_id || data?.data?.message_id;
|
|
2534
|
+
const externalId = data?.id || data?.data?.id || data?.message_id || data?.data?.message_id || void 0;
|
|
2526
2535
|
return {
|
|
2527
2536
|
ok: true,
|
|
2528
2537
|
provider: "SMS" /* SMS */,
|
|
@@ -2531,22 +2540,27 @@ var SmsProvider = class {
|
|
|
2531
2540
|
meta: data
|
|
2532
2541
|
};
|
|
2533
2542
|
} catch (err) {
|
|
2543
|
+
const cause = err?.cause ?? err;
|
|
2534
2544
|
return {
|
|
2535
2545
|
ok: false,
|
|
2536
2546
|
provider: "SMS" /* SMS */,
|
|
2537
2547
|
recipients,
|
|
2538
|
-
error:
|
|
2548
|
+
error: `SMS request failed: ${cause?.code ?? cause?.message ?? String(cause)}`,
|
|
2549
|
+
meta: {
|
|
2550
|
+
url: this.url,
|
|
2551
|
+
code: cause?.code,
|
|
2552
|
+
message: cause?.message
|
|
2553
|
+
}
|
|
2539
2554
|
};
|
|
2540
2555
|
}
|
|
2541
2556
|
}
|
|
2542
|
-
//
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
*/
|
|
2557
|
+
// --------------------- internal helpers ---------------------
|
|
2558
|
+
normalizeUrl(u) {
|
|
2559
|
+
const x = (u ?? "").trim();
|
|
2560
|
+
if (!x) return DEFAULT_SMS_URL;
|
|
2561
|
+
if (!/^https?:\/\//i.test(x)) return `https://${x}`;
|
|
2562
|
+
return x;
|
|
2563
|
+
}
|
|
2550
2564
|
normalizePhones(input) {
|
|
2551
2565
|
const ccDigits = this.countryCode.replace(/[^\d]/g, "");
|
|
2552
2566
|
const normalized = (input ?? []).map((x) => String(x ?? "").trim()).filter(Boolean).map((x) => x.replace(/[^\d]/g, "")).map((digits) => {
|
|
@@ -2557,21 +2571,51 @@ var SmsProvider = class {
|
|
|
2557
2571
|
}).filter((x) => x.length >= 6);
|
|
2558
2572
|
return Array.from(new Set(normalized));
|
|
2559
2573
|
}
|
|
2560
|
-
normalizeUrl(u) {
|
|
2561
|
-
const x = (u ?? "").trim();
|
|
2562
|
-
if (!x) return "https://web.nsemfua.com/api/http/sms/send";
|
|
2563
|
-
if (!/^https?:\/\//i.test(x)) return `https://${x}`;
|
|
2564
|
-
return x;
|
|
2565
|
-
}
|
|
2566
|
-
/** Mirror PHP cleanup (strip tags, collapse nbsp, trim) */
|
|
2567
2574
|
cleanMessage(msg) {
|
|
2568
2575
|
const noTags = String(msg ?? "").replace(/<\/?[^>]+(>|$)/g, "");
|
|
2569
2576
|
return noTags.replace(/ |&nbsp;/g, " ").trim();
|
|
2570
2577
|
}
|
|
2578
|
+
pickFallbackIp() {
|
|
2579
|
+
const ip = FALLBACK_SMS_IPS[rr++ % FALLBACK_SMS_IPS.length];
|
|
2580
|
+
return ip;
|
|
2581
|
+
}
|
|
2582
|
+
async resolveHostToIp(host) {
|
|
2583
|
+
try {
|
|
2584
|
+
const ips = await import_promises.default.resolve4(host);
|
|
2585
|
+
if (ips?.length) return ips[0];
|
|
2586
|
+
} catch (e) {
|
|
2587
|
+
this.logger.error(`[SmsProvider] DNS resolve4 failed for ${host}: ${e?.code || e?.message}`);
|
|
2588
|
+
}
|
|
2589
|
+
const ip = this.pickFallbackIp();
|
|
2590
|
+
this.logger.info(`[SmsProvider] Using fallback IP for ${host}: ${ip}`);
|
|
2591
|
+
return ip;
|
|
2592
|
+
}
|
|
2593
|
+
async postByIp(urlStr, payload) {
|
|
2594
|
+
const u = new import_node_url.URL(urlStr);
|
|
2595
|
+
const host = u.hostname;
|
|
2596
|
+
const ip = await this.resolveHostToIp(host);
|
|
2597
|
+
const ipUrl = urlStr.replace(host, ip);
|
|
2598
|
+
const httpsAgent = new import_node_https.default.Agent({
|
|
2599
|
+
keepAlive: true,
|
|
2600
|
+
servername: host
|
|
2601
|
+
// ✅ TLS SNI
|
|
2602
|
+
});
|
|
2603
|
+
return import_axios2.default.post(ipUrl, payload, {
|
|
2604
|
+
timeout: 15e3,
|
|
2605
|
+
httpsAgent,
|
|
2606
|
+
headers: {
|
|
2607
|
+
"Content-Type": "application/json",
|
|
2608
|
+
Accept: "application/json",
|
|
2609
|
+
Host: host
|
|
2610
|
+
// ✅ important
|
|
2611
|
+
},
|
|
2612
|
+
validateStatus: () => true
|
|
2613
|
+
});
|
|
2614
|
+
}
|
|
2571
2615
|
};
|
|
2572
2616
|
|
|
2573
2617
|
// src/providers/whatsapp.provider.ts
|
|
2574
|
-
var
|
|
2618
|
+
var import_axios3 = __toESM(require("axios"));
|
|
2575
2619
|
|
|
2576
2620
|
// src/utils/notification.utils.ts
|
|
2577
2621
|
function defaultValueField(t) {
|
|
@@ -2886,7 +2930,7 @@ var WhatsAppProvider = class {
|
|
|
2886
2930
|
}
|
|
2887
2931
|
try {
|
|
2888
2932
|
const { requestBody, headers } = this.buildRequest(to, inp);
|
|
2889
|
-
const response = await
|
|
2933
|
+
const response = await import_axios3.default.post(this.apiUrl, requestBody, { headers });
|
|
2890
2934
|
const data = response.data;
|
|
2891
2935
|
return {
|
|
2892
2936
|
ok: true,
|
|
@@ -2944,7 +2988,7 @@ var WhatsAppProvider = class {
|
|
|
2944
2988
|
const items = await mapWithConcurrency(recipients, concurrency, async (recipient) => {
|
|
2945
2989
|
try {
|
|
2946
2990
|
const { requestBody, headers } = this.buildRequest(recipient, baseInp);
|
|
2947
|
-
const response = await
|
|
2991
|
+
const response = await import_axios3.default.post(this.apiUrl, requestBody, { headers });
|
|
2948
2992
|
const data = response.data;
|
|
2949
2993
|
return {
|
|
2950
2994
|
recipient,
|
|
@@ -3198,36 +3242,19 @@ var NotificationService = class {
|
|
|
3198
3242
|
});
|
|
3199
3243
|
const now = /* @__PURE__ */ new Date();
|
|
3200
3244
|
const auditRecipients = (bulk.recipients?.length ? bulk.recipients : recipients).filter(Boolean);
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
});
|
|
3215
|
-
} else {
|
|
3216
|
-
const errMsg = bulk.error ?? "SMS bulk send failed";
|
|
3217
|
-
await this.prisma.eventDeliveryItem.createMany({
|
|
3218
|
-
data: auditRecipients.map((r) => ({
|
|
3219
|
-
deliveryId,
|
|
3220
|
-
notificationType: "SMS" /* SMS */,
|
|
3221
|
-
recipient: r,
|
|
3222
|
-
messageContent: body,
|
|
3223
|
-
thirdPartyResponse: bulk.meta ?? void 0,
|
|
3224
|
-
isSent: false,
|
|
3225
|
-
sentAt: null,
|
|
3226
|
-
externalId: bulk.externalId ?? null,
|
|
3227
|
-
error: errMsg
|
|
3228
|
-
}))
|
|
3229
|
-
});
|
|
3230
|
-
}
|
|
3245
|
+
await this.prisma.eventDeliveryItem.createMany({
|
|
3246
|
+
data: auditRecipients.map((r) => ({
|
|
3247
|
+
deliveryId,
|
|
3248
|
+
notificationType: "SMS" /* SMS */,
|
|
3249
|
+
recipient: r,
|
|
3250
|
+
messageContent: body,
|
|
3251
|
+
thirdPartyResponse: bulk.meta ?? void 0,
|
|
3252
|
+
isSent: bulk.ok,
|
|
3253
|
+
sentAt: bulk.ok ? now : null,
|
|
3254
|
+
externalId: bulk.externalId ?? null,
|
|
3255
|
+
error: bulk.ok ? null : bulk.error ?? "SMS bulk send failed"
|
|
3256
|
+
}))
|
|
3257
|
+
});
|
|
3231
3258
|
}
|
|
3232
3259
|
async processAppChannel(args) {
|
|
3233
3260
|
const { cfg, evt, deliveryId } = args;
|
package/dist/index.mjs
CHANGED
|
@@ -2397,31 +2397,47 @@ var EmailProvider = class {
|
|
|
2397
2397
|
};
|
|
2398
2398
|
|
|
2399
2399
|
// src/providers/sms.provider.ts
|
|
2400
|
+
import axios2 from "axios";
|
|
2401
|
+
import https from "https";
|
|
2402
|
+
import dns from "dns/promises";
|
|
2403
|
+
import { URL } from "url";
|
|
2404
|
+
var DEFAULT_SMS_URL = "https://web.nsemfua.com/api/http/sms/send";
|
|
2405
|
+
var FALLBACK_SMS_IPS = [
|
|
2406
|
+
"185.38.109.200",
|
|
2407
|
+
"185.38.109.201",
|
|
2408
|
+
"185.38.109.202",
|
|
2409
|
+
"185.38.109.203",
|
|
2410
|
+
"185.38.109.204",
|
|
2411
|
+
"185.38.109.205",
|
|
2412
|
+
"185.38.109.206",
|
|
2413
|
+
"185.38.109.207",
|
|
2414
|
+
"185.38.109.208",
|
|
2415
|
+
"185.38.109.209"
|
|
2416
|
+
];
|
|
2417
|
+
var rr = 0;
|
|
2400
2418
|
var SmsProvider = class {
|
|
2401
2419
|
constructor(logger = console, args) {
|
|
2402
2420
|
this.logger = logger;
|
|
2403
2421
|
this.args = args;
|
|
2404
2422
|
const safeArgs = { ...args, apiKey: args.apiKey ? "***" : "" };
|
|
2405
2423
|
this.logger.info(`[NotificationService] args for sms : ${JSON.stringify(safeArgs)}`);
|
|
2406
|
-
this.url = args.apiUrl
|
|
2407
|
-
this.token = (args.apiKey
|
|
2408
|
-
this.sender = args.senderId
|
|
2409
|
-
this.countryCode = (args.countryCode
|
|
2424
|
+
this.url = this.normalizeUrl(args.apiUrl);
|
|
2425
|
+
this.token = (args.apiKey ?? "").trim();
|
|
2426
|
+
this.sender = (args.senderId ?? "AlmaMedLab").trim();
|
|
2427
|
+
this.countryCode = (args.countryCode ?? "+233").trim();
|
|
2428
|
+
this.masterNumber = args.masterNumber ?? void 0;
|
|
2410
2429
|
}
|
|
2411
2430
|
url;
|
|
2412
2431
|
token;
|
|
2413
2432
|
sender;
|
|
2414
2433
|
countryCode;
|
|
2434
|
+
masterNumber;
|
|
2415
2435
|
/**
|
|
2416
|
-
* Single
|
|
2436
|
+
* Single wrapper (still uses bulk API with one number)
|
|
2417
2437
|
*/
|
|
2418
2438
|
async send(args) {
|
|
2419
|
-
const phone = args?.recipient?.phone;
|
|
2420
|
-
if (!phone) {
|
|
2421
|
-
return { ok: false, provider: "SMS" /* SMS */, error: "Missing recipient.phone" };
|
|
2422
|
-
}
|
|
2423
2439
|
const bulk = await this.sendBulk({
|
|
2424
|
-
phones: [phone],
|
|
2440
|
+
phones: [args.phone],
|
|
2425
2441
|
message: args.body,
|
|
2426
2442
|
includeMaster: true
|
|
2427
2443
|
});
|
|
@@ -2431,38 +2447,31 @@ var SmsProvider = class {
|
|
|
2431
2447
|
return { ok: true, provider: "SMS" /* SMS */, externalId: bulk.externalId, meta: bulk.meta };
|
|
2432
2448
|
}
|
|
2433
2449
|
/**
|
|
2434
|
-
* ✅ Bulk SMS in ONE
|
|
2450
|
+
* ✅ Bulk SMS in ONE API call (recipient: "988..., 977...")
|
|
2435
2451
|
*/
|
|
2436
2452
|
async sendBulk(args) {
|
|
2437
|
-
if (!this.url) {
|
|
2438
|
-
return { ok: false, provider: "SMS" /* SMS */, recipients: [], error: "Missing sms apiUrl" };
|
|
2439
|
-
}
|
|
2440
2453
|
if (!this.token) {
|
|
2441
2454
|
return { ok: false, provider: "SMS" /* SMS */, recipients: [], error: "Missing sms apiKey" };
|
|
2442
2455
|
}
|
|
2443
2456
|
const includeMaster = args.includeMaster ?? true;
|
|
2444
2457
|
const phones = [...args.phones ?? []];
|
|
2445
|
-
if (includeMaster && this.
|
|
2458
|
+
if (includeMaster && this.masterNumber) phones.push(this.masterNumber);
|
|
2446
2459
|
const recipients = this.normalizePhones(phones);
|
|
2447
2460
|
if (!recipients.length) {
|
|
2448
2461
|
return { ok: false, provider: "SMS" /* SMS */, recipients: [], error: "No valid phone recipients" };
|
|
2449
2462
|
}
|
|
2450
|
-
const
|
|
2463
|
+
const payload = {
|
|
2464
|
+
api_token: this.token,
|
|
2465
|
+
recipient: recipients.join(", "),
|
|
2466
|
+
// PHP parity: comma-space separated
|
|
2467
|
+
sender_id: this.sender,
|
|
2468
|
+
type: "plain",
|
|
2469
|
+
message: this.cleanMessage(args.message)
|
|
2470
|
+
};
|
|
2451
2471
|
try {
|
|
2452
|
-
const
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
sender_id: this.sender,
|
|
2456
|
-
type: "plain",
|
|
2457
|
-
message: this.cleanMessage(args.message)
|
|
2458
|
-
};
|
|
2459
|
-
const res = await fetch(this.normalizeUrl(this.url), {
|
|
2460
|
-
method: "POST",
|
|
2461
|
-
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
2462
|
-
body: JSON.stringify(payload)
|
|
2463
|
-
});
|
|
2464
|
-
const data = await res.json().catch(() => ({}));
|
|
2465
|
-
const isError = !res.ok || data?.status === "error";
|
|
2472
|
+
const res = await this.postByIp(this.url, payload);
|
|
2473
|
+
const data = res.data ?? {};
|
|
2474
|
+
const isError = res.status >= 400 || data?.status === "error";
|
|
2466
2475
|
if (isError) {
|
|
2467
2476
|
return {
|
|
2468
2477
|
ok: false,
|
|
@@ -2472,7 +2481,7 @@ var SmsProvider = class {
|
|
|
2472
2481
|
meta: data
|
|
2473
2482
|
};
|
|
2474
2483
|
}
|
|
2475
|
-
const externalId = data?.id || data?.data?.id || data?.message_id || data?.data?.message_id;
|
|
2484
|
+
const externalId = data?.id || data?.data?.id || data?.message_id || data?.data?.message_id || void 0;
|
|
2476
2485
|
return {
|
|
2477
2486
|
ok: true,
|
|
2478
2487
|
provider: "SMS" /* SMS */,
|
|
@@ -2481,22 +2490,27 @@ var SmsProvider = class {
|
|
|
2481
2490
|
meta: data
|
|
2482
2491
|
};
|
|
2483
2492
|
} catch (err) {
|
|
2493
|
+
const cause = err?.cause ?? err;
|
|
2484
2494
|
return {
|
|
2485
2495
|
ok: false,
|
|
2486
2496
|
provider: "SMS" /* SMS */,
|
|
2487
2497
|
recipients,
|
|
2488
|
-
error:
|
|
2498
|
+
error: `SMS request failed: ${cause?.code ?? cause?.message ?? String(cause)}`,
|
|
2499
|
+
meta: {
|
|
2500
|
+
url: this.url,
|
|
2501
|
+
code: cause?.code,
|
|
2502
|
+
message: cause?.message
|
|
2503
|
+
}
|
|
2489
2504
|
};
|
|
2490
2505
|
}
|
|
2491
2506
|
}
|
|
2492
|
-
//
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
*/
|
|
2507
|
+
// --------------------- internal helpers ---------------------
|
|
2508
|
+
normalizeUrl(u) {
|
|
2509
|
+
const x = (u ?? "").trim();
|
|
2510
|
+
if (!x) return DEFAULT_SMS_URL;
|
|
2511
|
+
if (!/^https?:\/\//i.test(x)) return `https://${x}`;
|
|
2512
|
+
return x;
|
|
2513
|
+
}
|
|
2500
2514
|
normalizePhones(input) {
|
|
2501
2515
|
const ccDigits = this.countryCode.replace(/[^\d]/g, "");
|
|
2502
2516
|
const normalized = (input ?? []).map((x) => String(x ?? "").trim()).filter(Boolean).map((x) => x.replace(/[^\d]/g, "")).map((digits) => {
|
|
@@ -2507,21 +2521,51 @@ var SmsProvider = class {
|
|
|
2507
2521
|
}).filter((x) => x.length >= 6);
|
|
2508
2522
|
return Array.from(new Set(normalized));
|
|
2509
2523
|
}
|
|
2510
|
-
normalizeUrl(u) {
|
|
2511
|
-
const x = (u ?? "").trim();
|
|
2512
|
-
if (!x) return "https://web.nsemfua.com/api/http/sms/send";
|
|
2513
|
-
if (!/^https?:\/\//i.test(x)) return `https://${x}`;
|
|
2514
|
-
return x;
|
|
2515
|
-
}
|
|
2516
|
-
/** Mirror PHP cleanup (strip tags, collapse nbsp, trim) */
|
|
2517
2524
|
cleanMessage(msg) {
|
|
2518
2525
|
const noTags = String(msg ?? "").replace(/<\/?[^>]+(>|$)/g, "");
|
|
2519
2526
|
return noTags.replace(/ |&nbsp;/g, " ").trim();
|
|
2520
2527
|
}
|
|
2528
|
+
pickFallbackIp() {
|
|
2529
|
+
const ip = FALLBACK_SMS_IPS[rr++ % FALLBACK_SMS_IPS.length];
|
|
2530
|
+
return ip;
|
|
2531
|
+
}
|
|
2532
|
+
async resolveHostToIp(host) {
|
|
2533
|
+
try {
|
|
2534
|
+
const ips = await dns.resolve4(host);
|
|
2535
|
+
if (ips?.length) return ips[0];
|
|
2536
|
+
} catch (e) {
|
|
2537
|
+
this.logger.error(`[SmsProvider] DNS resolve4 failed for ${host}: ${e?.code || e?.message}`);
|
|
2538
|
+
}
|
|
2539
|
+
const ip = this.pickFallbackIp();
|
|
2540
|
+
this.logger.info(`[SmsProvider] Using fallback IP for ${host}: ${ip}`);
|
|
2541
|
+
return ip;
|
|
2542
|
+
}
|
|
2543
|
+
async postByIp(urlStr, payload) {
|
|
2544
|
+
const u = new URL(urlStr);
|
|
2545
|
+
const host = u.hostname;
|
|
2546
|
+
const ip = await this.resolveHostToIp(host);
|
|
2547
|
+
const ipUrl = urlStr.replace(host, ip);
|
|
2548
|
+
const httpsAgent = new https.Agent({
|
|
2549
|
+
keepAlive: true,
|
|
2550
|
+
servername: host
|
|
2551
|
+
// ✅ TLS SNI
|
|
2552
|
+
});
|
|
2553
|
+
return axios2.post(ipUrl, payload, {
|
|
2554
|
+
timeout: 15e3,
|
|
2555
|
+
httpsAgent,
|
|
2556
|
+
headers: {
|
|
2557
|
+
"Content-Type": "application/json",
|
|
2558
|
+
Accept: "application/json",
|
|
2559
|
+
Host: host
|
|
2560
|
+
// ✅ important
|
|
2561
|
+
},
|
|
2562
|
+
validateStatus: () => true
|
|
2563
|
+
});
|
|
2564
|
+
}
|
|
2521
2565
|
};
|
|
2522
2566
|
|
|
2523
2567
|
// src/providers/whatsapp.provider.ts
|
|
2524
|
-
import
|
|
2568
|
+
import axios3 from "axios";
|
|
2525
2569
|
|
|
2526
2570
|
// src/utils/notification.utils.ts
|
|
2527
2571
|
function defaultValueField(t) {
|
|
@@ -2836,7 +2880,7 @@ var WhatsAppProvider = class {
|
|
|
2836
2880
|
}
|
|
2837
2881
|
try {
|
|
2838
2882
|
const { requestBody, headers } = this.buildRequest(to, inp);
|
|
2839
|
-
const response = await
|
|
2883
|
+
const response = await axios3.post(this.apiUrl, requestBody, { headers });
|
|
2840
2884
|
const data = response.data;
|
|
2841
2885
|
return {
|
|
2842
2886
|
ok: true,
|
|
@@ -2894,7 +2938,7 @@ var WhatsAppProvider = class {
|
|
|
2894
2938
|
const items = await mapWithConcurrency(recipients, concurrency, async (recipient) => {
|
|
2895
2939
|
try {
|
|
2896
2940
|
const { requestBody, headers } = this.buildRequest(recipient, baseInp);
|
|
2897
|
-
const response = await
|
|
2941
|
+
const response = await axios3.post(this.apiUrl, requestBody, { headers });
|
|
2898
2942
|
const data = response.data;
|
|
2899
2943
|
return {
|
|
2900
2944
|
recipient,
|
|
@@ -3148,36 +3192,19 @@ var NotificationService = class {
|
|
|
3148
3192
|
});
|
|
3149
3193
|
const now = /* @__PURE__ */ new Date();
|
|
3150
3194
|
const auditRecipients = (bulk.recipients?.length ? bulk.recipients : recipients).filter(Boolean);
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
});
|
|
3165
|
-
} else {
|
|
3166
|
-
const errMsg = bulk.error ?? "SMS bulk send failed";
|
|
3167
|
-
await this.prisma.eventDeliveryItem.createMany({
|
|
3168
|
-
data: auditRecipients.map((r) => ({
|
|
3169
|
-
deliveryId,
|
|
3170
|
-
notificationType: "SMS" /* SMS */,
|
|
3171
|
-
recipient: r,
|
|
3172
|
-
messageContent: body,
|
|
3173
|
-
thirdPartyResponse: bulk.meta ?? void 0,
|
|
3174
|
-
isSent: false,
|
|
3175
|
-
sentAt: null,
|
|
3176
|
-
externalId: bulk.externalId ?? null,
|
|
3177
|
-
error: errMsg
|
|
3178
|
-
}))
|
|
3179
|
-
});
|
|
3180
|
-
}
|
|
3195
|
+
await this.prisma.eventDeliveryItem.createMany({
|
|
3196
|
+
data: auditRecipients.map((r) => ({
|
|
3197
|
+
deliveryId,
|
|
3198
|
+
notificationType: "SMS" /* SMS */,
|
|
3199
|
+
recipient: r,
|
|
3200
|
+
messageContent: body,
|
|
3201
|
+
thirdPartyResponse: bulk.meta ?? void 0,
|
|
3202
|
+
isSent: bulk.ok,
|
|
3203
|
+
sentAt: bulk.ok ? now : null,
|
|
3204
|
+
externalId: bulk.externalId ?? null,
|
|
3205
|
+
error: bulk.ok ? null : bulk.error ?? "SMS bulk send failed"
|
|
3206
|
+
}))
|
|
3207
|
+
});
|
|
3181
3208
|
}
|
|
3182
3209
|
async processAppChannel(args) {
|
|
3183
3210
|
const { cfg, evt, deliveryId } = args;
|