@redonvn/zalo-ads-sdk 0.2.4 → 0.2.7

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
@@ -1531,6 +1531,30 @@ var OP_ZaloAdsDeleteCampaign = {
1531
1531
  "status"
1532
1532
  ]
1533
1533
  };
1534
+ var OP_ZaloAdsCreateSpellCheckV3Job = {
1535
+ operationId: "zalo_ads_create_spell_check_v3_job",
1536
+ method: "POST",
1537
+ endpoint: "/api/spell-check/v3",
1538
+ baseUrl: "https://ads.zalo.me",
1539
+ binaryFields: [],
1540
+ pathFields: [],
1541
+ queryFields: [],
1542
+ headerFields: [],
1543
+ cookieFields: [],
1544
+ bodyFields: ["title", "caption"]
1545
+ };
1546
+ var OP_ZaloAdsGetSpellCheckV3Job = {
1547
+ operationId: "zalo_ads_get_spell_check_v3_job",
1548
+ method: "GET",
1549
+ endpoint: "/api/spell-check/v3/{jobId}",
1550
+ baseUrl: "https://ads.zalo.me",
1551
+ binaryFields: [],
1552
+ pathFields: ["jobId"],
1553
+ queryFields: [],
1554
+ headerFields: [],
1555
+ cookieFields: [],
1556
+ bodyFields: []
1557
+ };
1534
1558
  var ZaloCampaignsService = class {
1535
1559
  constructor(client) {
1536
1560
  this.client = client;
@@ -1680,6 +1704,48 @@ var ZaloCampaignsService = class {
1680
1704
  getSpellCheckV2(...args) {
1681
1705
  return this.getApiSpellCheckV2(...args);
1682
1706
  }
1707
+ /**
1708
+ * Khởi tạo tác vụ kiểm tra chính tả và vi phạm quy chuẩn quảng cáo AI V3 (POST /api/spell-check/v3).
1709
+ */
1710
+ createSpellCheckV3Job(request, options) {
1711
+ return this.client.requestJson(
1712
+ OP_ZaloAdsCreateSpellCheckV3Job,
1713
+ this.client.toTransportInput(OP_ZaloAdsCreateSpellCheckV3Job, request),
1714
+ options
1715
+ );
1716
+ }
1717
+ /**
1718
+ * Lấy kết quả kiểm tra chính tả AI V3 theo jobId (GET /api/spell-check/v3/{jobId}).
1719
+ */
1720
+ getSpellCheckV3Job(request, options) {
1721
+ return this.client.requestWithoutBody(
1722
+ OP_ZaloAdsGetSpellCheckV3Job,
1723
+ this.client.toTransportInput(OP_ZaloAdsGetSpellCheckV3Job, request),
1724
+ options
1725
+ );
1726
+ }
1727
+ /**
1728
+ * Helper kiểm tra chính tả AI V3 trọn gói: Gửi kiểm tra và tự động polling cho đến khi hoàn thành (hoặc timeout).
1729
+ * @param request Tiêu đề (title) và chú thích (caption) cần kiểm tra.
1730
+ * @param pollIntervalMs Chu kỳ polling kiểm tra trạng thái (mặc định: 600ms).
1731
+ * @param timeoutMs Thời gian chờ tối đa (mặc định: 15.000ms = 15 giây).
1732
+ */
1733
+ async checkSpellV3AndWait(request, pollIntervalMs = 600, timeoutMs = 15e3, options) {
1734
+ const jobRes = await this.createSpellCheckV3Job(request, options);
1735
+ const jobId = jobRes?.data?.jobId;
1736
+ if (!jobId) {
1737
+ throw new Error(`[SpellCheckV3] Kh\xF4ng nh\u1EADn \u0111\u01B0\u1EE3c jobId t\u1EEB Zalo Ads (code: ${jobRes?.code})`);
1738
+ }
1739
+ const startTime = Date.now();
1740
+ while (Date.now() - startTime < timeoutMs) {
1741
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
1742
+ const res = await this.getSpellCheckV3Job({ jobId }, options);
1743
+ if (res?.data?.status === "COMPLETED") {
1744
+ return res;
1745
+ }
1746
+ }
1747
+ throw new Error(`[SpellCheckV3] Qu\xE1 th\u1EDDi gian ch\u1EDD (${timeoutMs}ms) cho t\xE1c v\u1EE5 ki\u1EC3m tra ch\xEDnh t\u1EA3 jobId: ${jobId}`);
1748
+ }
1683
1749
  };
1684
1750
 
1685
1751
  // src/services/account.service.ts
@@ -1834,6 +1900,365 @@ var ZaloAccountService = class {
1834
1900
  }
1835
1901
  };
1836
1902
 
1903
+ // src/validators/audiences.validator.ts
1904
+ function validateCreateSavedAudienceRequest(input) {
1905
+ const errors = [];
1906
+ if (!input || typeof input !== "object") {
1907
+ return { isValid: false, errors: ["Input ph\u1EA3i l\xE0 m\u1ED9t object."], data: void 0 };
1908
+ }
1909
+ const raw = input;
1910
+ const name = typeof raw.name === "string" ? raw.name.trim() : "";
1911
+ if (!name) {
1912
+ errors.push("T\xEAn nh\xF3m \u0111\u1ED1i t\u01B0\u1EE3ng 'name' l\xE0 b\u1EAFt bu\u1ED9c.");
1913
+ } else if (name.length < 2 || name.length > 255) {
1914
+ errors.push("T\xEAn nh\xF3m \u0111\u1ED1i t\u01B0\u1EE3ng 'name' ph\u1EA3i t\u1EEB 2 \u0111\u1EBFn 255 k\xFD t\u1EF1.");
1915
+ }
1916
+ let targetingObj;
1917
+ if (typeof raw.targeting === "string") {
1918
+ try {
1919
+ targetingObj = JSON.parse(raw.targeting);
1920
+ } catch {
1921
+ errors.push("Tr\u01B0\u1EDDng 'targeting' l\xE0 chu\u1ED7i JSON kh\xF4ng h\u1EE3p l\u1EC7.");
1922
+ targetingObj = {};
1923
+ }
1924
+ } else if (raw.targeting && typeof raw.targeting === "object") {
1925
+ targetingObj = raw.targeting;
1926
+ } else {
1927
+ errors.push("Tr\u01B0\u1EDDng 'targeting' l\xE0 b\u1EAFt bu\u1ED9c (chu\u1ED7i JSON ho\u1EB7c Object c\u1EA5u h\xECnh targeting).");
1928
+ targetingObj = {};
1929
+ }
1930
+ const gender = typeof targetingObj.Gender === "number" ? targetingObj.Gender : 0;
1931
+ if (![0, 1, 2].includes(gender)) {
1932
+ errors.push("Tr\u01B0\u1EDDng 'Gender' ph\u1EA3i l\xE0 0 (T\u1EA5t c\u1EA3), 1 (Nam), ho\u1EB7c 2 (N\u1EEF).");
1933
+ }
1934
+ const VALID_AGE_RANGES = [10282, 10283, 10284, 10285, 10286, 10287, 10288];
1935
+ const newAgeRanges = Array.isArray(targetingObj.NewAgeRanges) && targetingObj.NewAgeRanges.length > 0 ? targetingObj.NewAgeRanges.map(Number) : VALID_AGE_RANGES;
1936
+ for (const age of newAgeRanges) {
1937
+ if (!VALID_AGE_RANGES.includes(age)) {
1938
+ errors.push(`M\xE3 \u0111\u1ED9 tu\u1ED5i '${age}' kh\xF4ng h\u1EE3p l\u1EC7. C\xE1c m\xE3 cho ph\xE9p: ${VALID_AGE_RANGES.join(", ")}.`);
1939
+ }
1940
+ }
1941
+ const VALID_OS = [0, 1, 2, 3];
1942
+ const os = Array.isArray(targetingObj.Os) && targetingObj.Os.length > 0 ? targetingObj.Os.map(Number) : [0, 1, 3];
1943
+ for (const o of os) {
1944
+ if (!VALID_OS.includes(o)) {
1945
+ errors.push(`M\xE3 h\u1EC7 \u0111i\u1EC1u h\xE0nh '${o}' kh\xF4ng h\u1EE3p l\u1EC7 (0: Android, 1: iOS, 2: Windows Phone, 3: PC).`);
1946
+ }
1947
+ }
1948
+ let location = targetingObj.Location;
1949
+ if (!location || typeof location !== "object") {
1950
+ location = {
1951
+ Addresses: [],
1952
+ Cities: [],
1953
+ WardTargeting: { Includes: [], Excludes: [] }
1954
+ };
1955
+ } else {
1956
+ location = {
1957
+ Addresses: Array.isArray(location.Addresses) ? location.Addresses : [],
1958
+ Cities: Array.isArray(location.Cities) ? location.Cities : [],
1959
+ WardTargeting: location.WardTargeting && typeof location.WardTargeting === "object" ? location.WardTargeting : { Includes: [], Excludes: [] }
1960
+ };
1961
+ if (location.WardTargeting.Includes && !Array.isArray(location.WardTargeting.Includes)) {
1962
+ errors.push("Tr\u01B0\u1EDDng 'Location.WardTargeting.Includes' ph\u1EA3i l\xE0 m\u1ED9t m\u1EA3ng khu v\u1EF1c.");
1963
+ } else if (Array.isArray(location.WardTargeting.Includes)) {
1964
+ for (const inc of location.WardTargeting.Includes) {
1965
+ if (![1, 2, 3].includes(Number(inc.Id))) {
1966
+ errors.push(`M\xE3 v\xF9ng mi\u1EC1n Id='${inc.Id}' kh\xF4ng h\u1EE3p l\u1EC7 (1: Mi\u1EC1n B\u1EAFc, 2: Mi\u1EC1n Trung, 3: Mi\u1EC1n Nam).`);
1967
+ }
1968
+ if (inc.Provinces && !Array.isArray(inc.Provinces)) {
1969
+ errors.push(`Tr\u01B0\u1EDDng 'Provinces' trong v\xF9ng mi\u1EC1n Id=${inc.Id} ph\u1EA3i l\xE0 m\u1ED9t m\u1EA3ng t\u1EC9nh/th\xE0nh.`);
1970
+ }
1971
+ }
1972
+ }
1973
+ }
1974
+ const finalTargeting = {
1975
+ ...targetingObj,
1976
+ CustomAudienceId: 0,
1977
+ Gender: gender,
1978
+ NewAgeRanges: newAgeRanges,
1979
+ Os: os,
1980
+ Location: location
1981
+ };
1982
+ return {
1983
+ isValid: errors.length === 0,
1984
+ errors,
1985
+ data: errors.length === 0 ? {
1986
+ name,
1987
+ caType: 1,
1988
+ targeting: JSON.stringify(finalTargeting)
1989
+ } : void 0
1990
+ };
1991
+ }
1992
+ function validateCreatePhoneAudienceRequest(input) {
1993
+ const errors = [];
1994
+ if (!input || typeof input !== "object") {
1995
+ return { isValid: false, errors: ["Input ph\u1EA3i l\xE0 m\u1ED9t object."], data: void 0 };
1996
+ }
1997
+ const raw = input;
1998
+ const name = typeof raw.name === "string" ? raw.name.trim() : "";
1999
+ if (!name || name.length < 2 || name.length > 255) {
2000
+ errors.push("T\xEAn nh\xF3m \u0111\u1ED1i t\u01B0\u1EE3ng 'name' ph\u1EA3i t\u1EEB 2 \u0111\u1EBFn 255 k\xFD t\u1EF1.");
2001
+ }
2002
+ let targetingObj = {};
2003
+ if (typeof raw.targeting === "string") {
2004
+ try {
2005
+ targetingObj = JSON.parse(raw.targeting);
2006
+ } catch {
2007
+ errors.push("Tr\u01B0\u1EDDng 'targeting' l\xE0 chu\u1ED7i JSON kh\xF4ng h\u1EE3p l\u1EC7.");
2008
+ }
2009
+ } else if (raw.targeting && typeof raw.targeting === "object") {
2010
+ targetingObj = raw.targeting;
2011
+ } else {
2012
+ errors.push("Tr\u01B0\u1EDDng 'targeting' l\xE0 b\u1EAFt bu\u1ED9c.");
2013
+ }
2014
+ const path = typeof targetingObj.Path === "string" ? targetingObj.Path.trim() : "";
2015
+ if (!path) {
2016
+ errors.push("Tr\u01B0\u1EDDng 'Path' (URL file .txt sau khi upload) l\xE0 b\u1EAFt bu\u1ED9c.");
2017
+ }
2018
+ const total = typeof targetingObj.Total === "number" ? targetingObj.Total : 0;
2019
+ if (total <= 0) {
2020
+ errors.push("Tr\u01B0\u1EDDng 'Total' (s\u1ED1 l\u01B0\u1EE3ng S\u0110T trong file) ph\u1EA3i l\u1EDBn h\u01A1n 0.");
2021
+ }
2022
+ return {
2023
+ isValid: errors.length === 0,
2024
+ errors,
2025
+ data: errors.length === 0 ? {
2026
+ name,
2027
+ caType: 3,
2028
+ targeting: JSON.stringify({
2029
+ Name: String(targetingObj.Name || "phones.txt"),
2030
+ Path: path,
2031
+ Total: total,
2032
+ ZaloId: Number(targetingObj.ZaloId || 0),
2033
+ OriginAudience: 0
2034
+ })
2035
+ } : void 0
2036
+ };
2037
+ }
2038
+ function validateCreateLookalikeAudienceRequest(input) {
2039
+ const errors = [];
2040
+ if (!input || typeof input !== "object") {
2041
+ return { isValid: false, errors: ["Input ph\u1EA3i l\xE0 m\u1ED9t object."], data: void 0 };
2042
+ }
2043
+ const raw = input;
2044
+ const name = typeof raw.name === "string" ? raw.name.trim() : "";
2045
+ if (!name || name.length < 2 || name.length > 255) {
2046
+ errors.push("T\xEAn nh\xF3m \u0111\u1ED1i t\u01B0\u1EE3ng 'name' ph\u1EA3i t\u1EEB 2 \u0111\u1EBFn 255 k\xFD t\u1EF1.");
2047
+ }
2048
+ let targetingObj = {};
2049
+ if (typeof raw.targeting === "string") {
2050
+ try {
2051
+ targetingObj = JSON.parse(raw.targeting);
2052
+ } catch {
2053
+ errors.push("Tr\u01B0\u1EDDng 'targeting' l\xE0 chu\u1ED7i JSON kh\xF4ng h\u1EE3p l\u1EC7.");
2054
+ }
2055
+ } else if (raw.targeting && typeof raw.targeting === "object") {
2056
+ targetingObj = raw.targeting;
2057
+ } else {
2058
+ errors.push("Tr\u01B0\u1EDDng 'targeting' l\xE0 b\u1EAFt bu\u1ED9c.");
2059
+ }
2060
+ const originAudience = Number(targetingObj.OriginAudience);
2061
+ if (!originAudience || originAudience <= 0) {
2062
+ errors.push("Tr\u01B0\u1EDDng 'OriginAudience' (ID nh\xF3m \u0111\u1ED1i t\u01B0\u1EE3ng S\u0110T g\u1ED1c) l\xE0 b\u1EAFt bu\u1ED9c.");
2063
+ }
2064
+ const total = Number(targetingObj.Total);
2065
+ if (![1e6, 15e5, 2e6].includes(total)) {
2066
+ errors.push("Tr\u01B0\u1EDDng 'Total' c\u1EE7a Lookalike ch\u1EC9 ch\u1EA5p nh\u1EADn c\xE1c m\u1ED1c: 1.000.000, 1.500.000 ho\u1EB7c 2.000.000.");
2067
+ }
2068
+ return {
2069
+ isValid: errors.length === 0,
2070
+ errors,
2071
+ data: errors.length === 0 ? {
2072
+ name,
2073
+ caType: 6,
2074
+ targeting: JSON.stringify({
2075
+ OriginAudience: originAudience,
2076
+ Total: total,
2077
+ Name: String(targetingObj.Name || "Lookalike Audience"),
2078
+ Path: String(targetingObj.Path || "")
2079
+ })
2080
+ } : void 0
2081
+ };
2082
+ }
2083
+ function validateCreateFormEventAudienceRequest(input) {
2084
+ const errors = [];
2085
+ if (!input || typeof input !== "object") {
2086
+ return { isValid: false, errors: ["Input ph\u1EA3i l\xE0 m\u1ED9t object."], data: void 0 };
2087
+ }
2088
+ const raw = input;
2089
+ const name = typeof raw.name === "string" ? raw.name.trim() : "";
2090
+ if (!name || name.length < 2 || name.length > 255) {
2091
+ errors.push("T\xEAn nh\xF3m \u0111\u1ED1i t\u01B0\u1EE3ng 'name' ph\u1EA3i t\u1EEB 2 \u0111\u1EBFn 255 k\xFD t\u1EF1.");
2092
+ }
2093
+ let targetingObj = {};
2094
+ if (typeof raw.targeting === "string") {
2095
+ try {
2096
+ targetingObj = JSON.parse(raw.targeting);
2097
+ } catch {
2098
+ errors.push("Tr\u01B0\u1EDDng 'targeting' l\xE0 chu\u1ED7i JSON kh\xF4ng h\u1EE3p l\u1EC7.");
2099
+ }
2100
+ } else if (raw.targeting && typeof raw.targeting === "object") {
2101
+ targetingObj = raw.targeting;
2102
+ }
2103
+ const eventType = Number(targetingObj.EventType);
2104
+ if (![1, 2, 3, 4].includes(eventType)) {
2105
+ errors.push("Tr\u01B0\u1EDDng 'EventType' ph\u1EA3i l\xE0 1 (\u0110\xE3 xem ch\u01B0a g\u1EEDi), 2 (\u0110\xE3 xem & g\u1EEDi), 3 (\u0110\xE3 xem), ho\u1EB7c 4 (M\u1EDF chat t\u1EEB Form).");
2106
+ }
2107
+ const oaId = typeof targetingObj.OaId === "string" ? targetingObj.OaId.trim() : String(targetingObj.OaId || "");
2108
+ if (!oaId) {
2109
+ errors.push("Tr\u01B0\u1EDDng 'OaId' (d\u1EA1ng chu\u1ED7i c\u1EE7a pageId ho\u1EB7c noisedId) l\xE0 b\u1EAFt bu\u1ED9c.");
2110
+ }
2111
+ const numDays = Number(targetingObj.NumDays);
2112
+ if (isNaN(numDays) || numDays < 1 || numDays > 90) {
2113
+ errors.push("Tr\u01B0\u1EDDng 'NumDays' ph\u1EA3i n\u1EB1m trong kho\u1EA3ng t\u1EEB 1 \u0111\u1EBFn 90 ng\xE0y.");
2114
+ }
2115
+ const formIds = Array.isArray(targetingObj.FormIds) ? targetingObj.FormIds : [];
2116
+ if (formIds.length === 0) {
2117
+ errors.push("Tr\u01B0\u1EDDng 'FormIds' ph\u1EA3i ch\u1EE9a \xEDt nh\u1EA5t 1 ID Form.");
2118
+ }
2119
+ return {
2120
+ isValid: errors.length === 0,
2121
+ errors,
2122
+ data: errors.length === 0 ? {
2123
+ name,
2124
+ caType: 12,
2125
+ targeting: JSON.stringify({
2126
+ EventType: eventType,
2127
+ OaId: oaId,
2128
+ NumDays: numDays,
2129
+ FormIds: formIds
2130
+ })
2131
+ } : void 0
2132
+ };
2133
+ }
2134
+ function validateCreateMessageOaEventAudienceRequest(input) {
2135
+ const errors = [];
2136
+ if (!input || typeof input !== "object") {
2137
+ return { isValid: false, errors: ["Input ph\u1EA3i l\xE0 m\u1ED9t object."], data: void 0 };
2138
+ }
2139
+ const raw = input;
2140
+ const name = typeof raw.name === "string" ? raw.name.trim() : "";
2141
+ if (!name || name.length < 2 || name.length > 255) {
2142
+ errors.push("T\xEAn nh\xF3m \u0111\u1ED1i t\u01B0\u1EE3ng 'name' ph\u1EA3i t\u1EEB 2 \u0111\u1EBFn 255 k\xFD t\u1EF1.");
2143
+ }
2144
+ let targetingObj = {};
2145
+ if (typeof raw.targeting === "string") {
2146
+ try {
2147
+ targetingObj = JSON.parse(raw.targeting);
2148
+ } catch {
2149
+ errors.push("Tr\u01B0\u1EDDng 'targeting' l\xE0 chu\u1ED7i JSON kh\xF4ng h\u1EE3p l\u1EC7.");
2150
+ }
2151
+ } else if (raw.targeting && typeof raw.targeting === "object") {
2152
+ targetingObj = raw.targeting;
2153
+ }
2154
+ const eventId = Number(targetingObj.EventId ?? targetingObj.EventType ?? 1);
2155
+ const oaId = typeof targetingObj.OaId === "string" ? targetingObj.OaId.trim() : String(targetingObj.OaId || "");
2156
+ if (!oaId) {
2157
+ errors.push("Tr\u01B0\u1EDDng 'OaId' (chu\u1ED7i pageId ho\u1EB7c noisedId c\u1EE7a OA) l\xE0 b\u1EAFt bu\u1ED9c.");
2158
+ }
2159
+ const numDays = Number(targetingObj.NumDays);
2160
+ if (isNaN(numDays) || numDays < 1 || numDays > 90) {
2161
+ errors.push("Tr\u01B0\u1EDDng 'NumDays' ph\u1EA3i n\u1EB1m trong kho\u1EA3ng t\u1EEB 1 \u0111\u1EBFn 90 ng\xE0y.");
2162
+ }
2163
+ return {
2164
+ isValid: errors.length === 0,
2165
+ errors,
2166
+ data: errors.length === 0 ? {
2167
+ name,
2168
+ caType: 11,
2169
+ targeting: JSON.stringify({
2170
+ EventId: eventId,
2171
+ OaId: oaId,
2172
+ NumDays: numDays
2173
+ })
2174
+ } : void 0
2175
+ };
2176
+ }
2177
+ function validateCreateMessagePersonalEventAudienceRequest(input) {
2178
+ const errors = [];
2179
+ if (!input || typeof input !== "object") {
2180
+ return { isValid: false, errors: ["Input ph\u1EA3i l\xE0 m\u1ED9t object."], data: void 0 };
2181
+ }
2182
+ const raw = input;
2183
+ const name = typeof raw.name === "string" ? raw.name.trim() : "";
2184
+ if (!name || name.length < 2 || name.length > 255) {
2185
+ errors.push("T\xEAn nh\xF3m \u0111\u1ED1i t\u01B0\u1EE3ng 'name' ph\u1EA3i t\u1EEB 2 \u0111\u1EBFn 255 k\xFD t\u1EF1.");
2186
+ }
2187
+ let targetingObj = {};
2188
+ if (typeof raw.targeting === "string") {
2189
+ try {
2190
+ targetingObj = JSON.parse(raw.targeting);
2191
+ } catch {
2192
+ errors.push("Tr\u01B0\u1EDDng 'targeting' l\xE0 chu\u1ED7i JSON kh\xF4ng h\u1EE3p l\u1EC7.");
2193
+ }
2194
+ } else if (raw.targeting && typeof raw.targeting === "object") {
2195
+ targetingObj = raw.targeting;
2196
+ }
2197
+ const eventId = Number(targetingObj.EventId ?? targetingObj.EventType ?? 1);
2198
+ if (![1, 2, 3].includes(eventId)) {
2199
+ errors.push("Tr\u01B0\u1EDDng 'EventId' ph\u1EA3i l\xE0 1 (\u0110\xE3 li\xEAn h\u1EC7), 2 (\u0110\xE3 xem kh\xF4ng li\xEAn h\u1EC7), ho\u1EB7c 3 (Xem carousel kh\xF4ng li\xEAn h\u1EC7).");
2200
+ }
2201
+ const numDays = Number(targetingObj.NumDays);
2202
+ if (isNaN(numDays) || numDays < 1 || numDays > 90) {
2203
+ errors.push("Tr\u01B0\u1EDDng 'NumDays' ph\u1EA3i n\u1EB1m trong kho\u1EA3ng t\u1EEB 1 \u0111\u1EBFn 90 ng\xE0y.");
2204
+ }
2205
+ const pageIds = Array.isArray(targetingObj.PageIds) ? targetingObj.PageIds.map(String) : [];
2206
+ if (pageIds.length === 0) {
2207
+ errors.push("Tr\u01B0\u1EDDng 'PageIds' ph\u1EA3i ch\u1EE9a \xEDt nh\u1EA5t 1 ID trang c\xE1 nh\xE2n.");
2208
+ }
2209
+ return {
2210
+ isValid: errors.length === 0,
2211
+ errors,
2212
+ data: errors.length === 0 ? {
2213
+ name,
2214
+ caType: 14,
2215
+ targeting: JSON.stringify({
2216
+ EventId: eventId,
2217
+ NumDays: numDays,
2218
+ PageIds: pageIds
2219
+ })
2220
+ } : void 0
2221
+ };
2222
+ }
2223
+ function validateEstimateAudienceRequest(input) {
2224
+ const errors = [];
2225
+ if (!input || typeof input !== "object") {
2226
+ return { isValid: false, errors: ["Input ph\u1EA3i l\xE0 m\u1ED9t object."], data: void 0 };
2227
+ }
2228
+ const raw = input;
2229
+ const gender = typeof raw.gender === "number" ? raw.gender : 0;
2230
+ if (![0, 1, 2].includes(gender)) {
2231
+ errors.push("Tr\u01B0\u1EDDng 'gender' ph\u1EA3i l\xE0 0, 1 ho\u1EB7c 2.");
2232
+ }
2233
+ const ageRanges = Array.isArray(raw.ageRanges) && raw.ageRanges.length > 0 ? raw.ageRanges.map(Number) : [10283, 10284, 10285, 10286, 10287];
2234
+ const platforms = Array.isArray(raw.platforms) && raw.platforms.length > 0 ? raw.platforms.map(Number) : [0, 1, 3];
2235
+ const priceType = typeof raw.priceType === "number" ? raw.priceType : 2;
2236
+ const wardsTargeting = typeof raw.wardsTargeting === "string" && raw.wardsTargeting.trim() ? raw.wardsTargeting.trim() : JSON.stringify({ Includes: [], Excludes: [] });
2237
+ return {
2238
+ isValid: errors.length === 0,
2239
+ errors,
2240
+ data: errors.length === 0 ? {
2241
+ gender,
2242
+ ageRanges,
2243
+ platforms,
2244
+ locations: typeof raw.locations === "string" ? raw.locations : "",
2245
+ provinces: Array.isArray(raw.provinces) ? raw.provinces.map(Number) : [],
2246
+ wardsTargeting,
2247
+ priceType,
2248
+ number: typeof raw.number === "string" ? raw.number : String(raw.number || "0")
2249
+ } : void 0
2250
+ };
2251
+ }
2252
+ var ZaloAudiencesValidator = {
2253
+ createSavedAudience: validateCreateSavedAudienceRequest,
2254
+ createPhoneAudience: validateCreatePhoneAudienceRequest,
2255
+ createLookalikeAudience: validateCreateLookalikeAudienceRequest,
2256
+ createFormEventAudience: validateCreateFormEventAudienceRequest,
2257
+ createMessageOaEventAudience: validateCreateMessageOaEventAudienceRequest,
2258
+ createMessagePersonalEventAudience: validateCreateMessagePersonalEventAudienceRequest,
2259
+ estimateAudience: validateEstimateAudienceRequest
2260
+ };
2261
+
1837
2262
  // src/services/audiences.service.ts
1838
2263
  var OP_ZaloAdsCreateCustomAudience = {
1839
2264
  "operationId": "ZaloAds_createCustomAudience",
@@ -1934,6 +2359,7 @@ var ZaloAudiencesService = class {
1934
2359
  constructor(client) {
1935
2360
  this.client = client;
1936
2361
  }
2362
+ static validator = ZaloAudiencesValidator;
1937
2363
  postApiAdEstimateaudience(request, options) {
1938
2364
  return this.client.requestJson(OP_ZaloAdsPostApiAdEstimateaudience, this.client.toTransportInput(OP_ZaloAdsPostApiAdEstimateaudience, request), options);
1939
2365
  }
@@ -1986,7 +2412,22 @@ var ZaloAudiencesService = class {
1986
2412
  }
1987
2413
  /** Tạo mới Nhóm đối tượng phát sinh sự kiện trên Kịch bản Tin nhắn cá nhân (`caType = 14` - `MESSAGE_PERSONAL_EVENT_AUDIENCE`). */
1988
2414
  createMessagePersonalEventAudience(request, options) {
1989
- const targetingStr = typeof request.targeting === "string" ? request.targeting : JSON.stringify(request.targeting);
2415
+ let targetingObj;
2416
+ if (typeof request.targeting === "string") {
2417
+ try {
2418
+ targetingObj = JSON.parse(request.targeting);
2419
+ } catch {
2420
+ targetingObj = null;
2421
+ }
2422
+ } else if (request.targeting && typeof request.targeting === "object") {
2423
+ targetingObj = { ...request.targeting };
2424
+ }
2425
+ if (targetingObj && typeof targetingObj === "object") {
2426
+ if (targetingObj.EventId === void 0 && targetingObj.EventType !== void 0) {
2427
+ targetingObj.EventId = targetingObj.EventType;
2428
+ }
2429
+ }
2430
+ const targetingStr = targetingObj ? JSON.stringify(targetingObj) : typeof request.targeting === "string" ? request.targeting : JSON.stringify(request.targeting);
1990
2431
  return this.createCustomAudience({ name: request.name, caType: 14, targeting: targetingStr }, options);
1991
2432
  }
1992
2433
  /** Tạo mới Nhóm đối tượng từ Trung tâm Lead - Zalo Form (`caType = 10` - `FORM_AUDIENCE`). */
@@ -2542,6 +2983,236 @@ var ZaloAutomatedRulesService = class {
2542
2983
  }
2543
2984
  };
2544
2985
 
2986
+ // src/validators/flows.validator.ts
2987
+ var MAX_INT_32 = 2147483647;
2988
+ function is32BitPositiveInteger(val) {
2989
+ if (typeof val === "number") {
2990
+ return Number.isInteger(val) && val > 0 && val <= MAX_INT_32;
2991
+ }
2992
+ if (typeof val === "string" && val.trim() !== "") {
2993
+ const num = Number(val);
2994
+ return Number.isInteger(num) && num > 0 && num <= MAX_INT_32;
2995
+ }
2996
+ return false;
2997
+ }
2998
+ function isPositiveInteger(val) {
2999
+ if (typeof val === "number") return Number.isInteger(val) && val > 0;
3000
+ if (typeof val === "string" && val.trim() !== "") {
3001
+ const num = Number(val);
3002
+ return Number.isInteger(num) && num > 0;
3003
+ }
3004
+ return false;
3005
+ }
3006
+ function isNonNegativeInteger(val) {
3007
+ if (typeof val === "number") return Number.isInteger(val) && val >= 0;
3008
+ if (typeof val === "string" && val.trim() !== "") {
3009
+ const num = Number(val);
3010
+ return Number.isInteger(num) && num >= 0;
3011
+ }
3012
+ return false;
3013
+ }
3014
+ function toPositiveInteger(val) {
3015
+ return typeof val === "number" ? Math.floor(val) : parseInt(String(val), 10);
3016
+ }
3017
+ function validateFlowButtons(buttons, errors, prefix) {
3018
+ if (!Array.isArray(buttons)) {
3019
+ errors.push(`${prefix}: Tr\u01B0\u1EDDng 'buttons' ph\u1EA3i l\xE0 m\u1ED9t m\u1EA3ng.`);
3020
+ return [];
3021
+ }
3022
+ const cleanButtons = [];
3023
+ buttons.forEach((btn, idx) => {
3024
+ const btnPrefix = `${prefix}.buttons[${idx}]`;
3025
+ if (!btn || typeof btn !== "object") {
3026
+ errors.push(`${btnPrefix}: N\xFAt b\u1EA5m ph\u1EA3i l\xE0 m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng.`);
3027
+ return;
3028
+ }
3029
+ const b = btn;
3030
+ if (typeof b.text !== "string" || b.text.trim() === "") {
3031
+ errors.push(`${btnPrefix}: Nh\xE3n n\xFAt 'text' l\xE0 b\u1EAFt bu\u1ED9c v\xE0 kh\xF4ng \u0111\u01B0\u1EE3c \u0111\u1EC3 tr\u1ED1ng.`);
3032
+ }
3033
+ const btnType = Number(b.type);
3034
+ if (![3, 10, 12].includes(btnType)) {
3035
+ errors.push(`${btnPrefix}: Lo\u1EA1i n\xFAt 'type' ph\u1EA3i l\xE0 3 (nh\xE1nh h\u1ED9i tho\u1EA1i), 10 (m\u1EDF website), ho\u1EB7c 12 (g\u1ECDi hotline).`);
3036
+ }
3037
+ const cleanBtn = {
3038
+ type: btnType,
3039
+ text: String(b.text ?? "").trim(),
3040
+ editable: b.editable !== false
3041
+ };
3042
+ if (btnType === 10) {
3043
+ if (typeof b.url !== "string" || b.url.trim() === "") {
3044
+ errors.push(`${btnPrefix}: N\xFAt lo\u1EA1i 10 (m\u1EDF website) b\u1EAFt bu\u1ED9c ph\u1EA3i c\xF3 tr\u01B0\u1EDDng 'url' h\u1EE3p l\u1EC7.`);
3045
+ } else {
3046
+ cleanBtn.url = b.url.trim();
3047
+ }
3048
+ } else if (btnType === 12) {
3049
+ if (typeof b.phone !== "string" || b.phone.trim() === "") {
3050
+ errors.push(`${btnPrefix}: N\xFAt lo\u1EA1i 12 (g\u1ECDi hotline) b\u1EAFt bu\u1ED9c ph\u1EA3i c\xF3 tr\u01B0\u1EDDng 'phone' h\u1EE3p l\u1EC7.`);
3051
+ } else {
3052
+ cleanBtn.phone = b.phone.trim();
3053
+ }
3054
+ } else if (btnType === 3) {
3055
+ if (!Array.isArray(b.messages) || b.messages.length === 0) {
3056
+ errors.push(`${btnPrefix}: N\xFAt lo\u1EA1i 3 (nh\xE1nh h\u1ED9i tho\u1EA1i) b\u1EAFt bu\u1ED9c ph\u1EA3i c\xF3 m\u1EA3ng 'messages' ch\u1EE9a \xEDt nh\u1EA5t 1 tin nh\u1EAFn con ph\u1EA3n h\u1ED3i.`);
3057
+ } else {
3058
+ const cleanChildMsgs = [];
3059
+ b.messages.forEach((child, cIdx) => {
3060
+ const childPrefix = `${btnPrefix}.messages[${cIdx}]`;
3061
+ if (!child || typeof child !== "object") {
3062
+ errors.push(`${childPrefix}: Tin nh\u1EAFn con ph\u1EA3i l\xE0 m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng.`);
3063
+ return;
3064
+ }
3065
+ const c = child;
3066
+ if (typeof c.text !== "string" || c.text.trim() === "") {
3067
+ errors.push(`${childPrefix}: N\u1ED9i dung tin nh\u1EAFn con 'text' kh\xF4ng \u0111\u01B0\u1EE3c \u0111\u1EC3 tr\u1ED1ng.`);
3068
+ } else if (c.text.length > 1961) {
3069
+ errors.push(`${childPrefix}: N\u1ED9i dung tin nh\u1EAFn con v\u01B0\u1EE3t qu\xE1 1961 k\xFD t\u1EF1 (hi\u1EC7n c\xF3 ${c.text.length} k\xFD t\u1EF1).`);
3070
+ }
3071
+ cleanChildMsgs.push({
3072
+ type: 8,
3073
+ text: String(c.text ?? "").trim()
3074
+ });
3075
+ });
3076
+ cleanBtn.messages = cleanChildMsgs;
3077
+ }
3078
+ }
3079
+ cleanButtons.push(cleanBtn);
3080
+ });
3081
+ return cleanButtons;
3082
+ }
3083
+ function validateFlowMessages(messages, errors) {
3084
+ if (!Array.isArray(messages)) {
3085
+ errors.push("Tr\u01B0\u1EDDng 'messages' ph\u1EA3i l\xE0 m\u1ED9t m\u1EA3ng ch\u1EE9a tin nh\u1EAFn k\u1ECBch b\u1EA3n.");
3086
+ return [];
3087
+ }
3088
+ if (messages.length !== 1) {
3089
+ errors.push(`Zalo Ads ch\u1EC9 cho ph\xE9p k\u1ECBch b\u1EA3n ch\u1EE9a DUY NH\u1EA4T 1 tin nh\u1EAFn ch\xE0o m\u1EEBng c\u1EA5p cao (hi\u1EC7n c\xF3 ${messages.length} tin nh\u1EAFn). C\xE1c nh\xE1nh h\u1ED9i tho\u1EA1i ti\u1EBFp theo ph\u1EA3i c\u1EA5u h\xECnh b\xEAn trong n\xFAt b\u1EA5m lo\u1EA1i 3 (type=3).`);
3090
+ return [];
3091
+ }
3092
+ const msg = messages[0];
3093
+ if (!msg || typeof msg !== "object") {
3094
+ errors.push("Tin nh\u1EAFn k\u1ECBch b\u1EA3n ph\u1EA3i l\xE0 m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng.");
3095
+ return [];
3096
+ }
3097
+ const m = msg;
3098
+ const msgType = Number(m.type);
3099
+ if (![1, 2].includes(msgType)) {
3100
+ errors.push("Lo\u1EA1i tin nh\u1EAFn 'type' ph\u1EA3i l\xE0 1 (v\u0103n b\u1EA3n) ho\u1EB7c 2 (k\xE8m h\xECnh \u1EA3nh).");
3101
+ }
3102
+ if (typeof m.text !== "string" || m.text.trim() === "") {
3103
+ errors.push("N\u1ED9i dung tin nh\u1EAFn 'text' l\xE0 b\u1EAFt bu\u1ED9c v\xE0 kh\xF4ng \u0111\u01B0\u1EE3c \u0111\u1EC3 tr\u1ED1ng.");
3104
+ } else if (m.text.length > 1961) {
3105
+ errors.push(`N\u1ED9i dung tin nh\u1EAFn v\u01B0\u1EE3t qu\xE1 1961 k\xFD t\u1EF1 (hi\u1EC7n c\xF3 ${m.text.length} k\xFD t\u1EF1).`);
3106
+ }
3107
+ const cleanMsg = {
3108
+ type: msgType,
3109
+ text: String(m.text ?? "").trim()
3110
+ };
3111
+ if (msgType === 2) {
3112
+ if (typeof m.url !== "string" || m.url.trim() === "") {
3113
+ errors.push("Tin nh\u1EAFn lo\u1EA1i 2 (k\xE8m \u1EA3nh) b\u1EAFt bu\u1ED9c ph\u1EA3i c\xF3 tr\u01B0\u1EDDng 'url' ch\u1EE9a \u0111\u01B0\u1EDDng d\u1EABn h\xECnh \u1EA3nh.");
3114
+ } else {
3115
+ cleanMsg.url = m.url.trim();
3116
+ }
3117
+ }
3118
+ if (m.buttons !== void 0 && m.buttons !== null) {
3119
+ cleanMsg.buttons = validateFlowButtons(m.buttons, errors, "messages[0]");
3120
+ }
3121
+ return [cleanMsg];
3122
+ }
3123
+ function validateListFlowsByOfficialAccountRequest(input) {
3124
+ const errors = [];
3125
+ if (!input || typeof input !== "object") {
3126
+ return { isValid: false, errors: ["D\u1EEF li\u1EC7u y\xEAu c\u1EA7u l\u1EA5y danh s\xE1ch k\u1ECBch b\u1EA3n ph\u1EA3i l\xE0 m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng."] };
3127
+ }
3128
+ const obj = input;
3129
+ if (!is32BitPositiveInteger(obj.oaId)) {
3130
+ errors.push("Tr\u01B0\u1EDDng 'oaId' l\xE0 b\u1EAFt bu\u1ED9c v\xE0 ph\u1EA3i l\xE0 m\xE3 pageId n\u1ED9i b\u1ED9 ki\u1EC3u s\u1ED1 nguy\xEAn 32-bit (<= 2,147,483,647). Kh\xF4ng truy\u1EC1n chu\u1ED7i noisedId c\xF4ng khai (18 ch\u1EEF s\u1ED1) v\xEC backend Play Framework s\u1EBD t\u1EEB ch\u1ED1i.");
3131
+ }
3132
+ if (!isPositiveInteger(obj.limit)) {
3133
+ errors.push("Tr\u01B0\u1EDDng 'limit' l\xE0 b\u1EAFt bu\u1ED9c v\xE0 ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn d\u01B0\u01A1ng (> 0).");
3134
+ }
3135
+ if (obj.offset !== void 0 && obj.offset !== null && !isNonNegativeInteger(obj.offset)) {
3136
+ errors.push("Tr\u01B0\u1EDDng 'offset' n\u1EBFu c\xF3 ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn kh\xF4ng \xE2m (>= 0).");
3137
+ }
3138
+ if (obj.flowId !== void 0 && obj.flowId !== null && !isPositiveInteger(obj.flowId)) {
3139
+ errors.push("Tr\u01B0\u1EDDng 'flowId' n\u1EBFu c\xF3 ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn d\u01B0\u01A1ng (> 0).");
3140
+ }
3141
+ const cleanData = {
3142
+ oaId: toPositiveInteger(obj.oaId),
3143
+ limit: toPositiveInteger(obj.limit)
3144
+ };
3145
+ if (obj.offset !== void 0 && obj.offset !== null) cleanData.offset = toPositiveInteger(obj.offset);
3146
+ if (obj.flowId !== void 0 && obj.flowId !== null) cleanData.flowId = toPositiveInteger(obj.flowId);
3147
+ return {
3148
+ isValid: errors.length === 0,
3149
+ errors,
3150
+ data: errors.length === 0 ? cleanData : void 0
3151
+ };
3152
+ }
3153
+ function validateCreateFlowRequest(input) {
3154
+ const errors = [];
3155
+ if (!input || typeof input !== "object") {
3156
+ return { isValid: false, errors: ["D\u1EEF li\u1EC7u y\xEAu c\u1EA7u t\u1EA1o k\u1ECBch b\u1EA3n ph\u1EA3i l\xE0 m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng."] };
3157
+ }
3158
+ const obj = input;
3159
+ if (!is32BitPositiveInteger(obj.oaId)) {
3160
+ errors.push("Tr\u01B0\u1EDDng 'oaId' l\xE0 b\u1EAFt bu\u1ED9c v\xE0 ph\u1EA3i l\xE0 m\xE3 pageId n\u1ED9i b\u1ED9 ki\u1EC3u s\u1ED1 nguy\xEAn 32-bit (<= 2,147,483,647).");
3161
+ }
3162
+ if (typeof obj.name !== "string" || obj.name.trim() === "") {
3163
+ errors.push("Tr\u01B0\u1EDDng 'name' (t\xEAn k\u1ECBch b\u1EA3n) l\xE0 b\u1EAFt bu\u1ED9c v\xE0 kh\xF4ng \u0111\u01B0\u1EE3c \u0111\u1EC3 tr\u1ED1ng.");
3164
+ } else if (obj.name.trim().length > 50) {
3165
+ errors.push(`T\xEAn k\u1ECBch b\u1EA3n kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 50 k\xFD t\u1EF1 (hi\u1EC7n c\xF3 ${obj.name.trim().length} k\xFD t\u1EF1).`);
3166
+ }
3167
+ const cleanMessages = validateFlowMessages(obj.messages, errors);
3168
+ const cleanData = {
3169
+ oaId: toPositiveInteger(obj.oaId),
3170
+ id: null,
3171
+ name: String(obj.name ?? "").trim(),
3172
+ messages: cleanMessages
3173
+ };
3174
+ return {
3175
+ isValid: errors.length === 0,
3176
+ errors,
3177
+ data: errors.length === 0 ? cleanData : void 0
3178
+ };
3179
+ }
3180
+ function validateUpdateFlowRequest(input) {
3181
+ const errors = [];
3182
+ if (!input || typeof input !== "object") {
3183
+ return { isValid: false, errors: ["D\u1EEF li\u1EC7u y\xEAu c\u1EA7u c\u1EADp nh\u1EADt k\u1ECBch b\u1EA3n ph\u1EA3i l\xE0 m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng."] };
3184
+ }
3185
+ const obj = input;
3186
+ if (!isPositiveInteger(obj.id)) {
3187
+ errors.push("Tr\u01B0\u1EDDng 'id' (ID Flow c\u1EA7n c\u1EADp nh\u1EADt) l\xE0 b\u1EAFt bu\u1ED9c v\xE0 ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn d\u01B0\u01A1ng (> 0).");
3188
+ }
3189
+ if (!is32BitPositiveInteger(obj.oaId)) {
3190
+ errors.push("Tr\u01B0\u1EDDng 'oaId' l\xE0 b\u1EAFt bu\u1ED9c v\xE0 ph\u1EA3i l\xE0 m\xE3 pageId n\u1ED9i b\u1ED9 ki\u1EC3u s\u1ED1 nguy\xEAn 32-bit (<= 2,147,483,647).");
3191
+ }
3192
+ if (typeof obj.name !== "string" || obj.name.trim() === "") {
3193
+ errors.push("Tr\u01B0\u1EDDng 'name' (t\xEAn k\u1ECBch b\u1EA3n) l\xE0 b\u1EAFt bu\u1ED9c v\xE0 kh\xF4ng \u0111\u01B0\u1EE3c \u0111\u1EC3 tr\u1ED1ng.");
3194
+ } else if (obj.name.trim().length > 50) {
3195
+ errors.push(`T\xEAn k\u1ECBch b\u1EA3n kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 50 k\xFD t\u1EF1 (hi\u1EC7n c\xF3 ${obj.name.trim().length} k\xFD t\u1EF1).`);
3196
+ }
3197
+ const cleanMessages = validateFlowMessages(obj.messages, errors);
3198
+ const cleanData = {
3199
+ id: toPositiveInteger(obj.id),
3200
+ oaId: toPositiveInteger(obj.oaId),
3201
+ name: String(obj.name ?? "").trim(),
3202
+ messages: cleanMessages
3203
+ };
3204
+ return {
3205
+ isValid: errors.length === 0,
3206
+ errors,
3207
+ data: errors.length === 0 ? cleanData : void 0
3208
+ };
3209
+ }
3210
+ var ZaloFlowsValidator = {
3211
+ listFlowsByOfficialAccount: validateListFlowsByOfficialAccountRequest,
3212
+ createFlow: validateCreateFlowRequest,
3213
+ updateFlow: validateUpdateFlowRequest
3214
+ };
3215
+
2545
3216
  // src/services/flows.service.ts
2546
3217
  var OP_ZaloAdsListFlowsByOfficialAccount = {
2547
3218
  operationId: "ZaloAds_listFlowsByOfficialAccount",
@@ -2583,6 +3254,12 @@ var ZaloFlowsService = class {
2583
3254
  constructor(client) {
2584
3255
  this.client = client;
2585
3256
  }
3257
+ /**
3258
+ * Bộ công cụ kiểm tra tính hợp lệ dữ liệu (Standalone Validators) cho Message Flows APIs.
3259
+ * Dùng để validate dữ liệu đầu vào trước khi lưu DB hoặc gọi Zalo Ads.
3260
+ */
3261
+ static validator = ZaloFlowsValidator;
3262
+ validator = ZaloFlowsValidator;
2586
3263
  listFlowsByOfficialAccount(request, options) {
2587
3264
  return this.client.requestWithoutBody(OP_ZaloAdsListFlowsByOfficialAccount, this.client.toTransportInput(OP_ZaloAdsListFlowsByOfficialAccount, request), options);
2588
3265
  }
@@ -3496,7 +4173,301 @@ var ZaloChatWidgetService = class {
3496
4173
  }
3497
4174
  };
3498
4175
 
4176
+ // src/validators/forms.validator.ts
4177
+ function isValidUrl(val) {
4178
+ if (typeof val !== "string" || val.trim() === "") return false;
4179
+ try {
4180
+ const url = new URL(val);
4181
+ return url.protocol === "http:" || url.protocol === "https:";
4182
+ } catch {
4183
+ return false;
4184
+ }
4185
+ }
4186
+ function validateCreateFormRequest(input) {
4187
+ const errors = [];
4188
+ if (!input || typeof input !== "object") {
4189
+ return {
4190
+ isValid: false,
4191
+ errors: ["D\u1EEF li\u1EC7u y\xEAu c\u1EA7u t\u1EA1o Form ph\u1EA3i l\xE0 m\u1ED9t object."],
4192
+ data: void 0
4193
+ };
4194
+ }
4195
+ let raw = input;
4196
+ if (typeof input.data === "string") {
4197
+ try {
4198
+ raw = JSON.parse(input.data);
4199
+ } catch {
4200
+ errors.push("Tr\u01B0\u1EDDng 'data' kh\xF4ng ph\u1EA3i l\xE0 chu\u1ED7i JSON h\u1EE3p l\u1EC7.");
4201
+ return { isValid: false, errors, data: void 0 };
4202
+ }
4203
+ } else if (typeof input.data === "object" && input.data !== null) {
4204
+ raw = input.data;
4205
+ }
4206
+ const oaIdRaw = raw.oaId;
4207
+ let cleanOaId = "";
4208
+ if (typeof oaIdRaw === "string" && /^[0-9]+$/.test(oaIdRaw.trim())) {
4209
+ cleanOaId = oaIdRaw.trim();
4210
+ } else if (typeof oaIdRaw === "number" && Number.isInteger(oaIdRaw) && oaIdRaw > 0) {
4211
+ cleanOaId = String(oaIdRaw);
4212
+ } else {
4213
+ errors.push("Tr\u01B0\u1EDDng 'oaId' b\u1EAFt bu\u1ED9c ph\u1EA3i l\xE0 chu\u1ED7i s\u1ED1 nguy\xEAn d\u01B0\u01A1ng \u0111\u1EA1i di\u1EC7n cho pageId n\u1ED9i b\u1ED9 c\u1EE7a OA (v\xED d\u1EE5: '429753475').");
4214
+ }
4215
+ const title = typeof raw.title === "string" ? raw.title.trim() : "";
4216
+ if (!title) {
4217
+ errors.push("Tr\u01B0\u1EDDng 'title' (ti\xEAu \u0111\u1EC1 form) l\xE0 b\u1EAFt bu\u1ED9c.");
4218
+ } else if (title.length < 2 || title.length > 40) {
4219
+ errors.push(`Tr\u01B0\u1EDDng 'title' ph\u1EA3i c\xF3 \u0111\u1ED9 d\xE0i t\u1EEB 2 \u0111\u1EBFn 40 k\xFD t\u1EF1 (hi\u1EC7n t\u1EA1i: ${title.length} k\xFD t\u1EF1).`);
4220
+ }
4221
+ const formName = typeof raw.formName === "string" ? raw.formName.trim() : "";
4222
+ if (!formName) {
4223
+ errors.push("Tr\u01B0\u1EDDng 'formName' (t\xEAn qu\u1EA3n tr\u1ECB form) l\xE0 b\u1EAFt bu\u1ED9c.");
4224
+ } else if (formName.length < 2 || formName.length > 100) {
4225
+ errors.push(`Tr\u01B0\u1EDDng 'formName' ph\u1EA3i c\xF3 \u0111\u1ED9 d\xE0i t\u1EEB 2 \u0111\u1EBFn 100 k\xFD t\u1EF1 (hi\u1EC7n t\u1EA1i: ${formName.length} k\xFD t\u1EF1).`);
4226
+ }
4227
+ let cleanDescription = void 0;
4228
+ if (raw.description !== void 0 && raw.description !== null) {
4229
+ const desc = String(raw.description).trim();
4230
+ if (desc.length > 600) {
4231
+ errors.push(`Tr\u01B0\u1EDDng 'description' kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 600 k\xFD t\u1EF1 (hi\u1EC7n t\u1EA1i: ${desc.length} k\xFD t\u1EF1).`);
4232
+ } else {
4233
+ cleanDescription = desc;
4234
+ }
4235
+ }
4236
+ const coverPhoto = typeof raw.coverPhoto === "string" ? raw.coverPhoto.trim() : "";
4237
+ if (!coverPhoto) {
4238
+ errors.push("Tr\u01B0\u1EDDng 'coverPhoto' (\u1EA3nh b\xECa form) l\xE0 b\u1EAFt bu\u1ED9c.");
4239
+ } else if (!isValidUrl(coverPhoto)) {
4240
+ errors.push(`Tr\u01B0\u1EDDng 'coverPhoto' ph\u1EA3i l\xE0 URL h\u1EE3p l\u1EC7 (http:// ho\u1EB7c https://).`);
4241
+ }
4242
+ const submitTitle = typeof raw.submitTitle === "string" && raw.submitTitle.trim() !== "" ? raw.submitTitle.trim() : "G\u1EEDi th\xF4ng tin th\xE0nh c\xF4ng";
4243
+ if (submitTitle.length > 90) {
4244
+ errors.push(`Tr\u01B0\u1EDDng 'submitTitle' kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 90 k\xFD t\u1EF1 (hi\u1EC7n t\u1EA1i: ${submitTitle.length} k\xFD t\u1EF1).`);
4245
+ }
4246
+ const thanks = typeof raw.thanks === "string" && raw.thanks.trim() !== "" ? raw.thanks.trim() : "C\u1EA3m \u01A1n b\u1EA1n \u0111\xE3 g\u1EEDi th\xF4ng tin. Ch\xFAng t\xF4i s\u1EBD li\xEAn h\u1EC7 trong th\u1EDDi gian s\u1EDBm nh\u1EA5t.";
4247
+ if (thanks.length > 255) {
4248
+ errors.push(`Tr\u01B0\u1EDDng 'thanks' kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1 (hi\u1EC7n t\u1EA1i: ${thanks.length} k\xFD t\u1EF1).`);
4249
+ }
4250
+ const gotoActionType = raw.gotoActionType === 0 ? 0 : 1;
4251
+ const gotoText = typeof raw.gotoText === "string" && raw.gotoText.trim() !== "" ? raw.gotoText.trim() : gotoActionType === 1 ? "Xem trang Web" : "\u0110\xF3ng l\u1EA1i";
4252
+ let cleanWebsite = void 0;
4253
+ if (gotoActionType === 1) {
4254
+ if (!raw.website || !isValidUrl(raw.website)) {
4255
+ errors.push("Khi 'gotoActionType' = 1 (m\u1EDF website), tr\u01B0\u1EDDng 'website' l\xE0 b\u1EAFt bu\u1ED9c v\xE0 ph\u1EA3i l\xE0 URL h\u1EE3p l\u1EC7.");
4256
+ } else {
4257
+ cleanWebsite = String(raw.website).trim();
4258
+ }
4259
+ }
4260
+ const useCustomConsent = Boolean(raw.useCustomConsent);
4261
+ let cleanConsentName = void 0;
4262
+ let cleanConsentUrl = void 0;
4263
+ if (useCustomConsent) {
4264
+ const cName = typeof raw.consentName === "string" ? raw.consentName.trim() : "";
4265
+ if (!cName) {
4266
+ errors.push("Khi 'useCustomConsent' = true, tr\u01B0\u1EDDng 'consentName' (ti\xEAu \u0111\u1EC1 \u0111i\u1EC1u kho\u1EA3n) l\xE0 b\u1EAFt bu\u1ED9c.");
4267
+ } else if (cName.length > 255) {
4268
+ errors.push(`Tr\u01B0\u1EDDng 'consentName' kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 255 k\xFD t\u1EF1 (hi\u1EC7n t\u1EA1i: ${cName.length} k\xFD t\u1EF1).`);
4269
+ } else {
4270
+ cleanConsentName = cName;
4271
+ }
4272
+ if (!raw.consentUrl || !isValidUrl(raw.consentUrl)) {
4273
+ errors.push("Khi 'useCustomConsent' = true, tr\u01B0\u1EDDng 'consentUrl' ph\u1EA3i l\xE0 URL h\u1EE3p l\u1EC7 ch\u1EE9a ch\xEDnh s\xE1ch b\u1EA3o m\u1EADt.");
4274
+ } else {
4275
+ cleanConsentUrl = String(raw.consentUrl).trim();
4276
+ }
4277
+ }
4278
+ if (!Array.isArray(raw.questions) || raw.questions.length === 0) {
4279
+ errors.push("Bi\u1EC3u m\u1EABu b\u1EAFt bu\u1ED9c ph\u1EA3i c\xF3 \xEDt nh\u1EA5t 1 c\xE2u h\u1ECFi trong m\u1EA3ng 'questions'.");
4280
+ }
4281
+ const cleanQuestions = [];
4282
+ let hasPhonePrimary = false;
4283
+ let hasPhoneSecondary = false;
4284
+ if (Array.isArray(raw.questions)) {
4285
+ raw.questions.forEach((q, idx) => {
4286
+ const qPrefix = `C\xE2u h\u1ECFi [${idx}]`;
4287
+ if (!q || typeof q !== "object") {
4288
+ errors.push(`${qPrefix} ph\u1EA3i l\xE0 m\u1ED9t object.`);
4289
+ return;
4290
+ }
4291
+ const qTitle = typeof q.title === "string" ? q.title.trim() : "";
4292
+ if (qTitle.length < 2 || qTitle.length > 180) {
4293
+ errors.push(`${qPrefix}: Ti\xEAu \u0111\u1EC1 'title' ph\u1EA3i c\xF3 \u0111\u1ED9 d\xE0i t\u1EEB 2 \u0111\u1EBFn 180 k\xFD t\u1EF1.`);
4294
+ }
4295
+ if (!Array.isArray(q.answers) || q.answers.length === 0) {
4296
+ errors.push(`${qPrefix}: Ph\u1EA3i c\xF3 \xEDt nh\u1EA5t 1 \u0111\xE1p \xE1n trong m\u1EA3ng 'answers'.`);
4297
+ return;
4298
+ }
4299
+ const cleanAnswers = [];
4300
+ q.answers.forEach((ans, aIdx) => {
4301
+ const aType = Number(ans?.type);
4302
+ if (![2, 7, 13].includes(aType)) {
4303
+ errors.push(`${qPrefix} \u0111\xE1p \xE1n [${aIdx}]: 'type' ph\u1EA3i l\xE0 7 (H\u1ECD t\xEAn), 13 (S\u0110T chu\u1EA9n), ho\u1EB7c 2 (S\u0110T ph\u1EE5).`);
4304
+ }
4305
+ if (aType === 13) hasPhonePrimary = true;
4306
+ if (aType === 2) hasPhoneSecondary = true;
4307
+ cleanAnswers.push({
4308
+ type: aType,
4309
+ placeHolder: ans?.placeHolder ? String(ans.placeHolder).trim() : void 0,
4310
+ value: ans?.value ? String(ans.value).trim() : null,
4311
+ priority: typeof ans?.priority === "number" ? ans.priority : 500
4312
+ });
4313
+ });
4314
+ cleanQuestions.push({
4315
+ title: qTitle,
4316
+ type: typeof q.type === "number" ? q.type : 1,
4317
+ isRequired: q.isRequired !== void 0 ? Boolean(q.isRequired) : true,
4318
+ editDisabled: Boolean(q.editDisabled),
4319
+ priority: typeof q.priority === "number" ? q.priority : (idx + 1) * 100,
4320
+ answers: cleanAnswers
4321
+ });
4322
+ });
4323
+ }
4324
+ if (hasPhoneSecondary) {
4325
+ cleanQuestions.forEach((q) => {
4326
+ if (q.answers.some((a) => a.type === 13)) {
4327
+ q.editDisabled = true;
4328
+ }
4329
+ });
4330
+ }
4331
+ const cleanSections = [];
4332
+ if (Array.isArray(raw.sections)) {
4333
+ raw.sections.forEach((sec, sIdx) => {
4334
+ const sPrefix = `Section [${sIdx}]`;
4335
+ const sType = Number(sec?.type);
4336
+ if (isNaN(sType) || sType < 0 || sType > 4) {
4337
+ errors.push(`${sPrefix}: 'type' ph\u1EA3i l\xE0 s\u1ED1 t\u1EEB 0 \u0111\u1EBFn 4 (0=t\u1ED5ng quan, 1=chi ti\u1EBFt, 2=b\u1EA3ng gi\xE1, 3=\u01B0u \u0111i\u1EC3m, 4=\u01B0u \u0111\xE3i).`);
4338
+ }
4339
+ const sTitle = typeof sec?.title === "string" ? sec.title.trim() : "";
4340
+ if (sTitle.length > 60) {
4341
+ errors.push(`${sPrefix}: 'title' kh\xF4ng \u0111\u01B0\u1EE3c v\u01B0\u1EE3t qu\xE1 60 k\xFD t\u1EF1.`);
4342
+ }
4343
+ cleanSections.push({
4344
+ type: sType,
4345
+ title: sTitle,
4346
+ disable: Boolean(sec?.disable),
4347
+ expand: Boolean(sec?.expand),
4348
+ content: sec?.content ? sec.content : {}
4349
+ });
4350
+ });
4351
+ }
4352
+ const cleanData = {
4353
+ oaId: cleanOaId,
4354
+ title,
4355
+ formName,
4356
+ description: cleanDescription,
4357
+ coverPhoto,
4358
+ submitTitle,
4359
+ thanks,
4360
+ gotoActionType,
4361
+ gotoText,
4362
+ website: cleanWebsite,
4363
+ reviewSubmit: raw.reviewSubmit !== void 0 ? Boolean(raw.reviewSubmit) : true,
4364
+ questions: cleanQuestions,
4365
+ sections: cleanSections.length > 0 ? cleanSections : void 0,
4366
+ useCustomConsent,
4367
+ consentName: cleanConsentName,
4368
+ consentUrl: cleanConsentUrl
4369
+ };
4370
+ return {
4371
+ isValid: errors.length === 0,
4372
+ errors,
4373
+ data: errors.length === 0 ? cleanData : void 0
4374
+ };
4375
+ }
4376
+ function validateListFormsByOfficialAccountRequest(input) {
4377
+ const errors = [];
4378
+ if (!input || typeof input !== "object") {
4379
+ return { isValid: false, errors: ["Input ph\u1EA3i l\xE0 m\u1ED9t object."], data: void 0 };
4380
+ }
4381
+ const raw = input;
4382
+ let cleanOaId = "";
4383
+ if (typeof raw.oaId === "string" && /^[0-9]+$/.test(raw.oaId.trim())) {
4384
+ cleanOaId = raw.oaId.trim();
4385
+ } else if (typeof raw.oaId === "number" && Number.isInteger(raw.oaId) && raw.oaId > 0) {
4386
+ cleanOaId = String(raw.oaId);
4387
+ } else {
4388
+ errors.push("Tr\u01B0\u1EDDng 'oaId' b\u1EAFt bu\u1ED9c ph\u1EA3i l\xE0 chu\u1ED7i s\u1ED1 nguy\xEAn d\u01B0\u01A1ng \u0111\u1EA1i di\u1EC7n cho pageId c\u1EE7a OA.");
4389
+ }
4390
+ return {
4391
+ isValid: errors.length === 0,
4392
+ errors,
4393
+ data: errors.length === 0 ? { oaId: cleanOaId, isAll: raw.isAll !== void 0 ? Boolean(raw.isAll) : true } : void 0
4394
+ };
4395
+ }
4396
+ function validateListFormLeadsRequest(input) {
4397
+ const errors = [];
4398
+ if (!input || typeof input !== "object") {
4399
+ return { isValid: false, errors: ["Input ph\u1EA3i l\xE0 m\u1ED9t object."], data: void 0 };
4400
+ }
4401
+ const raw = input;
4402
+ const oaId = typeof raw.oaId === "string" ? raw.oaId.trim() : "";
4403
+ if (!oaId) {
4404
+ errors.push("Tr\u01B0\u1EDDng 'oaId' l\xE0 b\u1EAFt bu\u1ED9c (m\xE3 ch\u1EEF t\u1EEB getAuthSession, v\xED d\u1EE5 'J4UB9MRE497YDQKKK').");
4405
+ } else if (/^[0-9]+$/.test(oaId)) {
4406
+ errors.push("Tr\u01B0\u1EDDng 'oaId' tr\xEAn Lead Center ph\u1EA3i l\xE0 m\xE3 ch\u1EEF alphanumeric t\u1EEB getAuthSession, kh\xF4ng d\xF9ng chu\u1ED7i s\u1ED1 pageId (s\u1EBD b\u1ECB l\u1ED7i 403 Forbidden).");
4407
+ }
4408
+ const type = Number(raw.type);
4409
+ if (![1, 5].includes(type)) {
4410
+ errors.push("Tr\u01B0\u1EDDng 'type' ph\u1EA3i l\xE0 1 (ZALOFORM) ho\u1EB7c 5 (COMMERCE).");
4411
+ }
4412
+ const limit = typeof raw.limit === "number" && raw.limit > 0 ? Math.floor(raw.limit) : 20;
4413
+ const offset = typeof raw.offset === "number" && raw.offset >= 0 ? Math.floor(raw.offset) : 0;
4414
+ const status = typeof raw.status === "string" && raw.status.trim() !== "" ? raw.status.trim() : "2,6,1,0,7,4,5,3";
4415
+ const now = Math.floor(Date.now() / 1e3);
4416
+ const fromTime = typeof raw.fromTime === "number" && raw.fromTime >= 0 ? Math.floor(raw.fromTime) : now - 90 * 86400;
4417
+ const toTime = typeof raw.toTime === "number" && raw.toTime >= 0 ? Math.floor(raw.toTime) : now;
4418
+ if (toTime < fromTime) {
4419
+ errors.push("M\u1ED1c th\u1EDDi gian k\u1EBFt th\xFAc 'toTime' ph\u1EA3i l\u1EDBn h\u01A1n ho\u1EB7c b\u1EB1ng 'fromTime'.");
4420
+ }
4421
+ return {
4422
+ isValid: errors.length === 0,
4423
+ errors,
4424
+ data: errors.length === 0 ? {
4425
+ oaId,
4426
+ type,
4427
+ limit,
4428
+ offset,
4429
+ status,
4430
+ fromTime,
4431
+ toTime,
4432
+ formIds: raw.formIds ? String(raw.formIds).trim() : void 0,
4433
+ keyword: raw.keyword ? String(raw.keyword).trim() : void 0,
4434
+ reason: raw.reason ? String(raw.reason).trim() : void 0,
4435
+ labelIds: raw.labelIds ? String(raw.labelIds).trim() : void 0,
4436
+ isCommerce: raw.isCommerce !== void 0 ? Boolean(raw.isCommerce) : false
4437
+ } : void 0
4438
+ };
4439
+ }
4440
+ var ZaloFormsValidator = {
4441
+ createForm: validateCreateFormRequest,
4442
+ listFormsByOfficialAccount: validateListFormsByOfficialAccountRequest,
4443
+ listFormLeads: validateListFormLeadsRequest
4444
+ };
4445
+
3499
4446
  // src/services/forms.service.ts
4447
+ var OP_ZaloAdsCreateForm2 = {
4448
+ operationId: "zalo_ads_create_form",
4449
+ method: "POST",
4450
+ endpoint: "/api/form/create",
4451
+ baseUrl: "https://ads.zalo.me",
4452
+ binaryFields: [],
4453
+ pathFields: [],
4454
+ queryFields: [],
4455
+ headerFields: [],
4456
+ cookieFields: [],
4457
+ bodyFields: ["data"]
4458
+ };
4459
+ var OP_ZaloAdsListFormsByOfficialAccount2 = {
4460
+ operationId: "zalo_ads_list_forms_by_official_account",
4461
+ method: "GET",
4462
+ endpoint: "/api/form/getByOaId",
4463
+ baseUrl: "https://ads.zalo.me",
4464
+ binaryFields: [],
4465
+ pathFields: [],
4466
+ queryFields: ["oaId", "isAll"],
4467
+ headerFields: [],
4468
+ cookieFields: [],
4469
+ bodyFields: []
4470
+ };
3500
4471
  var OP_ZaloFormsDisableFormLeadNotification = {
3501
4472
  "operationId": "ZaloForms_disableFormLeadNotification",
3502
4473
  "method": "POST",
@@ -3570,7 +4541,8 @@ var OP_ZaloFormsListConversationLeads = {
3570
4541
  "keyword",
3571
4542
  "fromTime",
3572
4543
  "labelIds",
3573
- "sceneIds"
4544
+ "sceneIds",
4545
+ "reason"
3574
4546
  ],
3575
4547
  "headerFields": [],
3576
4548
  "cookieFields": [],
@@ -3594,7 +4566,8 @@ var OP_ZaloFormsListFormLeads = {
3594
4566
  "keyword",
3595
4567
  "fromTime",
3596
4568
  "labelIds",
3597
- "isCommerce"
4569
+ "isCommerce",
4570
+ "reason"
3598
4571
  ],
3599
4572
  "headerFields": [],
3600
4573
  "cookieFields": [],
@@ -3676,10 +4649,59 @@ var OP_ZaloFormsGetAuthSession = {
3676
4649
  "cookieFields": [],
3677
4650
  "bodyFields": []
3678
4651
  };
4652
+ var OP_ZaloFormsTrackManageFormEvent = {
4653
+ operationId: "zalo_forms_track_manage_form_event",
4654
+ method: "GET",
4655
+ endpoint: "/client/manage/api/manageForm/tracking",
4656
+ baseUrl: "https://form.ads.zalo.me",
4657
+ binaryFields: [],
4658
+ pathFields: [],
4659
+ queryFields: ["eventId", "oaId", "formId"],
4660
+ headerFields: [],
4661
+ cookieFields: [],
4662
+ bodyFields: []
4663
+ };
3679
4664
  var ZaloFormsService = class {
3680
4665
  constructor(client) {
3681
4666
  this.client = client;
3682
4667
  }
4668
+ validator = ZaloFormsValidator;
4669
+ static validator = ZaloFormsValidator;
4670
+ /**
4671
+ * Tạo biểu mẫu mới gắn với Official Account (POST https://ads.zalo.me/api/form/create).
4672
+ * Hỗ trợ truyền thẳng Typed Payload (tự động validate qua ZaloFormsValidator và mã hóa urlencoded)
4673
+ * hoặc object dạng `{ data: JSON.stringify(...) }`.
4674
+ */
4675
+ async createForm(request, options) {
4676
+ let payloadStr;
4677
+ if (typeof request.data === "string") {
4678
+ payloadStr = request.data;
4679
+ } else {
4680
+ const val = ZaloFormsValidator.createForm(request);
4681
+ if (!val.isValid || !val.data) {
4682
+ throw new Error(`[ZaloFormsValidator] D\u1EEF li\u1EC7u t\u1EA1o form kh\xF4ng h\u1EE3p l\u1EC7:
4683
+ - ${val.errors.join("\n - ")}`);
4684
+ }
4685
+ payloadStr = JSON.stringify(val.data);
4686
+ }
4687
+ return this.client.requestFormUrlEncoded(
4688
+ OP_ZaloAdsCreateForm2,
4689
+ this.client.toTransportInput(OP_ZaloAdsCreateForm2, { data: payloadStr }),
4690
+ options
4691
+ );
4692
+ }
4693
+ /**
4694
+ * Lấy danh sách biểu mẫu Zalo Ads theo Official Account (GET https://ads.zalo.me/api/form/getByOaId).
4695
+ */
4696
+ listFormsByOfficialAccount(request, options) {
4697
+ const val = ZaloFormsValidator.listFormsByOfficialAccount(request);
4698
+ const cleanInput = val.isValid && val.data ? val.data : request;
4699
+ return this.client.requestWithoutBody(
4700
+ OP_ZaloAdsListFormsByOfficialAccount2,
4701
+ this.client.toTransportInput(OP_ZaloAdsListFormsByOfficialAccount2, cleanInput),
4702
+ options
4703
+ );
4704
+ }
3683
4705
  getAuthSession(options) {
3684
4706
  return this.client.requestWithoutBody(OP_ZaloFormsGetAuthSession, void 0, options);
3685
4707
  }
@@ -3713,10 +4735,20 @@ var ZaloFormsService = class {
3713
4735
  updateFormLeadNotificationInterval(request, options) {
3714
4736
  return this.client.requestJson(OP_ZaloFormsUpdateFormLeadNotificationInterval, this.client.toTransportInput(OP_ZaloFormsUpdateFormLeadNotificationInterval, request), options);
3715
4737
  }
4738
+ /**
4739
+ * Ghi nhận sự kiện tương tác trên Lead Center (GET /client/manage/api/manageForm/tracking).
4740
+ */
4741
+ trackManageFormEvent(request, options) {
4742
+ return this.client.requestWithoutBody(
4743
+ OP_ZaloFormsTrackManageFormEvent,
4744
+ this.client.toTransportInput(OP_ZaloFormsTrackManageFormEvent, request),
4745
+ options
4746
+ );
4747
+ }
3716
4748
  };
3717
4749
 
3718
4750
  // src/validators/instant-pages.validator.ts
3719
- function isPositiveInteger(val) {
4751
+ function isPositiveInteger2(val) {
3720
4752
  if (typeof val === "number") return Number.isInteger(val) && val > 0;
3721
4753
  if (typeof val === "string" && val.trim() !== "") {
3722
4754
  const num = Number(val);
@@ -3724,7 +4756,7 @@ function isPositiveInteger(val) {
3724
4756
  }
3725
4757
  return false;
3726
4758
  }
3727
- function toPositiveInteger(val) {
4759
+ function toPositiveInteger2(val) {
3728
4760
  return typeof val === "number" ? Math.floor(val) : parseInt(String(val), 10);
3729
4761
  }
3730
4762
  function validateCloneInstantPageRequest(input) {
@@ -3733,13 +4765,13 @@ function validateCloneInstantPageRequest(input) {
3733
4765
  return { isValid: false, errors: ["D\u1EEF li\u1EC7u y\xEAu c\u1EA7u sao ch\xE9p Instant Page ph\u1EA3i l\xE0 m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng (object)."] };
3734
4766
  }
3735
4767
  const obj = input;
3736
- if (!isPositiveInteger(obj.instantPageId)) {
4768
+ if (!isPositiveInteger2(obj.instantPageId)) {
3737
4769
  errors.push("Tr\u01B0\u1EDDng 'instantPageId' l\xE0 b\u1EAFt bu\u1ED9c v\xE0 ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn d\u01B0\u01A1ng (> 0).");
3738
4770
  }
3739
4771
  return {
3740
4772
  isValid: errors.length === 0,
3741
4773
  errors,
3742
- data: errors.length === 0 ? { instantPageId: toPositiveInteger(obj.instantPageId) } : void 0
4774
+ data: errors.length === 0 ? { instantPageId: toPositiveInteger2(obj.instantPageId) } : void 0
3743
4775
  };
3744
4776
  }
3745
4777
  function validateGetInstantPageDetailRequest(input) {
@@ -3748,13 +4780,13 @@ function validateGetInstantPageDetailRequest(input) {
3748
4780
  return { isValid: false, errors: ["D\u1EEF li\u1EC7u y\xEAu c\u1EA7u l\u1EA5y chi ti\u1EBFt Instant Page ph\u1EA3i l\xE0 m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng (object)."] };
3749
4781
  }
3750
4782
  const obj = input;
3751
- if (!isPositiveInteger(obj.instantPageId)) {
4783
+ if (!isPositiveInteger2(obj.instantPageId)) {
3752
4784
  errors.push("Tr\u01B0\u1EDDng 'instantPageId' l\xE0 b\u1EAFt bu\u1ED9c v\xE0 ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn d\u01B0\u01A1ng (> 0).");
3753
4785
  }
3754
4786
  return {
3755
4787
  isValid: errors.length === 0,
3756
4788
  errors,
3757
- data: errors.length === 0 ? { instantPageId: toPositiveInteger(obj.instantPageId) } : void 0
4789
+ data: errors.length === 0 ? { instantPageId: toPositiveInteger2(obj.instantPageId) } : void 0
3758
4790
  };
3759
4791
  }
3760
4792
  function validateGetInstantPageSharedUserRequest(input) {
@@ -3763,18 +4795,18 @@ function validateGetInstantPageSharedUserRequest(input) {
3763
4795
  return { isValid: false, errors: ["D\u1EEF li\u1EC7u y\xEAu c\u1EA7u l\u1EA5y th\xF4ng tin ng\u01B0\u1EDDi d\xF9ng chia s\u1EBB ph\u1EA3i l\xE0 m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng (object)."] };
3764
4796
  }
3765
4797
  const obj = input;
3766
- if (!isPositiveInteger(obj.instantPageId)) {
4798
+ if (!isPositiveInteger2(obj.instantPageId)) {
3767
4799
  errors.push("Tr\u01B0\u1EDDng 'instantPageId' l\xE0 b\u1EAFt bu\u1ED9c v\xE0 ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn d\u01B0\u01A1ng (> 0).");
3768
4800
  }
3769
- if (!isPositiveInteger(obj.userId)) {
4801
+ if (!isPositiveInteger2(obj.userId)) {
3770
4802
  errors.push("Tr\u01B0\u1EDDng 'userId' l\xE0 b\u1EAFt bu\u1ED9c v\xE0 ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn d\u01B0\u01A1ng (> 0).");
3771
4803
  }
3772
4804
  return {
3773
4805
  isValid: errors.length === 0,
3774
4806
  errors,
3775
4807
  data: errors.length === 0 ? {
3776
- instantPageId: toPositiveInteger(obj.instantPageId),
3777
- userId: toPositiveInteger(obj.userId)
4808
+ instantPageId: toPositiveInteger2(obj.instantPageId),
4809
+ userId: toPositiveInteger2(obj.userId)
3778
4810
  } : void 0
3779
4811
  };
3780
4812
  }
@@ -3784,15 +4816,15 @@ function validateListInstantPageEditHistoryRequest(input) {
3784
4816
  return { isValid: false, errors: ["D\u1EEF li\u1EC7u y\xEAu c\u1EA7u l\u1EA5y l\u1ECBch s\u1EED ch\u1EC9nh s\u1EEDa ph\u1EA3i l\xE0 m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng (object)."] };
3785
4817
  }
3786
4818
  const obj = input;
3787
- if (!isPositiveInteger(obj.instantPageId)) {
4819
+ if (!isPositiveInteger2(obj.instantPageId)) {
3788
4820
  errors.push("Tr\u01B0\u1EDDng 'instantPageId' l\xE0 b\u1EAFt bu\u1ED9c v\xE0 ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn d\u01B0\u01A1ng (> 0).");
3789
4821
  }
3790
4822
  let limit = void 0;
3791
4823
  if (obj.limit !== void 0 && obj.limit !== null) {
3792
- if (!isPositiveInteger(obj.limit)) {
4824
+ if (!isPositiveInteger2(obj.limit)) {
3793
4825
  errors.push("Tr\u01B0\u1EDDng 'limit' n\u1EBFu c\xF3 ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn >= 1.");
3794
4826
  } else {
3795
- limit = toPositiveInteger(obj.limit);
4827
+ limit = toPositiveInteger2(obj.limit);
3796
4828
  }
3797
4829
  }
3798
4830
  let offset = void 0;
@@ -3808,7 +4840,7 @@ function validateListInstantPageEditHistoryRequest(input) {
3808
4840
  isValid: errors.length === 0,
3809
4841
  errors,
3810
4842
  data: errors.length === 0 ? {
3811
- instantPageId: toPositiveInteger(obj.instantPageId),
4843
+ instantPageId: toPositiveInteger2(obj.instantPageId),
3812
4844
  ...limit !== void 0 ? { limit } : {},
3813
4845
  ...offset !== void 0 ? { offset } : {}
3814
4846
  } : void 0
@@ -3820,13 +4852,13 @@ function validateListInstantPageFormRecordsRequest(input) {
3820
4852
  return { isValid: false, errors: ["D\u1EEF li\u1EC7u y\xEAu c\u1EA7u t\u1EA3i b\u1EA3n ghi form ph\u1EA3i l\xE0 m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng (object)."] };
3821
4853
  }
3822
4854
  const obj = input;
3823
- if (!isPositiveInteger(obj.instantPageId)) {
4855
+ if (!isPositiveInteger2(obj.instantPageId)) {
3824
4856
  errors.push("Tr\u01B0\u1EDDng 'instantPageId' l\xE0 b\u1EAFt bu\u1ED9c v\xE0 ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn d\u01B0\u01A1ng (> 0).");
3825
4857
  }
3826
4858
  return {
3827
4859
  isValid: errors.length === 0,
3828
4860
  errors,
3829
- data: errors.length === 0 ? { instantPageId: toPositiveInteger(obj.instantPageId) } : void 0
4861
+ data: errors.length === 0 ? { instantPageId: toPositiveInteger2(obj.instantPageId) } : void 0
3830
4862
  };
3831
4863
  }
3832
4864
  function validateListInstantPageSharesRequest(input) {
@@ -3835,13 +4867,13 @@ function validateListInstantPageSharesRequest(input) {
3835
4867
  return { isValid: false, errors: ["D\u1EEF li\u1EC7u y\xEAu c\u1EA7u l\u1EA5y danh s\xE1ch ng\u01B0\u1EDDi \u0111\u01B0\u1EE3c chia s\u1EBB ph\u1EA3i l\xE0 m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng (object)."] };
3836
4868
  }
3837
4869
  const obj = input;
3838
- if (!isPositiveInteger(obj.instantPageId)) {
4870
+ if (!isPositiveInteger2(obj.instantPageId)) {
3839
4871
  errors.push("Tr\u01B0\u1EDDng 'instantPageId' l\xE0 b\u1EAFt bu\u1ED9c v\xE0 ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn d\u01B0\u01A1ng (> 0).");
3840
4872
  }
3841
4873
  return {
3842
4874
  isValid: errors.length === 0,
3843
4875
  errors,
3844
- data: errors.length === 0 ? { instantPageId: toPositiveInteger(obj.instantPageId) } : void 0
4876
+ data: errors.length === 0 ? { instantPageId: toPositiveInteger2(obj.instantPageId) } : void 0
3845
4877
  };
3846
4878
  }
3847
4879
  function validateListInstantPageUsersRequest(input) {
@@ -3867,10 +4899,10 @@ function validateSearchInstantPagesRequest(input) {
3867
4899
  const obj = input;
3868
4900
  const data = {};
3869
4901
  if (obj.id !== void 0 && obj.id !== null && obj.id !== "") {
3870
- if (!isPositiveInteger(obj.id)) {
4902
+ if (!isPositiveInteger2(obj.id)) {
3871
4903
  errors.push("B\u1ED9 l\u1ECDc 'id' n\u1EBFu c\xF3 ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn d\u01B0\u01A1ng (> 0).");
3872
4904
  } else {
3873
- data.id = toPositiveInteger(obj.id);
4905
+ data.id = toPositiveInteger2(obj.id);
3874
4906
  }
3875
4907
  }
3876
4908
  if (obj.name !== void 0 && obj.name !== null) {
@@ -3901,10 +4933,10 @@ function validateUpdateInstantPageRequest(input) {
3901
4933
  }
3902
4934
  const obj = input;
3903
4935
  const instantPageId = obj.instantPageId ?? obj.id;
3904
- if (!isPositiveInteger(instantPageId)) {
4936
+ if (!isPositiveInteger2(instantPageId)) {
3905
4937
  errors.push("Tr\u01B0\u1EDDng 'instantPageId' (ho\u1EB7c 'id') l\xE0 b\u1EAFt bu\u1ED9c v\xE0 ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn d\u01B0\u01A1ng (> 0).");
3906
4938
  }
3907
- const numericId = toPositiveInteger(instantPageId);
4939
+ const numericId = toPositiveInteger2(instantPageId);
3908
4940
  const data = {
3909
4941
  instantPageId: numericId,
3910
4942
  id: numericId
@@ -3998,7 +5030,7 @@ function validateListInstantPageLeadsRequest(input) {
3998
5030
  errors.push("Tr\u01B0\u1EDDng 'ids' kh\xF4ng ch\u1EE9a b\u1EA5t k\u1EF3 ID h\u1EE3p l\u1EC7 n\xE0o.");
3999
5031
  } else {
4000
5032
  for (const id of idParts) {
4001
- if (!isPositiveInteger(id)) {
5033
+ if (!isPositiveInteger2(id)) {
4002
5034
  errors.push(`M\xE3 trang '${id}' trong danh s\xE1ch 'ids' kh\xF4ng ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn d\u01B0\u01A1ng h\u1EE3p l\u1EC7.`);
4003
5035
  }
4004
5036
  }
@@ -4022,7 +5054,7 @@ function validateUpsertInstantPageFormRequest(input) {
4022
5054
  return { isValid: false, errors: ["D\u1EEF li\u1EC7u c\u1EA5u h\xECnh bi\u1EC3u m\u1EABu Instant Page ph\u1EA3i l\xE0 m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng."] };
4023
5055
  }
4024
5056
  const obj = input;
4025
- if (!isPositiveInteger(obj.instantPageId)) {
5057
+ if (!isPositiveInteger2(obj.instantPageId)) {
4026
5058
  errors.push("Tr\u01B0\u1EDDng 'instantPageId' l\xE0 b\u1EAFt bu\u1ED9c v\xE0 ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn d\u01B0\u01A1ng (> 0).");
4027
5059
  }
4028
5060
  if (!obj.oaId || typeof obj.oaId !== "string" || !/^\d+$/.test(obj.oaId.trim())) {
@@ -4075,7 +5107,7 @@ function validateUpsertInstantPageFormRequest(input) {
4075
5107
  }
4076
5108
  }
4077
5109
  const data = {
4078
- instantPageId: toPositiveInteger(obj.instantPageId),
5110
+ instantPageId: toPositiveInteger2(obj.instantPageId),
4079
5111
  oaId: String(obj.oaId).trim(),
4080
5112
  formName: String(obj.formName).trim(),
4081
5113
  questions: obj.questions ?? [],
@@ -4885,8 +5917,10 @@ var ZaloAdsCreateFlowRequest = class {
4885
5917
  messages;
4886
5918
  };
4887
5919
  var ZaloAdsCreateFlowResponse = class {
4888
- /** 0 khi tạo thành công. */
5920
+ /** 0 khi tạo thành công; 1 khi lỗi (ví dụ: đã tới hạn mức 20 kịch bản). */
4889
5921
  code;
5922
+ /** Thông báo lỗi từ Zalo Ads khi code khác 0. */
5923
+ msg;
4890
5924
  /** ID kịch bản mới, truyền vào data.ZaloFlowId khi cập nhật quảng cáo Tin nhắn. */
4891
5925
  data;
4892
5926
  };
@@ -4992,13 +6026,16 @@ export {
4992
6026
  ZaloAdsUpdateVideoAdRequest,
4993
6027
  ZaloAdsUpdateVideoAdResponse,
4994
6028
  ZaloAudiencesService,
6029
+ ZaloAudiencesValidator,
4995
6030
  ZaloAuthManager,
4996
6031
  ZaloAutomatedRulesService,
4997
6032
  ZaloCampaignsService,
4998
6033
  ZaloChatWidgetService,
4999
6034
  ZaloConversionsService,
5000
6035
  ZaloFlowsService,
6036
+ ZaloFlowsValidator,
5001
6037
  ZaloFormsService,
6038
+ ZaloFormsValidator,
5002
6039
  ZaloInstantPageBlockType,
5003
6040
  ZaloInstantPagesService,
5004
6041
  ZaloInstantPagesValidator,
@@ -5016,8 +6053,20 @@ export {
5016
6053
  deriveAccountKeyFromZpsid,
5017
6054
  parseZaloCookieInput,
5018
6055
  validateCloneInstantPageRequest,
6056
+ validateCreateFlowRequest,
6057
+ validateCreateFormEventAudienceRequest,
6058
+ validateCreateFormRequest,
6059
+ validateCreateLookalikeAudienceRequest,
6060
+ validateCreateMessageOaEventAudienceRequest,
6061
+ validateCreateMessagePersonalEventAudienceRequest,
6062
+ validateCreatePhoneAudienceRequest,
6063
+ validateCreateSavedAudienceRequest,
6064
+ validateEstimateAudienceRequest,
5019
6065
  validateGetInstantPageDetailRequest,
5020
6066
  validateGetInstantPageSharedUserRequest,
6067
+ validateListFlowsByOfficialAccountRequest,
6068
+ validateListFormLeadsRequest,
6069
+ validateListFormsByOfficialAccountRequest,
5021
6070
  validateListInstantPageEditHistoryRequest,
5022
6071
  validateListInstantPageFormRecordsRequest,
5023
6072
  validateListInstantPageLeadsRequest,
@@ -5026,6 +6075,7 @@ export {
5026
6075
  validateListMiniPageTemplatesRequest,
5027
6076
  validateListOfficialAccountsRequest,
5028
6077
  validateSearchInstantPagesRequest,
6078
+ validateUpdateFlowRequest,
5029
6079
  validateUpdateInstantPageRequest,
5030
6080
  validateUpsertInstantPageFormRequest
5031
6081
  };