@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.mjs CHANGED
@@ -2048,7 +2048,24 @@ var VALID_AD_TYPES = {
2048
2048
  COMMERCE: 28,
2049
2049
  // Server trả về 28 (không phải 23)
2050
2050
  ARTICLE: 3,
2051
- DISPLAY: 21
2051
+ DISPLAY: 21,
2052
+ // Masthead Mobile (Format 1) & Masthead Desktop (Format 2)
2053
+ DISPLAY_HALFPAGE: 26,
2054
+ // Halfpage Mobile (Format 13) & Halfpage PC (Format 14)
2055
+ DISPLAY_MEDIUM_RECTANGLE: 23
2056
+ // Medium Rectangle 300x250 (Format 6)
2057
+ };
2058
+ var ZALO_DISPLAY_AD_FORMAT = {
2059
+ MASTHEAD_MOBILE: 1,
2060
+ // Kích thước 640x360, Os: [0, 1]
2061
+ MASTHEAD_DESKTOP: 2,
2062
+ // Kích thước 970x250, Os: [3]
2063
+ MEDIUM_RECTANGLE: 6,
2064
+ // Kích thước 300x250, Os: [0, 1]
2065
+ HALFPAGE_MOBILE: 13,
2066
+ // Kích thước 300x600, Os: [0, 1]
2067
+ HALFPAGE_PC: 14
2068
+ // Kích thước 300x600, Os: [3]
2052
2069
  };
2053
2070
  var ALLOWED_CTAS_PER_AD_TYPE = {
2054
2071
  // Website (Type 5): 9 CTAs
@@ -2099,7 +2116,41 @@ var ALLOWED_CTAS_PER_AD_TYPE = {
2099
2116
  ZaloAdsActionType.XEM_THEM
2100
2117
  ],
2101
2118
  // OA (Type 2): Cố định Quan tâm OA (6)
2102
- [VALID_AD_TYPES.OA]: [ZaloAdsActionType.QUAN_TAM_OA]
2119
+ [VALID_AD_TYPES.OA]: [ZaloAdsActionType.QUAN_TAM_OA],
2120
+ // Display (Type 21) & Display Halfpage (Type 26): Hỗ trợ các hành động cơ bản
2121
+ [VALID_AD_TYPES.DISPLAY]: [
2122
+ ZaloAdsActionType.DAT_NGAY,
2123
+ ZaloAdsActionType.MUA_NGAY,
2124
+ ZaloAdsActionType.THU_NGAY,
2125
+ ZaloAdsActionType.TAI_NGAY,
2126
+ ZaloAdsActionType.XEM_THEM,
2127
+ ZaloAdsActionType.NGHE_NGAY,
2128
+ ZaloAdsActionType.CHOI_NGAY,
2129
+ ZaloAdsActionType.DANG_KY,
2130
+ ZaloAdsActionType.GOI_DIEN
2131
+ ],
2132
+ [VALID_AD_TYPES.DISPLAY_HALFPAGE]: [
2133
+ ZaloAdsActionType.DAT_NGAY,
2134
+ ZaloAdsActionType.MUA_NGAY,
2135
+ ZaloAdsActionType.THU_NGAY,
2136
+ ZaloAdsActionType.TAI_NGAY,
2137
+ ZaloAdsActionType.XEM_THEM,
2138
+ ZaloAdsActionType.NGHE_NGAY,
2139
+ ZaloAdsActionType.CHOI_NGAY,
2140
+ ZaloAdsActionType.DANG_KY,
2141
+ ZaloAdsActionType.GOI_DIEN
2142
+ ],
2143
+ [VALID_AD_TYPES.DISPLAY_MEDIUM_RECTANGLE]: [
2144
+ ZaloAdsActionType.DAT_NGAY,
2145
+ ZaloAdsActionType.MUA_NGAY,
2146
+ ZaloAdsActionType.THU_NGAY,
2147
+ ZaloAdsActionType.TAI_NGAY,
2148
+ ZaloAdsActionType.XEM_THEM,
2149
+ ZaloAdsActionType.NGHE_NGAY,
2150
+ ZaloAdsActionType.CHOI_NGAY,
2151
+ ZaloAdsActionType.DANG_KY,
2152
+ ZaloAdsActionType.GOI_DIEN
2153
+ ]
2103
2154
  };
2104
2155
  function validateCreateCampaignPayload(payload, options = {}) {
2105
2156
  const errors = [];
@@ -2117,11 +2168,18 @@ function validateCreateCampaignPayload(payload, options = {}) {
2117
2168
  `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).`
2118
2169
  );
2119
2170
  }
2120
- if (payload.campaignType !== VALID_CAMPAIGN_TYPES.DISPLAY) {
2171
+ const OA_REQUIRED_CAMPAIGN_TYPES = [
2172
+ VALID_CAMPAIGN_TYPES.FORM,
2173
+ VALID_CAMPAIGN_TYPES.MESSAGE,
2174
+ VALID_CAMPAIGN_TYPES.OA,
2175
+ VALID_CAMPAIGN_TYPES.COMMERCE,
2176
+ VALID_CAMPAIGN_TYPES.ARTICLE
2177
+ ];
2178
+ if (payload.campaignType !== void 0 && OA_REQUIRED_CAMPAIGN_TYPES.includes(payload.campaignType)) {
2121
2179
  if (!payload.pageId || payload.pageId <= 0) {
2122
- 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).");
2180
+ 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).");
2123
2181
  }
2124
- } else {
2182
+ } else if (payload.campaignType === VALID_CAMPAIGN_TYPES.DISPLAY) {
2125
2183
  if (payload.pageId !== -1 && payload.pageId !== 0 && !payload.pageId) {
2126
2184
  warnings.push("Qu\u1EA3ng c\xE1o Display th\u01B0\u1EDDng s\u1EED d\u1EE5ng pageId = -1.");
2127
2185
  }
@@ -2188,11 +2246,15 @@ function validateUpdateAdPayload(payload, options = {}) {
2188
2246
  if (!adInfo) {
2189
2247
  errors.push("Settings.AdInfo l\xE0 b\u1EAFt bu\u1ED9c.");
2190
2248
  } else {
2249
+ const rawTypeNum = Number(payload.Type);
2250
+ const isDisplayAd = rawTypeNum === 21 || rawTypeNum === 23 || rawTypeNum === 26 || adInfo.AdFormat === 1 || adInfo.AdFormat === 2 || adInfo.AdFormat === 6 || adInfo.AdFormat === 13 || adInfo.AdFormat === 14;
2191
2251
  if (!adInfo.Caption || !adInfo.Caption.trim()) {
2192
- errors.push("Settings.AdInfo.Caption l\xE0 b\u1EAFt bu\u1ED9c.");
2252
+ if (!isDisplayAd) {
2253
+ errors.push("Settings.AdInfo.Caption l\xE0 b\u1EAFt bu\u1ED9c.");
2254
+ }
2193
2255
  } else {
2194
2256
  const captionLen = adInfo.Caption.trim().length;
2195
- if (captionLen < 35) {
2257
+ if (!isDisplayAd && captionLen < 35) {
2196
2258
  errors.push(`Settings.AdInfo.Caption qu\xE1 ng\u1EAFn (${captionLen}/35 k\xFD t\u1EF1 t\u1ED1i thi\u1EC3u).`);
2197
2259
  } else if (captionLen > 90) {
2198
2260
  errors.push(`Settings.AdInfo.Caption qu\xE1 d\xE0i (${captionLen}/90 k\xFD t\u1EF1 t\u1ED1i \u0111a).`);
@@ -2216,6 +2278,14 @@ function validateUpdateAdPayload(payload, options = {}) {
2216
2278
  );
2217
2279
  }
2218
2280
  }
2281
+ if (isDisplayAd) {
2282
+ const targetUrl = typeof adInfo.TargetUrl === "object" ? adInfo.TargetUrl?.Url : adInfo.TargetUrl;
2283
+ if (!targetUrl || typeof targetUrl !== "string" || !targetUrl.trim()) {
2284
+ errors.push("Settings.AdInfo.TargetUrl l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Display.");
2285
+ } else if (!/^https?:\/\//i.test(targetUrl.trim())) {
2286
+ 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://).");
2287
+ }
2288
+ }
2219
2289
  if (adInfo.Action !== void 0 && payload.Type) {
2220
2290
  const allowedCtas = ALLOWED_CTAS_PER_AD_TYPE[payload.Type];
2221
2291
  if (allowedCtas && !allowedCtas.includes(adInfo.Action)) {
@@ -2339,6 +2409,65 @@ function validateUpdateAdPayload(payload, options = {}) {
2339
2409
  "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."
2340
2410
  );
2341
2411
  }
2412
+ } 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) {
2413
+ const adFormat = payload.Settings?.AdInfo?.AdFormat;
2414
+ const typeNum = Number(payload.Type);
2415
+ const isHalfpage = typeNum === 26 || adFormat === 13 || adFormat === 14 || (payload.AdName || "").toLowerCase().includes("halfpage");
2416
+ const isMediumRectangle = typeNum === 23 || adFormat === 6 || (payload.AdName || "").toLowerCase().includes("medium rectangle") || (payload.AdName || "").toLowerCase().includes("300x250");
2417
+ const adNameLower = (payload.AdName || "").toLowerCase();
2418
+ const isWelcome = adNameLower.includes("welcome");
2419
+ const isMasthead = (adNameLower.includes("masthead") || typeNum === 21 || adFormat === 1 || adFormat === 2) && !isWelcome && !isMediumRectangle;
2420
+ if (price.Type !== 1 && price.Type !== 2) {
2421
+ errors.push(
2422
+ "\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)."
2423
+ );
2424
+ }
2425
+ if ((isHalfpage || isMasthead) && price.Type === 2) {
2426
+ errors.push(
2427
+ `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.`
2428
+ );
2429
+ }
2430
+ if (price.Type === 1) {
2431
+ if (price.Bid !== void 0) {
2432
+ if (isWelcome && price.Bid < 3e4) {
2433
+ errors.push(
2434
+ `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.`
2435
+ );
2436
+ } else if (isHalfpage && price.Bid < 16e3) {
2437
+ errors.push(
2438
+ `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.`
2439
+ );
2440
+ } else if (isMasthead && price.Bid < 13e3) {
2441
+ errors.push(
2442
+ `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.`
2443
+ );
2444
+ } else if (isMediumRectangle && price.Bid < 8e3) {
2445
+ errors.push(
2446
+ `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.`
2447
+ );
2448
+ } else if (price.Bid < 8e3) {
2449
+ errors.push(
2450
+ `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.`
2451
+ );
2452
+ }
2453
+ }
2454
+ if (price.Limit !== void 0 && price.Limit > 0 && price.Limit < 50) {
2455
+ errors.push(
2456
+ "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)."
2457
+ );
2458
+ }
2459
+ } else if (price.Type === 2) {
2460
+ if (price.Bid !== void 0 && price.Bid < 1800) {
2461
+ errors.push(
2462
+ `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.`
2463
+ );
2464
+ }
2465
+ if (price.Limit !== void 0 && price.Limit > 0 && price.Limit < 50) {
2466
+ errors.push(
2467
+ "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."
2468
+ );
2469
+ }
2470
+ }
2342
2471
  }
2343
2472
  if (payload.Settings && payload.Settings.DeliveryType !== void 0) {
2344
2473
  const deliveryType = payload.Settings.DeliveryType;
@@ -2355,6 +2484,21 @@ function validateUpdateAdPayload(payload, options = {}) {
2355
2484
  }
2356
2485
  const targeting = payload.Settings?.Targeting;
2357
2486
  if (targeting) {
2487
+ if (targeting.Gender !== void 0 && targeting.Gender !== null) {
2488
+ if (![0, 1, 2].includes(Number(targeting.Gender))) {
2489
+ 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).`);
2490
+ }
2491
+ }
2492
+ if (targeting.CustomAudienceId !== void 0 && targeting.CustomAudienceId !== null) {
2493
+ if (typeof targeting.CustomAudienceId !== "number" || targeting.CustomAudienceId < 0) {
2494
+ errors.push("CustomAudienceId ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn kh\xF4ng \xE2m (>= 0).");
2495
+ }
2496
+ }
2497
+ if (targeting.ExcludedAudienceId !== void 0 && targeting.ExcludedAudienceId !== null) {
2498
+ if (typeof targeting.ExcludedAudienceId !== "number" || targeting.ExcludedAudienceId < 0) {
2499
+ errors.push("ExcludedAudienceId ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn kh\xF4ng \xE2m (>= 0).");
2500
+ }
2501
+ }
2358
2502
  const newAges = targeting.NewAgeRanges;
2359
2503
  const oldAges = targeting.AgeRanges;
2360
2504
  if (newAges && newAges.length > 0) {
@@ -2477,6 +2621,14 @@ function validateUpdateAdPayload(payload, options = {}) {
2477
2621
  if (!payload.ZaloFeedId && !payload.articleId) {
2478
2622
  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).");
2479
2623
  }
2624
+ } 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) {
2625
+ const img = payload.Settings?.Image;
2626
+ const hasImage = img?.LandscapeCoverUrl || img?.BaseLandscapeCoverUrl || img?.PortraitCoverUrl || img?.SquareCoverUrl;
2627
+ if (!hasImage) {
2628
+ errors.push(
2629
+ "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)."
2630
+ );
2631
+ }
2480
2632
  }
2481
2633
  return {
2482
2634
  isValid: errors.length === 0,
@@ -2600,14 +2752,183 @@ function validateCropCoordinates(input) {
2600
2752
  data: errors.length === 0 ? cleanData : void 0
2601
2753
  };
2602
2754
  }
2755
+ function validateCreateCommerceCampaign(payload, options = {}) {
2756
+ const errors = [];
2757
+ const warnings = [];
2758
+ if (!payload.name || typeof payload.name !== "string" || !payload.name.trim()) {
2759
+ 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.");
2760
+ } else if (payload.name.length > 255) {
2761
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1.");
2762
+ }
2763
+ if (!payload.pageId || payload.pageId <= 0) {
2764
+ 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).");
2765
+ }
2766
+ if (payload.productId === void 0 || payload.productId === null || payload.productId <= 0) {
2767
+ 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).");
2768
+ }
2769
+ return { isValid: errors.length === 0, errors, warnings };
2770
+ }
2771
+ function validateCreateDisplayCampaign(payload, options = {}) {
2772
+ const errors = [];
2773
+ const warnings = [];
2774
+ if (!payload.name || typeof payload.name !== "string" || !payload.name.trim()) {
2775
+ 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.");
2776
+ } else if (payload.name.length > 255) {
2777
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1.");
2778
+ }
2779
+ if (payload.targetUrl && !/^https?:\/\/.+/i.test(payload.targetUrl)) {
2780
+ 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://.");
2781
+ }
2782
+ return { isValid: errors.length === 0, errors, warnings };
2783
+ }
2784
+ function validateCreateWebsiteCampaign(payload, options = {}) {
2785
+ const errors = [];
2786
+ const warnings = [];
2787
+ if (!payload.name || typeof payload.name !== "string" || !payload.name.trim()) {
2788
+ 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.");
2789
+ } else if (payload.name.length > 255) {
2790
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1.");
2791
+ }
2792
+ if (!payload.targetUrl || typeof payload.targetUrl !== "string" || !payload.targetUrl.trim()) {
2793
+ errors.push("Li\xEAn k\u1EBFt website ('targetUrl') l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Website.");
2794
+ } else if (!/^https?:\/\/.+/i.test(payload.targetUrl)) {
2795
+ 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://.");
2796
+ }
2797
+ return { isValid: errors.length === 0, errors, warnings };
2798
+ }
2799
+ function validateCreateFormCampaign(payload, options = {}) {
2800
+ const errors = [];
2801
+ const warnings = [];
2802
+ if (!payload.name || typeof payload.name !== "string" || !payload.name.trim()) {
2803
+ 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.");
2804
+ } else if (payload.name.length > 255) {
2805
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1.");
2806
+ }
2807
+ if (!payload.pageId || payload.pageId <= 0) {
2808
+ 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).");
2809
+ }
2810
+ return { isValid: errors.length === 0, errors, warnings };
2811
+ }
2812
+ function validateCreateMessageCampaign(payload, options = {}) {
2813
+ const errors = [];
2814
+ const warnings = [];
2815
+ if (!payload.name || typeof payload.name !== "string" || !payload.name.trim()) {
2816
+ 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.");
2817
+ } else if (payload.name.length > 255) {
2818
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1.");
2819
+ }
2820
+ if (!payload.pageId || payload.pageId <= 0) {
2821
+ 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).");
2822
+ }
2823
+ return { isValid: errors.length === 0, errors, warnings };
2824
+ }
2825
+ function validateCreateOfficialAccountCampaign(payload, options = {}) {
2826
+ const errors = [];
2827
+ const warnings = [];
2828
+ if (!payload.name || typeof payload.name !== "string" || !payload.name.trim()) {
2829
+ 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.");
2830
+ } else if (payload.name.length > 255) {
2831
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1.");
2832
+ }
2833
+ if (!payload.pageId || payload.pageId <= 0) {
2834
+ 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).");
2835
+ }
2836
+ return { isValid: errors.length === 0, errors, warnings };
2837
+ }
2838
+ function validateCreateArticleCampaign(payload, options = {}) {
2839
+ const errors = [];
2840
+ const warnings = [];
2841
+ if (!payload.name || typeof payload.name !== "string" || !payload.name.trim()) {
2842
+ 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.");
2843
+ } else if (payload.name.length > 255) {
2844
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1.");
2845
+ }
2846
+ if (!payload.pageId || payload.pageId <= 0) {
2847
+ 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).");
2848
+ }
2849
+ if (!payload.articleId || payload.articleId <= 0) {
2850
+ 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).");
2851
+ }
2852
+ return { isValid: errors.length === 0, errors, warnings };
2853
+ }
2854
+ function validateCreateVideoCampaign(payload, options = {}) {
2855
+ const errors = [];
2856
+ const warnings = [];
2857
+ if (!payload.name || typeof payload.name !== "string" || !payload.name.trim()) {
2858
+ 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.");
2859
+ } else if (payload.name.length > 255) {
2860
+ errors.push("T\xEAn chi\u1EBFn d\u1ECBch ('name') kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1.");
2861
+ }
2862
+ if (!payload.targetUrl || typeof payload.targetUrl !== "string" || !payload.targetUrl.trim()) {
2863
+ errors.push("Li\xEAn k\u1EBFt Website ('targetUrl') l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Video.");
2864
+ } else if (!/^https?:\/\/.+/i.test(payload.targetUrl)) {
2865
+ 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://.");
2866
+ }
2867
+ return { isValid: errors.length === 0, errors, warnings };
2868
+ }
2869
+ function validateUpdateWebsiteAd(payload, options = {}) {
2870
+ return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.WEBSITE }, options);
2871
+ }
2872
+ function validateUpdateDisplayAd(payload, options = {}) {
2873
+ const adFormat = payload.Settings?.AdInfo?.AdFormat;
2874
+ const rawType = Number(payload.Type);
2875
+ const isHalfpage = rawType === 26 || adFormat === 13 || adFormat === 14;
2876
+ const isMediumRectangle = rawType === 23 || adFormat === 6;
2877
+ let effectiveType;
2878
+ if (isHalfpage) {
2879
+ effectiveType = VALID_AD_TYPES.DISPLAY_HALFPAGE;
2880
+ } else if (isMediumRectangle) {
2881
+ effectiveType = VALID_AD_TYPES.DISPLAY_MEDIUM_RECTANGLE;
2882
+ } else {
2883
+ effectiveType = payload.Type ?? VALID_AD_TYPES.DISPLAY;
2884
+ }
2885
+ return validateUpdateAdPayload({ ...payload, Type: effectiveType }, options);
2886
+ }
2887
+ function validateUpdateVideoAd(payload, options = {}) {
2888
+ return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.VIDEO }, options);
2889
+ }
2890
+ function validateUpdateCommerceAd(payload, options = {}) {
2891
+ return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.COMMERCE }, options);
2892
+ }
2893
+ function validateUpdateFormAd(payload, options = {}) {
2894
+ return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.FORM }, options);
2895
+ }
2896
+ function validateUpdateMessageAd(payload, options = {}) {
2897
+ return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.MESSAGE }, options);
2898
+ }
2899
+ function validateUpdateOfficialAccountAd(payload, options = {}) {
2900
+ return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.OA }, options);
2901
+ }
2902
+ function validateUpdateArticleAd(payload, options = {}) {
2903
+ return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.ARTICLE }, options);
2904
+ }
2603
2905
  var ZaloCampaignsValidator = {
2906
+ // Generic
2604
2907
  createCampaign: validateCreateCampaignPayload,
2605
2908
  updateAd: validateUpdateAdPayload,
2606
2909
  renameCampaign: validateRenameCampaignParams,
2607
2910
  changeStatus: validateChangeCampaignStatusParams,
2608
2911
  duplicateAd: validateDuplicateAdParams,
2609
2912
  validateCropCoordinates,
2610
- validateUploadCropAdImage: validateCropCoordinates
2913
+ validateUploadCropAdImage: validateCropCoordinates,
2914
+ // Specific Create Campaign
2915
+ createCommerceCampaign: validateCreateCommerceCampaign,
2916
+ createDisplayCampaign: validateCreateDisplayCampaign,
2917
+ createWebsiteCampaign: validateCreateWebsiteCampaign,
2918
+ createFormCampaign: validateCreateFormCampaign,
2919
+ createMessageCampaign: validateCreateMessageCampaign,
2920
+ createOfficialAccountCampaign: validateCreateOfficialAccountCampaign,
2921
+ createArticleCampaign: validateCreateArticleCampaign,
2922
+ createVideoCampaign: validateCreateVideoCampaign,
2923
+ // Specific Update Ad
2924
+ updateWebsiteAd: validateUpdateWebsiteAd,
2925
+ updateDisplayAd: validateUpdateDisplayAd,
2926
+ updateVideoAd: validateUpdateVideoAd,
2927
+ updateCommerceAd: validateUpdateCommerceAd,
2928
+ updateFormAd: validateUpdateFormAd,
2929
+ updateMessageAd: validateUpdateMessageAd,
2930
+ updateOfficialAccountAd: validateUpdateOfficialAccountAd,
2931
+ updateArticleAd: validateUpdateArticleAd
2611
2932
  };
2612
2933
 
2613
2934
  // src/services/campaigns.service.ts
@@ -5759,8 +6080,8 @@ function validateListFormLeadsRequest(input) {
5759
6080
  const offset = typeof raw.offset === "number" && raw.offset >= 0 ? Math.floor(raw.offset) : 0;
5760
6081
  const status = typeof raw.status === "string" && raw.status.trim() !== "" ? raw.status.trim() : "2,6,1,0,7,4,5,3";
5761
6082
  const now = Math.floor(Date.now() / 1e3);
5762
- const fromTime = typeof raw.fromTime === "number" && raw.fromTime >= 0 ? Math.floor(raw.fromTime) : now - 90 * 86400;
5763
- const toTime = typeof raw.toTime === "number" && raw.toTime >= 0 ? Math.floor(raw.toTime) : now;
6083
+ const fromTime = typeof raw.fromTime === "number" && raw.fromTime >= 0 ? raw.fromTime >= 1e10 ? Math.floor(raw.fromTime / 1e3) : Math.floor(raw.fromTime) : now - 90 * 86400;
6084
+ const toTime = typeof raw.toTime === "number" && raw.toTime >= 0 ? raw.toTime >= 1e10 ? Math.floor(raw.toTime / 1e3) : Math.floor(raw.toTime) : now;
5764
6085
  if (toTime < fromTime) {
5765
6086
  errors.push("M\u1ED1c th\u1EDDi gian k\u1EBFt th\xFAc 'toTime' ph\u1EA3i l\u1EDBn h\u01A1n ho\u1EB7c b\u1EB1ng 'fromTime'.");
5766
6087
  }
@@ -8707,6 +9028,7 @@ export {
8707
9028
  VALID_AD_TYPES,
8708
9029
  VALID_CAMPAIGN_TYPES,
8709
9030
  VIETNAM_PHONE_REGEX,
9031
+ ZALO_DISPLAY_AD_FORMAT,
8710
9032
  ZALO_NEW_REGION_PROVINCE_CODES,
8711
9033
  ZALO_PROFILE_ADS_PROVINCES,
8712
9034
  ZALO_PROFILE_ADS_SUB_CATEGORIES,
@@ -8781,18 +9103,26 @@ export {
8781
9103
  sanitizeCanvasKeys,
8782
9104
  validateChangeCampaignStatusParams,
8783
9105
  validateCloneInstantPageRequest,
9106
+ validateCreateArticleCampaign,
8784
9107
  validateCreateCampaignPayload,
9108
+ validateCreateCommerceCampaign,
8785
9109
  validateCreateCustomAudienceRequest,
9110
+ validateCreateDisplayCampaign,
8786
9111
  validateCreateFlowRequest,
9112
+ validateCreateFormCampaign,
8787
9113
  validateCreateFormEventAudienceRequest,
8788
9114
  validateCreateFormRequest,
8789
9115
  validateCreateInstantPageRequest,
8790
9116
  validateCreateLookalikeAudienceRequest,
9117
+ validateCreateMessageCampaign,
8791
9118
  validateCreateMessageOaEventAudienceRequest,
8792
9119
  validateCreateMessagePersonalEventAudienceRequest,
8793
9120
  validateCreateOaPageRequest,
9121
+ validateCreateOfficialAccountCampaign,
8794
9122
  validateCreatePhoneAudienceRequest,
8795
9123
  validateCreateSavedAudienceRequest,
9124
+ validateCreateVideoCampaign,
9125
+ validateCreateWebsiteCampaign,
8796
9126
  validateCropCoordinates,
8797
9127
  validateDateRangeReportRequest,
8798
9128
  validateDuplicateAdParams,
@@ -8815,10 +9145,18 @@ export {
8815
9145
  validateSearchInstantPagesRequest,
8816
9146
  validateToggleLeadNotificationRequest,
8817
9147
  validateUpdateAdPayload,
9148
+ validateUpdateArticleAd,
9149
+ validateUpdateCommerceAd,
9150
+ validateUpdateDisplayAd,
8818
9151
  validateUpdateFlowRequest,
9152
+ validateUpdateFormAd,
8819
9153
  validateUpdateInstantPageRequest,
8820
9154
  validateUpdateInstantPageSharesRequest,
8821
9155
  validateUpdateLeadNotificationIntervalRequest,
9156
+ validateUpdateMessageAd,
9157
+ validateUpdateOfficialAccountAd,
9158
+ validateUpdateVideoAd,
9159
+ validateUpdateWebsiteAd,
8822
9160
  validateUploadCustomAudiencePhoneListRequest,
8823
9161
  validateUploadMediaRequest,
8824
9162
  validateUpsertCustomReportRequest,