@redonvn/zalo-ads-sdk 0.2.19 → 0.2.25

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 CHANGED
@@ -49,6 +49,7 @@ __export(index_exports, {
49
49
  VALID_AD_TYPES: () => VALID_AD_TYPES,
50
50
  VALID_CAMPAIGN_TYPES: () => VALID_CAMPAIGN_TYPES,
51
51
  VIETNAM_PHONE_REGEX: () => VIETNAM_PHONE_REGEX,
52
+ ZALO_DISPLAY_AD_FORMAT: () => ZALO_DISPLAY_AD_FORMAT,
52
53
  ZALO_NEW_REGION_PROVINCE_CODES: () => ZALO_NEW_REGION_PROVINCE_CODES,
53
54
  ZALO_PROFILE_ADS_PROVINCES: () => ZALO_PROFILE_ADS_PROVINCES,
54
55
  ZALO_PROFILE_ADS_SUB_CATEGORIES: () => ZALO_PROFILE_ADS_SUB_CATEGORIES,
@@ -123,18 +124,26 @@ __export(index_exports, {
123
124
  sanitizeCanvasKeys: () => sanitizeCanvasKeys,
124
125
  validateChangeCampaignStatusParams: () => validateChangeCampaignStatusParams,
125
126
  validateCloneInstantPageRequest: () => validateCloneInstantPageRequest,
127
+ validateCreateArticleCampaign: () => validateCreateArticleCampaign,
126
128
  validateCreateCampaignPayload: () => validateCreateCampaignPayload,
129
+ validateCreateCommerceCampaign: () => validateCreateCommerceCampaign,
127
130
  validateCreateCustomAudienceRequest: () => validateCreateCustomAudienceRequest,
131
+ validateCreateDisplayCampaign: () => validateCreateDisplayCampaign,
128
132
  validateCreateFlowRequest: () => validateCreateFlowRequest,
133
+ validateCreateFormCampaign: () => validateCreateFormCampaign,
129
134
  validateCreateFormEventAudienceRequest: () => validateCreateFormEventAudienceRequest,
130
135
  validateCreateFormRequest: () => validateCreateFormRequest,
131
136
  validateCreateInstantPageRequest: () => validateCreateInstantPageRequest,
132
137
  validateCreateLookalikeAudienceRequest: () => validateCreateLookalikeAudienceRequest,
138
+ validateCreateMessageCampaign: () => validateCreateMessageCampaign,
133
139
  validateCreateMessageOaEventAudienceRequest: () => validateCreateMessageOaEventAudienceRequest,
134
140
  validateCreateMessagePersonalEventAudienceRequest: () => validateCreateMessagePersonalEventAudienceRequest,
135
141
  validateCreateOaPageRequest: () => validateCreateOaPageRequest,
142
+ validateCreateOfficialAccountCampaign: () => validateCreateOfficialAccountCampaign,
136
143
  validateCreatePhoneAudienceRequest: () => validateCreatePhoneAudienceRequest,
137
144
  validateCreateSavedAudienceRequest: () => validateCreateSavedAudienceRequest,
145
+ validateCreateVideoCampaign: () => validateCreateVideoCampaign,
146
+ validateCreateWebsiteCampaign: () => validateCreateWebsiteCampaign,
138
147
  validateCropCoordinates: () => validateCropCoordinates,
139
148
  validateDateRangeReportRequest: () => validateDateRangeReportRequest,
140
149
  validateDuplicateAdParams: () => validateDuplicateAdParams,
@@ -157,10 +166,18 @@ __export(index_exports, {
157
166
  validateSearchInstantPagesRequest: () => validateSearchInstantPagesRequest,
158
167
  validateToggleLeadNotificationRequest: () => validateToggleLeadNotificationRequest,
159
168
  validateUpdateAdPayload: () => validateUpdateAdPayload,
169
+ validateUpdateArticleAd: () => validateUpdateArticleAd,
170
+ validateUpdateCommerceAd: () => validateUpdateCommerceAd,
171
+ validateUpdateDisplayAd: () => validateUpdateDisplayAd,
160
172
  validateUpdateFlowRequest: () => validateUpdateFlowRequest,
173
+ validateUpdateFormAd: () => validateUpdateFormAd,
161
174
  validateUpdateInstantPageRequest: () => validateUpdateInstantPageRequest,
162
175
  validateUpdateInstantPageSharesRequest: () => validateUpdateInstantPageSharesRequest,
163
176
  validateUpdateLeadNotificationIntervalRequest: () => validateUpdateLeadNotificationIntervalRequest,
177
+ validateUpdateMessageAd: () => validateUpdateMessageAd,
178
+ validateUpdateOfficialAccountAd: () => validateUpdateOfficialAccountAd,
179
+ validateUpdateVideoAd: () => validateUpdateVideoAd,
180
+ validateUpdateWebsiteAd: () => validateUpdateWebsiteAd,
164
181
  validateUploadCustomAudiencePhoneListRequest: () => validateUploadCustomAudiencePhoneListRequest,
165
182
  validateUploadMediaRequest: () => validateUploadMediaRequest,
166
183
  validateUpsertCustomReportRequest: () => validateUpsertCustomReportRequest,
@@ -2218,7 +2235,24 @@ var VALID_AD_TYPES = {
2218
2235
  COMMERCE: 28,
2219
2236
  // Server trả về 28 (không phải 23)
2220
2237
  ARTICLE: 3,
2221
- DISPLAY: 21
2238
+ DISPLAY: 21,
2239
+ // Masthead Mobile (Format 1) & Masthead Desktop (Format 2)
2240
+ DISPLAY_HALFPAGE: 26,
2241
+ // Halfpage Mobile (Format 13) & Halfpage PC (Format 14)
2242
+ DISPLAY_MEDIUM_RECTANGLE: 23
2243
+ // Medium Rectangle 300x250 (Format 6)
2244
+ };
2245
+ var ZALO_DISPLAY_AD_FORMAT = {
2246
+ MASTHEAD_MOBILE: 1,
2247
+ // Kích thước 640x360, Os: [0, 1]
2248
+ MASTHEAD_DESKTOP: 2,
2249
+ // Kích thước 970x250, Os: [3]
2250
+ MEDIUM_RECTANGLE: 6,
2251
+ // Kích thước 300x250, Os: [0, 1]
2252
+ HALFPAGE_MOBILE: 13,
2253
+ // Kích thước 300x600, Os: [0, 1]
2254
+ HALFPAGE_PC: 14
2255
+ // Kích thước 300x600, Os: [3]
2222
2256
  };
2223
2257
  var ALLOWED_CTAS_PER_AD_TYPE = {
2224
2258
  // Website (Type 5): 9 CTAs
@@ -2269,7 +2303,41 @@ var ALLOWED_CTAS_PER_AD_TYPE = {
2269
2303
  ZaloAdsActionType.XEM_THEM
2270
2304
  ],
2271
2305
  // OA (Type 2): Cố định Quan tâm OA (6)
2272
- [VALID_AD_TYPES.OA]: [ZaloAdsActionType.QUAN_TAM_OA]
2306
+ [VALID_AD_TYPES.OA]: [ZaloAdsActionType.QUAN_TAM_OA],
2307
+ // Display (Type 21) & Display Halfpage (Type 26): Hỗ trợ các hành động cơ bản
2308
+ [VALID_AD_TYPES.DISPLAY]: [
2309
+ ZaloAdsActionType.DAT_NGAY,
2310
+ ZaloAdsActionType.MUA_NGAY,
2311
+ ZaloAdsActionType.THU_NGAY,
2312
+ ZaloAdsActionType.TAI_NGAY,
2313
+ ZaloAdsActionType.XEM_THEM,
2314
+ ZaloAdsActionType.NGHE_NGAY,
2315
+ ZaloAdsActionType.CHOI_NGAY,
2316
+ ZaloAdsActionType.DANG_KY,
2317
+ ZaloAdsActionType.GOI_DIEN
2318
+ ],
2319
+ [VALID_AD_TYPES.DISPLAY_HALFPAGE]: [
2320
+ ZaloAdsActionType.DAT_NGAY,
2321
+ ZaloAdsActionType.MUA_NGAY,
2322
+ ZaloAdsActionType.THU_NGAY,
2323
+ ZaloAdsActionType.TAI_NGAY,
2324
+ ZaloAdsActionType.XEM_THEM,
2325
+ ZaloAdsActionType.NGHE_NGAY,
2326
+ ZaloAdsActionType.CHOI_NGAY,
2327
+ ZaloAdsActionType.DANG_KY,
2328
+ ZaloAdsActionType.GOI_DIEN
2329
+ ],
2330
+ [VALID_AD_TYPES.DISPLAY_MEDIUM_RECTANGLE]: [
2331
+ ZaloAdsActionType.DAT_NGAY,
2332
+ ZaloAdsActionType.MUA_NGAY,
2333
+ ZaloAdsActionType.THU_NGAY,
2334
+ ZaloAdsActionType.TAI_NGAY,
2335
+ ZaloAdsActionType.XEM_THEM,
2336
+ ZaloAdsActionType.NGHE_NGAY,
2337
+ ZaloAdsActionType.CHOI_NGAY,
2338
+ ZaloAdsActionType.DANG_KY,
2339
+ ZaloAdsActionType.GOI_DIEN
2340
+ ]
2273
2341
  };
2274
2342
  function validateCreateCampaignPayload(payload, options = {}) {
2275
2343
  const errors = [];
@@ -2287,11 +2355,18 @@ function validateCreateCampaignPayload(payload, options = {}) {
2287
2355
  `campaignType: ${payload.campaignType} kh\xF4ng h\u1EE3p l\u1EC7. C\xE1c lo\u1EA1i h\u1ED7 tr\u1EE3: 6 (Website), 17 (Form), 18 (Message), 3 (OA), 14 (Video), 22 (Commerce), 4 (Article), 20 (Display).`
2288
2356
  );
2289
2357
  }
2290
- if (payload.campaignType !== VALID_CAMPAIGN_TYPES.DISPLAY) {
2358
+ const OA_REQUIRED_CAMPAIGN_TYPES = [
2359
+ VALID_CAMPAIGN_TYPES.FORM,
2360
+ VALID_CAMPAIGN_TYPES.MESSAGE,
2361
+ VALID_CAMPAIGN_TYPES.OA,
2362
+ VALID_CAMPAIGN_TYPES.COMMERCE,
2363
+ VALID_CAMPAIGN_TYPES.ARTICLE
2364
+ ];
2365
+ if (payload.campaignType !== void 0 && OA_REQUIRED_CAMPAIGN_TYPES.includes(payload.campaignType)) {
2291
2366
  if (!payload.pageId || payload.pageId <= 0) {
2292
- errors.push("pageId c\u1EE7a Official Account l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi lo\u1EA1i chi\u1EBFn d\u1ECBch n\xE0y (ph\u1EA3i > 0).");
2367
+ errors.push("pageId c\u1EE7a Official Account l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi lo\u1EA1i chi\u1EBFn d\u1ECBch n\xE0y (ph\u1EA3i > 0, ch\u1ECDn t\u1EEB Danh s\xE1ch t\xE0i kho\u1EA3n OA).");
2293
2368
  }
2294
- } else {
2369
+ } else if (payload.campaignType === VALID_CAMPAIGN_TYPES.DISPLAY) {
2295
2370
  if (payload.pageId !== -1 && payload.pageId !== 0 && !payload.pageId) {
2296
2371
  warnings.push("Qu\u1EA3ng c\xE1o Display th\u01B0\u1EDDng s\u1EED d\u1EE5ng pageId = -1.");
2297
2372
  }
@@ -2358,11 +2433,15 @@ function validateUpdateAdPayload(payload, options = {}) {
2358
2433
  if (!adInfo) {
2359
2434
  errors.push("Settings.AdInfo l\xE0 b\u1EAFt bu\u1ED9c.");
2360
2435
  } else {
2436
+ const rawTypeNum = Number(payload.Type);
2437
+ const isDisplayAd = rawTypeNum === 21 || rawTypeNum === 23 || rawTypeNum === 26 || adInfo.AdFormat === 1 || adInfo.AdFormat === 2 || adInfo.AdFormat === 6 || adInfo.AdFormat === 13 || adInfo.AdFormat === 14;
2361
2438
  if (!adInfo.Caption || !adInfo.Caption.trim()) {
2362
- errors.push("Settings.AdInfo.Caption l\xE0 b\u1EAFt bu\u1ED9c.");
2439
+ if (!isDisplayAd) {
2440
+ errors.push("Settings.AdInfo.Caption l\xE0 b\u1EAFt bu\u1ED9c.");
2441
+ }
2363
2442
  } else {
2364
2443
  const captionLen = adInfo.Caption.trim().length;
2365
- if (captionLen < 35) {
2444
+ if (!isDisplayAd && captionLen < 35) {
2366
2445
  errors.push(`Settings.AdInfo.Caption qu\xE1 ng\u1EAFn (${captionLen}/35 k\xFD t\u1EF1 t\u1ED1i thi\u1EC3u).`);
2367
2446
  } else if (captionLen > 90) {
2368
2447
  errors.push(`Settings.AdInfo.Caption qu\xE1 d\xE0i (${captionLen}/90 k\xFD t\u1EF1 t\u1ED1i \u0111a).`);
@@ -2386,6 +2465,14 @@ function validateUpdateAdPayload(payload, options = {}) {
2386
2465
  );
2387
2466
  }
2388
2467
  }
2468
+ if (isDisplayAd) {
2469
+ const targetUrl = typeof adInfo.TargetUrl === "object" ? adInfo.TargetUrl?.Url : adInfo.TargetUrl;
2470
+ if (!targetUrl || typeof targetUrl !== "string" || !targetUrl.trim()) {
2471
+ errors.push("Settings.AdInfo.TargetUrl l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Display.");
2472
+ } else if (!/^https?:\/\//i.test(targetUrl.trim())) {
2473
+ errors.push("Settings.AdInfo.TargetUrl ph\u1EA3i l\xE0 m\u1ED9t \u0111\u01B0\u1EDDng d\u1EABn h\u1EE3p l\u1EC7 (b\u1EAFt \u0111\u1EA7u b\u1EB1ng http:// ho\u1EB7c https://).");
2474
+ }
2475
+ }
2389
2476
  if (adInfo.Action !== void 0 && payload.Type) {
2390
2477
  const allowedCtas = ALLOWED_CTAS_PER_AD_TYPE[payload.Type];
2391
2478
  if (allowedCtas && !allowedCtas.includes(adInfo.Action)) {
@@ -2509,6 +2596,65 @@ function validateUpdateAdPayload(payload, options = {}) {
2509
2596
  "Ng\xE2n s\xE1ch t\u1ED1i thi\u1EC3u cho Qu\u1EA3ng c\xE1o Tin nh\u1EAFn l\xE0 600,000 VN\u0110 (Price.Limit >= 600000). N\u1EBFu \u0111\u1EB7t d\u01B0\u1EDBi 600k m\xE1y ch\u1EE7 s\u1EBD t\u1EEB ch\u1ED1i."
2510
2597
  );
2511
2598
  }
2599
+ } else if (Number(payload.Type) === 21 || Number(payload.Type) === 23 || Number(payload.Type) === 26 || payload.Type === VALID_AD_TYPES.DISPLAY || payload.Type === VALID_AD_TYPES.DISPLAY_HALFPAGE || payload.Type === VALID_AD_TYPES.DISPLAY_MEDIUM_RECTANGLE) {
2600
+ const adFormat = payload.Settings?.AdInfo?.AdFormat;
2601
+ const typeNum = Number(payload.Type);
2602
+ const isHalfpage = typeNum === 26 || adFormat === 13 || adFormat === 14 || (payload.AdName || "").toLowerCase().includes("halfpage");
2603
+ const isMediumRectangle = typeNum === 23 || adFormat === 6 || (payload.AdName || "").toLowerCase().includes("medium rectangle") || (payload.AdName || "").toLowerCase().includes("300x250");
2604
+ const adNameLower = (payload.AdName || "").toLowerCase();
2605
+ const isWelcome = adNameLower.includes("welcome");
2606
+ const isMasthead = (adNameLower.includes("masthead") || typeNum === 21 || adFormat === 1 || adFormat === 2) && !isWelcome && !isMediumRectangle;
2607
+ if (price.Type !== 1 && price.Type !== 2) {
2608
+ errors.push(
2609
+ "\u0110\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Display, Price.Type ch\u1EC9 ch\u1EA5p nh\u1EADn 1 (CPM - L\u01B0\u1EE3t hi\u1EC3n th\u1ECB) ho\u1EB7c 2 (CPC - L\u01B0\u1EE3t nh\u1EA5n)."
2610
+ );
2611
+ }
2612
+ if ((isHalfpage || isMasthead) && price.Type === 2) {
2613
+ errors.push(
2614
+ `Qu\u1EA3ng c\xE1o ${isHalfpage ? "Halfpage (Type 26 / AdFormat 13, 14)" : "Masthead (Type 21)"} ch\u1EC9 h\u1ED7 tr\u1EE3 t\xEDnh ti\u1EC1n theo l\u01B0\u1EE3t hi\u1EC3n th\u1ECB CPM (Price.Type = 1), kh\xF4ng h\u1ED7 tr\u1EE3 CPC.`
2615
+ );
2616
+ }
2617
+ if (price.Type === 1) {
2618
+ if (price.Bid !== void 0) {
2619
+ if (isWelcome && price.Bid < 3e4) {
2620
+ errors.push(
2621
+ `Gi\xE1 \u0111\u1EB7t m\u1ED7i 1,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB (Price.Bid) cho Qu\u1EA3ng c\xE1o Welcome Mobile t\u1ED1i thi\u1EC3u l\xE0 30,000 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
2622
+ );
2623
+ } else if (isHalfpage && price.Bid < 16e3) {
2624
+ errors.push(
2625
+ `Gi\xE1 \u0111\u1EB7t m\u1ED7i 1,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB (Price.Bid) cho Qu\u1EA3ng c\xE1o Halfpage t\u1ED1i thi\u1EC3u l\xE0 16,000 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
2626
+ );
2627
+ } else if (isMasthead && price.Bid < 13e3) {
2628
+ errors.push(
2629
+ `Gi\xE1 \u0111\u1EB7t m\u1ED7i 1,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB (Price.Bid) cho Qu\u1EA3ng c\xE1o Masthead t\u1ED1i thi\u1EC3u l\xE0 13,000 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
2630
+ );
2631
+ } else if (isMediumRectangle && price.Bid < 8e3) {
2632
+ errors.push(
2633
+ `Gi\xE1 \u0111\u1EB7t m\u1ED7i 1,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB (Price.Bid) cho Qu\u1EA3ng c\xE1o Medium Rectangle CPM t\u1ED1i thi\u1EC3u l\xE0 8,000 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
2634
+ );
2635
+ } else if (price.Bid < 8e3) {
2636
+ errors.push(
2637
+ `Gi\xE1 \u0111\u1EB7t m\u1ED7i 1,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB (Price.Bid) cho Qu\u1EA3ng c\xE1o Display CPM t\u1ED1i thi\u1EC3u l\xE0 8,000 VN\u0110 (s\xE0n h\u1EC7 th\u1ED1ng). Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
2638
+ );
2639
+ }
2640
+ }
2641
+ if (price.Limit !== void 0 && price.Limit > 0 && price.Limit < 50) {
2642
+ errors.push(
2643
+ "S\u1ED1 l\u01B0\u1EE3ng l\u01B0\u1EE3t hi\u1EC3n th\u1ECB t\u1ED1i thi\u1EC3u (Price.Limit) cho Qu\u1EA3ng c\xE1o Display CPM l\xE0 50 (t\u01B0\u01A1ng \u1EE9ng 50,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB)."
2644
+ );
2645
+ }
2646
+ } else if (price.Type === 2) {
2647
+ if (price.Bid !== void 0 && price.Bid < 1800) {
2648
+ errors.push(
2649
+ `Gi\xE1 \u0111\u1EB7t m\u1ED7i l\u01B0\u1EE3t nh\u1EA5n (Price.Bid) cho Qu\u1EA3ng c\xE1o Display CPC t\u1ED1i thi\u1EC3u l\xE0 1,800 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
2650
+ );
2651
+ }
2652
+ if (price.Limit !== void 0 && price.Limit > 0 && price.Limit < 50) {
2653
+ errors.push(
2654
+ "S\u1ED1 l\u01B0\u1EE3ng l\u01B0\u1EE3t nh\u1EA5n t\u1ED1i thi\u1EC3u (Price.Limit) cho Qu\u1EA3ng c\xE1o Display CPC l\xE0 50 l\u01B0\u1EE3t nh\u1EA5n."
2655
+ );
2656
+ }
2657
+ }
2512
2658
  }
2513
2659
  if (payload.Settings && payload.Settings.DeliveryType !== void 0) {
2514
2660
  const deliveryType = payload.Settings.DeliveryType;
@@ -2525,6 +2671,21 @@ function validateUpdateAdPayload(payload, options = {}) {
2525
2671
  }
2526
2672
  const targeting = payload.Settings?.Targeting;
2527
2673
  if (targeting) {
2674
+ if (targeting.Gender !== void 0 && targeting.Gender !== null) {
2675
+ if (![0, 1, 2].includes(Number(targeting.Gender))) {
2676
+ errors.push(`M\xE3 gi\u1EDBi t\xEDnh 'Gender' (${targeting.Gender}) kh\xF4ng h\u1EE3p l\u1EC7. H\u1EE3p l\u1EC7: 0 (T\u1EA5t c\u1EA3), 1 (Nam), 2 (N\u1EEF).`);
2677
+ }
2678
+ }
2679
+ if (targeting.CustomAudienceId !== void 0 && targeting.CustomAudienceId !== null) {
2680
+ if (typeof targeting.CustomAudienceId !== "number" || targeting.CustomAudienceId < 0) {
2681
+ errors.push("CustomAudienceId ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn kh\xF4ng \xE2m (>= 0).");
2682
+ }
2683
+ }
2684
+ if (targeting.ExcludedAudienceId !== void 0 && targeting.ExcludedAudienceId !== null) {
2685
+ if (typeof targeting.ExcludedAudienceId !== "number" || targeting.ExcludedAudienceId < 0) {
2686
+ errors.push("ExcludedAudienceId ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn kh\xF4ng \xE2m (>= 0).");
2687
+ }
2688
+ }
2528
2689
  const newAges = targeting.NewAgeRanges;
2529
2690
  const oldAges = targeting.AgeRanges;
2530
2691
  if (newAges && newAges.length > 0) {
@@ -2647,6 +2808,14 @@ function validateUpdateAdPayload(payload, options = {}) {
2647
2808
  if (!payload.ZaloFeedId && !payload.articleId) {
2648
2809
  errors.push("ZaloFeedId ho\u1EB7c articleId l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o B\xE0i Vi\u1EBFt (Ad Type 3).");
2649
2810
  }
2811
+ } else if (Number(payload.Type) === 21 || Number(payload.Type) === 23 || Number(payload.Type) === 26 || payload.Type === VALID_AD_TYPES.DISPLAY || payload.Type === VALID_AD_TYPES.DISPLAY_HALFPAGE || payload.Type === VALID_AD_TYPES.DISPLAY_MEDIUM_RECTANGLE) {
2812
+ const img = payload.Settings?.Image;
2813
+ const hasImage = img?.LandscapeCoverUrl || img?.BaseLandscapeCoverUrl || img?.PortraitCoverUrl || img?.SquareCoverUrl;
2814
+ if (!hasImage) {
2815
+ errors.push(
2816
+ "Qu\u1EA3ng c\xE1o Display b\u1EAFt bu\u1ED9c ph\u1EA3i c\xF3 \xEDt nh\u1EA5t m\u1ED9t banner h\xECnh \u1EA3nh (Settings.Image.LandscapeCoverUrl ho\u1EB7c BaseLandscapeCoverUrl)."
2817
+ );
2818
+ }
2650
2819
  }
2651
2820
  return {
2652
2821
  isValid: errors.length === 0,
@@ -2770,14 +2939,183 @@ function validateCropCoordinates(input) {
2770
2939
  data: errors.length === 0 ? cleanData : void 0
2771
2940
  };
2772
2941
  }
2942
+ function validateCreateCommerceCampaign(payload, options = {}) {
2943
+ const errors = [];
2944
+ const warnings = [];
2945
+ if (!payload.name || typeof payload.name !== "string" || !payload.name.trim()) {
2946
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') l\xE0 b\u1EAFt bu\u1ED9c v\xE0 kh\xF4ng \u0111\u01B0\u1EE3c \u0111\u1EC3 tr\u1ED1ng.");
2947
+ } else if (payload.name.length > 255) {
2948
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1.");
2949
+ }
2950
+ if (!payload.pageId || payload.pageId <= 0) {
2951
+ errors.push("T\xE0i kho\u1EA3n OA ('pageId') l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Commerce (ch\u1ECDn t\u1EEB Danh s\xE1ch t\xE0i kho\u1EA3n OA, ph\u1EA3i > 0).");
2952
+ }
2953
+ if (payload.productId === void 0 || payload.productId === null || payload.productId <= 0) {
2954
+ warnings.push("Qu\u1EA3ng c\xE1o Commerce n\xEAn ch\u1EC9 \u0111\u1ECBnh productId (ho\u1EB7c -1/0 khi d\xF9ng Instant Page s\u1EA3n ph\u1EA9m).");
2955
+ }
2956
+ return { isValid: errors.length === 0, errors, warnings };
2957
+ }
2958
+ function validateCreateDisplayCampaign(payload, options = {}) {
2959
+ const errors = [];
2960
+ const warnings = [];
2961
+ if (!payload.name || typeof payload.name !== "string" || !payload.name.trim()) {
2962
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') l\xE0 b\u1EAFt bu\u1ED9c v\xE0 kh\xF4ng \u0111\u01B0\u1EE3c \u0111\u1EC3 tr\u1ED1ng.");
2963
+ } else if (payload.name.length > 255) {
2964
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1.");
2965
+ }
2966
+ if (payload.targetUrl && !/^https?:\/\/.+/i.test(payload.targetUrl)) {
2967
+ errors.push("targetUrl ph\u1EA3i l\xE0 m\u1ED9t \u0111\u01B0\u1EDDng link h\u1EE3p l\u1EC7 b\u1EAFt \u0111\u1EA7u b\u1EB1ng http:// ho\u1EB7c https://.");
2968
+ }
2969
+ return { isValid: errors.length === 0, errors, warnings };
2970
+ }
2971
+ function validateCreateWebsiteCampaign(payload, options = {}) {
2972
+ const errors = [];
2973
+ const warnings = [];
2974
+ if (!payload.name || typeof payload.name !== "string" || !payload.name.trim()) {
2975
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') l\xE0 b\u1EAFt bu\u1ED9c v\xE0 kh\xF4ng \u0111\u01B0\u1EE3c \u0111\u1EC3 tr\u1ED1ng.");
2976
+ } else if (payload.name.length > 255) {
2977
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1.");
2978
+ }
2979
+ if (!payload.targetUrl || typeof payload.targetUrl !== "string" || !payload.targetUrl.trim()) {
2980
+ errors.push("Li\xEAn k\u1EBFt website ('targetUrl') l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Website.");
2981
+ } else if (!/^https?:\/\/.+/i.test(payload.targetUrl)) {
2982
+ errors.push("Li\xEAn k\u1EBFt website ('targetUrl') ph\u1EA3i l\xE0 \u0111\u01B0\u1EDDng link h\u1EE3p l\u1EC7 b\u1EAFt \u0111\u1EA7u b\u1EB1ng http:// ho\u1EB7c https://.");
2983
+ }
2984
+ return { isValid: errors.length === 0, errors, warnings };
2985
+ }
2986
+ function validateCreateFormCampaign(payload, options = {}) {
2987
+ const errors = [];
2988
+ const warnings = [];
2989
+ if (!payload.name || typeof payload.name !== "string" || !payload.name.trim()) {
2990
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') l\xE0 b\u1EAFt bu\u1ED9c v\xE0 kh\xF4ng \u0111\u01B0\u1EE3c \u0111\u1EC3 tr\u1ED1ng.");
2991
+ } else if (payload.name.length > 255) {
2992
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1.");
2993
+ }
2994
+ if (!payload.pageId || payload.pageId <= 0) {
2995
+ errors.push("T\xE0i kho\u1EA3n OA ('pageId') l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Form (ch\u1ECDn t\u1EEB Danh s\xE1ch t\xE0i kho\u1EA3n OA, ph\u1EA3i > 0).");
2996
+ }
2997
+ return { isValid: errors.length === 0, errors, warnings };
2998
+ }
2999
+ function validateCreateMessageCampaign(payload, options = {}) {
3000
+ const errors = [];
3001
+ const warnings = [];
3002
+ if (!payload.name || typeof payload.name !== "string" || !payload.name.trim()) {
3003
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') l\xE0 b\u1EAFt bu\u1ED9c v\xE0 kh\xF4ng \u0111\u01B0\u1EE3c \u0111\u1EC3 tr\u1ED1ng.");
3004
+ } else if (payload.name.length > 255) {
3005
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1.");
3006
+ }
3007
+ if (!payload.pageId || payload.pageId <= 0) {
3008
+ errors.push("T\xE0i kho\u1EA3n OA ('pageId') l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Tin nh\u1EAFn (ch\u1ECDn t\u1EEB Danh s\xE1ch t\xE0i kho\u1EA3n OA, ph\u1EA3i > 0).");
3009
+ }
3010
+ return { isValid: errors.length === 0, errors, warnings };
3011
+ }
3012
+ function validateCreateOfficialAccountCampaign(payload, options = {}) {
3013
+ const errors = [];
3014
+ const warnings = [];
3015
+ if (!payload.name || typeof payload.name !== "string" || !payload.name.trim()) {
3016
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') l\xE0 b\u1EAFt bu\u1ED9c v\xE0 kh\xF4ng \u0111\u01B0\u1EE3c \u0111\u1EC3 tr\u1ED1ng.");
3017
+ } else if (payload.name.length > 255) {
3018
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1.");
3019
+ }
3020
+ if (!payload.pageId || payload.pageId <= 0) {
3021
+ errors.push("T\xE0i kho\u1EA3n OA ('pageId') l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Zalo Official Account (ch\u1ECDn t\u1EEB Danh s\xE1ch t\xE0i kho\u1EA3n OA, ph\u1EA3i > 0).");
3022
+ }
3023
+ return { isValid: errors.length === 0, errors, warnings };
3024
+ }
3025
+ function validateCreateArticleCampaign(payload, options = {}) {
3026
+ const errors = [];
3027
+ const warnings = [];
3028
+ if (!payload.name || typeof payload.name !== "string" || !payload.name.trim()) {
3029
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') l\xE0 b\u1EAFt bu\u1ED9c v\xE0 kh\xF4ng \u0111\u01B0\u1EE3c \u0111\u1EC3 tr\u1ED1ng.");
3030
+ } else if (payload.name.length > 255) {
3031
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1.");
3032
+ }
3033
+ if (!payload.pageId || payload.pageId <= 0) {
3034
+ errors.push("T\xE0i kho\u1EA3n OA ('pageId') l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o B\xE0i vi\u1EBFt (ch\u1ECDn t\u1EEB Danh s\xE1ch t\xE0i kho\u1EA3n OA, ph\u1EA3i > 0).");
3035
+ }
3036
+ if (!payload.articleId || payload.articleId <= 0) {
3037
+ errors.push("B\xE0i vi\u1EBFt ('articleId') l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o B\xE0i vi\u1EBFt (ch\u1ECDn t\u1EEB Danh s\xE1ch b\xE0i vi\u1EBFt c\u1EE7a OA \u0111\xF3, l\u1EA5y qua getOwnedArticles).");
3038
+ }
3039
+ return { isValid: errors.length === 0, errors, warnings };
3040
+ }
3041
+ function validateCreateVideoCampaign(payload, options = {}) {
3042
+ const errors = [];
3043
+ const warnings = [];
3044
+ if (!payload.name || typeof payload.name !== "string" || !payload.name.trim()) {
3045
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') l\xE0 b\u1EAFt bu\u1ED9c v\xE0 kh\xF4ng \u0111\u01B0\u1EE3c \u0111\u1EC3 tr\u1ED1ng.");
3046
+ } else if (payload.name.length > 255) {
3047
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1.");
3048
+ }
3049
+ if (!payload.targetUrl || typeof payload.targetUrl !== "string" || !payload.targetUrl.trim()) {
3050
+ errors.push("Li\xEAn k\u1EBFt Website ('targetUrl') l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Video.");
3051
+ } else if (!/^https?:\/\/.+/i.test(payload.targetUrl)) {
3052
+ errors.push("Li\xEAn k\u1EBFt Website ('targetUrl') ph\u1EA3i l\xE0 \u0111\u01B0\u1EDDng link h\u1EE3p l\u1EC7 b\u1EAFt \u0111\u1EA7u b\u1EB1ng http:// ho\u1EB7c https://.");
3053
+ }
3054
+ return { isValid: errors.length === 0, errors, warnings };
3055
+ }
3056
+ function validateUpdateWebsiteAd(payload, options = {}) {
3057
+ return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.WEBSITE }, options);
3058
+ }
3059
+ function validateUpdateDisplayAd(payload, options = {}) {
3060
+ const adFormat = payload.Settings?.AdInfo?.AdFormat;
3061
+ const rawType = Number(payload.Type);
3062
+ const isHalfpage = rawType === 26 || adFormat === 13 || adFormat === 14;
3063
+ const isMediumRectangle = rawType === 23 || adFormat === 6;
3064
+ let effectiveType;
3065
+ if (isHalfpage) {
3066
+ effectiveType = VALID_AD_TYPES.DISPLAY_HALFPAGE;
3067
+ } else if (isMediumRectangle) {
3068
+ effectiveType = VALID_AD_TYPES.DISPLAY_MEDIUM_RECTANGLE;
3069
+ } else {
3070
+ effectiveType = payload.Type ?? VALID_AD_TYPES.DISPLAY;
3071
+ }
3072
+ return validateUpdateAdPayload({ ...payload, Type: effectiveType }, options);
3073
+ }
3074
+ function validateUpdateVideoAd(payload, options = {}) {
3075
+ return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.VIDEO }, options);
3076
+ }
3077
+ function validateUpdateCommerceAd(payload, options = {}) {
3078
+ return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.COMMERCE }, options);
3079
+ }
3080
+ function validateUpdateFormAd(payload, options = {}) {
3081
+ return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.FORM }, options);
3082
+ }
3083
+ function validateUpdateMessageAd(payload, options = {}) {
3084
+ return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.MESSAGE }, options);
3085
+ }
3086
+ function validateUpdateOfficialAccountAd(payload, options = {}) {
3087
+ return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.OA }, options);
3088
+ }
3089
+ function validateUpdateArticleAd(payload, options = {}) {
3090
+ return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.ARTICLE }, options);
3091
+ }
2773
3092
  var ZaloCampaignsValidator = {
3093
+ // Generic
2774
3094
  createCampaign: validateCreateCampaignPayload,
2775
3095
  updateAd: validateUpdateAdPayload,
2776
3096
  renameCampaign: validateRenameCampaignParams,
2777
3097
  changeStatus: validateChangeCampaignStatusParams,
2778
3098
  duplicateAd: validateDuplicateAdParams,
2779
3099
  validateCropCoordinates,
2780
- validateUploadCropAdImage: validateCropCoordinates
3100
+ validateUploadCropAdImage: validateCropCoordinates,
3101
+ // Specific Create Campaign
3102
+ createCommerceCampaign: validateCreateCommerceCampaign,
3103
+ createDisplayCampaign: validateCreateDisplayCampaign,
3104
+ createWebsiteCampaign: validateCreateWebsiteCampaign,
3105
+ createFormCampaign: validateCreateFormCampaign,
3106
+ createMessageCampaign: validateCreateMessageCampaign,
3107
+ createOfficialAccountCampaign: validateCreateOfficialAccountCampaign,
3108
+ createArticleCampaign: validateCreateArticleCampaign,
3109
+ createVideoCampaign: validateCreateVideoCampaign,
3110
+ // Specific Update Ad
3111
+ updateWebsiteAd: validateUpdateWebsiteAd,
3112
+ updateDisplayAd: validateUpdateDisplayAd,
3113
+ updateVideoAd: validateUpdateVideoAd,
3114
+ updateCommerceAd: validateUpdateCommerceAd,
3115
+ updateFormAd: validateUpdateFormAd,
3116
+ updateMessageAd: validateUpdateMessageAd,
3117
+ updateOfficialAccountAd: validateUpdateOfficialAccountAd,
3118
+ updateArticleAd: validateUpdateArticleAd
2781
3119
  };
2782
3120
 
2783
3121
  // src/services/campaigns.service.ts
@@ -5929,8 +6267,8 @@ function validateListFormLeadsRequest(input) {
5929
6267
  const offset = typeof raw.offset === "number" && raw.offset >= 0 ? Math.floor(raw.offset) : 0;
5930
6268
  const status = typeof raw.status === "string" && raw.status.trim() !== "" ? raw.status.trim() : "2,6,1,0,7,4,5,3";
5931
6269
  const now = Math.floor(Date.now() / 1e3);
5932
- const fromTime = typeof raw.fromTime === "number" && raw.fromTime >= 0 ? Math.floor(raw.fromTime) : now - 90 * 86400;
5933
- const toTime = typeof raw.toTime === "number" && raw.toTime >= 0 ? Math.floor(raw.toTime) : now;
6270
+ const fromTime = typeof raw.fromTime === "number" && raw.fromTime >= 0 ? raw.fromTime >= 1e10 ? Math.floor(raw.fromTime / 1e3) : Math.floor(raw.fromTime) : now - 90 * 86400;
6271
+ const toTime = typeof raw.toTime === "number" && raw.toTime >= 0 ? raw.toTime >= 1e10 ? Math.floor(raw.toTime / 1e3) : Math.floor(raw.toTime) : now;
5934
6272
  if (toTime < fromTime) {
5935
6273
  errors.push("M\u1ED1c th\u1EDDi gian k\u1EBFt th\xFAc 'toTime' ph\u1EA3i l\u1EDBn h\u01A1n ho\u1EB7c b\u1EB1ng 'fromTime'.");
5936
6274
  }
@@ -8878,6 +9216,7 @@ var ZaloMediaValidator = {
8878
9216
  VALID_AD_TYPES,
8879
9217
  VALID_CAMPAIGN_TYPES,
8880
9218
  VIETNAM_PHONE_REGEX,
9219
+ ZALO_DISPLAY_AD_FORMAT,
8881
9220
  ZALO_NEW_REGION_PROVINCE_CODES,
8882
9221
  ZALO_PROFILE_ADS_PROVINCES,
8883
9222
  ZALO_PROFILE_ADS_SUB_CATEGORIES,
@@ -8951,18 +9290,26 @@ var ZaloMediaValidator = {
8951
9290
  sanitizeCanvasKeys,
8952
9291
  validateChangeCampaignStatusParams,
8953
9292
  validateCloneInstantPageRequest,
9293
+ validateCreateArticleCampaign,
8954
9294
  validateCreateCampaignPayload,
9295
+ validateCreateCommerceCampaign,
8955
9296
  validateCreateCustomAudienceRequest,
9297
+ validateCreateDisplayCampaign,
8956
9298
  validateCreateFlowRequest,
9299
+ validateCreateFormCampaign,
8957
9300
  validateCreateFormEventAudienceRequest,
8958
9301
  validateCreateFormRequest,
8959
9302
  validateCreateInstantPageRequest,
8960
9303
  validateCreateLookalikeAudienceRequest,
9304
+ validateCreateMessageCampaign,
8961
9305
  validateCreateMessageOaEventAudienceRequest,
8962
9306
  validateCreateMessagePersonalEventAudienceRequest,
8963
9307
  validateCreateOaPageRequest,
9308
+ validateCreateOfficialAccountCampaign,
8964
9309
  validateCreatePhoneAudienceRequest,
8965
9310
  validateCreateSavedAudienceRequest,
9311
+ validateCreateVideoCampaign,
9312
+ validateCreateWebsiteCampaign,
8966
9313
  validateCropCoordinates,
8967
9314
  validateDateRangeReportRequest,
8968
9315
  validateDuplicateAdParams,
@@ -8985,10 +9332,18 @@ var ZaloMediaValidator = {
8985
9332
  validateSearchInstantPagesRequest,
8986
9333
  validateToggleLeadNotificationRequest,
8987
9334
  validateUpdateAdPayload,
9335
+ validateUpdateArticleAd,
9336
+ validateUpdateCommerceAd,
9337
+ validateUpdateDisplayAd,
8988
9338
  validateUpdateFlowRequest,
9339
+ validateUpdateFormAd,
8989
9340
  validateUpdateInstantPageRequest,
8990
9341
  validateUpdateInstantPageSharesRequest,
8991
9342
  validateUpdateLeadNotificationIntervalRequest,
9343
+ validateUpdateMessageAd,
9344
+ validateUpdateOfficialAccountAd,
9345
+ validateUpdateVideoAd,
9346
+ validateUpdateWebsiteAd,
8992
9347
  validateUploadCustomAudiencePhoneListRequest,
8993
9348
  validateUploadMediaRequest,
8994
9349
  validateUpsertCustomReportRequest,