@redonvn/zalo-ads-sdk 0.2.20 → 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.d.mts +25 -1
- package/dist/index.d.ts +25 -1
- package/dist/index.js +164 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +163 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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 = [];
|
|
@@ -2195,11 +2246,15 @@ function validateUpdateAdPayload(payload, options = {}) {
|
|
|
2195
2246
|
if (!adInfo) {
|
|
2196
2247
|
errors.push("Settings.AdInfo l\xE0 b\u1EAFt bu\u1ED9c.");
|
|
2197
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;
|
|
2198
2251
|
if (!adInfo.Caption || !adInfo.Caption.trim()) {
|
|
2199
|
-
|
|
2252
|
+
if (!isDisplayAd) {
|
|
2253
|
+
errors.push("Settings.AdInfo.Caption l\xE0 b\u1EAFt bu\u1ED9c.");
|
|
2254
|
+
}
|
|
2200
2255
|
} else {
|
|
2201
2256
|
const captionLen = adInfo.Caption.trim().length;
|
|
2202
|
-
if (captionLen < 35) {
|
|
2257
|
+
if (!isDisplayAd && captionLen < 35) {
|
|
2203
2258
|
errors.push(`Settings.AdInfo.Caption qu\xE1 ng\u1EAFn (${captionLen}/35 k\xFD t\u1EF1 t\u1ED1i thi\u1EC3u).`);
|
|
2204
2259
|
} else if (captionLen > 90) {
|
|
2205
2260
|
errors.push(`Settings.AdInfo.Caption qu\xE1 d\xE0i (${captionLen}/90 k\xFD t\u1EF1 t\u1ED1i \u0111a).`);
|
|
@@ -2223,6 +2278,14 @@ function validateUpdateAdPayload(payload, options = {}) {
|
|
|
2223
2278
|
);
|
|
2224
2279
|
}
|
|
2225
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
|
+
}
|
|
2226
2289
|
if (adInfo.Action !== void 0 && payload.Type) {
|
|
2227
2290
|
const allowedCtas = ALLOWED_CTAS_PER_AD_TYPE[payload.Type];
|
|
2228
2291
|
if (allowedCtas && !allowedCtas.includes(adInfo.Action)) {
|
|
@@ -2346,6 +2409,65 @@ function validateUpdateAdPayload(payload, options = {}) {
|
|
|
2346
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."
|
|
2347
2410
|
);
|
|
2348
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
|
+
}
|
|
2349
2471
|
}
|
|
2350
2472
|
if (payload.Settings && payload.Settings.DeliveryType !== void 0) {
|
|
2351
2473
|
const deliveryType = payload.Settings.DeliveryType;
|
|
@@ -2362,6 +2484,21 @@ function validateUpdateAdPayload(payload, options = {}) {
|
|
|
2362
2484
|
}
|
|
2363
2485
|
const targeting = payload.Settings?.Targeting;
|
|
2364
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
|
+
}
|
|
2365
2502
|
const newAges = targeting.NewAgeRanges;
|
|
2366
2503
|
const oldAges = targeting.AgeRanges;
|
|
2367
2504
|
if (newAges && newAges.length > 0) {
|
|
@@ -2484,6 +2621,14 @@ function validateUpdateAdPayload(payload, options = {}) {
|
|
|
2484
2621
|
if (!payload.ZaloFeedId && !payload.articleId) {
|
|
2485
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).");
|
|
2486
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
|
+
}
|
|
2487
2632
|
}
|
|
2488
2633
|
return {
|
|
2489
2634
|
isValid: errors.length === 0,
|
|
@@ -2725,7 +2870,19 @@ function validateUpdateWebsiteAd(payload, options = {}) {
|
|
|
2725
2870
|
return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.WEBSITE }, options);
|
|
2726
2871
|
}
|
|
2727
2872
|
function validateUpdateDisplayAd(payload, options = {}) {
|
|
2728
|
-
|
|
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);
|
|
2729
2886
|
}
|
|
2730
2887
|
function validateUpdateVideoAd(payload, options = {}) {
|
|
2731
2888
|
return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.VIDEO }, options);
|
|
@@ -8871,6 +9028,7 @@ export {
|
|
|
8871
9028
|
VALID_AD_TYPES,
|
|
8872
9029
|
VALID_CAMPAIGN_TYPES,
|
|
8873
9030
|
VIETNAM_PHONE_REGEX,
|
|
9031
|
+
ZALO_DISPLAY_AD_FORMAT,
|
|
8874
9032
|
ZALO_NEW_REGION_PROVINCE_CODES,
|
|
8875
9033
|
ZALO_PROFILE_ADS_PROVINCES,
|
|
8876
9034
|
ZALO_PROFILE_ADS_SUB_CATEGORIES,
|