@warriorteam/redai-zalo-sdk 1.28.0 → 1.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +62 -0
- package/ZNS-TYPE-IMPROVEMENTS.md +220 -0
- package/dist/services/zns.service.d.ts.map +1 -1
- package/dist/services/zns.service.js +145 -157
- package/dist/services/zns.service.js.map +1 -1
- package/dist/types/zns.d.ts +95 -0
- package/dist/types/zns.d.ts.map +1 -1
- package/examples/zns-validation-example.ts +362 -0
- package/package.json +10 -4
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ZNSService = void 0;
|
|
4
|
+
const common_1 = require("../types/common");
|
|
4
5
|
/**
|
|
5
6
|
* Service for Zalo Notification Service (ZNS)
|
|
6
7
|
*
|
|
@@ -207,7 +208,7 @@ class ZNSService {
|
|
|
207
208
|
try {
|
|
208
209
|
// Validate limit (max 100)
|
|
209
210
|
if (limit > 100) {
|
|
210
|
-
throw new
|
|
211
|
+
throw new common_1.ZaloSDKError("Limit không được vượt quá 100", 400);
|
|
211
212
|
}
|
|
212
213
|
// Prepare query parameters
|
|
213
214
|
const params = { offset, limit };
|
|
@@ -357,25 +358,12 @@ class ZNSService {
|
|
|
357
358
|
*/
|
|
358
359
|
async updateTemplate(accessToken, templateData) {
|
|
359
360
|
try {
|
|
360
|
-
// Validate
|
|
361
|
+
// Validate template_id first
|
|
361
362
|
if (!templateData.template_id) {
|
|
362
|
-
throw new
|
|
363
|
-
}
|
|
364
|
-
if (!templateData.template_name) {
|
|
365
|
-
throw new Error("template_name is required");
|
|
366
|
-
}
|
|
367
|
-
if (!templateData.template_type) {
|
|
368
|
-
throw new Error("template_type is required");
|
|
369
|
-
}
|
|
370
|
-
if (!templateData.tag) {
|
|
371
|
-
throw new Error("tag is required");
|
|
372
|
-
}
|
|
373
|
-
if (!templateData.layout) {
|
|
374
|
-
throw new Error("layout is required");
|
|
375
|
-
}
|
|
376
|
-
if (!templateData.tracking_id) {
|
|
377
|
-
throw new Error("tracking_id is required");
|
|
363
|
+
throw new common_1.ZaloSDKError("template_id là bắt buộc", 400);
|
|
378
364
|
}
|
|
365
|
+
// Comprehensive validation (same as createTemplate)
|
|
366
|
+
this.validateZNSTemplateRequest(templateData);
|
|
379
367
|
const response = await this.client.apiPost(this.endpoints.template.edit, accessToken, templateData);
|
|
380
368
|
return response;
|
|
381
369
|
}
|
|
@@ -406,13 +394,13 @@ class ZNSService {
|
|
|
406
394
|
.toLowerCase()
|
|
407
395
|
.substring(filename.lastIndexOf("."));
|
|
408
396
|
if (!allowedExtensions.includes(fileExtension)) {
|
|
409
|
-
throw new
|
|
397
|
+
throw new common_1.ZaloSDKError("File phải có định dạng JPG hoặc PNG", 400);
|
|
410
398
|
}
|
|
411
399
|
// Validate file size if it's a Buffer (max 500KB)
|
|
412
400
|
if (Buffer.isBuffer(imageFile)) {
|
|
413
401
|
const maxSize = 500 * 1024; // 500KB
|
|
414
402
|
if (imageFile.length > maxSize) {
|
|
415
|
-
throw new
|
|
403
|
+
throw new common_1.ZaloSDKError("Dung lượng file không được vượt quá 500KB", 400);
|
|
416
404
|
}
|
|
417
405
|
}
|
|
418
406
|
const response = await this.client.apiUploadFile(this.endpoints.template.uploadImage, accessToken, imageFile, filename);
|
|
@@ -439,7 +427,7 @@ class ZNSService {
|
|
|
439
427
|
// 5. Note validation if provided
|
|
440
428
|
if (templateData.note) {
|
|
441
429
|
if (templateData.note.length < 1 || templateData.note.length > 400) {
|
|
442
|
-
throw new
|
|
430
|
+
throw new common_1.ZaloSDKError("note phải có độ dài từ 1 đến 400 ký tự", 400);
|
|
443
431
|
}
|
|
444
432
|
}
|
|
445
433
|
}
|
|
@@ -448,31 +436,31 @@ class ZNSService {
|
|
|
448
436
|
*/
|
|
449
437
|
validateBasicFields(templateData) {
|
|
450
438
|
if (!templateData.template_name) {
|
|
451
|
-
throw new
|
|
439
|
+
throw new common_1.ZaloSDKError("template_name là bắt buộc", 400);
|
|
452
440
|
}
|
|
453
441
|
if (templateData.template_name.length < 10 || templateData.template_name.length > 60) {
|
|
454
|
-
throw new
|
|
442
|
+
throw new common_1.ZaloSDKError("template_name phải có độ dài từ 10 đến 60 ký tự", 400);
|
|
455
443
|
}
|
|
456
444
|
if (!templateData.template_type) {
|
|
457
|
-
throw new
|
|
445
|
+
throw new common_1.ZaloSDKError("template_type là bắt buộc", 400);
|
|
458
446
|
}
|
|
459
447
|
if (![1, 2, 3, 4, 5].includes(templateData.template_type)) {
|
|
460
|
-
throw new
|
|
448
|
+
throw new common_1.ZaloSDKError("template_type phải là 1, 2, 3, 4 hoặc 5", 400);
|
|
461
449
|
}
|
|
462
450
|
if (!templateData.tag) {
|
|
463
|
-
throw new
|
|
451
|
+
throw new common_1.ZaloSDKError("tag là bắt buộc", 400);
|
|
464
452
|
}
|
|
465
453
|
if (!["1", "2", "3"].includes(templateData.tag)) {
|
|
466
|
-
throw new
|
|
454
|
+
throw new common_1.ZaloSDKError("tag phải là '1', '2' hoặc '3'", 400);
|
|
467
455
|
}
|
|
468
456
|
if (!templateData.layout) {
|
|
469
|
-
throw new
|
|
457
|
+
throw new common_1.ZaloSDKError("layout là bắt buộc", 400);
|
|
470
458
|
}
|
|
471
459
|
if (!Array.isArray(templateData.layout) && typeof templateData.layout !== 'object') {
|
|
472
|
-
throw new
|
|
460
|
+
throw new common_1.ZaloSDKError("layout phải là array hoặc object", 400);
|
|
473
461
|
}
|
|
474
462
|
if (!templateData.tracking_id) {
|
|
475
|
-
throw new
|
|
463
|
+
throw new common_1.ZaloSDKError("tracking_id là bắt buộc", 400);
|
|
476
464
|
}
|
|
477
465
|
}
|
|
478
466
|
/**
|
|
@@ -487,7 +475,7 @@ class ZNSService {
|
|
|
487
475
|
5: ["2"] // ZNS đánh giá dịch vụ
|
|
488
476
|
};
|
|
489
477
|
if (!compatibility[templateType]?.includes(tag)) {
|
|
490
|
-
throw new
|
|
478
|
+
throw new common_1.ZaloSDKError(`template_type ${templateType} không tương thích với tag ${tag}`, 400);
|
|
491
479
|
}
|
|
492
480
|
}
|
|
493
481
|
/**
|
|
@@ -520,7 +508,7 @@ class ZNSService {
|
|
|
520
508
|
allComponents = [...headerComponents, ...bodyComponents, ...footerComponents];
|
|
521
509
|
}
|
|
522
510
|
else {
|
|
523
|
-
throw new
|
|
511
|
+
throw new common_1.ZaloSDKError("layout phải là array hoặc object có cấu trúc header/body/footer", 400);
|
|
524
512
|
}
|
|
525
513
|
switch (templateType) {
|
|
526
514
|
case 1: // ZNS tùy chỉnh
|
|
@@ -546,20 +534,20 @@ class ZNSService {
|
|
|
546
534
|
* Check if component belongs to header
|
|
547
535
|
*/
|
|
548
536
|
isHeaderComponent(component) {
|
|
549
|
-
return
|
|
537
|
+
return 'LOGO' in component || 'IMAGES' in component;
|
|
550
538
|
}
|
|
551
539
|
/**
|
|
552
540
|
* Check if component belongs to body
|
|
553
541
|
*/
|
|
554
542
|
isBodyComponent(component) {
|
|
555
|
-
return
|
|
556
|
-
|
|
543
|
+
return 'TITLE' in component || 'PARAGRAPH' in component || 'TABLE' in component ||
|
|
544
|
+
'OTP' in component || 'PAYMENT' in component || 'VOUCHER' in component || 'RATING' in component;
|
|
557
545
|
}
|
|
558
546
|
/**
|
|
559
547
|
* Check if component belongs to footer
|
|
560
548
|
*/
|
|
561
549
|
isFooterComponent(component) {
|
|
562
|
-
return component
|
|
550
|
+
return 'BUTTONS' in component;
|
|
563
551
|
}
|
|
564
552
|
/**
|
|
565
553
|
* Validate custom template layout (type 1)
|
|
@@ -567,29 +555,29 @@ class ZNSService {
|
|
|
567
555
|
validateCustomTemplateLayout(header, body, footer) {
|
|
568
556
|
// Header: Logo OR Image (exactly 1)
|
|
569
557
|
if (header.length !== 1) {
|
|
570
|
-
throw new
|
|
558
|
+
throw new common_1.ZaloSDKError("ZNS tùy chỉnh phải có đúng 1 component trong header (Logo hoặc Image)", 400);
|
|
571
559
|
}
|
|
572
560
|
// Body: Title (1) + Paragraph (0-4) + Table (0-1)
|
|
573
|
-
const titles = body.filter(c => c
|
|
574
|
-
const paragraphs = body.filter(c => c
|
|
575
|
-
const tables = body.filter(c => c
|
|
561
|
+
const titles = body.filter(c => 'TITLE' in c);
|
|
562
|
+
const paragraphs = body.filter(c => 'PARAGRAPH' in c);
|
|
563
|
+
const tables = body.filter(c => 'TABLE' in c);
|
|
576
564
|
if (titles.length !== 1) {
|
|
577
|
-
throw new
|
|
565
|
+
throw new common_1.ZaloSDKError("ZNS tùy chỉnh phải có đúng 1 component TITLE", 400);
|
|
578
566
|
}
|
|
579
567
|
if (paragraphs.length > 4) {
|
|
580
|
-
throw new
|
|
568
|
+
throw new common_1.ZaloSDKError("ZNS tùy chỉnh không được có quá 4 component PARAGRAPH", 400);
|
|
581
569
|
}
|
|
582
570
|
if (tables.length > 1) {
|
|
583
|
-
throw new
|
|
571
|
+
throw new common_1.ZaloSDKError("ZNS tùy chỉnh không được có quá 1 component TABLE", 400);
|
|
584
572
|
}
|
|
585
573
|
// Footer: Buttons (0-2)
|
|
586
574
|
if (footer.length > 2) {
|
|
587
|
-
throw new
|
|
575
|
+
throw new common_1.ZaloSDKError("ZNS tùy chỉnh không được có quá 2 button", 400);
|
|
588
576
|
}
|
|
589
577
|
// If has image, must have at least 1 button
|
|
590
|
-
const hasImage = header.some(c => c
|
|
578
|
+
const hasImage = header.some(c => 'IMAGES' in c);
|
|
591
579
|
if (hasImage && footer.length === 0) {
|
|
592
|
-
throw new
|
|
580
|
+
throw new common_1.ZaloSDKError("ZNS có component Image phải có ít nhất 1 button", 400);
|
|
593
581
|
}
|
|
594
582
|
}
|
|
595
583
|
/**
|
|
@@ -597,21 +585,21 @@ class ZNSService {
|
|
|
597
585
|
*/
|
|
598
586
|
validateAuthTemplateLayout(header, body, footer) {
|
|
599
587
|
// Header: Logo only (1)
|
|
600
|
-
if (header.length !== 1 || !header[0]
|
|
601
|
-
throw new
|
|
588
|
+
if (header.length !== 1 || !('LOGO' in header[0])) {
|
|
589
|
+
throw new common_1.ZaloSDKError("ZNS xác thực phải có đúng 1 component LOGO trong header", 400);
|
|
602
590
|
}
|
|
603
591
|
// Body: OTP (1) + Paragraph (1)
|
|
604
|
-
const otps = body.filter(c => c
|
|
605
|
-
const paragraphs = body.filter(c => c
|
|
592
|
+
const otps = body.filter(c => 'OTP' in c);
|
|
593
|
+
const paragraphs = body.filter(c => 'PARAGRAPH' in c);
|
|
606
594
|
if (otps.length !== 1) {
|
|
607
|
-
throw new
|
|
595
|
+
throw new common_1.ZaloSDKError("ZNS xác thực phải có đúng 1 component OTP", 400);
|
|
608
596
|
}
|
|
609
597
|
if (paragraphs.length !== 1) {
|
|
610
|
-
throw new
|
|
598
|
+
throw new common_1.ZaloSDKError("ZNS xác thực phải có đúng 1 component PARAGRAPH", 400);
|
|
611
599
|
}
|
|
612
600
|
// Footer: None
|
|
613
601
|
if (footer.length > 0) {
|
|
614
|
-
throw new
|
|
602
|
+
throw new common_1.ZaloSDKError("ZNS xác thực không được có component trong footer", 400);
|
|
615
603
|
}
|
|
616
604
|
}
|
|
617
605
|
/**
|
|
@@ -619,29 +607,29 @@ class ZNSService {
|
|
|
619
607
|
*/
|
|
620
608
|
validatePaymentTemplateLayout(header, body, footer) {
|
|
621
609
|
// Header: Logo only (1)
|
|
622
|
-
if (header.length !== 1 || !header[0]
|
|
623
|
-
throw new
|
|
610
|
+
if (header.length !== 1 || !('LOGO' in header[0])) {
|
|
611
|
+
throw new common_1.ZaloSDKError("ZNS yêu cầu thanh toán phải có đúng 1 component LOGO trong header", 400);
|
|
624
612
|
}
|
|
625
613
|
// Body: Title (1) + Paragraph (0-4) + Table (0-1) + Payment (1)
|
|
626
|
-
const titles = body.filter(c => c
|
|
627
|
-
const paragraphs = body.filter(c => c
|
|
628
|
-
const tables = body.filter(c => c
|
|
629
|
-
const payments = body.filter(c => c
|
|
614
|
+
const titles = body.filter(c => 'TITLE' in c);
|
|
615
|
+
const paragraphs = body.filter(c => 'PARAGRAPH' in c);
|
|
616
|
+
const tables = body.filter(c => 'TABLE' in c);
|
|
617
|
+
const payments = body.filter(c => 'PAYMENT' in c);
|
|
630
618
|
if (titles.length !== 1) {
|
|
631
|
-
throw new
|
|
619
|
+
throw new common_1.ZaloSDKError("ZNS yêu cầu thanh toán phải có đúng 1 component TITLE", 400);
|
|
632
620
|
}
|
|
633
621
|
if (paragraphs.length > 4) {
|
|
634
|
-
throw new
|
|
622
|
+
throw new common_1.ZaloSDKError("ZNS yêu cầu thanh toán không được có quá 4 component PARAGRAPH", 400);
|
|
635
623
|
}
|
|
636
624
|
if (tables.length > 1) {
|
|
637
|
-
throw new
|
|
625
|
+
throw new common_1.ZaloSDKError("ZNS yêu cầu thanh toán không được có quá 1 component TABLE", 400);
|
|
638
626
|
}
|
|
639
627
|
if (payments.length !== 1) {
|
|
640
|
-
throw new
|
|
628
|
+
throw new common_1.ZaloSDKError("ZNS yêu cầu thanh toán phải có đúng 1 component PAYMENT", 400);
|
|
641
629
|
}
|
|
642
630
|
// Footer: Buttons (0-2)
|
|
643
631
|
if (footer.length > 2) {
|
|
644
|
-
throw new
|
|
632
|
+
throw new common_1.ZaloSDKError("ZNS yêu cầu thanh toán không được có quá 2 button", 400);
|
|
645
633
|
}
|
|
646
634
|
}
|
|
647
635
|
/**
|
|
@@ -650,33 +638,33 @@ class ZNSService {
|
|
|
650
638
|
validateVoucherTemplateLayout(header, body, footer) {
|
|
651
639
|
// Header: Logo OR Image (exactly 1)
|
|
652
640
|
if (header.length !== 1) {
|
|
653
|
-
throw new
|
|
641
|
+
throw new common_1.ZaloSDKError("ZNS voucher phải có đúng 1 component trong header (Logo hoặc Image)", 400);
|
|
654
642
|
}
|
|
655
643
|
// Body: Title (1) + Paragraph (0-4) + Table (0-1) + Voucher (1)
|
|
656
|
-
const titles = body.filter(c => c
|
|
657
|
-
const paragraphs = body.filter(c => c
|
|
658
|
-
const tables = body.filter(c => c
|
|
659
|
-
const vouchers = body.filter(c => c
|
|
644
|
+
const titles = body.filter(c => 'TITLE' in c);
|
|
645
|
+
const paragraphs = body.filter(c => 'PARAGRAPH' in c);
|
|
646
|
+
const tables = body.filter(c => 'TABLE' in c);
|
|
647
|
+
const vouchers = body.filter(c => 'VOUCHER' in c);
|
|
660
648
|
if (titles.length !== 1) {
|
|
661
|
-
throw new
|
|
649
|
+
throw new common_1.ZaloSDKError("ZNS voucher phải có đúng 1 component TITLE", 400);
|
|
662
650
|
}
|
|
663
651
|
if (paragraphs.length > 4) {
|
|
664
|
-
throw new
|
|
652
|
+
throw new common_1.ZaloSDKError("ZNS voucher không được có quá 4 component PARAGRAPH", 400);
|
|
665
653
|
}
|
|
666
654
|
if (tables.length > 1) {
|
|
667
|
-
throw new
|
|
655
|
+
throw new common_1.ZaloSDKError("ZNS voucher không được có quá 1 component TABLE", 400);
|
|
668
656
|
}
|
|
669
657
|
if (vouchers.length !== 1) {
|
|
670
|
-
throw new
|
|
658
|
+
throw new common_1.ZaloSDKError("ZNS voucher phải có đúng 1 component VOUCHER", 400);
|
|
671
659
|
}
|
|
672
660
|
// Footer: Buttons (0-2)
|
|
673
661
|
if (footer.length > 2) {
|
|
674
|
-
throw new
|
|
662
|
+
throw new common_1.ZaloSDKError("ZNS voucher không được có quá 2 button", 400);
|
|
675
663
|
}
|
|
676
664
|
// If has image, must have at least 1 button, max 2
|
|
677
|
-
const hasImage = header.some(c => c
|
|
665
|
+
const hasImage = header.some(c => 'IMAGES' in c);
|
|
678
666
|
if (hasImage && footer.length === 0) {
|
|
679
|
-
throw new
|
|
667
|
+
throw new common_1.ZaloSDKError("ZNS voucher có component Image phải có ít nhất 1 button", 400);
|
|
680
668
|
}
|
|
681
669
|
}
|
|
682
670
|
/**
|
|
@@ -684,59 +672,59 @@ class ZNSService {
|
|
|
684
672
|
*/
|
|
685
673
|
validateRatingTemplateLayout(header, body, footer) {
|
|
686
674
|
// Header: Logo only (1)
|
|
687
|
-
if (header.length !== 1 || !header[0]
|
|
688
|
-
throw new
|
|
675
|
+
if (header.length !== 1 || !('LOGO' in header[0])) {
|
|
676
|
+
throw new common_1.ZaloSDKError("ZNS đánh giá dịch vụ phải có đúng 1 component LOGO trong header", 400);
|
|
689
677
|
}
|
|
690
678
|
// Body: Title (1) + Paragraph (0-1) + Rating (1)
|
|
691
|
-
const titles = body.filter(c => c
|
|
692
|
-
const paragraphs = body.filter(c => c
|
|
693
|
-
const ratings = body.filter(c => c
|
|
679
|
+
const titles = body.filter(c => 'TITLE' in c);
|
|
680
|
+
const paragraphs = body.filter(c => 'PARAGRAPH' in c);
|
|
681
|
+
const ratings = body.filter(c => 'RATING' in c);
|
|
694
682
|
if (titles.length !== 1) {
|
|
695
|
-
throw new
|
|
683
|
+
throw new common_1.ZaloSDKError("ZNS đánh giá dịch vụ phải có đúng 1 component TITLE", 400);
|
|
696
684
|
}
|
|
697
685
|
if (paragraphs.length > 1) {
|
|
698
|
-
throw new
|
|
686
|
+
throw new common_1.ZaloSDKError("ZNS đánh giá dịch vụ không được có quá 1 component PARAGRAPH", 400);
|
|
699
687
|
}
|
|
700
688
|
if (ratings.length !== 1) {
|
|
701
|
-
throw new
|
|
689
|
+
throw new common_1.ZaloSDKError("ZNS đánh giá dịch vụ phải có đúng 1 component RATING", 400);
|
|
702
690
|
}
|
|
703
691
|
// Footer: Buttons (0-2)
|
|
704
692
|
if (footer.length > 2) {
|
|
705
|
-
throw new
|
|
693
|
+
throw new common_1.ZaloSDKError("ZNS đánh giá dịch vụ không được có quá 2 button", 400);
|
|
706
694
|
}
|
|
707
695
|
}
|
|
708
696
|
/**
|
|
709
697
|
* Validate individual component content
|
|
710
698
|
*/
|
|
711
699
|
validateComponent(component) {
|
|
712
|
-
if (component
|
|
700
|
+
if ('TITLE' in component) {
|
|
713
701
|
this.validateTitleComponent(component.TITLE);
|
|
714
702
|
}
|
|
715
|
-
if (component
|
|
703
|
+
if ('PARAGRAPH' in component) {
|
|
716
704
|
this.validateParagraphComponent(component.PARAGRAPH);
|
|
717
705
|
}
|
|
718
|
-
if (component
|
|
706
|
+
if ('OTP' in component) {
|
|
719
707
|
this.validateOTPComponent(component.OTP);
|
|
720
708
|
}
|
|
721
|
-
if (component
|
|
709
|
+
if ('TABLE' in component) {
|
|
722
710
|
this.validateTableComponent(component.TABLE);
|
|
723
711
|
}
|
|
724
|
-
if (component
|
|
712
|
+
if ('LOGO' in component) {
|
|
725
713
|
this.validateLogoComponent(component.LOGO);
|
|
726
714
|
}
|
|
727
|
-
if (component
|
|
715
|
+
if ('IMAGES' in component) {
|
|
728
716
|
this.validateImagesComponent(component.IMAGES);
|
|
729
717
|
}
|
|
730
|
-
if (component
|
|
718
|
+
if ('BUTTONS' in component) {
|
|
731
719
|
this.validateButtonsComponent(component.BUTTONS);
|
|
732
720
|
}
|
|
733
|
-
if (component
|
|
721
|
+
if ('PAYMENT' in component) {
|
|
734
722
|
this.validatePaymentComponent(component.PAYMENT);
|
|
735
723
|
}
|
|
736
|
-
if (component
|
|
724
|
+
if ('VOUCHER' in component) {
|
|
737
725
|
this.validateVoucherComponent(component.VOUCHER);
|
|
738
726
|
}
|
|
739
|
-
if (component
|
|
727
|
+
if ('RATING' in component) {
|
|
740
728
|
this.validateRatingComponent(component.RATING);
|
|
741
729
|
}
|
|
742
730
|
}
|
|
@@ -745,15 +733,15 @@ class ZNSService {
|
|
|
745
733
|
*/
|
|
746
734
|
validateTitleComponent(title) {
|
|
747
735
|
if (!title.value || typeof title.value !== 'string') {
|
|
748
|
-
throw new
|
|
736
|
+
throw new common_1.ZaloSDKError("TITLE component phải có field value kiểu string", 400);
|
|
749
737
|
}
|
|
750
738
|
if (title.value.length < 9 || title.value.length > 65) {
|
|
751
|
-
throw new
|
|
739
|
+
throw new common_1.ZaloSDKError("TITLE value phải có độ dài từ 9 đến 65 ký tự", 400);
|
|
752
740
|
}
|
|
753
741
|
// Check max 4 params
|
|
754
742
|
const paramCount = (title.value.match(/\{\{[^}]+\}\}/g) || []).length;
|
|
755
743
|
if (paramCount > 4) {
|
|
756
|
-
throw new
|
|
744
|
+
throw new common_1.ZaloSDKError("TITLE component không được có quá 4 params", 400);
|
|
757
745
|
}
|
|
758
746
|
}
|
|
759
747
|
/**
|
|
@@ -761,15 +749,15 @@ class ZNSService {
|
|
|
761
749
|
*/
|
|
762
750
|
validateParagraphComponent(paragraph) {
|
|
763
751
|
if (!paragraph.value || typeof paragraph.value !== 'string') {
|
|
764
|
-
throw new
|
|
752
|
+
throw new common_1.ZaloSDKError("PARAGRAPH component phải có field value kiểu string", 400);
|
|
765
753
|
}
|
|
766
754
|
if (paragraph.value.length < 9 || paragraph.value.length > 400) {
|
|
767
|
-
throw new
|
|
755
|
+
throw new common_1.ZaloSDKError("PARAGRAPH value phải có độ dài từ 9 đến 400 ký tự", 400);
|
|
768
756
|
}
|
|
769
757
|
// Check max 10 params
|
|
770
758
|
const paramCount = (paragraph.value.match(/\{\{[^}]+\}\}/g) || []).length;
|
|
771
759
|
if (paramCount > 10) {
|
|
772
|
-
throw new
|
|
760
|
+
throw new common_1.ZaloSDKError("PARAGRAPH component không được có quá 10 params", 400);
|
|
773
761
|
}
|
|
774
762
|
}
|
|
775
763
|
/**
|
|
@@ -777,10 +765,10 @@ class ZNSService {
|
|
|
777
765
|
*/
|
|
778
766
|
validateOTPComponent(otp) {
|
|
779
767
|
if (!otp.value || typeof otp.value !== 'string') {
|
|
780
|
-
throw new
|
|
768
|
+
throw new common_1.ZaloSDKError("OTP component phải có field value kiểu string", 400);
|
|
781
769
|
}
|
|
782
770
|
if (otp.value.length < 1 || otp.value.length > 10) {
|
|
783
|
-
throw new
|
|
771
|
+
throw new common_1.ZaloSDKError("OTP value phải có độ dài từ 1 đến 10 ký tự", 400);
|
|
784
772
|
}
|
|
785
773
|
}
|
|
786
774
|
/**
|
|
@@ -788,26 +776,26 @@ class ZNSService {
|
|
|
788
776
|
*/
|
|
789
777
|
validateTableComponent(table) {
|
|
790
778
|
if (!table.rows || !Array.isArray(table.rows)) {
|
|
791
|
-
throw new
|
|
779
|
+
throw new common_1.ZaloSDKError("TABLE component phải có field rows kiểu array", 400);
|
|
792
780
|
}
|
|
793
781
|
if (table.rows.length < 2 || table.rows.length > 8) {
|
|
794
|
-
throw new
|
|
782
|
+
throw new common_1.ZaloSDKError("TABLE rows phải có từ 2 đến 8 objects", 400);
|
|
795
783
|
}
|
|
796
784
|
table.rows.forEach((row, index) => {
|
|
797
785
|
if (!row.title || typeof row.title !== 'string') {
|
|
798
|
-
throw new
|
|
786
|
+
throw new common_1.ZaloSDKError(`TABLE row ${index + 1} phải có field title kiểu string`, 400);
|
|
799
787
|
}
|
|
800
788
|
if (row.title.length < 3 || row.title.length > 36) {
|
|
801
|
-
throw new
|
|
789
|
+
throw new common_1.ZaloSDKError(`TABLE row ${index + 1} title phải có độ dài từ 3 đến 36 ký tự`, 400);
|
|
802
790
|
}
|
|
803
791
|
if (!row.value || typeof row.value !== 'string') {
|
|
804
|
-
throw new
|
|
792
|
+
throw new common_1.ZaloSDKError(`TABLE row ${index + 1} phải có field value kiểu string`, 400);
|
|
805
793
|
}
|
|
806
794
|
if (row.value.length < 3 || row.value.length > 90) {
|
|
807
|
-
throw new
|
|
795
|
+
throw new common_1.ZaloSDKError(`TABLE row ${index + 1} value phải có độ dài từ 3 đến 90 ký tự`, 400);
|
|
808
796
|
}
|
|
809
797
|
if (row.row_type !== undefined && ![0, 1, 2, 3, 4, 5].includes(row.row_type)) {
|
|
810
|
-
throw new
|
|
798
|
+
throw new common_1.ZaloSDKError(`TABLE row ${index + 1} row_type phải là 0, 1, 2, 3, 4 hoặc 5`, 400);
|
|
811
799
|
}
|
|
812
800
|
});
|
|
813
801
|
}
|
|
@@ -816,7 +804,7 @@ class ZNSService {
|
|
|
816
804
|
*/
|
|
817
805
|
validateLogoComponent(logo) {
|
|
818
806
|
if (!logo.light || !logo.dark) {
|
|
819
|
-
throw new
|
|
807
|
+
throw new common_1.ZaloSDKError("LOGO component phải có cả light và dark attachment", 400);
|
|
820
808
|
}
|
|
821
809
|
this.validateAttachment(logo.light, "LOGO light");
|
|
822
810
|
this.validateAttachment(logo.dark, "LOGO dark");
|
|
@@ -826,10 +814,10 @@ class ZNSService {
|
|
|
826
814
|
*/
|
|
827
815
|
validateImagesComponent(images) {
|
|
828
816
|
if (!images.items || !Array.isArray(images.items)) {
|
|
829
|
-
throw new
|
|
817
|
+
throw new common_1.ZaloSDKError("IMAGES component phải có field items kiểu array", 400);
|
|
830
818
|
}
|
|
831
819
|
if (images.items.length < 1 || images.items.length > 3) {
|
|
832
|
-
throw new
|
|
820
|
+
throw new common_1.ZaloSDKError("IMAGES items phải có từ 1 đến 3 attachments", 400);
|
|
833
821
|
}
|
|
834
822
|
images.items.forEach((item, index) => {
|
|
835
823
|
this.validateAttachment(item, `IMAGES item ${index + 1}`);
|
|
@@ -840,23 +828,23 @@ class ZNSService {
|
|
|
840
828
|
*/
|
|
841
829
|
validateButtonsComponent(buttons) {
|
|
842
830
|
if (!buttons.items || !Array.isArray(buttons.items)) {
|
|
843
|
-
throw new
|
|
831
|
+
throw new common_1.ZaloSDKError("BUTTONS component phải có field items kiểu array", 400);
|
|
844
832
|
}
|
|
845
833
|
if (buttons.items.length < 1 || buttons.items.length > 2) {
|
|
846
|
-
throw new
|
|
834
|
+
throw new common_1.ZaloSDKError("BUTTONS items phải có từ 1 đến 2 objects", 400);
|
|
847
835
|
}
|
|
848
836
|
buttons.items.forEach((button, index) => {
|
|
849
837
|
if (!button.type || ![1, 2, 3, 4, 5, 6, 7, 8, 9].includes(button.type)) {
|
|
850
|
-
throw new
|
|
838
|
+
throw new common_1.ZaloSDKError(`BUTTON ${index + 1} type phải là 1, 2, 3, 4, 5, 6, 7, 8 hoặc 9`, 400);
|
|
851
839
|
}
|
|
852
840
|
if (!button.title || typeof button.title !== 'string') {
|
|
853
|
-
throw new
|
|
841
|
+
throw new common_1.ZaloSDKError(`BUTTON ${index + 1} phải có field title kiểu string`, 400);
|
|
854
842
|
}
|
|
855
843
|
if (button.title.length < 5 || button.title.length > 30) {
|
|
856
|
-
throw new
|
|
844
|
+
throw new common_1.ZaloSDKError(`BUTTON ${index + 1} title phải có độ dài từ 5 đến 30 ký tự`, 400);
|
|
857
845
|
}
|
|
858
846
|
if (!button.content || typeof button.content !== 'string') {
|
|
859
|
-
throw new
|
|
847
|
+
throw new common_1.ZaloSDKError(`BUTTON ${index + 1} phải có field content kiểu string`, 400);
|
|
860
848
|
}
|
|
861
849
|
});
|
|
862
850
|
}
|
|
@@ -865,25 +853,25 @@ class ZNSService {
|
|
|
865
853
|
*/
|
|
866
854
|
validatePaymentComponent(payment) {
|
|
867
855
|
if (!payment.bank_code || typeof payment.bank_code !== 'string') {
|
|
868
|
-
throw new
|
|
856
|
+
throw new common_1.ZaloSDKError("PAYMENT component phải có field bank_code kiểu string", 400);
|
|
869
857
|
}
|
|
870
858
|
if (!payment.account_name || typeof payment.account_name !== 'string') {
|
|
871
|
-
throw new
|
|
859
|
+
throw new common_1.ZaloSDKError("PAYMENT component phải có field account_name kiểu string", 400);
|
|
872
860
|
}
|
|
873
861
|
if (payment.account_name.length < 1 || payment.account_name.length > 100) {
|
|
874
|
-
throw new
|
|
862
|
+
throw new common_1.ZaloSDKError("PAYMENT account_name phải có độ dài từ 1 đến 100 ký tự", 400);
|
|
875
863
|
}
|
|
876
864
|
if (!payment.bank_account || typeof payment.bank_account !== 'string') {
|
|
877
|
-
throw new
|
|
865
|
+
throw new common_1.ZaloSDKError("PAYMENT component phải có field bank_account kiểu string", 400);
|
|
878
866
|
}
|
|
879
867
|
if (payment.bank_account.length < 1 || payment.bank_account.length > 100) {
|
|
880
|
-
throw new
|
|
868
|
+
throw new common_1.ZaloSDKError("PAYMENT bank_account phải có độ dài từ 1 đến 100 ký tự", 400);
|
|
881
869
|
}
|
|
882
870
|
if (!payment.amount) {
|
|
883
|
-
throw new
|
|
871
|
+
throw new common_1.ZaloSDKError("PAYMENT component phải có field amount", 400);
|
|
884
872
|
}
|
|
885
873
|
if (payment.note && (payment.note.length < 1 || payment.note.length > 90)) {
|
|
886
|
-
throw new
|
|
874
|
+
throw new common_1.ZaloSDKError("PAYMENT note phải có độ dài từ 1 đến 90 ký tự", 400);
|
|
887
875
|
}
|
|
888
876
|
}
|
|
889
877
|
/**
|
|
@@ -891,28 +879,28 @@ class ZNSService {
|
|
|
891
879
|
*/
|
|
892
880
|
validateVoucherComponent(voucher) {
|
|
893
881
|
if (!voucher.name || typeof voucher.name !== 'string') {
|
|
894
|
-
throw new
|
|
882
|
+
throw new common_1.ZaloSDKError("VOUCHER component phải có field name kiểu string", 400);
|
|
895
883
|
}
|
|
896
884
|
if (voucher.name.length < 1 || voucher.name.length > 30) {
|
|
897
|
-
throw new
|
|
885
|
+
throw new common_1.ZaloSDKError("VOUCHER name phải có độ dài từ 1 đến 30 ký tự", 400);
|
|
898
886
|
}
|
|
899
887
|
if (!voucher.condition || typeof voucher.condition !== 'string') {
|
|
900
|
-
throw new
|
|
888
|
+
throw new common_1.ZaloSDKError("VOUCHER component phải có field condition kiểu string", 400);
|
|
901
889
|
}
|
|
902
890
|
if (voucher.condition.length < 1 || voucher.condition.length > 40) {
|
|
903
|
-
throw new
|
|
891
|
+
throw new common_1.ZaloSDKError("VOUCHER condition phải có độ dài từ 1 đến 40 ký tự", 400);
|
|
904
892
|
}
|
|
905
893
|
if (!voucher.end_date || typeof voucher.end_date !== 'string') {
|
|
906
|
-
throw new
|
|
894
|
+
throw new common_1.ZaloSDKError("VOUCHER component phải có field end_date kiểu string", 400);
|
|
907
895
|
}
|
|
908
896
|
if (!voucher.voucher_code || typeof voucher.voucher_code !== 'string') {
|
|
909
|
-
throw new
|
|
897
|
+
throw new common_1.ZaloSDKError("VOUCHER component phải có field voucher_code kiểu string", 400);
|
|
910
898
|
}
|
|
911
899
|
if (voucher.voucher_code.length < 1 || voucher.voucher_code.length > 25) {
|
|
912
|
-
throw new
|
|
900
|
+
throw new common_1.ZaloSDKError("VOUCHER voucher_code phải có độ dài từ 1 đến 25 ký tự", 400);
|
|
913
901
|
}
|
|
914
902
|
if (voucher.display_code !== undefined && ![1, 2, 3].includes(voucher.display_code)) {
|
|
915
|
-
throw new
|
|
903
|
+
throw new common_1.ZaloSDKError("VOUCHER display_code phải là 1, 2 hoặc 3", 400);
|
|
916
904
|
}
|
|
917
905
|
}
|
|
918
906
|
/**
|
|
@@ -920,46 +908,46 @@ class ZNSService {
|
|
|
920
908
|
*/
|
|
921
909
|
validateRatingComponent(rating) {
|
|
922
910
|
if (!rating.items || !Array.isArray(rating.items)) {
|
|
923
|
-
throw new
|
|
911
|
+
throw new common_1.ZaloSDKError("RATING component phải có field items kiểu array", 400);
|
|
924
912
|
}
|
|
925
913
|
if (rating.items.length !== 5) {
|
|
926
|
-
throw new
|
|
914
|
+
throw new common_1.ZaloSDKError("RATING items phải có đúng 5 objects", 400);
|
|
927
915
|
}
|
|
928
916
|
rating.items.forEach((item, index) => {
|
|
929
|
-
const starValue = index + 1;
|
|
917
|
+
const starValue = (index + 1);
|
|
930
918
|
if (item.star !== starValue) {
|
|
931
|
-
throw new
|
|
919
|
+
throw new common_1.ZaloSDKError(`RATING item ${index + 1} phải có star = ${starValue}`, 400);
|
|
932
920
|
}
|
|
933
921
|
if (!item.title || typeof item.title !== 'string') {
|
|
934
|
-
throw new
|
|
922
|
+
throw new common_1.ZaloSDKError(`RATING item ${index + 1} phải có field title kiểu string`, 400);
|
|
935
923
|
}
|
|
936
924
|
if (item.title.length < 1 || item.title.length > 50) {
|
|
937
|
-
throw new
|
|
925
|
+
throw new common_1.ZaloSDKError(`RATING item ${index + 1} title phải có độ dài từ 1 đến 50 ký tự`, 400);
|
|
938
926
|
}
|
|
939
927
|
if (item.question && (item.question.length < 1 || item.question.length > 100)) {
|
|
940
|
-
throw new
|
|
928
|
+
throw new common_1.ZaloSDKError(`RATING item ${index + 1} question phải có độ dài từ 1 đến 100 ký tự`, 400);
|
|
941
929
|
}
|
|
942
930
|
if (item.answers && Array.isArray(item.answers)) {
|
|
943
931
|
if (item.answers.length < 1 || item.answers.length > 5) {
|
|
944
|
-
throw new
|
|
932
|
+
throw new common_1.ZaloSDKError(`RATING item ${index + 1} answers phải có từ 1 đến 5 câu trả lời`, 400);
|
|
945
933
|
}
|
|
946
934
|
item.answers.forEach((answer, answerIndex) => {
|
|
947
935
|
if (!answer || answer.length < 1 || answer.length > 50) {
|
|
948
|
-
throw new
|
|
936
|
+
throw new common_1.ZaloSDKError(`RATING item ${index + 1} answer ${answerIndex + 1} phải có độ dài từ 1 đến 50 ký tự`, 400);
|
|
949
937
|
}
|
|
950
938
|
});
|
|
951
939
|
}
|
|
952
940
|
if (!item.thanks || typeof item.thanks !== 'string') {
|
|
953
|
-
throw new
|
|
941
|
+
throw new common_1.ZaloSDKError(`RATING item ${index + 1} phải có field thanks kiểu string`, 400);
|
|
954
942
|
}
|
|
955
943
|
if (item.thanks.length < 1 || item.thanks.length > 100) {
|
|
956
|
-
throw new
|
|
944
|
+
throw new common_1.ZaloSDKError(`RATING item ${index + 1} thanks phải có độ dài từ 1 đến 100 ký tự`, 400);
|
|
957
945
|
}
|
|
958
946
|
if (!item.description || typeof item.description !== 'string') {
|
|
959
|
-
throw new
|
|
947
|
+
throw new common_1.ZaloSDKError(`RATING item ${index + 1} phải có field description kiểu string`, 400);
|
|
960
948
|
}
|
|
961
949
|
if (item.description.length < 1 || item.description.length > 200) {
|
|
962
|
-
throw new
|
|
950
|
+
throw new common_1.ZaloSDKError(`RATING item ${index + 1} description phải có độ dài từ 1 đến 200 ký tự`, 400);
|
|
963
951
|
}
|
|
964
952
|
});
|
|
965
953
|
}
|
|
@@ -968,10 +956,10 @@ class ZNSService {
|
|
|
968
956
|
*/
|
|
969
957
|
validateAttachment(attachment, context) {
|
|
970
958
|
if (!attachment.type || !attachment.media_id) {
|
|
971
|
-
throw new
|
|
959
|
+
throw new common_1.ZaloSDKError(`${context} phải có type và media_id`, 400);
|
|
972
960
|
}
|
|
973
961
|
if (attachment.type !== "IMAGE") {
|
|
974
|
-
throw new
|
|
962
|
+
throw new common_1.ZaloSDKError(`${context} type phải là "IMAGE"`, 400);
|
|
975
963
|
}
|
|
976
964
|
}
|
|
977
965
|
/**
|
|
@@ -1008,36 +996,36 @@ class ZNSService {
|
|
|
1008
996
|
// Validate each param
|
|
1009
997
|
params.forEach((param, index) => {
|
|
1010
998
|
if (!param.name || typeof param.name !== 'string') {
|
|
1011
|
-
throw new
|
|
999
|
+
throw new common_1.ZaloSDKError(`Param ${index + 1} phải có field name kiểu string`, 400);
|
|
1012
1000
|
}
|
|
1013
1001
|
if (!param.type || typeof param.type !== 'string') {
|
|
1014
|
-
throw new
|
|
1002
|
+
throw new common_1.ZaloSDKError(`Param ${index + 1} phải có field type kiểu string`, 400);
|
|
1015
1003
|
}
|
|
1016
1004
|
if (!Object.keys(paramTypeConstraints).includes(param.type)) {
|
|
1017
|
-
throw new
|
|
1005
|
+
throw new common_1.ZaloSDKError(`Param ${index + 1} type phải là 1-15`, 400);
|
|
1018
1006
|
}
|
|
1019
1007
|
if (!param.sample_value || typeof param.sample_value !== 'string') {
|
|
1020
|
-
throw new
|
|
1008
|
+
throw new common_1.ZaloSDKError(`Param ${index + 1} phải có field sample_value kiểu string`, 400);
|
|
1021
1009
|
}
|
|
1022
1010
|
// Validate sample_value length based on type
|
|
1023
1011
|
const maxLength = paramTypeConstraints[param.type];
|
|
1024
1012
|
if (param.sample_value.length > maxLength) {
|
|
1025
|
-
throw new
|
|
1013
|
+
throw new common_1.ZaloSDKError(`Param ${index + 1} sample_value không được vượt quá ${maxLength} ký tự cho type ${param.type}`, 400);
|
|
1026
1014
|
}
|
|
1027
1015
|
// Remove param from used set if found
|
|
1028
1016
|
usedParams.delete(param.name);
|
|
1029
1017
|
});
|
|
1030
1018
|
// Check if all used params are defined
|
|
1031
1019
|
if (usedParams.size > 0) {
|
|
1032
|
-
throw new
|
|
1020
|
+
throw new common_1.ZaloSDKError(`Các param sau được sử dụng trong layout nhưng chưa được định nghĩa: ${Array.from(usedParams).join(', ')}`, 400);
|
|
1033
1021
|
}
|
|
1034
1022
|
}
|
|
1035
1023
|
handleZNSError(error, defaultMessage) {
|
|
1036
1024
|
if (error.response?.data) {
|
|
1037
1025
|
const errorData = error.response.data;
|
|
1038
|
-
return new
|
|
1026
|
+
return new common_1.ZaloSDKError(`${defaultMessage}: ${errorData.message || errorData.error || "Unknown error"}`, errorData.error || -1, errorData);
|
|
1039
1027
|
}
|
|
1040
|
-
return new
|
|
1028
|
+
return new common_1.ZaloSDKError(`${defaultMessage}: ${error.message || "Unknown error"}`, -1, error);
|
|
1041
1029
|
}
|
|
1042
1030
|
}
|
|
1043
1031
|
exports.ZNSService = ZNSService;
|