@adkit/cli 1.13.19 → 1.13.21
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/cli.js +344 -126
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -88,6 +88,108 @@ var CliError = class extends Error {
|
|
|
88
88
|
}
|
|
89
89
|
};
|
|
90
90
|
|
|
91
|
+
// src/cli-utils.ts
|
|
92
|
+
function parseArgs(argv, options) {
|
|
93
|
+
const args = [];
|
|
94
|
+
const flags = {};
|
|
95
|
+
const multiSet = new Set(options?.multi);
|
|
96
|
+
for (let i = 0; i < argv.length; i++) {
|
|
97
|
+
const arg = argv[i];
|
|
98
|
+
if (!arg.startsWith("--")) {
|
|
99
|
+
args.push(arg);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const eqIdx = arg.indexOf("=");
|
|
103
|
+
let key;
|
|
104
|
+
let value;
|
|
105
|
+
if (eqIdx !== -1) {
|
|
106
|
+
key = arg.slice(2, eqIdx);
|
|
107
|
+
value = arg.slice(eqIdx + 1);
|
|
108
|
+
} else {
|
|
109
|
+
key = arg.slice(2);
|
|
110
|
+
const next = argv[i + 1];
|
|
111
|
+
if (next && !next.startsWith("--")) {
|
|
112
|
+
value = next;
|
|
113
|
+
i++;
|
|
114
|
+
} else value = true;
|
|
115
|
+
}
|
|
116
|
+
if (multiSet.has(key) && typeof value === "string") {
|
|
117
|
+
const existing = flags[key];
|
|
118
|
+
if (Array.isArray(existing)) existing.push(value);
|
|
119
|
+
else flags[key] = [value];
|
|
120
|
+
} else flags[key] = value;
|
|
121
|
+
}
|
|
122
|
+
return { args, flags };
|
|
123
|
+
}
|
|
124
|
+
var GLOBAL_FLAGS = ["account", "json", "fields", "publish", "data", "platform-overrides", "force", "project"];
|
|
125
|
+
function validateFlags(flags, allowed, command) {
|
|
126
|
+
const allAllowed = /* @__PURE__ */ new Set([...GLOBAL_FLAGS, ...allowed]);
|
|
127
|
+
const unknown = Object.keys(flags).filter((k) => !allAllowed.has(k));
|
|
128
|
+
if (unknown.length) throw new CliError("UNKNOWN_FLAG", `Unknown flag${unknown.length > 1 ? "s" : ""}: ${unknown.map((f) => `--${f}`).join(", ")}`, `Run: adkit ${command} --help`);
|
|
129
|
+
}
|
|
130
|
+
function requireArg(args, index, label, hint) {
|
|
131
|
+
const val = args[index];
|
|
132
|
+
if (!val) throw new CliError("MISSING_ARGUMENT", `Missing required argument: \`<${label}>\``, hint);
|
|
133
|
+
return val;
|
|
134
|
+
}
|
|
135
|
+
function requireFlag(flags, key, hint) {
|
|
136
|
+
const val = flags[key];
|
|
137
|
+
if (typeof val !== "string") throw new CliError("MISSING_FLAG", `Missing required flag: \`--${key}\``, hint);
|
|
138
|
+
return val;
|
|
139
|
+
}
|
|
140
|
+
function parseDataFlag(flags, hint) {
|
|
141
|
+
const raw = requireFlag(flags, "data", hint);
|
|
142
|
+
try {
|
|
143
|
+
return JSON.parse(raw);
|
|
144
|
+
} catch {
|
|
145
|
+
const truncated = raw.length > 80 ? raw.slice(0, 80) + "..." : raw;
|
|
146
|
+
throw new CliError("INVALID_VALUE", `Invalid JSON in \`--data\` flag: ${truncated}`, "Check JSON syntax in --data");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function mergeAccountId(body, flags) {
|
|
150
|
+
if (typeof body !== "object" || body === null || Array.isArray(body)) return body;
|
|
151
|
+
const obj = body;
|
|
152
|
+
if (!obj.accountId && typeof flags.account === "string") obj.accountId = flags.account;
|
|
153
|
+
return obj;
|
|
154
|
+
}
|
|
155
|
+
function queryString(params) {
|
|
156
|
+
const entries = Object.entries(params).filter((entry) => entry[1] !== void 0);
|
|
157
|
+
if (entries.length === 0) return "";
|
|
158
|
+
return "?" + entries.map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join("&");
|
|
159
|
+
}
|
|
160
|
+
function isDisplayRow(value) {
|
|
161
|
+
return typeof value === "object" && value !== null;
|
|
162
|
+
}
|
|
163
|
+
function isDisplayRowEntry(value) {
|
|
164
|
+
return isDisplayRow(value);
|
|
165
|
+
}
|
|
166
|
+
function isDisplayRowArray(value) {
|
|
167
|
+
if (!Array.isArray(value)) return false;
|
|
168
|
+
const everyItemIsDisplayRow = value.every(isDisplayRowEntry);
|
|
169
|
+
return everyItemIsDisplayRow;
|
|
170
|
+
}
|
|
171
|
+
function isWrappedRowArray(value) {
|
|
172
|
+
return isDisplayRowArray(value);
|
|
173
|
+
}
|
|
174
|
+
function getDateStamp() {
|
|
175
|
+
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
176
|
+
}
|
|
177
|
+
function collectFlagValues(flags, key) {
|
|
178
|
+
const value = flags[key];
|
|
179
|
+
if (Array.isArray(value)) return value;
|
|
180
|
+
if (typeof value === "string") return [value];
|
|
181
|
+
return [];
|
|
182
|
+
}
|
|
183
|
+
function unwrapList(data) {
|
|
184
|
+
if (isDisplayRowArray(data)) return data;
|
|
185
|
+
if (data && typeof data === "object") {
|
|
186
|
+
const values = Object.values(data);
|
|
187
|
+
const rowArray = values.find(isWrappedRowArray);
|
|
188
|
+
if (rowArray) return rowArray;
|
|
189
|
+
}
|
|
190
|
+
return [];
|
|
191
|
+
}
|
|
192
|
+
|
|
91
193
|
// src/client.ts
|
|
92
194
|
var noticePrinted = false;
|
|
93
195
|
function printServerNotice(response) {
|
|
@@ -166,22 +268,53 @@ function buildAuthSuggestion(code) {
|
|
|
166
268
|
if (!AUTH_CODES.has(normalizedCode)) return void 0;
|
|
167
269
|
return "Run: adkit setup manage";
|
|
168
270
|
}
|
|
271
|
+
function appendReadQueryFallback(path3, rawData) {
|
|
272
|
+
const parsedData = parseDataFlag({ data: rawData }, "Use a flat JSON object for read query parameters");
|
|
273
|
+
if (typeof parsedData !== "object" || parsedData === null || Array.isArray(parsedData)) throw new CliError("INVALID_VALUE", "Read --data must be a flat JSON object", 'Use an object such as {"adGroupIds":["123"]}');
|
|
274
|
+
const queryStart = path3.indexOf("?");
|
|
275
|
+
const existingQuery = queryStart === -1 ? "" : path3.slice(queryStart + 1);
|
|
276
|
+
const existingParams = new URLSearchParams(existingQuery);
|
|
277
|
+
const extraParams = [];
|
|
278
|
+
for (const [key, value] of Object.entries(parsedData)) {
|
|
279
|
+
const values = Array.isArray(value) ? value : [value];
|
|
280
|
+
if (values.length === 0) throw new CliError("INVALID_VALUE", `Cannot use --data field \`${key}\` as a read query parameter`, "Use a string, finite number, boolean, or non-empty array of those values");
|
|
281
|
+
const queryItems = [];
|
|
282
|
+
for (const item of values) {
|
|
283
|
+
const isScalar = typeof item === "string" || typeof item === "boolean" || typeof item === "number" && Number.isFinite(item);
|
|
284
|
+
if (!isScalar) throw new CliError("INVALID_VALUE", `Cannot use --data field \`${key}\` as a read query parameter`, "Use a string, finite number, boolean, or non-empty array of those values");
|
|
285
|
+
const queryItem = String(item);
|
|
286
|
+
queryItems.push(queryItem);
|
|
287
|
+
}
|
|
288
|
+
const queryValue = queryItems.join(",");
|
|
289
|
+
if (existingParams.has(key)) continue;
|
|
290
|
+
const encodedKey = encodeURIComponent(key);
|
|
291
|
+
const encodedValue = encodeURIComponent(queryValue);
|
|
292
|
+
extraParams.push(`${encodedKey}=${encodedValue}`);
|
|
293
|
+
}
|
|
294
|
+
if (extraParams.length === 0) return path3;
|
|
295
|
+
const separator = queryStart === -1 ? "?" : "&";
|
|
296
|
+
return `${path3}${separator}${extraParams.join("&")}`;
|
|
297
|
+
}
|
|
169
298
|
var AdkitClient = class {
|
|
170
299
|
apiKey;
|
|
171
300
|
baseUrl;
|
|
172
301
|
clientVersion;
|
|
173
302
|
projectId;
|
|
174
|
-
|
|
303
|
+
readQueryFallback;
|
|
304
|
+
constructor({ apiKey, baseUrl, clientVersion, projectId, readQueryFallback }) {
|
|
175
305
|
const isLocalhost = baseUrl.startsWith("http://localhost") || baseUrl.startsWith("http://127.0.0.1");
|
|
176
306
|
if (baseUrl.startsWith("http://") && !isLocalhost) throw new Error("HTTPS is required \u2014 insecure HTTP base URLs are not allowed");
|
|
177
307
|
this.apiKey = apiKey;
|
|
178
308
|
this.baseUrl = baseUrl;
|
|
179
309
|
this.clientVersion = clientVersion;
|
|
180
310
|
this.projectId = projectId;
|
|
311
|
+
this.readQueryFallback = readQueryFallback;
|
|
181
312
|
}
|
|
182
313
|
// eslint-disable-next-line max-lines-per-function -- shared client error mapping is intentionally centralized here.
|
|
183
314
|
async request(method, path3, body) {
|
|
184
|
-
|
|
315
|
+
if (method !== "GET") this.readQueryFallback = void 0;
|
|
316
|
+
const requestPath = method === "GET" && this.readQueryFallback !== void 0 ? appendReadQueryFallback(path3, this.readQueryFallback) : path3;
|
|
317
|
+
const url = `${this.baseUrl}${requestPath}`;
|
|
185
318
|
const headers = {
|
|
186
319
|
Authorization: `Bearer ${this.apiKey}`,
|
|
187
320
|
"Content-Type": "application/json",
|
|
@@ -249,7 +382,7 @@ var AdkitClient = class {
|
|
|
249
382
|
throw error2;
|
|
250
383
|
}
|
|
251
384
|
if (response.status === 404) {
|
|
252
|
-
const fallback = `Not found: ${method} ${
|
|
385
|
+
const fallback = `Not found: ${method} ${requestPath} \u2014 the resource may have been deleted or the ID is wrong`;
|
|
253
386
|
const error2 = new CliError("NOT_FOUND", appendErrorDetail(serverMessage || fallback, batchSummary), "Check the resource ID");
|
|
254
387
|
error2.notice = serverNotice;
|
|
255
388
|
throw error2;
|
|
@@ -1022,108 +1155,6 @@ function logout() {
|
|
|
1022
1155
|
console.log("Logged out \u2014 API key removed.");
|
|
1023
1156
|
}
|
|
1024
1157
|
|
|
1025
|
-
// src/cli-utils.ts
|
|
1026
|
-
function parseArgs(argv, options) {
|
|
1027
|
-
const args = [];
|
|
1028
|
-
const flags = {};
|
|
1029
|
-
const multiSet = new Set(options?.multi);
|
|
1030
|
-
for (let i = 0; i < argv.length; i++) {
|
|
1031
|
-
const arg = argv[i];
|
|
1032
|
-
if (!arg.startsWith("--")) {
|
|
1033
|
-
args.push(arg);
|
|
1034
|
-
continue;
|
|
1035
|
-
}
|
|
1036
|
-
const eqIdx = arg.indexOf("=");
|
|
1037
|
-
let key;
|
|
1038
|
-
let value;
|
|
1039
|
-
if (eqIdx !== -1) {
|
|
1040
|
-
key = arg.slice(2, eqIdx);
|
|
1041
|
-
value = arg.slice(eqIdx + 1);
|
|
1042
|
-
} else {
|
|
1043
|
-
key = arg.slice(2);
|
|
1044
|
-
const next = argv[i + 1];
|
|
1045
|
-
if (next && !next.startsWith("--")) {
|
|
1046
|
-
value = next;
|
|
1047
|
-
i++;
|
|
1048
|
-
} else value = true;
|
|
1049
|
-
}
|
|
1050
|
-
if (multiSet.has(key) && typeof value === "string") {
|
|
1051
|
-
const existing = flags[key];
|
|
1052
|
-
if (Array.isArray(existing)) existing.push(value);
|
|
1053
|
-
else flags[key] = [value];
|
|
1054
|
-
} else flags[key] = value;
|
|
1055
|
-
}
|
|
1056
|
-
return { args, flags };
|
|
1057
|
-
}
|
|
1058
|
-
var GLOBAL_FLAGS = ["account", "json", "fields", "publish", "data", "platform-overrides", "force", "project"];
|
|
1059
|
-
function validateFlags(flags, allowed, command) {
|
|
1060
|
-
const allAllowed = /* @__PURE__ */ new Set([...GLOBAL_FLAGS, ...allowed]);
|
|
1061
|
-
const unknown = Object.keys(flags).filter((k) => !allAllowed.has(k));
|
|
1062
|
-
if (unknown.length) throw new CliError("UNKNOWN_FLAG", `Unknown flag${unknown.length > 1 ? "s" : ""}: ${unknown.map((f) => `--${f}`).join(", ")}`, `Run: adkit ${command} --help`);
|
|
1063
|
-
}
|
|
1064
|
-
function requireArg(args, index, label, hint) {
|
|
1065
|
-
const val = args[index];
|
|
1066
|
-
if (!val) throw new CliError("MISSING_ARGUMENT", `Missing required argument: \`<${label}>\``, hint);
|
|
1067
|
-
return val;
|
|
1068
|
-
}
|
|
1069
|
-
function requireFlag(flags, key, hint) {
|
|
1070
|
-
const val = flags[key];
|
|
1071
|
-
if (typeof val !== "string") throw new CliError("MISSING_FLAG", `Missing required flag: \`--${key}\``, hint);
|
|
1072
|
-
return val;
|
|
1073
|
-
}
|
|
1074
|
-
function parseDataFlag(flags, hint) {
|
|
1075
|
-
const raw = requireFlag(flags, "data", hint);
|
|
1076
|
-
try {
|
|
1077
|
-
return JSON.parse(raw);
|
|
1078
|
-
} catch {
|
|
1079
|
-
const truncated = raw.length > 80 ? raw.slice(0, 80) + "..." : raw;
|
|
1080
|
-
throw new CliError("INVALID_VALUE", `Invalid JSON in \`--data\` flag: ${truncated}`, "Check JSON syntax in --data");
|
|
1081
|
-
}
|
|
1082
|
-
}
|
|
1083
|
-
function mergeAccountId(body, flags) {
|
|
1084
|
-
if (typeof body !== "object" || body === null || Array.isArray(body)) return body;
|
|
1085
|
-
const obj = body;
|
|
1086
|
-
if (!obj.accountId && typeof flags.account === "string") obj.accountId = flags.account;
|
|
1087
|
-
return obj;
|
|
1088
|
-
}
|
|
1089
|
-
function queryString(params) {
|
|
1090
|
-
const entries = Object.entries(params).filter((entry) => entry[1] !== void 0);
|
|
1091
|
-
if (entries.length === 0) return "";
|
|
1092
|
-
return "?" + entries.map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join("&");
|
|
1093
|
-
}
|
|
1094
|
-
function isDisplayRow(value) {
|
|
1095
|
-
return typeof value === "object" && value !== null;
|
|
1096
|
-
}
|
|
1097
|
-
function isDisplayRowEntry(value) {
|
|
1098
|
-
return isDisplayRow(value);
|
|
1099
|
-
}
|
|
1100
|
-
function isDisplayRowArray(value) {
|
|
1101
|
-
if (!Array.isArray(value)) return false;
|
|
1102
|
-
const everyItemIsDisplayRow = value.every(isDisplayRowEntry);
|
|
1103
|
-
return everyItemIsDisplayRow;
|
|
1104
|
-
}
|
|
1105
|
-
function isWrappedRowArray(value) {
|
|
1106
|
-
return isDisplayRowArray(value);
|
|
1107
|
-
}
|
|
1108
|
-
function getDateStamp() {
|
|
1109
|
-
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
1110
|
-
}
|
|
1111
|
-
function collectFlagValues(flags, key) {
|
|
1112
|
-
const value = flags[key];
|
|
1113
|
-
if (Array.isArray(value)) return value;
|
|
1114
|
-
if (typeof value === "string") return [value];
|
|
1115
|
-
return [];
|
|
1116
|
-
}
|
|
1117
|
-
function unwrapList(data) {
|
|
1118
|
-
if (isDisplayRowArray(data)) return data;
|
|
1119
|
-
if (data && typeof data === "object") {
|
|
1120
|
-
const values = Object.values(data);
|
|
1121
|
-
const rowArray = values.find(isWrappedRowArray);
|
|
1122
|
-
if (rowArray) return rowArray;
|
|
1123
|
-
}
|
|
1124
|
-
return [];
|
|
1125
|
-
}
|
|
1126
|
-
|
|
1127
1158
|
// src/commands/projects.ts
|
|
1128
1159
|
async function createProject(client, options) {
|
|
1129
1160
|
const response = await client.post("/manage/projects", options);
|
|
@@ -1165,7 +1196,7 @@ function isCreateProjectResponse(value) {
|
|
|
1165
1196
|
if (!value || typeof value !== "object") return false;
|
|
1166
1197
|
if (!("projectId" in value) || typeof value.projectId !== "string") return false;
|
|
1167
1198
|
if (!("name" in value) || typeof value.name !== "string") return false;
|
|
1168
|
-
return "website" in value
|
|
1199
|
+
return !("website" in value) || typeof value.website === "string";
|
|
1169
1200
|
}
|
|
1170
1201
|
function mapProjectEntry(project, selectedProject) {
|
|
1171
1202
|
const entry = {
|
|
@@ -1888,6 +1919,18 @@ function parseGoogleSitelinkShorthand(value) {
|
|
|
1888
1919
|
return normalizeSitelinkAsset({ type: "sitelink", linkText, finalUrls: [finalUrl] });
|
|
1889
1920
|
}
|
|
1890
1921
|
|
|
1922
|
+
// ../shared/dist/utils/type-guards.js
|
|
1923
|
+
function isPlainObject(value) {
|
|
1924
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1925
|
+
}
|
|
1926
|
+
function readProperty(value, key) {
|
|
1927
|
+
return value[key];
|
|
1928
|
+
}
|
|
1929
|
+
function readStringProperty(value, key) {
|
|
1930
|
+
const raw = value[key];
|
|
1931
|
+
return typeof raw === "string" ? raw : void 0;
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1891
1934
|
// src/commands/google.ts
|
|
1892
1935
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
1893
1936
|
import { basename, extname, resolve } from "node:path";
|
|
@@ -1895,10 +1938,13 @@ var ACCOUNT_CONNECT_FLAGS = ["manager"];
|
|
|
1895
1938
|
var ASSET_LIST_FLAGS = ["type", "scope", "scope-id", "raw"];
|
|
1896
1939
|
var ASSET_CREATE_FLAGS = ["type", "text", "sitelink", "header", "value", "description-1", "description-2", "start-date", "end-date", "tracking-url-template", "final-url-suffix", "country-code", "phone-number", "call-conversion-reporting"];
|
|
1897
1940
|
var ASSET_LINK_FLAGS = ["type", "scope", "scope-id", "status"];
|
|
1898
|
-
var MEDIA_UPLOAD_FLAGS = ["file", "url", "base64", "adkit-media", "filename", "content-type", "name"];
|
|
1941
|
+
var MEDIA_UPLOAD_FLAGS = ["file", "url", "base64", "adkit-media", "video-id", "filename", "content-type", "name"];
|
|
1899
1942
|
var CAMPAIGN_LIST_FLAGS = ["status", "limit", "offset"];
|
|
1900
1943
|
var CAMPAIGN_CREATE_FLAGS = ["name", "status", "budget-daily", "campaign-type", "bid-strategy", "target-cpa", "target-roas", "search-partners", "display-network", "tracking-url-suffix", "countries"];
|
|
1901
1944
|
var CAMPAIGN_UPDATE_FLAGS = ["name", "status", "budget-daily", "bid-strategy", "target-cpa", "target-roas", "search-partners", "display-network", "tracking-url-suffix", "countries"];
|
|
1945
|
+
var ASSET_GROUP_LIST_FLAGS = ["campaign", "limit", "offset"];
|
|
1946
|
+
var ASSET_GROUP_CREATE_FLAGS = ["campaign", "name", "status", "final-url"];
|
|
1947
|
+
var ASSET_GROUP_UPDATE_FLAGS = ["name", "status", "final-url"];
|
|
1902
1948
|
var AD_GROUP_LIST_FLAGS = ["campaign", "status", "limit", "offset"];
|
|
1903
1949
|
var AD_GROUP_FLAGS = ["campaign", "name", "status", "cpc-bid"];
|
|
1904
1950
|
var AD_LIST_FLAGS = ["ad-group", "campaign", "status", "policy-status", "limit", "offset"];
|
|
@@ -1921,6 +1967,7 @@ var KEYWORD_RESEARCH_FLAGS = ["url", "location", "language", "limit", "min-volum
|
|
|
1921
1967
|
var TARGETING_RESEARCH_FLAGS = ["limit"];
|
|
1922
1968
|
var GEO_LOCATION_SEARCH_FLAGS = ["country-code", "locale", "type", "limit"];
|
|
1923
1969
|
var NUMBER_FLAG_PATTERN = /^(?:\d+|\d+\.\d+|\.\d+)(?:e[+-]?\d+)?$/iu;
|
|
1970
|
+
var GOOGLE_NUMERIC_ID_PATTERN = /^\d+$/u;
|
|
1924
1971
|
function generateCampaignName2() {
|
|
1925
1972
|
return `campaign ${getDateStamp()}`;
|
|
1926
1973
|
}
|
|
@@ -1995,6 +2042,52 @@ function requireAssetReference(args, hint) {
|
|
|
1995
2042
|
throw new CliError("INVALID_VALUE", `Invalid asset reference: ${value}`, "Use asset:<numeric-id>, e.g. asset:123456789");
|
|
1996
2043
|
}
|
|
1997
2044
|
}
|
|
2045
|
+
function requireGoogleNumericId(args, label, hint) {
|
|
2046
|
+
const value = requireArg(args, 0, label, hint);
|
|
2047
|
+
if (!GOOGLE_NUMERIC_ID_PATTERN.test(value)) throw new CliError("INVALID_VALUE", `Invalid ${label}: ${value}`, "Use the numeric Google Ads platformId returned by list/get");
|
|
2048
|
+
return value;
|
|
2049
|
+
}
|
|
2050
|
+
function mergeGoogleAssetGroupAccountId(body, flags) {
|
|
2051
|
+
const bodyAccountId = isPlainObject(body) ? readStringProperty(body, "accountId") : void 0;
|
|
2052
|
+
const flagAccountId = typeof flags.account === "string" ? flags.account : void 0;
|
|
2053
|
+
if (bodyAccountId && flagAccountId && bodyAccountId !== flagAccountId) throw new CliError("INVALID_VALUE", `Conflicting accountId: --account ${flagAccountId} vs data.accountId ${bodyAccountId}`, "Pass the same account once, either with --account or inside --data");
|
|
2054
|
+
return mergeAccountId(body, flags);
|
|
2055
|
+
}
|
|
2056
|
+
function buildGoogleAssetGroupCreateBody(flags) {
|
|
2057
|
+
if (typeof flags.data !== "string") throw new CliError("MISSING_FLAG", "Asset-group create requires `--data` for its assets", `Pass the full {"assetGroups":[...]} body, or combine --campaign, --name, and --final-url with --data '{"assets":[...]}'`);
|
|
2058
|
+
const parsedData = parseDataFlag(flags, "Check JSON syntax in --data");
|
|
2059
|
+
if (!isPlainObject(parsedData)) throw new CliError("INVALID_VALUE", "`--data` must be a JSON object", 'Use {"assetGroups":[...]} or a single asset-group object');
|
|
2060
|
+
const explicitAssetGroups = readProperty(parsedData, "assetGroups");
|
|
2061
|
+
if (Array.isArray(explicitAssetGroups)) return mergeGoogleAssetGroupAccountId(parsedData, flags);
|
|
2062
|
+
const dataCampaignId = readStringProperty(parsedData, "campaignId");
|
|
2063
|
+
const dataName = readStringProperty(parsedData, "name");
|
|
2064
|
+
const dataFinalUrls = readProperty(parsedData, "finalUrls");
|
|
2065
|
+
const campaignId = dataCampaignId ?? requireFlag(flags, "campaign", "Pass --campaign <id> or include campaignId in --data");
|
|
2066
|
+
const name = dataName ?? requireFlag(flags, "name", "Pass --name or include name in --data");
|
|
2067
|
+
const finalUrls = Array.isArray(dataFinalUrls) ? dataFinalUrls : [requireFlag(flags, "final-url", "Pass --final-url or include finalUrls in --data")];
|
|
2068
|
+
const dataStatus = readProperty(parsedData, "status");
|
|
2069
|
+
const status2 = dataStatus ?? (typeof flags.status === "string" ? flags.status : void 0);
|
|
2070
|
+
const fragment = removeQueryOnlyBodyKeys(parsedData, ["accountId", "assetGroups"]);
|
|
2071
|
+
const assetGroup = {
|
|
2072
|
+
...isPlainObject(fragment) ? fragment : {},
|
|
2073
|
+
campaignId,
|
|
2074
|
+
name,
|
|
2075
|
+
finalUrls,
|
|
2076
|
+
...status2 === void 0 ? {} : { status: status2 }
|
|
2077
|
+
};
|
|
2078
|
+
const dataAccountId = readStringProperty(parsedData, "accountId");
|
|
2079
|
+
const body = { ...dataAccountId ? { accountId: dataAccountId } : {}, assetGroups: [assetGroup] };
|
|
2080
|
+
return mergeGoogleAssetGroupAccountId(body, flags);
|
|
2081
|
+
}
|
|
2082
|
+
function buildGoogleAssetGroupUpdateBody(flags) {
|
|
2083
|
+
const body = {};
|
|
2084
|
+
if (typeof flags.name === "string") body.name = flags.name;
|
|
2085
|
+
if (flags.status === "enabled" || flags.status === "paused") body.status = flags.status;
|
|
2086
|
+
else if (typeof flags.status === "string") throw new CliError("INVALID_VALUE", `Invalid asset group status: ${flags.status}`, "Use enabled or paused; use delete to remove the group");
|
|
2087
|
+
if (typeof flags["final-url"] === "string") body.finalUrls = [flags["final-url"]];
|
|
2088
|
+
if (Object.keys(body).length === 0) throw new CliError("MISSING_FLAG", "Asset-group update requires a change", "Pass --name, --status, --final-url, or --data with assets.add/assets.remove");
|
|
2089
|
+
return body;
|
|
2090
|
+
}
|
|
1998
2091
|
function inferGoogleMediaContentType(filename) {
|
|
1999
2092
|
const extension = extname(filename).toLowerCase();
|
|
2000
2093
|
if (extension === ".jpg" || extension === ".jpeg") return "image/jpeg";
|
|
@@ -2007,13 +2100,15 @@ function buildGoogleMediaUploadSource(flags) {
|
|
|
2007
2100
|
const url = readSingleFlagValue(flags, "url", "Use one media source per command, or switch to --data for batch upload");
|
|
2008
2101
|
const base64 = readSingleFlagValue(flags, "base64", "Use one media source per command, or switch to --data for batch upload");
|
|
2009
2102
|
const adkitMediaId = readSingleFlagValue(flags, "adkit-media", "Use one media source per command, or switch to --data for batch upload");
|
|
2103
|
+
const videoId = readSingleFlagValue(flags, "video-id", "Use one media source per command, or switch to --data for batch upload");
|
|
2010
2104
|
let sourceCount = 0;
|
|
2011
2105
|
if (filePath) sourceCount += 1;
|
|
2012
2106
|
if (url) sourceCount += 1;
|
|
2013
2107
|
if (base64) sourceCount += 1;
|
|
2014
2108
|
if (adkitMediaId) sourceCount += 1;
|
|
2015
|
-
if (
|
|
2016
|
-
if (sourceCount
|
|
2109
|
+
if (videoId) sourceCount += 1;
|
|
2110
|
+
if (sourceCount === 0) throw new CliError("MISSING_FLAG", "Missing required media source flag", "Use --file, --url, --base64, --adkit-media, or --video-id");
|
|
2111
|
+
if (sourceCount > 1) throw new CliError("INVALID_VALUE", "Use exactly one media source flag", "Use one of --file, --url, --base64, --adkit-media, or --video-id");
|
|
2017
2112
|
const filename = readSingleFlagValue(flags, "filename", "Use one --filename value");
|
|
2018
2113
|
const contentType = readSingleFlagValue(flags, "content-type", "Use one --content-type value");
|
|
2019
2114
|
const name = readSingleFlagValue(flags, "name", "Use one --name value");
|
|
@@ -2041,6 +2136,7 @@ function buildGoogleMediaUploadSource(flags) {
|
|
|
2041
2136
|
if (name) source2.name = name;
|
|
2042
2137
|
return source2;
|
|
2043
2138
|
}
|
|
2139
|
+
if (videoId) return { source: "youtube", videoId, ...name ? { name } : {} };
|
|
2044
2140
|
if (!adkitMediaId) throw new CliError("MISSING_FLAG", "Missing required flag: `--adkit-media`", "Use --adkit-media <studio-media-id>");
|
|
2045
2141
|
const source = { source: "adkit_media", mediaId: adkitMediaId };
|
|
2046
2142
|
if (name) source.name = name;
|
|
@@ -2500,6 +2596,45 @@ async function deleteCampaign2(client, args, flags) {
|
|
|
2500
2596
|
const path3 = `/manage/google/campaigns/${id}${qs}`;
|
|
2501
2597
|
return client.delete(path3);
|
|
2502
2598
|
}
|
|
2599
|
+
async function listGoogleAssetGroups(client, _args, flags) {
|
|
2600
|
+
validateFlags(flags, ASSET_GROUP_LIST_FLAGS, "manage google asset-groups list");
|
|
2601
|
+
const campaignId = requireFlag(flags, "campaign", "Run: adkit manage google asset-groups list --campaign <campaign-id>");
|
|
2602
|
+
const qs = buildGoogleListQuery(flags, { campaignId });
|
|
2603
|
+
return client.get(`/manage/google/asset-groups${qs}`);
|
|
2604
|
+
}
|
|
2605
|
+
async function getGoogleAssetGroup(client, args, flags) {
|
|
2606
|
+
validateFlags(flags, ["raw"], "manage google asset-groups <id>");
|
|
2607
|
+
const id = requireGoogleNumericId(args, "asset-group-id", "Run: adkit manage google asset-groups <asset-group-id>");
|
|
2608
|
+
const qs = buildGoogleListQuery(flags);
|
|
2609
|
+
return client.get(`/manage/google/asset-groups/${id}${qs}`);
|
|
2610
|
+
}
|
|
2611
|
+
async function createGoogleAssetGroup(client, _args, flags) {
|
|
2612
|
+
validateFlags(flags, ASSET_GROUP_CREATE_FLAGS, "manage google asset-groups create");
|
|
2613
|
+
const body = buildGoogleAssetGroupCreateBody(flags);
|
|
2614
|
+
const qs = buildGoogleMutationQuery(flags, body);
|
|
2615
|
+
return client.post(`/manage/google/asset-groups${qs}`, body);
|
|
2616
|
+
}
|
|
2617
|
+
async function updateGoogleAssetGroup(client, args, flags) {
|
|
2618
|
+
validateFlags(flags, ASSET_GROUP_UPDATE_FLAGS, "manage google asset-groups update");
|
|
2619
|
+
const id = requireGoogleNumericId(args, "asset-group-id", "Run: adkit manage google asset-groups update <asset-group-id> --data <json>");
|
|
2620
|
+
if (typeof flags.data === "string") {
|
|
2621
|
+
const parsedBody = parseDataFlag(flags, "Use assets.add and assets.remove for asset mutations");
|
|
2622
|
+
if (!isPlainObject(parsedBody)) throw new CliError("INVALID_VALUE", "`--data` must be a JSON object", "Use an asset-group update object");
|
|
2623
|
+
const scopedBody = mergeGoogleAssetGroupAccountId(parsedBody, flags);
|
|
2624
|
+
const qs2 = buildGoogleMutationQuery(flags, scopedBody);
|
|
2625
|
+
const body2 = removeQueryOnlyBodyKeys(scopedBody, ["accountId"]);
|
|
2626
|
+
return client.patch(`/manage/google/asset-groups/${id}${qs2}`, body2);
|
|
2627
|
+
}
|
|
2628
|
+
const body = buildGoogleAssetGroupUpdateBody(flags);
|
|
2629
|
+
const qs = buildGoogleMutationQuery(flags, body);
|
|
2630
|
+
return client.patch(`/manage/google/asset-groups/${id}${qs}`, body);
|
|
2631
|
+
}
|
|
2632
|
+
async function deleteGoogleAssetGroup(client, args, flags) {
|
|
2633
|
+
validateFlags(flags, [], "manage google asset-groups delete");
|
|
2634
|
+
const id = requireGoogleNumericId(args, "asset-group-id", "Run: adkit manage google asset-groups delete <asset-group-id>");
|
|
2635
|
+
const qs = buildGoogleMutationQuery(flags, {});
|
|
2636
|
+
return client.delete(`/manage/google/asset-groups/${id}${qs}`);
|
|
2637
|
+
}
|
|
2503
2638
|
async function listGoogleAdGroups(client, _args, flags) {
|
|
2504
2639
|
validateFlags(flags, AD_GROUP_LIST_FLAGS, "manage google ad-groups list");
|
|
2505
2640
|
const campaignId = typeof flags.campaign === "string" ? flags.campaign : void 0;
|
|
@@ -4619,7 +4754,7 @@ function isHelpSearchResponse(value) {
|
|
|
4619
4754
|
var require2 = createRequire(import.meta.url);
|
|
4620
4755
|
var CLI_VERSION = require2("../package.json").version;
|
|
4621
4756
|
var DEFAULT_BASE_URL = "https://app.adkit.so/api/v1";
|
|
4622
|
-
var
|
|
4757
|
+
var GOOGLE_NUMERIC_ID_PATTERN2 = /^\d+$/;
|
|
4623
4758
|
var GOOGLE_RESULTS_LEVEL_ACTIONS = /* @__PURE__ */ new Set(["campaigns", "ad-groups", "ads"]);
|
|
4624
4759
|
var TIKTOK_NUMERIC_ID_PATTERN = /^\d+$/;
|
|
4625
4760
|
var LINKEDIN_ID_PATTERN = /[\d:_]/;
|
|
@@ -5323,7 +5458,7 @@ Note:
|
|
|
5323
5458
|
Advanced geo examples: adkit manage google campaigns --help full
|
|
5324
5459
|
Display creation starts here: campaigns create --campaign-type display, then create Display ad groups and responsive_display ads.
|
|
5325
5460
|
Performance Max: campaignType "performance_max" with asset groups \u2014 build it with --data. See --help full.
|
|
5326
|
-
View a Performance Max campaign by ID to read back its assetGroups
|
|
5461
|
+
View a Performance Max campaign by ID to read back its assetGroups; manage existing groups with google asset-groups.
|
|
5327
5462
|
For spend/clicks/conversions: adkit manage google results
|
|
5328
5463
|
|
|
5329
5464
|
Examples:
|
|
@@ -5376,8 +5511,8 @@ Notes:
|
|
|
5376
5511
|
platformLocation accepts exact Google geo objects for advanced criteria and existing raw values.
|
|
5377
5512
|
Google exclusions support named locations. Proximity circles belong in include.
|
|
5378
5513
|
Display campaign creation uses campaignType:"display" or --campaign-type display. Videos are not supported for Display media in v1.
|
|
5379
|
-
Performance Max: campaignType "performance_max"
|
|
5380
|
-
View a Performance Max campaign by ID to read back assetGroups
|
|
5514
|
+
Performance Max: campaignType "performance_max" requires at least one assetGroups[] entry and supports multiple groups. Text assets are inline ({role,text}); upload images with google media first, then reference their id/resourceName. Needs an enabled conversion (publish is blocked without one). Non-retail only. Build it with --data.
|
|
5515
|
+
View a Performance Max campaign by ID to read back its assetGroups. After creation, manage groups with google asset-groups.
|
|
5381
5516
|
For spend/clicks/conversions: adkit manage google results
|
|
5382
5517
|
|
|
5383
5518
|
Examples:
|
|
@@ -5390,6 +5525,58 @@ Examples:
|
|
|
5390
5525
|
adkit manage google campaigns update 987654321 --status paused --account 1234567890
|
|
5391
5526
|
adkit manage google campaigns update 987654321 --data '{"targeting":{"geoLocations":{"match":"presence_or_interest"}}}' --account 1234567890
|
|
5392
5527
|
adkit manage google campaigns delete 987654321 --account 1234567890 --publish`;
|
|
5528
|
+
var GOOGLE_ASSET_GROUP_HELP = `adkit manage google asset-groups \u2014 Performance Max asset groups
|
|
5529
|
+
|
|
5530
|
+
list List groups in one campaign (requires --campaign)
|
|
5531
|
+
create Create one group or a batch
|
|
5532
|
+
update <id> Update by numeric Google asset group ID (platformId)
|
|
5533
|
+
delete <id> Delete by numeric Google asset group ID (platformId)
|
|
5534
|
+
<id> View one group by numeric Google asset group ID (platformId)
|
|
5535
|
+
|
|
5536
|
+
Flags (list):
|
|
5537
|
+
--campaign <id> Parent Performance Max campaign ID (required)
|
|
5538
|
+
--limit <n> Max results
|
|
5539
|
+
--offset <n> Pagination offset
|
|
5540
|
+
${FLAG.account}
|
|
5541
|
+
|
|
5542
|
+
Flags (create):
|
|
5543
|
+
--campaign <id> Parent campaign ID for a single-group JSON fragment
|
|
5544
|
+
--name <name> Group name for a single-group JSON fragment
|
|
5545
|
+
--status <s> enabled or paused
|
|
5546
|
+
--final-url <url> Landing page for a single-group JSON fragment
|
|
5547
|
+
--data <json> Required assets. Pass a full {"assetGroups":[...]} body for batches, or one group fragment with assets when using the named flags
|
|
5548
|
+
${FLAG.account}
|
|
5549
|
+
${FLAG.publish}
|
|
5550
|
+
|
|
5551
|
+
Flags (update):
|
|
5552
|
+
--name <name> New group name
|
|
5553
|
+
--status <s> enabled or paused; use delete to remove the group
|
|
5554
|
+
--final-url <url> Replace landing pages with one URL
|
|
5555
|
+
--data <json> Full update object. Use assets.add and assets.remove for asset changes
|
|
5556
|
+
${FLAG.account}
|
|
5557
|
+
${FLAG.publish}
|
|
5558
|
+
|
|
5559
|
+
Asset JSON:
|
|
5560
|
+
Text asset {"role":"headline|long_headline|description|business_name","text":"..."}
|
|
5561
|
+
Image asset {"role":"marketing_image|square_marketing_image|logo|landscape_logo","id":"<uploaded-google-asset-id>"}
|
|
5562
|
+
Remove asset {"linkResourceName":"customers/.../assetGroupAssets/..."} \u2014 copy the exact value returned by list/get
|
|
5563
|
+
Search theme {"type":"search_theme","text":"..."} \u2014 create/read only; signals cannot be edited
|
|
5564
|
+
|
|
5565
|
+
Notes:
|
|
5566
|
+
Mutations create drafts by default. Add --publish to apply immediately.
|
|
5567
|
+
Minimum per group: 3 headlines, 1 long_headline, 2 descriptions (at least one 60 characters or fewer), 1 business_name, 1 logo, 1 marketing_image, and 1 square_marketing_image.
|
|
5568
|
+
list/get return assets grouped by role; every linked asset includes linkResourceName for later removal.
|
|
5569
|
+
Upload images with google media before referencing their id or resourceName.
|
|
5570
|
+
Creating groups for campaigns with Google brand guidelines enabled is not supported.
|
|
5571
|
+
|
|
5572
|
+
Examples:
|
|
5573
|
+
adkit manage google asset-groups list --campaign 987654321 --account 1234567890
|
|
5574
|
+
adkit manage google asset-groups 555666777 --account 1234567890
|
|
5575
|
+
adkit manage google asset-groups create --campaign 987654321 --name "US Prospects" --final-url https://example.com --data '{"assets":[{"role":"headline","text":"Ship faster"},{"role":"headline","text":"Save hours every week"},{"role":"headline","text":"Start free today"},{"role":"long_headline","text":"Automate your ad workflow"},{"role":"description","text":"Launch campaigns in minutes"},{"role":"description","text":"No credit card required"},{"role":"business_name","text":"Acme"},{"role":"logo","id":"111"},{"role":"marketing_image","id":"222"},{"role":"square_marketing_image","id":"333"}]}' --account 1234567890
|
|
5576
|
+
adkit manage google asset-groups update 555666777 --name "US \u2014 refreshed" --account 1234567890
|
|
5577
|
+
adkit manage google asset-groups update 555666777 --data '{"assets":{"add":[{"role":"headline","text":"New headline"}],"remove":[{"linkResourceName":"customers/1234567890/assetGroupAssets/555666777~444~HEADLINE"}]}}' --account 1234567890
|
|
5578
|
+
adkit manage google asset-groups delete 555666777 --account 1234567890 --publish`;
|
|
5579
|
+
var GOOGLE_ASSET_GROUP_HELP_FULL = GOOGLE_ASSET_GROUP_HELP;
|
|
5393
5580
|
var GOOGLE_AD_GROUP_HELP = `adkit manage google ad-groups \u2014 Google Ads ad groups
|
|
5394
5581
|
|
|
5395
5582
|
list List ad groups
|
|
@@ -5929,15 +6116,16 @@ Examples:
|
|
|
5929
6116
|
Supported results contain type; unmapped Google categories contain platformType.
|
|
5930
6117
|
Pass type and the bare code into campaign targeting. For country, use {"type":"country","country":"US"}.
|
|
5931
6118
|
AdKit builds the Google resource name.`;
|
|
5932
|
-
var GOOGLE_MEDIA_HELP = `adkit manage google media \u2014 Upload creative media
|
|
6119
|
+
var GOOGLE_MEDIA_HELP = `adkit manage google media \u2014 Upload or register creative media with Google Ads
|
|
5933
6120
|
|
|
5934
|
-
upload Upload an image
|
|
6121
|
+
upload Upload an image or register a YouTube video
|
|
5935
6122
|
|
|
5936
6123
|
Flags:
|
|
5937
6124
|
--file <path> Local image file
|
|
5938
6125
|
--url <url> Public image URL
|
|
5939
6126
|
--base64 <data> Base64 image data
|
|
5940
6127
|
--adkit-media <id> Existing AdKit Studio media ID
|
|
6128
|
+
--video-id <id> Existing YouTube video ID
|
|
5941
6129
|
--filename <name> Required with --base64, optional with --url
|
|
5942
6130
|
--content-type <t> image/jpeg, image/png, or image/gif
|
|
5943
6131
|
--name <name> Google asset name
|
|
@@ -5948,11 +6136,13 @@ Examples:
|
|
|
5948
6136
|
adkit manage google media upload --file ./hero.png --account 1234567890
|
|
5949
6137
|
adkit manage google media upload --url https://example.com/hero.png --account 1234567890
|
|
5950
6138
|
adkit manage google media upload --adkit-media media_123 --account 1234567890
|
|
6139
|
+
adkit manage google media upload --video-id abcdefghijk --name "Product demo" --account 1234567890
|
|
5951
6140
|
|
|
5952
6141
|
Notes:
|
|
5953
|
-
|
|
6142
|
+
videoId: 11-character ID from the YouTube URL.
|
|
6143
|
+
Upload returns assets[].id and assets[].resourceName. Use either value when creating an ad.
|
|
5954
6144
|
Display media roles: marketing_image, square_marketing_image, logo, square_logo.
|
|
5955
|
-
|
|
6145
|
+
YouTube registration does not upload, copy, or re-host the video.`;
|
|
5956
6146
|
var GOOGLE_CONVERSIONS_HELP = `adkit manage google conversions \u2014 Google Ads conversion tracking
|
|
5957
6147
|
|
|
5958
6148
|
upload Upload offline click conversion events
|
|
@@ -6032,6 +6222,7 @@ Examples:
|
|
|
6032
6222
|
adkit manage google accounts disconnect 1234567890`.trim(),
|
|
6033
6223
|
"google assets": GOOGLE_ASSET_HELP,
|
|
6034
6224
|
"google campaigns": GOOGLE_CAMPAIGN_HELP,
|
|
6225
|
+
"google asset-groups": GOOGLE_ASSET_GROUP_HELP,
|
|
6035
6226
|
"google ad-groups": GOOGLE_AD_GROUP_HELP,
|
|
6036
6227
|
"google ads": GOOGLE_AD_HELP,
|
|
6037
6228
|
"google keywords": GOOGLE_KEYWORD_HELP,
|
|
@@ -6481,6 +6672,7 @@ Run adkit manage meta <group> --help for details.`.trim(),
|
|
|
6481
6672
|
Entity groups:
|
|
6482
6673
|
accounts List and connect Google Ads accounts
|
|
6483
6674
|
campaigns Manage Search, Display, and Performance Max campaigns
|
|
6675
|
+
asset-groups Manage Performance Max asset groups
|
|
6484
6676
|
ad-groups Manage ad groups and Display targeting
|
|
6485
6677
|
ads Manage responsive search and Display ads
|
|
6486
6678
|
keywords Manage keywords and negatives \u2014 config only, not metrics
|
|
@@ -6833,6 +7025,7 @@ var HELP_FULL = {
|
|
|
6833
7025
|
"meta lead-forms": LEAD_FORM_HELP,
|
|
6834
7026
|
"google assets": GOOGLE_ASSET_HELP_FULL,
|
|
6835
7027
|
"google campaigns": GOOGLE_CAMPAIGN_HELP_FULL,
|
|
7028
|
+
"google asset-groups": GOOGLE_ASSET_GROUP_HELP_FULL,
|
|
6836
7029
|
"google ad-groups": GOOGLE_AD_GROUP_HELP_FULL,
|
|
6837
7030
|
"google ads": GOOGLE_AD_HELP_FULL,
|
|
6838
7031
|
"google keywords": GOOGLE_KEYWORD_HELP_FULL,
|
|
@@ -6903,7 +7096,7 @@ function requireClient(flags, options = {}) {
|
|
|
6903
7096
|
if (!apiKey) throw new CliError("NOT_AUTHENTICATED", "No API key found", "Run: adkit setup");
|
|
6904
7097
|
const baseUrl = getBaseUrl();
|
|
6905
7098
|
const projectId = options.projectOptional ? void 0 : selectedProject;
|
|
6906
|
-
return new AdkitClient({ apiKey, baseUrl, clientVersion: CLI_VERSION, projectId });
|
|
7099
|
+
return new AdkitClient({ apiKey, baseUrl, clientVersion: CLI_VERSION, projectId, readQueryFallback: flags.data });
|
|
6907
7100
|
}
|
|
6908
7101
|
function toPrintListDisplayRows(rows, isJson) {
|
|
6909
7102
|
if (isJson) return rows;
|
|
@@ -7996,7 +8189,7 @@ async function main() {
|
|
|
7996
8189
|
data = await detachAsset(client, restArgs, flags);
|
|
7997
8190
|
break;
|
|
7998
8191
|
default:
|
|
7999
|
-
if (
|
|
8192
|
+
if (GOOGLE_NUMERIC_ID_PATTERN2.test(action)) data = await getAsset(client, [action], flags);
|
|
8000
8193
|
else throw new CliError("UNKNOWN_COMMAND", `Unknown action: google assets ${action}`, "Run: adkit manage google assets --help");
|
|
8001
8194
|
}
|
|
8002
8195
|
break;
|
|
@@ -8035,11 +8228,36 @@ async function main() {
|
|
|
8035
8228
|
data = await deleteCampaign2(client, restArgs, flags);
|
|
8036
8229
|
break;
|
|
8037
8230
|
default:
|
|
8038
|
-
if (
|
|
8231
|
+
if (GOOGLE_NUMERIC_ID_PATTERN2.test(action)) data = await getCampaign2(client, [action], flags);
|
|
8039
8232
|
else throw new CliError("UNKNOWN_COMMAND", `Unknown action: google campaigns ${action}`, "Run: adkit manage google campaigns --help");
|
|
8040
8233
|
}
|
|
8041
8234
|
break;
|
|
8042
8235
|
}
|
|
8236
|
+
case "asset-groups": {
|
|
8237
|
+
if (!action) {
|
|
8238
|
+
showHelp("google asset-groups", flags.help === "full");
|
|
8239
|
+
return;
|
|
8240
|
+
}
|
|
8241
|
+
switch (action) {
|
|
8242
|
+
case "list":
|
|
8243
|
+
data = await listGoogleAssetGroups(client, restArgs, flags);
|
|
8244
|
+
emptyHint = "No asset groups found in this campaign. Create one with `adkit manage google asset-groups create --help`.";
|
|
8245
|
+
break;
|
|
8246
|
+
case "create":
|
|
8247
|
+
data = await createGoogleAssetGroup(client, restArgs, flags);
|
|
8248
|
+
break;
|
|
8249
|
+
case "update":
|
|
8250
|
+
data = await updateGoogleAssetGroup(client, restArgs, flags);
|
|
8251
|
+
break;
|
|
8252
|
+
case "delete":
|
|
8253
|
+
data = await deleteGoogleAssetGroup(client, restArgs, flags);
|
|
8254
|
+
break;
|
|
8255
|
+
default:
|
|
8256
|
+
if (GOOGLE_NUMERIC_ID_PATTERN2.test(action)) data = await getGoogleAssetGroup(client, [action], flags);
|
|
8257
|
+
else throw new CliError("UNKNOWN_COMMAND", `Unknown action: google asset-groups ${action}`, "Run: adkit manage google asset-groups --help");
|
|
8258
|
+
}
|
|
8259
|
+
break;
|
|
8260
|
+
}
|
|
8043
8261
|
case "ad-groups": {
|
|
8044
8262
|
if (!action) {
|
|
8045
8263
|
showHelp("google ad-groups", flags.help === "full");
|
|
@@ -8060,7 +8278,7 @@ async function main() {
|
|
|
8060
8278
|
data = await deleteAdGroup(client, restArgs, flags);
|
|
8061
8279
|
break;
|
|
8062
8280
|
default:
|
|
8063
|
-
if (
|
|
8281
|
+
if (GOOGLE_NUMERIC_ID_PATTERN2.test(action)) data = await getAdGroup(client, [action], flags);
|
|
8064
8282
|
else throw new CliError("UNKNOWN_COMMAND", `Unknown action: google ad-groups ${action}`, "Run: adkit manage google ad-groups --help");
|
|
8065
8283
|
}
|
|
8066
8284
|
break;
|
|
@@ -8085,7 +8303,7 @@ async function main() {
|
|
|
8085
8303
|
data = await deleteAd2(client, restArgs, flags);
|
|
8086
8304
|
break;
|
|
8087
8305
|
default:
|
|
8088
|
-
if (
|
|
8306
|
+
if (GOOGLE_NUMERIC_ID_PATTERN2.test(action)) {
|
|
8089
8307
|
data = await getAd2(client, [action], flags);
|
|
8090
8308
|
detailEntity = "google-ad";
|
|
8091
8309
|
} else throw new CliError("UNKNOWN_COMMAND", `Unknown action: google ads ${action}`, "Run: adkit manage google ads --help");
|
|
@@ -8166,7 +8384,7 @@ async function main() {
|
|
|
8166
8384
|
break;
|
|
8167
8385
|
}
|
|
8168
8386
|
default:
|
|
8169
|
-
if (
|
|
8387
|
+
if (GOOGLE_NUMERIC_ID_PATTERN2.test(action)) data = await getKeyword(client, [action], flags);
|
|
8170
8388
|
else throw new CliError("UNKNOWN_COMMAND", `Unknown action: google keywords ${action}`, "Run: adkit manage google keywords --help (includes negatives)");
|
|
8171
8389
|
}
|
|
8172
8390
|
break;
|
|
@@ -8238,7 +8456,7 @@ async function main() {
|
|
|
8238
8456
|
break;
|
|
8239
8457
|
}
|
|
8240
8458
|
default:
|
|
8241
|
-
throw new CliError("UNKNOWN_COMMAND", `Unknown entity: google ${entity}`, "Available: accounts, assets, media, campaigns, ad-groups, ads, keywords, conversions, results, change-history, research, geo-locations");
|
|
8459
|
+
throw new CliError("UNKNOWN_COMMAND", `Unknown entity: google ${entity}`, "Available: accounts, assets, media, campaigns, asset-groups, ad-groups, ads, keywords, conversions, results, change-history, research, geo-locations");
|
|
8242
8460
|
}
|
|
8243
8461
|
} else if (platform2 === "tiktok") {
|
|
8244
8462
|
switch (entity) {
|
|
@@ -8773,8 +8991,8 @@ ${pageInfo}`);
|
|
|
8773
8991
|
break;
|
|
8774
8992
|
}
|
|
8775
8993
|
case "create": {
|
|
8776
|
-
const name =
|
|
8777
|
-
const website =
|
|
8994
|
+
const name = typeof flags.name === "string" ? flags.name : void 0;
|
|
8995
|
+
const website = typeof flags.website === "string" ? flags.website : void 0;
|
|
8778
8996
|
const descriptionValues = collectFlagValues(flags, "description");
|
|
8779
8997
|
const description = descriptionValues.length > 0 ? descriptionValues.join(" ") : void 0;
|
|
8780
8998
|
const tagsFlag = typeof flags.tags === "string" ? flags.tags : void 0;
|
package/package.json
CHANGED