@adkit.so/cli 1.0.0 → 1.0.2

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 CHANGED
@@ -1,16 +1,1407 @@
1
1
  #!/usr/bin/env node
2
- import { resolveConfig, readConfig } from './config.js';
3
- import { AdkitClient } from './client.js';
4
- import { formatOutput } from './output.js';
5
- import { login, logout } from './commands/auth.js';
6
- import { listProjects, useProject, currentProject } from './commands/projects.js';
7
- import { listAccounts, connectAccount, disconnectAccount, listPages, listPixels, listCampaigns, createCampaign, updateCampaign, deleteCampaign, listAdSets, createAdSet, updateAdSet, deleteAdSet, listAds, createAd, updateAd, deleteAd, createCreative, updateCreative, deleteCreative, uploadMedia, listMedia, deleteMedia, searchInterests } from './commands/meta.js';
8
- import { status } from './commands/status.js';
9
- import { listDrafts, getDraft, publishDraft, deleteDraft } from './commands/drafts.js';
10
- import { parseArgs, unwrapList } from './cli-utils.js';
11
- import { CliError } from './errors.js';
12
- const DEFAULT_BASE_URL = 'https://app.adkit.so/api/v1';
13
- const USAGE = `
2
+
3
+ // src/config.ts
4
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import { homedir } from "node:os";
7
+ var CONFIG_DIR = join(homedir(), ".config", "adkit");
8
+ var CONFIG_PATH = join(CONFIG_DIR, "config.json");
9
+ function parseConfigFile(raw) {
10
+ const parsed = JSON.parse(raw);
11
+ if (!parsed || typeof parsed !== "object") return {};
12
+ return parsed;
13
+ }
14
+ function readConfig() {
15
+ if (!existsSync(CONFIG_PATH)) return null;
16
+ try {
17
+ return parseConfigFile(readFileSync(CONFIG_PATH, "utf-8"));
18
+ } catch {
19
+ return null;
20
+ }
21
+ }
22
+ function writeConfig(updates) {
23
+ mkdirSync(CONFIG_DIR, { recursive: true });
24
+ let existing = {};
25
+ if (existsSync(CONFIG_PATH)) {
26
+ try {
27
+ existing = parseConfigFile(readFileSync(CONFIG_PATH, "utf-8"));
28
+ } catch {
29
+ }
30
+ }
31
+ const merged = { ...existing, ...updates };
32
+ writeFileSync(CONFIG_PATH, JSON.stringify(merged, null, 2), { mode: 384 });
33
+ }
34
+ function resolveConfig(flags = {}) {
35
+ const envKey = process.env.ADKIT_API_KEY;
36
+ if (envKey) return { apiKey: envKey };
37
+ const config = readConfig();
38
+ if (!config) return { apiKey: null };
39
+ if (flags.project) {
40
+ const projectKey = config.projects?.[flags.project]?.apiKey ?? null;
41
+ return { apiKey: projectKey, selectedProject: config.selectedProject };
42
+ }
43
+ if (config.selectedProject && config.projects?.[config.selectedProject]) {
44
+ return {
45
+ apiKey: config.projects[config.selectedProject]?.apiKey ?? null,
46
+ selectedProject: config.selectedProject
47
+ };
48
+ }
49
+ return {
50
+ apiKey: config.apiKey ?? null,
51
+ selectedProject: config.selectedProject
52
+ };
53
+ }
54
+ function getDefaultAccount(platform2) {
55
+ const config = readConfig();
56
+ if (!config?.selectedProject || !config.projects) return null;
57
+ const project = config.projects[config.selectedProject];
58
+ if (!project) return null;
59
+ return (platform2 === "meta" ? project.defaultMetaAccount : project.defaultGoogleAccount) ?? null;
60
+ }
61
+
62
+ // src/errors.ts
63
+ var CliError = class extends Error {
64
+ code;
65
+ suggestion;
66
+ constructor(code, message, suggestion) {
67
+ super(message);
68
+ this.code = code;
69
+ this.suggestion = suggestion;
70
+ }
71
+ };
72
+
73
+ // src/client.ts
74
+ function isErrorResponse(value) {
75
+ return value != null && typeof value === "object";
76
+ }
77
+ var AdkitClient = class {
78
+ apiKey;
79
+ baseUrl;
80
+ constructor({ apiKey, baseUrl }) {
81
+ const isLocalhost = baseUrl.startsWith("http://localhost") || baseUrl.startsWith("http://127.0.0.1");
82
+ if (baseUrl.startsWith("http://") && !isLocalhost) throw new Error("HTTPS is required \u2014 insecure HTTP base URLs are not allowed");
83
+ this.apiKey = apiKey;
84
+ this.baseUrl = baseUrl;
85
+ }
86
+ async request(method, path2, body) {
87
+ const url = `${this.baseUrl}${path2}`;
88
+ const headers = {
89
+ Authorization: `Bearer ${this.apiKey}`,
90
+ "Content-Type": "application/json"
91
+ };
92
+ const init = { method, headers };
93
+ if (body !== void 0) init.body = JSON.stringify(body);
94
+ let response;
95
+ try {
96
+ response = await fetch(url, init);
97
+ } catch (err) {
98
+ if (err instanceof DOMException && err.name === "AbortError") throw new CliError("NETWORK_ERROR", "Request timed out", "Retry the command");
99
+ throw new CliError("NETWORK_ERROR", "Network connection error \u2014 check your internet connection and try again. If using a custom base URL, verify `ADKIT_BASE_URL` is correct.", "Check internet connection");
100
+ }
101
+ if (response.status === 204) return void 0;
102
+ if (!response.ok) {
103
+ let serverMessage = "";
104
+ let dataMessage = "";
105
+ let retryable;
106
+ try {
107
+ const json = await response.json();
108
+ if (isErrorResponse(json)) {
109
+ serverMessage = json.statusMessage ?? json.message ?? "";
110
+ dataMessage = json.data?.message ?? "";
111
+ retryable = json.data?.retryable;
112
+ }
113
+ } catch {
114
+ }
115
+ if (response.status === 401) throw new CliError("INVALID_API_KEY", `Invalid or expired API key${serverMessage ? ` \u2014 ${serverMessage}` : ""}`, "Run: adkit setup");
116
+ if (response.status === 429) {
117
+ const retryAfter = response.headers.get("Retry-After") ?? "60";
118
+ throw new CliError("RATE_LIMITED", serverMessage || "Rate limit exceeded", `Wait ${retryAfter} seconds before retrying`);
119
+ }
120
+ if (response.status === 404) {
121
+ const fallback = `Not found: ${method} ${path2} \u2014 the resource may have been deleted or the ID is wrong`;
122
+ throw new CliError("NOT_FOUND", serverMessage || fallback, "Check the resource ID");
123
+ }
124
+ if (response.status >= 500) {
125
+ const errorMsg = dataMessage || serverMessage || `Server error (HTTP ${String(response.status)})`;
126
+ let suggestion;
127
+ if (retryable === true) suggestion = "Retry in a few seconds";
128
+ throw new CliError("SERVER_ERROR", errorMsg, suggestion);
129
+ }
130
+ throw new CliError("SERVER_ERROR", serverMessage || `Request failed (HTTP ${String(response.status)})`);
131
+ }
132
+ return response.json();
133
+ }
134
+ async get(path2) {
135
+ return this.request("GET", path2);
136
+ }
137
+ async post(path2, body) {
138
+ return this.request("POST", path2, body);
139
+ }
140
+ async patch(path2, body) {
141
+ return this.request("PATCH", path2, body);
142
+ }
143
+ async delete(path2) {
144
+ return this.request("DELETE", path2);
145
+ }
146
+ };
147
+
148
+ // src/output.ts
149
+ function filterFields(data, fields) {
150
+ return data.map((row) => {
151
+ const filtered = {};
152
+ for (const f of fields) {
153
+ if (f in row) filtered[f] = row[f];
154
+ }
155
+ return filtered;
156
+ });
157
+ }
158
+ function toStr(value) {
159
+ if (value == null) return "";
160
+ if (typeof value === "string") return value;
161
+ if (typeof value === "number" || typeof value === "boolean") return `${value}`;
162
+ return JSON.stringify(value);
163
+ }
164
+ function formatTable(data) {
165
+ if (data.length === 0) return "";
166
+ const keys = Object.keys(data[0]);
167
+ const widths = {};
168
+ for (const key of keys) {
169
+ widths[key] = key.length;
170
+ for (const row of data) {
171
+ const val = toStr(row[key]);
172
+ if (val.length > widths[key]) widths[key] = val.length;
173
+ }
174
+ }
175
+ const header = keys.map((k) => k.toUpperCase().padEnd(widths[k])).join(" ");
176
+ const separator = keys.map((k) => "-".repeat(widths[k])).join(" ");
177
+ const rows = data.map((row) => keys.map((k) => toStr(row[k]).padEnd(widths[k])).join(" "));
178
+ return [header, separator, ...rows].join("\n");
179
+ }
180
+ function formatOutput(data, options) {
181
+ let rows = data;
182
+ if (options.fields) {
183
+ rows = filterFields(rows, options.fields);
184
+ }
185
+ const json = options.json ?? !(process.stdout.isTTY ?? false);
186
+ if (json) {
187
+ return JSON.stringify(rows);
188
+ }
189
+ return formatTable(rows);
190
+ }
191
+
192
+ // ../../node_modules/open/index.js
193
+ import process7 from "node:process";
194
+ import { Buffer } from "node:buffer";
195
+ import path from "node:path";
196
+ import { fileURLToPath } from "node:url";
197
+ import { promisify as promisify5 } from "node:util";
198
+ import childProcess from "node:child_process";
199
+ import fs5, { constants as fsConstants2 } from "node:fs/promises";
200
+
201
+ // ../../node_modules/wsl-utils/index.js
202
+ import process3 from "node:process";
203
+ import fs4, { constants as fsConstants } from "node:fs/promises";
204
+
205
+ // ../../node_modules/is-wsl/index.js
206
+ import process2 from "node:process";
207
+ import os from "node:os";
208
+ import fs3 from "node:fs";
209
+
210
+ // ../../node_modules/is-inside-container/index.js
211
+ import fs2 from "node:fs";
212
+
213
+ // ../../node_modules/is-docker/index.js
214
+ import fs from "node:fs";
215
+ var isDockerCached;
216
+ function hasDockerEnv() {
217
+ try {
218
+ fs.statSync("/.dockerenv");
219
+ return true;
220
+ } catch {
221
+ return false;
222
+ }
223
+ }
224
+ function hasDockerCGroup() {
225
+ try {
226
+ return fs.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
227
+ } catch {
228
+ return false;
229
+ }
230
+ }
231
+ function isDocker() {
232
+ if (isDockerCached === void 0) {
233
+ isDockerCached = hasDockerEnv() || hasDockerCGroup();
234
+ }
235
+ return isDockerCached;
236
+ }
237
+
238
+ // ../../node_modules/is-inside-container/index.js
239
+ var cachedResult;
240
+ var hasContainerEnv = () => {
241
+ try {
242
+ fs2.statSync("/run/.containerenv");
243
+ return true;
244
+ } catch {
245
+ return false;
246
+ }
247
+ };
248
+ function isInsideContainer() {
249
+ if (cachedResult === void 0) {
250
+ cachedResult = hasContainerEnv() || isDocker();
251
+ }
252
+ return cachedResult;
253
+ }
254
+
255
+ // ../../node_modules/is-wsl/index.js
256
+ var isWsl = () => {
257
+ if (process2.platform !== "linux") {
258
+ return false;
259
+ }
260
+ if (os.release().toLowerCase().includes("microsoft")) {
261
+ if (isInsideContainer()) {
262
+ return false;
263
+ }
264
+ return true;
265
+ }
266
+ try {
267
+ return fs3.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isInsideContainer() : false;
268
+ } catch {
269
+ return false;
270
+ }
271
+ };
272
+ var is_wsl_default = process2.env.__IS_WSL_TEST__ ? isWsl : isWsl();
273
+
274
+ // ../../node_modules/wsl-utils/index.js
275
+ var wslDrivesMountPoint = /* @__PURE__ */ (() => {
276
+ const defaultMountPoint = "/mnt/";
277
+ let mountPoint;
278
+ return async function() {
279
+ if (mountPoint) {
280
+ return mountPoint;
281
+ }
282
+ const configFilePath = "/etc/wsl.conf";
283
+ let isConfigFileExists = false;
284
+ try {
285
+ await fs4.access(configFilePath, fsConstants.F_OK);
286
+ isConfigFileExists = true;
287
+ } catch {
288
+ }
289
+ if (!isConfigFileExists) {
290
+ return defaultMountPoint;
291
+ }
292
+ const configContent = await fs4.readFile(configFilePath, { encoding: "utf8" });
293
+ const configMountPoint = /(?<!#.*)root\s*=\s*(?<mountPoint>.*)/g.exec(configContent);
294
+ if (!configMountPoint) {
295
+ return defaultMountPoint;
296
+ }
297
+ mountPoint = configMountPoint.groups.mountPoint.trim();
298
+ mountPoint = mountPoint.endsWith("/") ? mountPoint : `${mountPoint}/`;
299
+ return mountPoint;
300
+ };
301
+ })();
302
+ var powerShellPathFromWsl = async () => {
303
+ const mountPoint = await wslDrivesMountPoint();
304
+ return `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`;
305
+ };
306
+ var powerShellPath = async () => {
307
+ if (is_wsl_default) {
308
+ return powerShellPathFromWsl();
309
+ }
310
+ return `${process3.env.SYSTEMROOT || process3.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
311
+ };
312
+
313
+ // ../../node_modules/define-lazy-prop/index.js
314
+ function defineLazyProperty(object, propertyName, valueGetter) {
315
+ const define = (value) => Object.defineProperty(object, propertyName, { value, enumerable: true, writable: true });
316
+ Object.defineProperty(object, propertyName, {
317
+ configurable: true,
318
+ enumerable: true,
319
+ get() {
320
+ const result = valueGetter();
321
+ define(result);
322
+ return result;
323
+ },
324
+ set(value) {
325
+ define(value);
326
+ }
327
+ });
328
+ return object;
329
+ }
330
+
331
+ // ../../node_modules/default-browser/index.js
332
+ import { promisify as promisify4 } from "node:util";
333
+ import process6 from "node:process";
334
+ import { execFile as execFile4 } from "node:child_process";
335
+
336
+ // ../../node_modules/default-browser-id/index.js
337
+ import { promisify } from "node:util";
338
+ import process4 from "node:process";
339
+ import { execFile } from "node:child_process";
340
+ var execFileAsync = promisify(execFile);
341
+ async function defaultBrowserId() {
342
+ if (process4.platform !== "darwin") {
343
+ throw new Error("macOS only");
344
+ }
345
+ const { stdout } = await execFileAsync("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
346
+ const match = /LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(stdout);
347
+ return match?.groups.id ?? "com.apple.Safari";
348
+ }
349
+
350
+ // ../../node_modules/run-applescript/index.js
351
+ import process5 from "node:process";
352
+ import { promisify as promisify2 } from "node:util";
353
+ import { execFile as execFile2, execFileSync } from "node:child_process";
354
+ var execFileAsync2 = promisify2(execFile2);
355
+ async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
356
+ if (process5.platform !== "darwin") {
357
+ throw new Error("macOS only");
358
+ }
359
+ const outputArguments = humanReadableOutput ? [] : ["-ss"];
360
+ const execOptions = {};
361
+ if (signal) {
362
+ execOptions.signal = signal;
363
+ }
364
+ const { stdout } = await execFileAsync2("osascript", ["-e", script, outputArguments], execOptions);
365
+ return stdout.trim();
366
+ }
367
+
368
+ // ../../node_modules/bundle-name/index.js
369
+ async function bundleName(bundleId) {
370
+ return runAppleScript(`tell application "Finder" to set app_path to application file id "${bundleId}" as string
371
+ tell application "System Events" to get value of property list item "CFBundleName" of property list file (app_path & ":Contents:Info.plist")`);
372
+ }
373
+
374
+ // ../../node_modules/default-browser/windows.js
375
+ import { promisify as promisify3 } from "node:util";
376
+ import { execFile as execFile3 } from "node:child_process";
377
+ var execFileAsync3 = promisify3(execFile3);
378
+ var windowsBrowserProgIds = {
379
+ AppXq0fevzme2pys62n3e0fbqa7peapykr8v: { name: "Edge", id: "com.microsoft.edge.old" },
380
+ MSEdgeDHTML: { name: "Edge", id: "com.microsoft.edge" },
381
+ // On macOS, it's "com.microsoft.edgemac"
382
+ MSEdgeHTM: { name: "Edge", id: "com.microsoft.edge" },
383
+ // Newer Edge/Win10 releases
384
+ "IE.HTTP": { name: "Internet Explorer", id: "com.microsoft.ie" },
385
+ FirefoxURL: { name: "Firefox", id: "org.mozilla.firefox" },
386
+ ChromeHTML: { name: "Chrome", id: "com.google.chrome" },
387
+ BraveHTML: { name: "Brave", id: "com.brave.Browser" },
388
+ BraveBHTML: { name: "Brave Beta", id: "com.brave.Browser.beta" },
389
+ BraveSSHTM: { name: "Brave Nightly", id: "com.brave.Browser.nightly" }
390
+ };
391
+ var UnknownBrowserError = class extends Error {
392
+ };
393
+ async function defaultBrowser(_execFileAsync = execFileAsync3) {
394
+ const { stdout } = await _execFileAsync("reg", [
395
+ "QUERY",
396
+ " HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
397
+ "/v",
398
+ "ProgId"
399
+ ]);
400
+ const match = /ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(stdout);
401
+ if (!match) {
402
+ throw new UnknownBrowserError(`Cannot find Windows browser in stdout: ${JSON.stringify(stdout)}`);
403
+ }
404
+ const { id } = match.groups;
405
+ const browser = windowsBrowserProgIds[id];
406
+ if (!browser) {
407
+ throw new UnknownBrowserError(`Unknown browser ID: ${id}`);
408
+ }
409
+ return browser;
410
+ }
411
+
412
+ // ../../node_modules/default-browser/index.js
413
+ var execFileAsync4 = promisify4(execFile4);
414
+ var titleize = (string) => string.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x) => x.toUpperCase());
415
+ async function defaultBrowser2() {
416
+ if (process6.platform === "darwin") {
417
+ const id = await defaultBrowserId();
418
+ const name = await bundleName(id);
419
+ return { name, id };
420
+ }
421
+ if (process6.platform === "linux") {
422
+ const { stdout } = await execFileAsync4("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
423
+ const id = stdout.trim();
424
+ const name = titleize(id.replace(/.desktop$/, "").replace("-", " "));
425
+ return { name, id };
426
+ }
427
+ if (process6.platform === "win32") {
428
+ return defaultBrowser();
429
+ }
430
+ throw new Error("Only macOS, Linux, and Windows are supported");
431
+ }
432
+
433
+ // ../../node_modules/open/index.js
434
+ var execFile5 = promisify5(childProcess.execFile);
435
+ var __dirname = path.dirname(fileURLToPath(import.meta.url));
436
+ var localXdgOpenPath = path.join(__dirname, "xdg-open");
437
+ var { platform, arch } = process7;
438
+ async function getWindowsDefaultBrowserFromWsl() {
439
+ const powershellPath = await powerShellPath();
440
+ const rawCommand = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
441
+ const encodedCommand = Buffer.from(rawCommand, "utf16le").toString("base64");
442
+ const { stdout } = await execFile5(
443
+ powershellPath,
444
+ [
445
+ "-NoProfile",
446
+ "-NonInteractive",
447
+ "-ExecutionPolicy",
448
+ "Bypass",
449
+ "-EncodedCommand",
450
+ encodedCommand
451
+ ],
452
+ { encoding: "utf8" }
453
+ );
454
+ const progId = stdout.trim();
455
+ const browserMap = {
456
+ ChromeHTML: "com.google.chrome",
457
+ BraveHTML: "com.brave.Browser",
458
+ MSEdgeHTM: "com.microsoft.edge",
459
+ FirefoxURL: "org.mozilla.firefox"
460
+ };
461
+ return browserMap[progId] ? { id: browserMap[progId] } : {};
462
+ }
463
+ var pTryEach = async (array, mapper) => {
464
+ let latestError;
465
+ for (const item of array) {
466
+ try {
467
+ return await mapper(item);
468
+ } catch (error) {
469
+ latestError = error;
470
+ }
471
+ }
472
+ throw latestError;
473
+ };
474
+ var baseOpen = async (options) => {
475
+ options = {
476
+ wait: false,
477
+ background: false,
478
+ newInstance: false,
479
+ allowNonzeroExitCode: false,
480
+ ...options
481
+ };
482
+ if (Array.isArray(options.app)) {
483
+ return pTryEach(options.app, (singleApp) => baseOpen({
484
+ ...options,
485
+ app: singleApp
486
+ }));
487
+ }
488
+ let { name: app, arguments: appArguments = [] } = options.app ?? {};
489
+ appArguments = [...appArguments];
490
+ if (Array.isArray(app)) {
491
+ return pTryEach(app, (appName) => baseOpen({
492
+ ...options,
493
+ app: {
494
+ name: appName,
495
+ arguments: appArguments
496
+ }
497
+ }));
498
+ }
499
+ if (app === "browser" || app === "browserPrivate") {
500
+ const ids = {
501
+ "com.google.chrome": "chrome",
502
+ "google-chrome.desktop": "chrome",
503
+ "com.brave.Browser": "brave",
504
+ "org.mozilla.firefox": "firefox",
505
+ "firefox.desktop": "firefox",
506
+ "com.microsoft.msedge": "edge",
507
+ "com.microsoft.edge": "edge",
508
+ "com.microsoft.edgemac": "edge",
509
+ "microsoft-edge.desktop": "edge"
510
+ };
511
+ const flags = {
512
+ chrome: "--incognito",
513
+ brave: "--incognito",
514
+ firefox: "--private-window",
515
+ edge: "--inPrivate"
516
+ };
517
+ const browser = is_wsl_default ? await getWindowsDefaultBrowserFromWsl() : await defaultBrowser2();
518
+ if (browser.id in ids) {
519
+ const browserName = ids[browser.id];
520
+ if (app === "browserPrivate") {
521
+ appArguments.push(flags[browserName]);
522
+ }
523
+ return baseOpen({
524
+ ...options,
525
+ app: {
526
+ name: apps[browserName],
527
+ arguments: appArguments
528
+ }
529
+ });
530
+ }
531
+ throw new Error(`${browser.name} is not supported as a default browser`);
532
+ }
533
+ let command;
534
+ const cliArguments = [];
535
+ const childProcessOptions = {};
536
+ if (platform === "darwin") {
537
+ command = "open";
538
+ if (options.wait) {
539
+ cliArguments.push("--wait-apps");
540
+ }
541
+ if (options.background) {
542
+ cliArguments.push("--background");
543
+ }
544
+ if (options.newInstance) {
545
+ cliArguments.push("--new");
546
+ }
547
+ if (app) {
548
+ cliArguments.push("-a", app);
549
+ }
550
+ } else if (platform === "win32" || is_wsl_default && !isInsideContainer() && !app) {
551
+ command = await powerShellPath();
552
+ cliArguments.push(
553
+ "-NoProfile",
554
+ "-NonInteractive",
555
+ "-ExecutionPolicy",
556
+ "Bypass",
557
+ "-EncodedCommand"
558
+ );
559
+ if (!is_wsl_default) {
560
+ childProcessOptions.windowsVerbatimArguments = true;
561
+ }
562
+ const encodedArguments = ["Start"];
563
+ if (options.wait) {
564
+ encodedArguments.push("-Wait");
565
+ }
566
+ if (app) {
567
+ encodedArguments.push(`"\`"${app}\`""`);
568
+ if (options.target) {
569
+ appArguments.push(options.target);
570
+ }
571
+ } else if (options.target) {
572
+ encodedArguments.push(`"${options.target}"`);
573
+ }
574
+ if (appArguments.length > 0) {
575
+ appArguments = appArguments.map((argument) => `"\`"${argument}\`""`);
576
+ encodedArguments.push("-ArgumentList", appArguments.join(","));
577
+ }
578
+ options.target = Buffer.from(encodedArguments.join(" "), "utf16le").toString("base64");
579
+ } else {
580
+ if (app) {
581
+ command = app;
582
+ } else {
583
+ const isBundled = !__dirname || __dirname === "/";
584
+ let exeLocalXdgOpen = false;
585
+ try {
586
+ await fs5.access(localXdgOpenPath, fsConstants2.X_OK);
587
+ exeLocalXdgOpen = true;
588
+ } catch {
589
+ }
590
+ const useSystemXdgOpen = process7.versions.electron ?? (platform === "android" || isBundled || !exeLocalXdgOpen);
591
+ command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
592
+ }
593
+ if (appArguments.length > 0) {
594
+ cliArguments.push(...appArguments);
595
+ }
596
+ if (!options.wait) {
597
+ childProcessOptions.stdio = "ignore";
598
+ childProcessOptions.detached = true;
599
+ }
600
+ }
601
+ if (platform === "darwin" && appArguments.length > 0) {
602
+ cliArguments.push("--args", ...appArguments);
603
+ }
604
+ if (options.target) {
605
+ cliArguments.push(options.target);
606
+ }
607
+ const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
608
+ if (options.wait) {
609
+ return new Promise((resolve, reject) => {
610
+ subprocess.once("error", reject);
611
+ subprocess.once("close", (exitCode) => {
612
+ if (!options.allowNonzeroExitCode && exitCode > 0) {
613
+ reject(new Error(`Exited with code ${exitCode}`));
614
+ return;
615
+ }
616
+ resolve(subprocess);
617
+ });
618
+ });
619
+ }
620
+ subprocess.unref();
621
+ return subprocess;
622
+ };
623
+ var open = (target, options) => {
624
+ if (typeof target !== "string") {
625
+ throw new TypeError("Expected a `target`");
626
+ }
627
+ return baseOpen({
628
+ ...options,
629
+ target
630
+ });
631
+ };
632
+ function detectArchBinary(binary) {
633
+ if (typeof binary === "string" || Array.isArray(binary)) {
634
+ return binary;
635
+ }
636
+ const { [arch]: archBinary } = binary;
637
+ if (!archBinary) {
638
+ throw new Error(`${arch} is not supported`);
639
+ }
640
+ return archBinary;
641
+ }
642
+ function detectPlatformBinary({ [platform]: platformBinary }, { wsl }) {
643
+ if (wsl && is_wsl_default) {
644
+ return detectArchBinary(wsl);
645
+ }
646
+ if (!platformBinary) {
647
+ throw new Error(`${platform} is not supported`);
648
+ }
649
+ return detectArchBinary(platformBinary);
650
+ }
651
+ var apps = {};
652
+ defineLazyProperty(apps, "chrome", () => detectPlatformBinary({
653
+ darwin: "google chrome",
654
+ win32: "chrome",
655
+ linux: ["google-chrome", "google-chrome-stable", "chromium"]
656
+ }, {
657
+ wsl: {
658
+ ia32: "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
659
+ x64: ["/mnt/c/Program Files/Google/Chrome/Application/chrome.exe", "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe"]
660
+ }
661
+ }));
662
+ defineLazyProperty(apps, "brave", () => detectPlatformBinary({
663
+ darwin: "brave browser",
664
+ win32: "brave",
665
+ linux: ["brave-browser", "brave"]
666
+ }, {
667
+ wsl: {
668
+ ia32: "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe",
669
+ x64: ["/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe", "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe"]
670
+ }
671
+ }));
672
+ defineLazyProperty(apps, "firefox", () => detectPlatformBinary({
673
+ darwin: "firefox",
674
+ win32: String.raw`C:\Program Files\Mozilla Firefox\firefox.exe`,
675
+ linux: "firefox"
676
+ }, {
677
+ wsl: "/mnt/c/Program Files/Mozilla Firefox/firefox.exe"
678
+ }));
679
+ defineLazyProperty(apps, "edge", () => detectPlatformBinary({
680
+ darwin: "microsoft edge",
681
+ win32: "msedge",
682
+ linux: ["microsoft-edge", "microsoft-edge-dev"]
683
+ }, {
684
+ wsl: "/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe"
685
+ }));
686
+ defineLazyProperty(apps, "browser", () => "browser");
687
+ defineLazyProperty(apps, "browserPrivate", () => "browserPrivate");
688
+ var open_default = open;
689
+
690
+ // src/commands/auth.ts
691
+ import { unlinkSync, existsSync as existsSync2 } from "node:fs";
692
+ import { hostname } from "node:os";
693
+ var MAX_POLL_ATTEMPTS = 450;
694
+ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
695
+ function createSpinner() {
696
+ let frame = 0;
697
+ let timer = null;
698
+ let currentText = "";
699
+ return {
700
+ start(text) {
701
+ currentText = text;
702
+ frame = 0;
703
+ timer = setInterval(() => {
704
+ process.stderr.write(`\r${SPINNER_FRAMES[frame++ % SPINNER_FRAMES.length]} ${currentText}`);
705
+ }, 80);
706
+ },
707
+ update(text) {
708
+ currentText = text;
709
+ },
710
+ stop(finalText) {
711
+ if (timer) clearInterval(timer);
712
+ process.stderr.write("\r\x1B[K");
713
+ if (finalText) console.log(finalText);
714
+ }
715
+ };
716
+ }
717
+ function printNextSteps(scope) {
718
+ const lines = ["Getting started:"];
719
+ if (scope?.includes("manage")) {
720
+ lines.push(" adkit meta accounts list List your connected ad accounts");
721
+ lines.push(" adkit meta campaigns list List campaigns");
722
+ lines.push(" adkit meta campaigns create Create a campaign");
723
+ lines.push(" adkit drafts list View pending drafts");
724
+ } else lines.push(" adkit setup manage Connect Meta Ads");
725
+ lines.push(" adkit --help See all commands");
726
+ lines.push("");
727
+ console.log(lines.join("\n"));
728
+ }
729
+ async function detectDefaultAccounts(baseUrl, apiKey) {
730
+ try {
731
+ const client = new AdkitClient({ apiKey, baseUrl });
732
+ const data = await client.get("/manage/status");
733
+ const config = readConfig();
734
+ if (!config?.selectedProject || !config.projects) return;
735
+ const project = config.projects[config.selectedProject];
736
+ if (!project) return;
737
+ let changed = false;
738
+ const metaAccounts = data.platforms?.meta?.accounts;
739
+ if (metaAccounts?.length === 1) {
740
+ project.defaultMetaAccount = metaAccounts[0].id;
741
+ changed = true;
742
+ console.log(`Default Meta account: ${metaAccounts[0].name} (${metaAccounts[0].id})`);
743
+ }
744
+ const googleAccounts = data.platforms?.google?.accounts;
745
+ if (googleAccounts?.length === 1) {
746
+ project.defaultGoogleAccount = googleAccounts[0].id;
747
+ changed = true;
748
+ console.log(`Default Google account: ${googleAccounts[0].name} (${googleAccounts[0].id})`);
749
+ }
750
+ if (changed) writeConfig({ projects: config.projects });
751
+ } catch {
752
+ }
753
+ }
754
+ async function login({ baseUrl, scope }) {
755
+ const spinner = createSpinner();
756
+ spinner.start("Connecting to AdKit...");
757
+ let createResponse;
758
+ try {
759
+ createResponse = await fetch(`${baseUrl}/auth/cli-session`, {
760
+ method: "POST",
761
+ headers: { "Content-Type": "application/json" },
762
+ body: JSON.stringify({ src: "cli", hostname: hostname(), scope: scope && scope.length > 0 ? scope : void 0 })
763
+ });
764
+ } catch {
765
+ spinner.stop();
766
+ throw new Error("Network connection failed \u2014 check your internet connection");
767
+ }
768
+ if (!createResponse.ok) {
769
+ spinner.stop();
770
+ let msg = "Failed to create session";
771
+ try {
772
+ const errData = await createResponse.json();
773
+ if (errData.message) msg = errData.message;
774
+ } catch {
775
+ }
776
+ throw new Error(msg);
777
+ }
778
+ const createData = await createResponse.json();
779
+ const sessionId = createData.session.sessionId;
780
+ const rawUrl = createData.session.url;
781
+ const origin = new URL(baseUrl).origin;
782
+ const sessionUrl = rawUrl.startsWith("http") ? rawUrl : `${origin}${rawUrl}`;
783
+ await open_default(sessionUrl);
784
+ spinner.stop(`\u2713 Browser opened \u2014 complete setup at ${sessionUrl}`);
785
+ spinner.start("Waiting for setup to complete...");
786
+ let projects;
787
+ let legacyApiKey;
788
+ for (let attempt = 0; attempt < MAX_POLL_ATTEMPTS; attempt++) {
789
+ let pollResponse;
790
+ try {
791
+ pollResponse = await fetch(`${baseUrl}/auth/cli-session/${sessionId}`, {
792
+ method: "GET"
793
+ });
794
+ } catch {
795
+ spinner.stop();
796
+ throw new Error("Network connection failed during polling");
797
+ }
798
+ if (!pollResponse.ok) {
799
+ spinner.stop();
800
+ if (pollResponse.status === 404) throw new Error("Session not found or expired");
801
+ throw new Error(`Poll failed with status ${pollResponse.status}`);
802
+ }
803
+ let pollData;
804
+ try {
805
+ pollData = await pollResponse.json();
806
+ } catch {
807
+ continue;
808
+ }
809
+ const status2 = pollData.session?.status;
810
+ if (status2 === "complete") {
811
+ projects = pollData.session.projects;
812
+ legacyApiKey = pollData.session.apiKey;
813
+ break;
814
+ }
815
+ if (status2 === "expired") {
816
+ spinner.stop();
817
+ throw new Error("Session expired \u2014 timed out waiting for authentication");
818
+ }
819
+ await new Promise((r) => setTimeout(r, 2e3));
820
+ }
821
+ spinner.stop();
822
+ if (!projects && !legacyApiKey) throw new Error("Login timed out \u2014 max poll attempts exceeded");
823
+ if (projects && projects.length > 0) {
824
+ const projectsMap = {};
825
+ for (const p of projects) projectsMap[p.id] = { name: p.name, apiKey: p.apiKey };
826
+ writeConfig({
827
+ projects: projectsMap,
828
+ selectedProject: projects[0].id,
829
+ apiKey: projects[0].apiKey
830
+ });
831
+ console.log("\n\u2705 AdKit is configured!\n");
832
+ const names = projects.map((p) => ` \u2022 ${p.name}`).join("\n");
833
+ console.log(`Projects:
834
+ ${names}
835
+ `);
836
+ if (scope?.includes("manage")) await detectDefaultAccounts(baseUrl, projects[0].apiKey);
837
+ printNextSteps(scope);
838
+ } else {
839
+ writeConfig({ apiKey: legacyApiKey });
840
+ console.log("\n\u2705 AdKit is configured!\n");
841
+ printNextSteps(scope);
842
+ }
843
+ }
844
+ function logout() {
845
+ if (existsSync2(CONFIG_PATH)) unlinkSync(CONFIG_PATH);
846
+ console.log("Logged out \u2014 API key removed.");
847
+ }
848
+
849
+ // src/commands/projects.ts
850
+ function listProjects(config) {
851
+ if (!config.projects) return [];
852
+ return Object.entries(config.projects).map(([id, value]) => {
853
+ const entry = { id, name: value.name, apiKey: value.apiKey };
854
+ if (config.selectedProject === id) {
855
+ entry.current = true;
856
+ }
857
+ return entry;
858
+ });
859
+ }
860
+ function useProject(projectId) {
861
+ const config = readConfig() ?? {};
862
+ if (!config.projects?.[projectId]) {
863
+ throw new Error(`Project not found: ${projectId}`);
864
+ }
865
+ writeConfig({ selectedProject: projectId });
866
+ }
867
+ function currentProject(config) {
868
+ if (!config.selectedProject) return null;
869
+ const entry = config.projects?.[config.selectedProject];
870
+ if (!entry) return null;
871
+ return { id: config.selectedProject, name: entry.name, apiKey: entry.apiKey };
872
+ }
873
+
874
+ // src/cli-utils.ts
875
+ function parseArgs(argv, options) {
876
+ const args = [];
877
+ const flags = {};
878
+ const multiSet = new Set(options?.multi);
879
+ for (let i = 0; i < argv.length; i++) {
880
+ const arg = argv[i];
881
+ if (!arg.startsWith("--")) {
882
+ args.push(arg);
883
+ continue;
884
+ }
885
+ const eqIdx = arg.indexOf("=");
886
+ let key;
887
+ let value;
888
+ if (eqIdx !== -1) {
889
+ key = arg.slice(2, eqIdx);
890
+ value = arg.slice(eqIdx + 1);
891
+ } else {
892
+ key = arg.slice(2);
893
+ const next = argv[i + 1];
894
+ if (next && !next.startsWith("--")) {
895
+ value = next;
896
+ i++;
897
+ } else value = true;
898
+ }
899
+ if (multiSet.has(key) && typeof value === "string") {
900
+ const existing = flags[key];
901
+ if (Array.isArray(existing)) existing.push(value);
902
+ else flags[key] = [value];
903
+ } else flags[key] = value;
904
+ }
905
+ return { args, flags };
906
+ }
907
+ var GLOBAL_FLAGS = ["account", "json", "fields", "publish", "data", "platform-overrides", "force", "project"];
908
+ function validateFlags(flags, allowed, command) {
909
+ const allAllowed = /* @__PURE__ */ new Set([...GLOBAL_FLAGS, ...allowed]);
910
+ const unknown = Object.keys(flags).filter((k) => !allAllowed.has(k));
911
+ if (unknown.length) throw new CliError("UNKNOWN_FLAG", `Unknown flag${unknown.length > 1 ? "s" : ""}: ${unknown.map((f) => `--${f}`).join(", ")}`, `Run: adkit ${command} --help`);
912
+ }
913
+ function unwrapList(data) {
914
+ if (Array.isArray(data)) return data;
915
+ if (data && typeof data === "object") {
916
+ const values = Object.values(data);
917
+ const arr = values.find((v) => Array.isArray(v));
918
+ if (arr) return arr;
919
+ }
920
+ return [];
921
+ }
922
+
923
+ // ../shared/dist/manage/meta/media-utils.js
924
+ var IMAGE_HASH_RE = /^[0-9a-f]{32}$/i;
925
+ var VIDEO_ID_RE = /^\d+$/;
926
+
927
+ // src/commands/meta.ts
928
+ function parseJsonObject(raw, label) {
929
+ let parsed;
930
+ try {
931
+ parsed = JSON.parse(raw);
932
+ } catch {
933
+ throw new CliError("INVALID_VALUE", `Invalid JSON in \`--${label}\``, `Check JSON syntax in --${label}`);
934
+ }
935
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new CliError("INVALID_VALUE", `Expected a JSON object in \`--${label}\``, `Check JSON syntax in --${label}`);
936
+ return parsed;
937
+ }
938
+ function dateStamp() {
939
+ return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
940
+ }
941
+ function generateCampaignName() {
942
+ return `campaign ${dateStamp()}`;
943
+ }
944
+ function generateAdSetName() {
945
+ return `adset ${dateStamp()}`;
946
+ }
947
+ function generateAdName() {
948
+ return `ad ${dateStamp()}`;
949
+ }
950
+ function generateCreativeName() {
951
+ return `creative ${dateStamp()}`;
952
+ }
953
+ function requireArg(args, index, label, hint) {
954
+ const val = args[index];
955
+ if (!val) throw new CliError("MISSING_ARGUMENT", `Missing required argument: \`<${label}>\``, hint);
956
+ return val;
957
+ }
958
+ function requireFlag(flags, key, hint) {
959
+ const val = flags[key];
960
+ if (typeof val !== "string") throw new CliError("MISSING_FLAG", `Missing required flag: \`--${key}\``, hint);
961
+ return val;
962
+ }
963
+ function parseDataFlag(flags, hint) {
964
+ const raw = requireFlag(flags, "data", hint);
965
+ try {
966
+ return JSON.parse(raw);
967
+ } catch {
968
+ const truncated = raw.length > 80 ? raw.slice(0, 80) + "..." : raw;
969
+ throw new CliError("INVALID_VALUE", `Invalid JSON in \`--data\` flag: ${truncated}`, "Check JSON syntax in --data");
970
+ }
971
+ }
972
+ function mergeAccountId(body, flags) {
973
+ if (typeof body !== "object" || body === null || Array.isArray(body)) return body;
974
+ const obj = body;
975
+ if (!obj.accountId) {
976
+ if (typeof flags.account === "string") obj.accountId = flags.account;
977
+ else {
978
+ const defaultAccount = getDefaultAccount("meta");
979
+ if (defaultAccount) obj.accountId = defaultAccount;
980
+ }
981
+ }
982
+ return obj;
983
+ }
984
+ function flagStr(flags, key) {
985
+ const val = flags[key];
986
+ if (typeof val === "string") return val;
987
+ if (Array.isArray(val)) return val[0];
988
+ return void 0;
989
+ }
990
+ function flagArr(flags, key) {
991
+ const val = flags[key];
992
+ if (Array.isArray(val)) return val;
993
+ if (typeof val === "string") return [val];
994
+ return [];
995
+ }
996
+ function queryString(params) {
997
+ const entries = Object.entries(params).filter((e) => e[1] !== void 0);
998
+ if (entries.length === 0) return "";
999
+ return "?" + entries.map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join("&");
1000
+ }
1001
+ function isMediaUploadResult(value) {
1002
+ if (typeof value !== "object" || value === null) return false;
1003
+ const obj = value;
1004
+ return obj.type === "image" && typeof obj.imageHash === "string" || obj.type === "video" && typeof obj.videoId === "string";
1005
+ }
1006
+ async function listAccounts(client, _args, _flags) {
1007
+ return client.get("/manage/meta/accounts");
1008
+ }
1009
+ async function connectAccount(client, args, _flags) {
1010
+ const id = requireArg(args, 0, "account-id", "Run: adkit manage meta accounts connect <account-id>");
1011
+ return client.post("/manage/meta/accounts/connect", { id });
1012
+ }
1013
+ async function disconnectAccount(client, args, _flags) {
1014
+ const id = requireArg(args, 0, "account-id", "Run: adkit manage meta accounts disconnect <account-id>");
1015
+ return client.delete(`/manage/meta/accounts/${id}`);
1016
+ }
1017
+ async function listPages(client, args, _flags) {
1018
+ const id = requireArg(args, 0, "account-id", "Run: adkit manage meta accounts <account-id> pages");
1019
+ return client.get(`/manage/meta/accounts/${id}/pages`);
1020
+ }
1021
+ async function listPixels(client, args, _flags) {
1022
+ const id = requireArg(args, 0, "account-id", "Run: adkit manage meta accounts <account-id> pixels");
1023
+ return client.get(`/manage/meta/accounts/${id}/pixels`);
1024
+ }
1025
+ function buildCampaignPayload(flags) {
1026
+ const payload = {};
1027
+ if (typeof flags.name === "string") payload.name = flags.name;
1028
+ if (typeof flags.objective === "string") payload.objective = flags.objective;
1029
+ if (typeof flags.status === "string") payload.status = flags.status;
1030
+ if (typeof flags["bid-strategy"] === "string") payload.bidStrategy = flags["bid-strategy"];
1031
+ if (flags.abo === true) payload.advantageCampaignBudget = false;
1032
+ else payload.advantageCampaignBudget = true;
1033
+ if (typeof flags["budget-daily"] === "string") payload.budget = { daily: parseFloat(flags["budget-daily"]) };
1034
+ if (typeof flags["budget-total"] === "string") payload.budget = { ...payload.budget, lifetime: parseFloat(flags["budget-total"]) };
1035
+ if (typeof flags["platform-overrides"] === "string") payload.platformOverrides = parseJsonObject(flags["platform-overrides"], "platform-overrides");
1036
+ return payload;
1037
+ }
1038
+ async function listCampaigns(client, _args, flags) {
1039
+ validateFlags(flags, [], "manage meta campaigns list");
1040
+ const accountId = typeof flags.account === "string" ? flags.account : void 0;
1041
+ const qs = queryString({ accountId });
1042
+ return client.get(`/manage/meta/campaigns${qs}`);
1043
+ }
1044
+ var CAMPAIGN_FLAGS = ["name", "objective", "status", "budget-daily", "budget-total", "abo", "bid-strategy"];
1045
+ var ADSET_FLAGS = ["campaign", "name", "status", "optimization", "budget-daily", "budget-total", "countries", "genders", "targeting", "pixel", "event-type", "interest"];
1046
+ var AD_FLAGS = ["creative", "adset", "name", "status", "media", "primary-text", "headline", "description", "cta", "url", "page"];
1047
+ var CREATIVE_FLAGS = ["page-id", "headline", "primary-text", "link-description", "link-url", "cta", "name", "image-hash", "image-url", "video-id", "force"];
1048
+ var MEDIA_FLAGS = ["file", "url", "account"];
1049
+ async function createCampaign(client, _args, flags) {
1050
+ if (typeof flags.data === "string") {
1051
+ const body2 = parseDataFlag(flags, "Check JSON syntax in --data");
1052
+ mergeAccountId(body2, flags);
1053
+ const publish2 = flags.publish === true ? "?publish=true" : "";
1054
+ return client.post(`/manage/meta/campaigns${publish2}`, body2);
1055
+ }
1056
+ validateFlags(flags, CAMPAIGN_FLAGS, "manage meta campaigns create");
1057
+ const payload = buildCampaignPayload(flags);
1058
+ if (!payload.name) payload.name = generateCampaignName();
1059
+ const body = { campaigns: [payload] };
1060
+ mergeAccountId(body, flags);
1061
+ const publish = flags.publish === true ? "?publish=true" : "";
1062
+ return client.post(`/manage/meta/campaigns${publish}`, body);
1063
+ }
1064
+ async function updateCampaign(client, args, flags) {
1065
+ const id = requireArg(args, 0, "campaign-id", `Run: adkit manage meta campaigns update <campaign-id> --status paused`);
1066
+ if (typeof flags.data === "string") {
1067
+ const body = parseDataFlag(flags, "Check JSON syntax in --data");
1068
+ mergeAccountId(body, flags);
1069
+ return client.patch(`/manage/meta/campaigns/${id}`, body);
1070
+ }
1071
+ validateFlags(flags, CAMPAIGN_FLAGS, "manage meta campaigns update");
1072
+ const payload = buildCampaignPayload(flags);
1073
+ mergeAccountId(payload, flags);
1074
+ return client.patch(`/manage/meta/campaigns/${id}`, payload);
1075
+ }
1076
+ async function deleteCampaign(client, args, _flags) {
1077
+ const id = requireArg(args, 0, "campaign-id", "Run: adkit manage meta campaigns delete <campaign-id>");
1078
+ return client.delete(`/manage/meta/campaigns/${id}`);
1079
+ }
1080
+ function buildAdSetPayload(flags) {
1081
+ const payload = {};
1082
+ if (typeof flags.campaign === "string") payload.campaignId = flags.campaign;
1083
+ if (typeof flags.name === "string") payload.name = flags.name;
1084
+ if (typeof flags.status === "string") payload.status = flags.status;
1085
+ if (typeof flags.optimization === "string") payload.optimization = flags.optimization;
1086
+ if (typeof flags["budget-daily"] === "string") payload.budget = { daily: parseFloat(flags["budget-daily"]) };
1087
+ if (typeof flags["budget-total"] === "string") payload.budget = { ...payload.budget, lifetime: parseFloat(flags["budget-total"]) };
1088
+ const targeting = {};
1089
+ if (typeof flags.countries === "string") targeting.countries = flags.countries.split(",");
1090
+ if (Array.isArray(flags.interest)) targeting.interests = flags.interest;
1091
+ else if (typeof flags.interest === "string") targeting.interests = [flags.interest];
1092
+ if (typeof flags.targeting === "string") Object.assign(targeting, parseJsonObject(flags.targeting, "targeting"));
1093
+ if (Object.keys(targeting).length) payload.targeting = targeting;
1094
+ if (typeof flags.pixel === "string") payload.pixelId = flags.pixel;
1095
+ if (typeof flags["event-type"] === "string") payload.eventType = flags["event-type"];
1096
+ if (typeof flags["platform-overrides"] === "string") payload.platformOverrides = parseJsonObject(flags["platform-overrides"], "platform-overrides");
1097
+ return payload;
1098
+ }
1099
+ async function listAdSets(client, _args, flags) {
1100
+ validateFlags(flags, ["campaign"], "manage meta adsets list");
1101
+ const accountId = typeof flags.account === "string" ? flags.account : void 0;
1102
+ const campaignId = typeof flags.campaign === "string" ? flags.campaign : void 0;
1103
+ const qs = queryString({ accountId, campaignId });
1104
+ return client.get(`/manage/meta/adsets${qs}`);
1105
+ }
1106
+ async function createAdSet(client, _args, flags) {
1107
+ if (typeof flags.data === "string") {
1108
+ const body2 = parseDataFlag(flags, "Check JSON syntax in --data");
1109
+ mergeAccountId(body2, flags);
1110
+ const publish2 = flags.publish === true ? "?publish=true" : "";
1111
+ return client.post(`/manage/meta/adsets${publish2}`, body2);
1112
+ }
1113
+ validateFlags(flags, ADSET_FLAGS, "manage meta adsets create");
1114
+ const payload = buildAdSetPayload(flags);
1115
+ if (!payload.campaignId) throw new CliError("MISSING_FLAG", "Missing required flag: `--campaign`", 'Run: adkit manage meta adsets create --campaign cmp_abc --name "US 25-44" --budget-daily 20 --optimization link_clicks');
1116
+ if (!payload.name) payload.name = generateAdSetName();
1117
+ const body = { adsets: [payload] };
1118
+ mergeAccountId(body, flags);
1119
+ const publish = flags.publish === true ? "?publish=true" : "";
1120
+ return client.post(`/manage/meta/adsets${publish}`, body);
1121
+ }
1122
+ async function updateAdSet(client, args, flags) {
1123
+ const id = requireArg(args, 0, "adset-id", `Run: adkit manage meta adsets update <adset-id> --budget-daily 50`);
1124
+ if (typeof flags.data === "string") {
1125
+ const body = parseDataFlag(flags, "Check JSON syntax in --data");
1126
+ mergeAccountId(body, flags);
1127
+ return client.patch(`/manage/meta/adsets/${id}`, body);
1128
+ }
1129
+ validateFlags(flags, ADSET_FLAGS, "manage meta adsets update");
1130
+ const payload = buildAdSetPayload(flags);
1131
+ mergeAccountId(payload, flags);
1132
+ return client.patch(`/manage/meta/adsets/${id}`, payload);
1133
+ }
1134
+ async function deleteAdSet(client, args, _flags) {
1135
+ const id = requireArg(args, 0, "adset-id", "Run: adkit manage meta adsets delete <adset-id>");
1136
+ return client.delete(`/manage/meta/adsets/${id}`);
1137
+ }
1138
+ async function listAds(client, _args, flags) {
1139
+ validateFlags(flags, ["adset"], "manage meta ads list");
1140
+ const accountId = typeof flags.account === "string" ? flags.account : void 0;
1141
+ const adsetId = typeof flags.adset === "string" ? flags.adset : void 0;
1142
+ const qs = queryString({ accountId, adsetId });
1143
+ return client.get(`/manage/meta/ads${qs}`);
1144
+ }
1145
+ async function createAd(client, _args, flags) {
1146
+ if (typeof flags.data === "string") {
1147
+ const body2 = parseDataFlag(flags, "Check JSON syntax in --data");
1148
+ mergeAccountId(body2, flags);
1149
+ const publish2 = flags.publish === true ? "?publish=true" : "";
1150
+ return client.post(`/manage/meta/ads${publish2}`, body2);
1151
+ }
1152
+ validateFlags(flags, AD_FLAGS, "manage meta ads create");
1153
+ const creativeId = typeof flags.creative === "string" ? flags.creative : void 0;
1154
+ const mediaFlags = ["media", "primary-text", "headline", "description", "cta"];
1155
+ const hasMediaFlags = mediaFlags.some((f) => flags[f] !== void 0);
1156
+ if (creativeId && hasMediaFlags) throw new CliError("INVALID_VALUE", "`--creative` cannot be combined with --media, --primary-text, --headline, --description, or --cta", "Use --creative to reference an existing creative, OR use --media/--primary-text/etc. to create a new one");
1157
+ if (creativeId) {
1158
+ const adsetId2 = requireFlag(flags, "adset", "Run: adkit manage meta ads create --creative cr_abc --adset as_xyz --publish");
1159
+ const ad2 = {
1160
+ adsetId: adsetId2,
1161
+ name: typeof flags.name === "string" ? flags.name : generateAdName(),
1162
+ creativeId
1163
+ };
1164
+ if (typeof flags.status === "string") ad2.status = flags.status;
1165
+ const body2 = { ads: [ad2] };
1166
+ mergeAccountId(body2, flags);
1167
+ const publish2 = flags.publish === true ? "?publish=true" : "";
1168
+ return client.post(`/manage/meta/ads${publish2}`, body2);
1169
+ }
1170
+ const mediaInputs = flagArr(flags, "media");
1171
+ const primaryTexts = flagArr(flags, "primary-text");
1172
+ const headlines = flagArr(flags, "headline");
1173
+ const descriptions = flagArr(flags, "description");
1174
+ if (mediaInputs.length === 0) throw new CliError("MISSING_FLAG", "Missing required flag: `--media` (or use `--creative` to reference an existing creative)", 'Run: adkit manage meta ads create --media ./hero.mp4 --primary-text "Hello" --adset as_xyz --publish');
1175
+ const adsetId = typeof flags.adset === "string" ? flags.adset : void 0;
1176
+ if (!adsetId) throw new CliError("MISSING_FLAG", "Missing required flag: `--adset`", "Run: adkit manage meta ads create --media ./hero.mp4 --adset as_789 --publish");
1177
+ function isMediaId(input) {
1178
+ return IMAGE_HASH_RE.test(input) || VIDEO_ID_RE.test(input);
1179
+ }
1180
+ const mediaIds = [];
1181
+ for (const input of mediaInputs) {
1182
+ if (isMediaId(input)) {
1183
+ mediaIds.push(input);
1184
+ } else {
1185
+ let uploadBody;
1186
+ if (input.startsWith("http://") || input.startsWith("https://")) uploadBody = { imageUrl: input };
1187
+ else {
1188
+ const fs6 = await import("node:fs");
1189
+ const path2 = await import("node:path");
1190
+ const VIDEO_EXTENSIONS = /* @__PURE__ */ new Set([".mp4", ".mov", ".avi", ".webm", ".mkv"]);
1191
+ const resolved = path2.resolve(input);
1192
+ const ext = path2.extname(resolved).toLowerCase();
1193
+ const filename = path2.basename(resolved);
1194
+ const base64 = fs6.readFileSync(resolved).toString("base64");
1195
+ if (VIDEO_EXTENSIONS.has(ext)) uploadBody = { videoBase64: base64, filename };
1196
+ else uploadBody = { imageBase64: base64, filename };
1197
+ }
1198
+ const result = await client.post("/manage/meta/media", uploadBody);
1199
+ if (!isMediaUploadResult(result)) throw new CliError("SERVER_ERROR", "Media upload did not return an image hash or video ID");
1200
+ const id = result.type === "image" ? result.imageHash : result.videoId;
1201
+ mediaIds.push(id);
1202
+ }
1203
+ }
1204
+ const ad = { adsetId, mediaIds };
1205
+ if (primaryTexts.length) ad.primaryTexts = primaryTexts;
1206
+ if (headlines.length) ad.headlines = headlines;
1207
+ if (descriptions.length) ad.descriptions = descriptions;
1208
+ if (typeof flags.cta === "string") ad.cta = flags.cta;
1209
+ if (typeof flags.name === "string") ad.name = flags.name;
1210
+ if (typeof flags.url === "string") ad.url = flags.url;
1211
+ if (typeof flags.page === "string") ad.pageId = flags.page;
1212
+ const body = { ads: [ad] };
1213
+ mergeAccountId(body, flags);
1214
+ const publish = flags.publish === true ? "?publish=true" : "";
1215
+ return client.post(`/manage/meta/ads${publish}`, body);
1216
+ }
1217
+ async function updateAd(client, args, flags) {
1218
+ const id = requireArg(args, 0, "ad-id", `Run: adkit manage meta ads update <ad-id> --data '{"status":"paused"}'`);
1219
+ const body = parseDataFlag(flags, "Check JSON syntax in --data");
1220
+ mergeAccountId(body, flags);
1221
+ return client.patch(`/manage/meta/ads/${id}`, body);
1222
+ }
1223
+ async function deleteAd(client, args, _flags) {
1224
+ const id = requireArg(args, 0, "ad-id", "Run: adkit manage meta ads delete <ad-id>");
1225
+ return client.delete(`/manage/meta/ads/${id}`);
1226
+ }
1227
+ function buildCreativePayload(flags) {
1228
+ const payload = {};
1229
+ const pageId = flagStr(flags, "page-id");
1230
+ const linkUrl = flagStr(flags, "link-url");
1231
+ const cta = flagStr(flags, "cta");
1232
+ const name = flagStr(flags, "name");
1233
+ const imageHash = flagStr(flags, "image-hash");
1234
+ const imageUrl = flagStr(flags, "image-url");
1235
+ const videoId = flagStr(flags, "video-id");
1236
+ if (pageId) payload.pageId = pageId;
1237
+ if (linkUrl) payload.linkUrl = linkUrl;
1238
+ if (cta) payload.cta = cta;
1239
+ if (name) payload.name = name;
1240
+ if (imageHash) payload.imageHash = imageHash;
1241
+ if (imageUrl) payload.imageUrl = imageUrl;
1242
+ if (videoId) payload.videoId = videoId;
1243
+ const headlines = flagArr(flags, "headline");
1244
+ if (headlines.length) payload.headlines = headlines;
1245
+ const primaryTexts = flagArr(flags, "primary-text");
1246
+ if (primaryTexts.length) payload.primaryTexts = primaryTexts;
1247
+ const linkDescriptions = flagArr(flags, "link-description");
1248
+ if (linkDescriptions.length) payload.linkDescriptions = linkDescriptions;
1249
+ if (typeof flags["platform-overrides"] === "string") payload.platformOverrides = parseJsonObject(flags["platform-overrides"], "platform-overrides");
1250
+ return payload;
1251
+ }
1252
+ async function createCreative(client, _args, flags) {
1253
+ if (typeof flags.data === "string") {
1254
+ const body = parseDataFlag(flags, "Check JSON syntax in --data");
1255
+ mergeAccountId(body, flags);
1256
+ const publish2 = flags.publish === true ? "?publish=true" : "";
1257
+ return client.post(`/manage/meta/creatives${publish2}`, body);
1258
+ }
1259
+ validateFlags(flags, CREATIVE_FLAGS, "manage meta creatives create");
1260
+ const payload = buildCreativePayload(flags);
1261
+ if (!payload.pageId) throw new CliError("MISSING_FLAG", "Missing required flag: `--page-id`", 'Run: adkit manage meta creatives create --page-id pg_123 --headline "Get Started" --primary-text "Try it free" --link-url https://example.com');
1262
+ if (!payload.headlines?.length) throw new CliError("MISSING_FLAG", "Missing required flag: `--headline`", 'Run: adkit manage meta creatives create --page-id pg_123 --headline "Get Started" --primary-text "Try it free" --link-url https://example.com');
1263
+ if (!payload.primaryTexts?.length) throw new CliError("MISSING_FLAG", "Missing required flag: `--primary-text`", 'Run: adkit manage meta creatives create --page-id pg_123 --headline "Get Started" --primary-text "Try it free" --link-url https://example.com');
1264
+ if (!payload.linkUrl) throw new CliError("MISSING_FLAG", "Missing required flag: `--link-url`", 'Run: adkit manage meta creatives create --page-id pg_123 --headline "Get Started" --primary-text "Try it free" --link-url https://example.com');
1265
+ const isMultiAsset = (payload.headlines?.length ?? 0) > 1 || (payload.primaryTexts?.length ?? 0) > 1 || (payload.linkDescriptions?.length ?? 0) > 1;
1266
+ if (isMultiAsset && flags.force !== true) throw new CliError("INVALID_VALUE", "Standalone creatives with multiple assets use Dynamic Creative format, which Meta doesn't support for sales/app_promotion. Use `ads create` instead (auto-detects the right format). Add --force to proceed anyway.");
1267
+ if (!payload.name) payload.name = generateCreativeName();
1268
+ mergeAccountId(payload, flags);
1269
+ const publish = flags.publish === true ? "?publish=true" : "";
1270
+ return client.post(`/manage/meta/creatives${publish}`, payload);
1271
+ }
1272
+ async function updateCreative(client, args, flags) {
1273
+ const id = requireArg(args, 0, "creative-id", `Run: adkit manage meta creatives update <creative-id> --primary-text "Start free trial"`);
1274
+ if (typeof flags.data === "string") {
1275
+ const body = parseDataFlag(flags, "Check JSON syntax in --data");
1276
+ mergeAccountId(body, flags);
1277
+ return client.patch(`/manage/meta/creatives/${id}`, body);
1278
+ }
1279
+ validateFlags(flags, CREATIVE_FLAGS, "manage meta creatives update");
1280
+ const payload = buildCreativePayload(flags);
1281
+ mergeAccountId(payload, flags);
1282
+ return client.patch(`/manage/meta/creatives/${id}`, payload);
1283
+ }
1284
+ async function deleteCreative(client, args, _flags) {
1285
+ const id = requireArg(args, 0, "creative-id", "Run: adkit manage meta creatives delete <creative-id>");
1286
+ return client.delete(`/manage/meta/creatives/${id}`);
1287
+ }
1288
+ async function searchInterests(client, args, flags) {
1289
+ if (!args.length) throw new CliError("MISSING_ARGUMENT", "Missing query", "Run: adkit manage meta interests search <query> [query2] [query3]");
1290
+ const accountId = typeof flags.account === "string" ? flags.account : void 0;
1291
+ const allResults = [];
1292
+ for (const query of args) {
1293
+ const qs = queryString({ accountId, q: query });
1294
+ const res = await client.get(`/manage/meta/interests/search${qs}`);
1295
+ const obj = res && typeof res === "object" && "results" in res ? res : null;
1296
+ const arr = obj && Array.isArray(obj.results) ? obj.results : [];
1297
+ for (const item of arr) allResults.push(item);
1298
+ }
1299
+ return { results: allResults };
1300
+ }
1301
+ async function uploadMedia(client, _args, flags) {
1302
+ validateFlags(flags, MEDIA_FLAGS, "manage meta media upload");
1303
+ const filePath = typeof flags.file === "string" ? flags.file : void 0;
1304
+ const url = typeof flags.url === "string" ? flags.url : void 0;
1305
+ if (!filePath && !url) throw new CliError("MISSING_FLAG", "Missing required flag: `--file` or `--url`", "Run: adkit manage meta media upload --file ./video.mp4");
1306
+ if (filePath) {
1307
+ const fs6 = await import("node:fs");
1308
+ const path2 = await import("node:path");
1309
+ const resolved = path2.resolve(filePath);
1310
+ const ext = path2.extname(resolved).toLowerCase();
1311
+ const isVideo = [".mp4", ".mov", ".avi", ".webm", ".mkv"].includes(ext);
1312
+ const base64 = fs6.readFileSync(resolved).toString("base64");
1313
+ const filename = path2.basename(resolved);
1314
+ if (isVideo) return client.post("/manage/meta/media", { videoBase64: base64, filename });
1315
+ else return client.post("/manage/meta/media", { imageBase64: base64, filename });
1316
+ }
1317
+ if (!url) throw new CliError("MISSING_FLAG", "Missing required flag: `--file` or `--url`");
1318
+ const VIDEO_EXTENSIONS = /* @__PURE__ */ new Set([".mp4", ".mov", ".avi", ".mkv", ".webm"]);
1319
+ const urlExt = new URL(url).pathname.match(/\.[^.]+$/)?.[0]?.toLowerCase() ?? "";
1320
+ if (VIDEO_EXTENSIONS.has(urlExt)) return client.post("/manage/meta/media", { videoUrl: url });
1321
+ return client.post("/manage/meta/media", { imageUrl: url });
1322
+ }
1323
+ async function listMedia(client, _args, flags) {
1324
+ const accountId = typeof flags.account === "string" ? flags.account : void 0;
1325
+ const qs = queryString({ accountId });
1326
+ return client.get(`/manage/meta/media${qs}`);
1327
+ }
1328
+ async function deleteMedia(client, args, flags) {
1329
+ const id = requireArg(args, 0, "media-id", "Run: adkit manage meta media delete <media-id>");
1330
+ const accountId = typeof flags.account === "string" ? flags.account : void 0;
1331
+ const qs = queryString({ accountId });
1332
+ return client.delete(`/manage/meta/media/${id}${qs}`);
1333
+ }
1334
+
1335
+ // src/commands/status.ts
1336
+ async function status(client, json) {
1337
+ const data = await client.get("/manage/status");
1338
+ if (json) {
1339
+ console.log(JSON.stringify(data));
1340
+ return;
1341
+ }
1342
+ const { project, platforms } = data;
1343
+ const lines = [];
1344
+ lines.push(`Project: ${project.name || "unnamed"} (${project.id})`);
1345
+ lines.push("");
1346
+ if (platforms.meta.connected) {
1347
+ lines.push("Meta: connected");
1348
+ for (const a of platforms.meta.accounts) {
1349
+ lines.push(` ${a.id} \u2014 ${a.name} (${a.currency}, ${a.status})`);
1350
+ if (a.defaults.pageId) lines.push(` Page: ${a.defaults.pageId}`);
1351
+ if (a.defaults.pixelId) lines.push(` Pixel: ${a.defaults.pixelId}`);
1352
+ }
1353
+ } else {
1354
+ lines.push("Meta: not connected");
1355
+ }
1356
+ if (platforms.google.connected) {
1357
+ lines.push("Google: connected");
1358
+ for (const a of platforms.google.accounts) {
1359
+ lines.push(` ${a.id} \u2014 ${a.name} (${a.currency})`);
1360
+ }
1361
+ } else {
1362
+ lines.push("Google: not connected");
1363
+ }
1364
+ console.log(lines.join("\n"));
1365
+ }
1366
+
1367
+ // src/commands/drafts.ts
1368
+ function requireArg2(args, index, label, hint) {
1369
+ const val = args[index];
1370
+ if (!val) {
1371
+ throw new CliError("MISSING_ARGUMENT", `Missing required argument: \`<${label}>\``, hint);
1372
+ }
1373
+ return val;
1374
+ }
1375
+ function queryString2(params) {
1376
+ const entries = Object.entries(params).filter((e) => e[1] !== void 0);
1377
+ if (entries.length === 0) return "";
1378
+ return "?" + entries.map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join("&");
1379
+ }
1380
+ var DRAFT_LIST_FLAGS = ["platform", "limit", "offset"];
1381
+ async function listDrafts(client, _args, flags) {
1382
+ validateFlags(flags, DRAFT_LIST_FLAGS, "manage drafts list");
1383
+ const platform2 = typeof flags.platform === "string" ? flags.platform : void 0;
1384
+ const limit = typeof flags.limit === "string" ? flags.limit : void 0;
1385
+ const offset = typeof flags.offset === "string" ? flags.offset : void 0;
1386
+ const qs = queryString2({ platform: platform2, limit, offset });
1387
+ return client.get(`/manage/drafts${qs}`);
1388
+ }
1389
+ async function getDraft(client, args, _flags) {
1390
+ const id = requireArg2(args, 0, "draft-id", "Run: adkit drafts get <draft-id>");
1391
+ return client.get(`/manage/drafts/${id}`);
1392
+ }
1393
+ async function publishDraft(client, args, _flags) {
1394
+ const id = requireArg2(args, 0, "draft-id", "Run: adkit drafts publish <draft-id>");
1395
+ return client.post(`/manage/drafts/${id}/publish`);
1396
+ }
1397
+ async function deleteDraft(client, args, _flags) {
1398
+ const id = requireArg2(args, 0, "draft-id", "Run: adkit drafts delete <draft-id>");
1399
+ return client.delete(`/manage/drafts/${id}`);
1400
+ }
1401
+
1402
+ // src/cli.ts
1403
+ var DEFAULT_BASE_URL = "https://app.adkit.so/api/v1";
1404
+ var USAGE = `
14
1405
  Usage: adkit <command> [options]
15
1406
 
16
1407
  Commands:
@@ -31,23 +1422,16 @@ Global flags:
31
1422
 
32
1423
  Run \`adkit <command> --help\` for details.
33
1424
  `.trim();
34
- // ---------------------------------------------------------------------------
35
- // Shared flag descriptions (DRY building blocks for help text)
36
- // ---------------------------------------------------------------------------
37
- const FLAG = {
38
- account: ' --account <id> Ad account ID (auto-resolved if only one)',
39
- publish: ' --publish Publish immediately (default: draft)',
40
- overrides: ' --platform-overrides <json> Raw Meta API fields merged onto payload',
41
- data: ' --data <json> Full JSON body bypasses named flags',
42
- status: ' --status <s> active, paused, archived',
43
- budgetDaily: ' --budget-daily <n> Daily budget in account currency',
44
- cta: ' --cta <type> sign_up, learn_more, shop_now, download, get_offer, contact_us, subscribe, get_quote, book_now, apply_now',
1425
+ var FLAG = {
1426
+ account: " --account <id> Ad account ID (auto-resolved if only one)",
1427
+ publish: " --publish Publish immediately (default: draft)",
1428
+ overrides: " --platform-overrides <json> Raw Meta API fields merged onto payload",
1429
+ data: " --data <json> Full JSON body \u2014 bypasses named flags",
1430
+ status: " --status <s> active, paused, archived",
1431
+ budgetDaily: " --budget-daily <n> Daily budget in account currency",
1432
+ cta: " --cta <type> sign_up, learn_more, shop_now, download, get_offer, contact_us, subscribe, get_quote, book_now, apply_now"
45
1433
  };
46
- // ---------------------------------------------------------------------------
47
- // Entity-specific help text
48
- // ---------------------------------------------------------------------------
49
- // --- Campaigns ---
50
- const CAMPAIGN_HELP = `adkit manage meta campaigns — Meta ad campaigns
1434
+ var CAMPAIGN_HELP = `adkit manage meta campaigns \u2014 Meta ad campaigns
51
1435
 
52
1436
  list List campaigns
53
1437
  create Create a campaign
@@ -66,7 +1450,7 @@ Examples:
66
1450
  adkit manage meta campaigns delete cmp_abc
67
1451
 
68
1452
  Run --help full for all fields and advanced options.`;
69
- const CAMPAIGN_HELP_FULL = `adkit manage meta campaigns Meta ad campaigns
1453
+ var CAMPAIGN_HELP_FULL = `adkit manage meta campaigns \u2014 Meta ad campaigns
70
1454
 
71
1455
  list List campaigns
72
1456
  create Create a campaign
@@ -101,8 +1485,7 @@ Examples:
101
1485
  "budget":{"lifetime":500},"specialAdCategories":["housing"],
102
1486
  "startDate":"2026-04-01T00:00:00+0000","endDate":"2026-04-30T23:59:59+0000"
103
1487
  }' --publish`;
104
- // --- Ad Sets ---
105
- const ADSET_HELP = `adkit manage meta adsets — Meta ad sets
1488
+ var ADSET_HELP = `adkit manage meta adsets \u2014 Meta ad sets
106
1489
 
107
1490
  list List ad sets
108
1491
  create Create an ad set
@@ -121,8 +1504,8 @@ ${FLAG.budgetDaily}
121
1504
  --interest <id> Interest ID (repeatable). Find IDs: adkit manage meta interests search <query>
122
1505
 
123
1506
  Rules:
124
- - objective=sales event-type: purchase, add_to_cart, complete_registration, subscribe, start_trial, content_view
125
- - objective=leads event-type: lead, contact, complete_registration, subscribe, other
1507
+ - objective=sales \u2192 event-type: purchase, add_to_cart, complete_registration, subscribe, start_trial, content_view
1508
+ - objective=leads \u2192 event-type: lead, contact, complete_registration, subscribe, other
126
1509
 
127
1510
  Examples:
128
1511
  adkit manage meta adsets create --campaign cmp_abc --name "US Broad" \\
@@ -134,7 +1517,7 @@ Examples:
134
1517
  adkit manage meta adsets delete as_xyz
135
1518
 
136
1519
  Run --help full for all fields and advanced options.`;
137
- const ADSET_HELP_FULL = `adkit manage meta adsets Meta ad sets
1520
+ var ADSET_HELP_FULL = `adkit manage meta adsets \u2014 Meta ad sets
138
1521
 
139
1522
  list List ad sets
140
1523
  create Create an ad set
@@ -153,8 +1536,8 @@ ${FLAG.budgetDaily}
153
1536
  --interest <id> Interest ID (repeatable). Find IDs: adkit manage meta interests search <query>
154
1537
 
155
1538
  Rules:
156
- - objective=sales event-type: purchase, add_to_cart, complete_registration, subscribe, start_trial, content_view
157
- - objective=leads event-type: lead, contact, complete_registration, subscribe, other
1539
+ - objective=sales \u2192 event-type: purchase, add_to_cart, complete_registration, subscribe, start_trial, content_view
1540
+ - objective=leads \u2192 event-type: lead, contact, complete_registration, subscribe, other
158
1541
 
159
1542
  Advanced flags:
160
1543
  --targeting <json> Complex targeting JSON, merged with simple flags (JSON keys take precedence)
@@ -199,15 +1582,14 @@ Examples:
199
1582
  }' --publish
200
1583
  adkit manage meta adsets update as_xyz --budget-daily 50
201
1584
  adkit manage meta adsets delete as_xyz`;
202
- // --- Ads ---
203
- const ADS_HELP = `adkit manage meta ads — Meta ads
1585
+ var ADS_HELP = `adkit manage meta ads \u2014 Meta ads
204
1586
 
205
1587
  list List ads
206
1588
  create Create an ad
207
1589
  update <id> Update an ad
208
1590
  delete <id> Delete an ad
209
1591
 
210
- Flags (create new creative from media):
1592
+ Flags (create \u2014 new creative from media):
211
1593
  --adset <id> Ad set ID (required)
212
1594
  --media <path|url> Media file or URL (repeatable). Handles upload + processing automatically
213
1595
  --primary-text <t> Ad body text (repeatable)
@@ -218,7 +1600,7 @@ ${FLAG.cta}
218
1600
  --url <url> Landing page URL
219
1601
  --page <id> Facebook Page ID (auto-resolved from account defaults)
220
1602
 
221
- Flags (create existing creative):
1603
+ Flags (create \u2014 existing creative):
222
1604
  --adset <id> Ad set ID (required)
223
1605
  --creative <id> Existing creative ID
224
1606
  --name <name> Ad name
@@ -236,14 +1618,14 @@ Examples:
236
1618
  adkit manage meta ads delete ad_123
237
1619
 
238
1620
  Run --help full for all fields and advanced options.`;
239
- const ADS_HELP_FULL = `adkit manage meta ads Meta ads
1621
+ var ADS_HELP_FULL = `adkit manage meta ads \u2014 Meta ads
240
1622
 
241
1623
  list List ads
242
1624
  create Create an ad
243
1625
  update <id> Update an ad
244
1626
  delete <id> Delete an ad
245
1627
 
246
- Flags (create new creative from media):
1628
+ Flags (create \u2014 new creative from media):
247
1629
  --adset <id> Ad set ID (required)
248
1630
  --media <path|url> Media file or URL (repeatable). Handles upload + processing automatically
249
1631
  --primary-text <t> Ad body text (repeatable)
@@ -254,7 +1636,7 @@ ${FLAG.cta}
254
1636
  --url <url> Landing page URL
255
1637
  --page <id> Facebook Page ID (auto-resolved from account defaults)
256
1638
 
257
- Flags (create existing creative):
1639
+ Flags (create \u2014 existing creative):
258
1640
  --adset <id> Ad set ID (required)
259
1641
  --creative <id> Existing creative ID
260
1642
  --name <name> Ad name
@@ -266,7 +1648,7 @@ Flags (list):
266
1648
  adsetId (required) Parent ad set ID
267
1649
  name (required) Ad name
268
1650
  status active, paused, archived, deleted
269
- creative { creativeId: "cr_..." } reference existing creative
1651
+ creative { creativeId: "cr_..." } \u2014 reference existing creative
270
1652
  platformOverrides Raw Meta API fields merged onto the payload
271
1653
 
272
1654
  Examples:
@@ -278,8 +1660,7 @@ Examples:
278
1660
  adkit manage meta ads list --adset as_xyz
279
1661
  adkit manage meta ads update ad_123 --data '{"status":"paused"}'
280
1662
  adkit manage meta ads delete ad_123`;
281
- // --- Creatives ---
282
- const CREATIVE_HELP = `adkit manage meta creatives — Meta ad creatives
1663
+ var CREATIVE_HELP = `adkit manage meta creatives \u2014 Meta ad creatives
283
1664
 
284
1665
  Prefer using "ads create --media" which handles creative creation automatically.
285
1666
 
@@ -306,7 +1687,7 @@ Examples:
306
1687
  adkit manage meta creatives delete cr_abc
307
1688
 
308
1689
  Run --help full for all fields and advanced options.`;
309
- const CREATIVE_HELP_FULL = `adkit manage meta creatives Meta ad creatives
1690
+ var CREATIVE_HELP_FULL = `adkit manage meta creatives \u2014 Meta ad creatives
310
1691
 
311
1692
  Prefer using "ads create --media" which handles creative creation automatically.
312
1693
 
@@ -346,11 +1727,8 @@ Examples:
346
1727
  }' --publish
347
1728
  adkit manage meta creatives update cr_abc --primary-text "Start free trial"
348
1729
  adkit manage meta creatives delete cr_abc`;
349
- // ---------------------------------------------------------------------------
350
- // Composed HELP and HELP_FULL
351
- // ---------------------------------------------------------------------------
352
- const HELP = {
353
- 'meta accounts': `adkit manage meta accounts — Meta ad accounts
1730
+ var HELP = {
1731
+ "meta accounts": `adkit manage meta accounts \u2014 Meta ad accounts
354
1732
 
355
1733
  list List connected ad accounts
356
1734
  connect <id> Connect an ad account
@@ -363,11 +1741,11 @@ Examples:
363
1741
  adkit manage meta accounts connect act_123456789
364
1742
  adkit manage meta accounts act_123456789 pages
365
1743
  adkit manage meta accounts disconnect act_123456789`.trim(),
366
- 'meta campaigns': CAMPAIGN_HELP,
367
- 'meta adsets': ADSET_HELP,
368
- 'meta ads': ADS_HELP,
369
- 'meta creatives': CREATIVE_HELP,
370
- 'meta media': `adkit manage meta media Upload media to Meta
1744
+ "meta campaigns": CAMPAIGN_HELP,
1745
+ "meta adsets": ADSET_HELP,
1746
+ "meta ads": ADS_HELP,
1747
+ "meta creatives": CREATIVE_HELP,
1748
+ "meta media": `adkit manage meta media \u2014 Upload media to Meta
371
1749
 
372
1750
  upload Upload an image or video
373
1751
 
@@ -378,7 +1756,7 @@ Flags:
378
1756
  Examples:
379
1757
  adkit manage meta media upload --file ./hero-video.mp4
380
1758
  adkit manage meta media upload --url https://example.com/hero.png`.trim(),
381
- 'meta interests': `adkit manage meta interests Search targeting interests
1759
+ "meta interests": `adkit manage meta interests \u2014 Search targeting interests
382
1760
 
383
1761
  search <query> Search for interests (multiple queries supported)
384
1762
 
@@ -387,14 +1765,14 @@ Output: Returns id and name for each interest. Use the id with --interest flag.
387
1765
  Examples:
388
1766
  adkit manage meta interests search "yoga"
389
1767
  adkit manage meta interests search "saas" "marketing" "digital ads"`.trim(),
390
- manage: `adkit manage Ad platform management
1768
+ manage: `adkit manage \u2014 Ad platform management
391
1769
 
392
1770
  Platforms:
393
1771
  meta Meta (Facebook/Instagram) ads
394
1772
  drafts Manage drafts across platforms
395
1773
 
396
1774
  Run adkit manage <platform> --help for details.`.trim(),
397
- meta: `adkit manage meta Meta Ads management
1775
+ meta: `adkit manage meta \u2014 Meta Ads management
398
1776
 
399
1777
  Entity groups:
400
1778
  accounts List connected ad accounts
@@ -411,7 +1789,7 @@ ${FLAG.data}
411
1789
 
412
1790
  Mutations are draft-first by default. Use --publish to publish immediately.
413
1791
  Run adkit manage meta <group> --help for details.`.trim(),
414
- drafts: `adkit manage drafts Manage drafts
1792
+ drafts: `adkit manage drafts \u2014 Manage drafts
415
1793
 
416
1794
  list List all drafts
417
1795
  get <id> Get a draft by ID
@@ -427,7 +1805,7 @@ Examples:
427
1805
  adkit manage drafts list --platform meta --limit 10
428
1806
  adkit manage drafts publish dft_abc123
429
1807
  adkit manage drafts delete dft_abc123`.trim(),
430
- status: `adkit status Show project context and connected accounts
1808
+ status: `adkit status \u2014 Show project context and connected accounts
431
1809
 
432
1810
  Displays project name, connected platforms, and ad accounts with defaults.
433
1811
  AI agents should call this first to understand the context.
@@ -435,7 +1813,7 @@ AI agents should call this first to understand the context.
435
1813
  Examples:
436
1814
  adkit status
437
1815
  adkit status --json`.trim(),
438
- projects: `adkit projects Manage projects
1816
+ projects: `adkit projects \u2014 Manage projects
439
1817
 
440
1818
  list List all configured projects
441
1819
  use <id> Switch active project
@@ -443,399 +1821,372 @@ Examples:
443
1821
 
444
1822
  Examples:
445
1823
  adkit projects list
446
- adkit projects use proj_abc123`.trim(),
1824
+ adkit projects use proj_abc123`.trim()
447
1825
  };
448
- const HELP_FULL = {
449
- 'meta campaigns': CAMPAIGN_HELP_FULL,
450
- 'meta adsets': ADSET_HELP_FULL,
451
- 'meta ads': ADS_HELP_FULL,
452
- 'meta creatives': CREATIVE_HELP_FULL,
1826
+ var HELP_FULL = {
1827
+ "meta campaigns": CAMPAIGN_HELP_FULL,
1828
+ "meta adsets": ADSET_HELP_FULL,
1829
+ "meta ads": ADS_HELP_FULL,
1830
+ "meta creatives": CREATIVE_HELP_FULL
453
1831
  };
454
1832
  function getBaseUrl() {
455
- return process.env.ADKIT_BASE_URL || DEFAULT_BASE_URL;
1833
+ return process.env.ADKIT_BASE_URL || DEFAULT_BASE_URL;
456
1834
  }
457
1835
  function wantsJson(flags) {
458
- return flags.json === true || !(process.stdout.isTTY ?? false);
1836
+ return flags.json === true || !(process.stdout.isTTY ?? false);
459
1837
  }
460
1838
  function requireClient(flags) {
461
- const projectFlag = typeof flags.project === 'string' ? flags.project : undefined;
462
- const { apiKey } = resolveConfig({ project: projectFlag });
463
- if (!apiKey)
464
- throw new CliError('NOT_AUTHENTICATED', 'No API key found', 'Run: adkit setup');
465
- return new AdkitClient({ apiKey, baseUrl: getBaseUrl() });
466
- }
467
- function printList(data, flags, emptyHint = 'No results.') {
468
- const rows = unwrapList(data);
469
- const fields = typeof flags.fields === 'string' ? flags.fields.split(',') : undefined;
470
- const output = formatOutput(rows, { fields, json: wantsJson(flags) });
471
- if (output)
472
- console.log(output);
473
- else
474
- console.log(emptyHint);
1839
+ const projectFlag = typeof flags.project === "string" ? flags.project : void 0;
1840
+ const { apiKey } = resolveConfig({ project: projectFlag });
1841
+ if (!apiKey) throw new CliError("NOT_AUTHENTICATED", "No API key found", "Run: adkit setup");
1842
+ return new AdkitClient({ apiKey, baseUrl: getBaseUrl() });
1843
+ }
1844
+ function printList(data, flags, emptyHint = "No results.") {
1845
+ const rows = unwrapList(data);
1846
+ const fields = typeof flags.fields === "string" ? flags.fields.split(",") : void 0;
1847
+ const output = formatOutput(rows, { fields, json: wantsJson(flags) });
1848
+ if (output) console.log(output);
1849
+ else console.log(emptyHint);
475
1850
  }
476
1851
  function hasArrayValues(v) {
477
- return v !== null && typeof v === 'object' && !Array.isArray(v) && Object.values(v).some(Array.isArray);
1852
+ return v !== null && typeof v === "object" && !Array.isArray(v) && Object.values(v).some(Array.isArray);
478
1853
  }
479
1854
  function printResult(data, flags, emptyHint) {
480
- if (data === undefined) {
481
- console.log('Done.');
482
- return;
483
- }
484
- if (wantsJson(flags))
485
- console.log(JSON.stringify(data));
486
- else if (Array.isArray(data) || hasArrayValues(data))
487
- printList(data, flags, emptyHint);
488
- else
489
- console.log(JSON.stringify(data, null, 2));
1855
+ if (data === void 0) {
1856
+ console.log("Done.");
1857
+ return;
1858
+ }
1859
+ if (wantsJson(flags)) console.log(JSON.stringify(data));
1860
+ else if (Array.isArray(data) || hasArrayValues(data)) printList(data, flags, emptyHint);
1861
+ else console.log(JSON.stringify(data, null, 2));
490
1862
  }
491
1863
  function showHelp(key, full = false) {
492
- const text = full ? HELP_FULL[key] || HELP[key] : HELP[key];
493
- if (text) {
494
- console.log(text);
495
- return true;
496
- }
497
- return false;
1864
+ const text = full ? HELP_FULL[key] || HELP[key] : HELP[key];
1865
+ if (text) {
1866
+ console.log(text);
1867
+ return true;
1868
+ }
1869
+ return false;
498
1870
  }
499
1871
  async function main() {
500
- const { args, flags } = parseArgs(process.argv.slice(2), {
501
- multi: ['media', 'primary-text', 'headline', 'description', 'link-description', 'interest'],
502
- });
503
- if (args.length === 0) {
504
- console.log(USAGE);
505
- process.exit(0);
1872
+ const { args, flags } = parseArgs(process.argv.slice(2), {
1873
+ multi: ["media", "primary-text", "headline", "description", "link-description", "interest"]
1874
+ });
1875
+ if (args.length === 0) {
1876
+ console.log(USAGE);
1877
+ process.exit(0);
1878
+ }
1879
+ if (flags.help && args.length === 0) {
1880
+ console.log(USAGE);
1881
+ process.exit(0);
1882
+ }
1883
+ try {
1884
+ if (args[0] === "status") {
1885
+ const client = requireClient(flags);
1886
+ await status(client, wantsJson(flags));
1887
+ return;
506
1888
  }
507
- // Top-level --help with no command
508
- if (flags.help && args.length === 0) {
1889
+ if (args[0] === "manage") {
1890
+ const manageTarget = args[1];
1891
+ if (flags.help && !manageTarget) {
1892
+ showHelp("manage", flags.help === "full");
1893
+ process.exit(0);
1894
+ }
1895
+ if (!manageTarget) {
1896
+ showHelp("manage", flags.help === "full");
1897
+ process.exit(0);
1898
+ }
1899
+ if (manageTarget === "drafts") {
1900
+ const action2 = args[2];
1901
+ const restArgs2 = args.slice(3);
1902
+ if (flags.help) {
1903
+ showHelp("drafts", flags.help === "full");
1904
+ process.exit(0);
1905
+ }
1906
+ const client2 = requireClient(flags);
1907
+ let data2;
1908
+ let emptyHint2;
1909
+ switch (action2) {
1910
+ case "list":
1911
+ case void 0:
1912
+ data2 = await listDrafts(client2, restArgs2, flags);
1913
+ emptyHint2 = "No drafts found. Drafts are created automatically when you create or update ads without `--publish`.";
1914
+ break;
1915
+ case "get":
1916
+ data2 = await getDraft(client2, restArgs2, flags);
1917
+ break;
1918
+ case "publish":
1919
+ data2 = await publishDraft(client2, restArgs2, flags);
1920
+ break;
1921
+ case "delete":
1922
+ data2 = await deleteDraft(client2, restArgs2, flags);
1923
+ break;
1924
+ default:
1925
+ throw new CliError("UNKNOWN_COMMAND", `Unknown action: manage drafts ${action2}`, "Available: list, get, publish, delete");
1926
+ }
1927
+ printResult(data2, flags, emptyHint2);
1928
+ return;
1929
+ }
1930
+ const platform2 = manageTarget;
1931
+ if (platform2 !== "meta") throw new CliError("UNKNOWN_COMMAND", `Unknown platform: ${platform2}`, "Available: meta");
1932
+ const entity = args[2];
1933
+ const action = args[3];
1934
+ const restArgs = args.slice(4);
1935
+ if (flags.help) {
1936
+ const helpKey = entity ? `meta ${entity}` : "meta";
1937
+ if (showHelp(helpKey, flags.help === "full")) process.exit(0);
509
1938
  console.log(USAGE);
510
1939
  process.exit(0);
511
- }
512
- try {
513
- // --- status ---
514
- if (args[0] === 'status') {
515
- const client = requireClient(flags);
516
- await status(client, wantsJson(flags));
517
- return;
1940
+ }
1941
+ if (!entity) {
1942
+ showHelp("meta", flags.help === "full");
1943
+ process.exit(0);
1944
+ }
1945
+ const client = requireClient(flags);
1946
+ let data;
1947
+ let emptyHint;
1948
+ switch (entity) {
1949
+ case "accounts": {
1950
+ if (action && action !== "list" && action !== "connect" && action !== "disconnect") {
1951
+ const accountId = action;
1952
+ const sub = args[4];
1953
+ if (sub === "pages") {
1954
+ data = await listPages(client, [accountId], flags);
1955
+ emptyHint = "No Facebook Pages found for this account.";
1956
+ } else if (sub === "pixels") {
1957
+ data = await listPixels(client, [accountId], flags);
1958
+ emptyHint = "No Meta Pixels found for this account.";
1959
+ } else throw new CliError("UNKNOWN_COMMAND", `Unknown subcommand: meta accounts ${accountId} ${sub ?? ""}`, "Expected: pages or pixels");
1960
+ break;
1961
+ }
1962
+ switch (action) {
1963
+ case "list":
1964
+ case void 0:
1965
+ data = await listAccounts(client, restArgs, flags);
1966
+ emptyHint = "No Meta ad accounts connected. Run `adkit setup manage` or connect via https://app.adkit.so/settings/integrations";
1967
+ break;
1968
+ case "connect":
1969
+ data = await connectAccount(client, restArgs, flags);
1970
+ break;
1971
+ case "disconnect":
1972
+ data = await disconnectAccount(client, restArgs, flags);
1973
+ break;
1974
+ default:
1975
+ throw new CliError("UNKNOWN_COMMAND", `Unknown action: meta accounts ${action}`, "Run: adkit manage meta accounts --help");
1976
+ }
1977
+ break;
518
1978
  }
519
- // --- manage commands (platform management) ---
520
- if (args[0] === 'manage') {
521
- const manageTarget = args[1];
522
- if (flags.help && !manageTarget) {
523
- showHelp('manage', flags.help === 'full');
524
- process.exit(0);
525
- }
526
- if (!manageTarget) {
527
- showHelp('manage', flags.help === 'full');
528
- process.exit(0);
529
- }
530
- // --- manage drafts ---
531
- if (manageTarget === 'drafts') {
532
- const action = args[2];
533
- const restArgs = args.slice(3);
534
- if (flags.help) {
535
- showHelp('drafts', flags.help === 'full');
536
- process.exit(0);
537
- }
538
- const client = requireClient(flags);
539
- let data;
540
- let emptyHint;
541
- switch (action) {
542
- case 'list':
543
- case undefined:
544
- data = await listDrafts(client, restArgs, flags);
545
- emptyHint = 'No drafts found. Drafts are created automatically when you create or update ads without `--publish`.';
546
- break;
547
- case 'get':
548
- data = await getDraft(client, restArgs, flags);
549
- break;
550
- case 'publish':
551
- data = await publishDraft(client, restArgs, flags);
552
- break;
553
- case 'delete':
554
- data = await deleteDraft(client, restArgs, flags);
555
- break;
556
- default:
557
- throw new CliError('UNKNOWN_COMMAND', `Unknown action: manage drafts ${action}`, 'Available: list, get, publish, delete');
558
- }
559
- printResult(data, flags, emptyHint);
560
- return;
561
- }
562
- // --- manage <platform> (meta, google, etc.) ---
563
- const platform = manageTarget;
564
- if (platform !== 'meta')
565
- throw new CliError('UNKNOWN_COMMAND', `Unknown platform: ${platform}`, 'Available: meta');
566
- const entity = args[2];
567
- const action = args[3];
568
- const restArgs = args.slice(4);
569
- // Help routing
570
- if (flags.help) {
571
- const helpKey = entity ? `meta ${entity}` : 'meta';
572
- if (showHelp(helpKey, flags.help === 'full'))
573
- process.exit(0);
574
- console.log(USAGE);
575
- process.exit(0);
576
- }
577
- if (!entity) {
578
- showHelp('meta', flags.help === 'full');
579
- process.exit(0);
580
- }
581
- const client = requireClient(flags);
582
- let data;
583
- let emptyHint;
584
- switch (entity) {
585
- case 'accounts': {
586
- // Special case: meta accounts <id> pages/pixels
587
- if (action && action !== 'list' && action !== 'connect' && action !== 'disconnect') {
588
- const accountId = action;
589
- const sub = args[4];
590
- if (sub === 'pages') {
591
- data = await listPages(client, [accountId], flags);
592
- emptyHint = 'No Facebook Pages found for this account.';
593
- }
594
- else if (sub === 'pixels') {
595
- data = await listPixels(client, [accountId], flags);
596
- emptyHint = 'No Meta Pixels found for this account.';
597
- }
598
- else
599
- throw new CliError('UNKNOWN_COMMAND', `Unknown subcommand: meta accounts ${accountId} ${sub ?? ''}`, 'Expected: pages or pixels');
600
- break;
601
- }
602
- switch (action) {
603
- case 'list':
604
- case undefined:
605
- data = await listAccounts(client, restArgs, flags);
606
- emptyHint = 'No Meta ad accounts connected. Run `adkit setup manage` or connect via https://app.adkit.so/settings/integrations';
607
- break;
608
- case 'connect':
609
- data = await connectAccount(client, restArgs, flags);
610
- break;
611
- case 'disconnect':
612
- data = await disconnectAccount(client, restArgs, flags);
613
- break;
614
- default:
615
- throw new CliError('UNKNOWN_COMMAND', `Unknown action: meta accounts ${action}`, 'Run: adkit manage meta accounts --help');
616
- }
617
- break;
618
- }
619
- case 'campaigns': {
620
- if (!action) {
621
- showHelp('meta campaigns', flags.help === 'full');
622
- process.exit(0);
623
- }
624
- switch (action) {
625
- case 'list':
626
- data = await listCampaigns(client, restArgs, flags);
627
- emptyHint = 'No campaigns found. Create one with `adkit manage meta campaigns create --name "My Campaign" --objective sales --publish`.';
628
- break;
629
- case 'create':
630
- data = await createCampaign(client, restArgs, flags);
631
- break;
632
- case 'update':
633
- data = await updateCampaign(client, restArgs, flags);
634
- break;
635
- case 'delete':
636
- data = await deleteCampaign(client, restArgs, flags);
637
- break;
638
- default:
639
- throw new CliError('UNKNOWN_COMMAND', `Unknown action: meta campaigns ${action}`, 'Run: adkit manage meta campaigns --help');
640
- }
641
- break;
642
- }
643
- case 'adsets': {
644
- if (!action) {
645
- showHelp('meta adsets', flags.help === 'full');
646
- process.exit(0);
647
- }
648
- switch (action) {
649
- case 'list':
650
- data = await listAdSets(client, restArgs, flags);
651
- emptyHint = 'No ad sets found. Create one with `adkit manage meta adsets create --campaign cmp_123 --name "My AdSet" --publish`.';
652
- break;
653
- case 'create':
654
- data = await createAdSet(client, restArgs, flags);
655
- break;
656
- case 'update':
657
- data = await updateAdSet(client, restArgs, flags);
658
- break;
659
- case 'delete':
660
- data = await deleteAdSet(client, restArgs, flags);
661
- break;
662
- default:
663
- throw new CliError('UNKNOWN_COMMAND', `Unknown action: meta adsets ${action}`, 'Run: adkit manage meta adsets --help');
664
- }
665
- break;
666
- }
667
- case 'ads': {
668
- if (!action) {
669
- showHelp('meta ads', flags.help === 'full');
670
- process.exit(0);
671
- }
672
- switch (action) {
673
- case 'list':
674
- data = await listAds(client, restArgs, flags);
675
- emptyHint = 'No ads found. Create one with `adkit manage meta ads create --data \'{"adsetId":"as_123","creativeId":"cr_123","name":"My Ad"}\'`.';
676
- break;
677
- case 'create':
678
- data = await createAd(client, restArgs, flags);
679
- break;
680
- case 'update':
681
- data = await updateAd(client, restArgs, flags);
682
- break;
683
- case 'delete':
684
- data = await deleteAd(client, restArgs, flags);
685
- break;
686
- default:
687
- throw new CliError('UNKNOWN_COMMAND', `Unknown action: meta ads ${action}`, 'Run: adkit manage meta ads --help');
688
- }
689
- break;
690
- }
691
- case 'creatives': {
692
- switch (action) {
693
- case 'create':
694
- data = await createCreative(client, restArgs, flags);
695
- break;
696
- case 'update':
697
- data = await updateCreative(client, restArgs, flags);
698
- break;
699
- case 'delete':
700
- data = await deleteCreative(client, restArgs, flags);
701
- break;
702
- default:
703
- throw new CliError('UNKNOWN_COMMAND', `Unknown action: meta creatives ${action ?? 'list'}`, 'Available: create, update, delete');
704
- }
705
- break;
706
- }
707
- case 'media': {
708
- switch (action) {
709
- case 'upload':
710
- data = await uploadMedia(client, restArgs, flags);
711
- break;
712
- case 'list':
713
- data = await listMedia(client, restArgs, flags);
714
- emptyHint = 'No media found for this account.';
715
- break;
716
- case 'delete':
717
- data = await deleteMedia(client, restArgs, flags);
718
- break;
719
- default:
720
- throw new CliError('UNKNOWN_COMMAND', `Unknown action: meta media ${action ?? ''}`, 'Available: upload, list, delete');
721
- }
722
- break;
723
- }
724
- case 'interests': {
725
- switch (action) {
726
- case 'search':
727
- data = await searchInterests(client, restArgs, flags);
728
- emptyHint = 'No interests found for that query.';
729
- break;
730
- default:
731
- throw new CliError('UNKNOWN_COMMAND', `Unknown action: meta interests ${action ?? ''}`, 'Available: search');
732
- }
733
- break;
734
- }
735
- default:
736
- throw new CliError('UNKNOWN_COMMAND', `Unknown entity: meta ${entity}`, 'Available: accounts, campaigns, adsets, ads, creatives, media, interests');
737
- }
738
- printResult(data, flags, emptyHint);
739
- return;
1979
+ case "campaigns": {
1980
+ if (!action) {
1981
+ showHelp("meta campaigns", flags.help === "full");
1982
+ process.exit(0);
1983
+ }
1984
+ switch (action) {
1985
+ case "list":
1986
+ data = await listCampaigns(client, restArgs, flags);
1987
+ emptyHint = 'No campaigns found. Create one with `adkit manage meta campaigns create --name "My Campaign" --objective sales --publish`.';
1988
+ break;
1989
+ case "create":
1990
+ data = await createCampaign(client, restArgs, flags);
1991
+ break;
1992
+ case "update":
1993
+ data = await updateCampaign(client, restArgs, flags);
1994
+ break;
1995
+ case "delete":
1996
+ data = await deleteCampaign(client, restArgs, flags);
1997
+ break;
1998
+ default:
1999
+ throw new CliError("UNKNOWN_COMMAND", `Unknown action: meta campaigns ${action}`, "Run: adkit manage meta campaigns --help");
2000
+ }
2001
+ break;
740
2002
  }
741
- // --- projects commands ---
742
- if (args[0] === 'projects') {
743
- const action = args[1];
744
- if (flags.help) {
745
- showHelp('projects', flags.help === 'full');
746
- process.exit(0);
747
- }
748
- switch (action) {
749
- case 'list':
750
- case undefined: {
751
- const config = readConfig() ?? {};
752
- const projects = listProjects(config);
753
- if (projects.length === 0)
754
- console.log('No projects configured. Run `adkit setup` to set up your first project.');
755
- else {
756
- for (const p of projects) {
757
- const marker = p.current ? '* ' : ' ';
758
- console.log(`${marker}${p.name} (${p.id})`);
759
- }
760
- }
761
- break;
762
- }
763
- case 'current': {
764
- const config = readConfig() ?? {};
765
- const project = currentProject(config);
766
- if (!project)
767
- console.log('No project selected. Run `adkit projects use <id>`.');
768
- else
769
- console.log(`Active project: ${project.name} (${project.id})`);
770
- break;
771
- }
772
- case 'use': {
773
- const projectId = args[2];
774
- if (!projectId)
775
- throw new CliError('MISSING_ARGUMENT', 'Missing required argument: `<project-id>`', 'Run: adkit projects use <project-id>');
776
- useProject(projectId);
777
- console.log(`Switched to project: ${projectId}`);
778
- break;
779
- }
780
- default:
781
- throw new CliError('UNKNOWN_COMMAND', `Unknown action: projects ${action}`, 'Available: list, use, current');
782
- }
783
- return;
2003
+ case "adsets": {
2004
+ if (!action) {
2005
+ showHelp("meta adsets", flags.help === "full");
2006
+ process.exit(0);
2007
+ }
2008
+ switch (action) {
2009
+ case "list":
2010
+ data = await listAdSets(client, restArgs, flags);
2011
+ emptyHint = 'No ad sets found. Create one with `adkit manage meta adsets create --campaign cmp_123 --name "My AdSet" --publish`.';
2012
+ break;
2013
+ case "create":
2014
+ data = await createAdSet(client, restArgs, flags);
2015
+ break;
2016
+ case "update":
2017
+ data = await updateAdSet(client, restArgs, flags);
2018
+ break;
2019
+ case "delete":
2020
+ data = await deleteAdSet(client, restArgs, flags);
2021
+ break;
2022
+ default:
2023
+ throw new CliError("UNKNOWN_COMMAND", `Unknown action: meta adsets ${action}`, "Run: adkit manage meta adsets --help");
2024
+ }
2025
+ break;
784
2026
  }
785
- // --- logout ---
786
- if (args[0] === 'logout') {
787
- logout();
788
- return;
2027
+ case "ads": {
2028
+ if (!action) {
2029
+ showHelp("meta ads", flags.help === "full");
2030
+ process.exit(0);
2031
+ }
2032
+ switch (action) {
2033
+ case "list":
2034
+ data = await listAds(client, restArgs, flags);
2035
+ emptyHint = 'No ads found. Create one with `adkit manage meta ads create --data \'{"adsetId":"as_123","creativeId":"cr_123","name":"My Ad"}\'`.';
2036
+ break;
2037
+ case "create":
2038
+ data = await createAd(client, restArgs, flags);
2039
+ break;
2040
+ case "update":
2041
+ data = await updateAd(client, restArgs, flags);
2042
+ break;
2043
+ case "delete":
2044
+ data = await deleteAd(client, restArgs, flags);
2045
+ break;
2046
+ default:
2047
+ throw new CliError("UNKNOWN_COMMAND", `Unknown action: meta ads ${action}`, "Run: adkit manage meta ads --help");
2048
+ }
2049
+ break;
789
2050
  }
790
- // --- setup (auth + onboarding) ---
791
- if (args[0] === 'setup') {
792
- const scope = args.slice(1); // e.g. ['manage'], ['manage', 'studio'], or []
793
- await login({ baseUrl: getBaseUrl(), scope });
794
- return;
2051
+ case "creatives": {
2052
+ switch (action) {
2053
+ case "create":
2054
+ data = await createCreative(client, restArgs, flags);
2055
+ break;
2056
+ case "update":
2057
+ data = await updateCreative(client, restArgs, flags);
2058
+ break;
2059
+ case "delete":
2060
+ data = await deleteCreative(client, restArgs, flags);
2061
+ break;
2062
+ default:
2063
+ throw new CliError("UNKNOWN_COMMAND", `Unknown action: meta creatives ${action ?? "list"}`, "Available: create, update, delete");
2064
+ }
2065
+ break;
795
2066
  }
796
- // --- fallback ---
797
- throw new CliError('UNKNOWN_COMMAND', `Unknown command: ${args.join(' ')}`, 'Run: adkit --help');
798
- }
799
- catch (err) {
800
- const jsonErrors = wantsJson(flags);
801
- if (err instanceof CliError) {
802
- if (!jsonErrors) {
803
- console.error(`Error: ${err.message}`);
804
- if (err.suggestion)
805
- console.error(`Suggestion: ${err.suggestion}`);
806
- }
807
- else {
808
- console.error(JSON.stringify({
809
- error: true,
810
- code: err.code,
811
- message: err.message,
812
- ...(err.suggestion && { suggestion: err.suggestion }),
813
- }));
814
- }
2067
+ case "media": {
2068
+ switch (action) {
2069
+ case "upload":
2070
+ data = await uploadMedia(client, restArgs, flags);
2071
+ break;
2072
+ case "list":
2073
+ data = await listMedia(client, restArgs, flags);
2074
+ emptyHint = "No media found for this account.";
2075
+ break;
2076
+ case "delete":
2077
+ data = await deleteMedia(client, restArgs, flags);
2078
+ break;
2079
+ default:
2080
+ throw new CliError("UNKNOWN_COMMAND", `Unknown action: meta media ${action ?? ""}`, "Available: upload, list, delete");
2081
+ }
2082
+ break;
2083
+ }
2084
+ case "interests": {
2085
+ switch (action) {
2086
+ case "search":
2087
+ data = await searchInterests(client, restArgs, flags);
2088
+ emptyHint = "No interests found for that query.";
2089
+ break;
2090
+ default:
2091
+ throw new CliError("UNKNOWN_COMMAND", `Unknown action: meta interests ${action ?? ""}`, "Available: search");
2092
+ }
2093
+ break;
815
2094
  }
816
- else {
817
- const message = err instanceof Error ? err.message : String(err);
818
- if (!jsonErrors)
819
- console.error(`Error: ${message}`);
820
- else {
821
- console.error(JSON.stringify({
822
- error: true,
823
- code: 'UNKNOWN',
824
- message,
825
- }));
2095
+ default:
2096
+ throw new CliError("UNKNOWN_COMMAND", `Unknown entity: meta ${entity}`, "Available: accounts, campaigns, adsets, ads, creatives, media, interests");
2097
+ }
2098
+ printResult(data, flags, emptyHint);
2099
+ return;
2100
+ }
2101
+ if (args[0] === "projects") {
2102
+ const action = args[1];
2103
+ if (flags.help) {
2104
+ showHelp("projects", flags.help === "full");
2105
+ process.exit(0);
2106
+ }
2107
+ switch (action) {
2108
+ case "list":
2109
+ case void 0: {
2110
+ const config = readConfig() ?? {};
2111
+ const projects = listProjects(config);
2112
+ if (projects.length === 0) console.log("No projects configured. Run `adkit setup` to set up your first project.");
2113
+ else {
2114
+ for (const p of projects) {
2115
+ const marker = p.current ? "* " : " ";
2116
+ console.log(`${marker}${p.name} (${p.id})`);
826
2117
  }
2118
+ }
2119
+ break;
2120
+ }
2121
+ case "current": {
2122
+ const config = readConfig() ?? {};
2123
+ const project = currentProject(config);
2124
+ if (!project) console.log("No project selected. Run `adkit projects use <id>`.");
2125
+ else console.log(`Active project: ${project.name} (${project.id})`);
2126
+ break;
2127
+ }
2128
+ case "use": {
2129
+ const projectId = args[2];
2130
+ if (!projectId) throw new CliError("MISSING_ARGUMENT", "Missing required argument: `<project-id>`", "Run: adkit projects use <project-id>");
2131
+ useProject(projectId);
2132
+ console.log(`Switched to project: ${projectId}`);
2133
+ break;
827
2134
  }
828
- const EXIT_CODES = {
829
- MISSING_ARGUMENT: 2,
830
- MISSING_FLAG: 2,
831
- INVALID_VALUE: 2,
832
- UNKNOWN_COMMAND: 2,
833
- UNKNOWN_FLAG: 2,
834
- NOT_FOUND: 3,
835
- INVALID_API_KEY: 4,
836
- NOT_AUTHENTICATED: 4,
837
- };
838
- process.exit(err instanceof CliError ? (EXIT_CODES[err.code] ?? 1) : 1);
2135
+ default:
2136
+ throw new CliError("UNKNOWN_COMMAND", `Unknown action: projects ${action}`, "Available: list, use, current");
2137
+ }
2138
+ return;
2139
+ }
2140
+ if (args[0] === "logout") {
2141
+ logout();
2142
+ return;
2143
+ }
2144
+ if (args[0] === "setup") {
2145
+ const scope = args.slice(1);
2146
+ await login({ baseUrl: getBaseUrl(), scope });
2147
+ return;
2148
+ }
2149
+ throw new CliError("UNKNOWN_COMMAND", `Unknown command: ${args.join(" ")}`, "Run: adkit --help");
2150
+ } catch (err) {
2151
+ const jsonErrors = wantsJson(flags);
2152
+ if (err instanceof CliError) {
2153
+ if (!jsonErrors) {
2154
+ console.error(`Error: ${err.message}`);
2155
+ if (err.suggestion) console.error(`Suggestion: ${err.suggestion}`);
2156
+ } else {
2157
+ console.error(
2158
+ JSON.stringify({
2159
+ error: true,
2160
+ code: err.code,
2161
+ message: err.message,
2162
+ ...err.suggestion && { suggestion: err.suggestion }
2163
+ })
2164
+ );
2165
+ }
2166
+ } else {
2167
+ const message = err instanceof Error ? err.message : String(err);
2168
+ if (!jsonErrors) console.error(`Error: ${message}`);
2169
+ else {
2170
+ console.error(
2171
+ JSON.stringify({
2172
+ error: true,
2173
+ code: "UNKNOWN",
2174
+ message
2175
+ })
2176
+ );
2177
+ }
839
2178
  }
2179
+ const EXIT_CODES = {
2180
+ MISSING_ARGUMENT: 2,
2181
+ MISSING_FLAG: 2,
2182
+ INVALID_VALUE: 2,
2183
+ UNKNOWN_COMMAND: 2,
2184
+ UNKNOWN_FLAG: 2,
2185
+ NOT_FOUND: 3,
2186
+ INVALID_API_KEY: 4,
2187
+ NOT_AUTHENTICATED: 4
2188
+ };
2189
+ process.exit(err instanceof CliError ? EXIT_CODES[err.code] ?? 1 : 1);
2190
+ }
840
2191
  }
841
2192
  void main();