@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/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@adkit.so/cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "AdKit CLI — manage campaigns and accounts from the terminal",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "adkit": "dist/cli.js"
8
8
  },
9
- "files": ["dist"],
9
+ "files": [
10
+ "dist"
11
+ ],
10
12
  "scripts": {
11
- "build": "tsc"
12
- },
13
- "dependencies": {
14
- "open": "^10.0.0"
13
+ "build": "esbuild src/cli.ts --bundle --format=esm --platform=node --target=node18 --outfile=dist/cli.js --banner:js='#!/usr/bin/env node'"
15
14
  },
16
15
  "devDependencies": {
17
16
  "@types/node": "^20.10.0",
17
+ "esbuild": "^0.25.12",
18
18
  "typescript": "^5.3.0"
19
19
  }
20
20
  }
@@ -1,11 +0,0 @@
1
- export type Flags = Record<string, string | string[] | true>;
2
- interface ParseOptions {
3
- multi?: string[];
4
- }
5
- export declare function parseArgs(argv: string[], options?: ParseOptions): {
6
- args: string[];
7
- flags: Record<string, string | true | string[]>;
8
- };
9
- export declare function validateFlags(flags: Flags, allowed: string[], command: string): void;
10
- export declare function unwrapList(data: unknown): Record<string, unknown>[];
11
- export {};
package/dist/cli-utils.js DELETED
@@ -1,58 +0,0 @@
1
- import { CliError } from './errors.js';
2
- export function parseArgs(argv, options) {
3
- const args = [];
4
- const flags = {};
5
- const multiSet = new Set(options?.multi);
6
- for (let i = 0; i < argv.length; i++) {
7
- const arg = argv[i];
8
- if (!arg.startsWith('--')) {
9
- args.push(arg);
10
- continue;
11
- }
12
- const eqIdx = arg.indexOf('=');
13
- let key;
14
- let value;
15
- if (eqIdx !== -1) {
16
- key = arg.slice(2, eqIdx);
17
- value = arg.slice(eqIdx + 1);
18
- }
19
- else {
20
- key = arg.slice(2);
21
- const next = argv[i + 1];
22
- if (next && !next.startsWith('--')) {
23
- value = next;
24
- i++;
25
- }
26
- else
27
- value = true;
28
- }
29
- if (multiSet.has(key) && typeof value === 'string') {
30
- const existing = flags[key];
31
- if (Array.isArray(existing))
32
- existing.push(value);
33
- else
34
- flags[key] = [value];
35
- }
36
- else
37
- flags[key] = value;
38
- }
39
- return { args, flags };
40
- }
41
- const GLOBAL_FLAGS = ['account', 'json', 'fields', 'publish', 'data', 'platform-overrides', 'force', 'project'];
42
- export function validateFlags(flags, allowed, command) {
43
- const allAllowed = new Set([...GLOBAL_FLAGS, ...allowed]);
44
- const unknown = Object.keys(flags).filter((k) => !allAllowed.has(k));
45
- if (unknown.length)
46
- throw new CliError('UNKNOWN_FLAG', `Unknown flag${unknown.length > 1 ? 's' : ''}: ${unknown.map((f) => `--${f}`).join(', ')}`, `Run: adkit ${command} --help`);
47
- }
48
- export function unwrapList(data) {
49
- if (Array.isArray(data))
50
- return data;
51
- if (data && typeof data === 'object') {
52
- const values = Object.values(data);
53
- const arr = values.find((v) => Array.isArray(v));
54
- if (arr)
55
- return arr;
56
- }
57
- return [];
58
- }
package/dist/cli.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
package/dist/client.d.ts DELETED
@@ -1,13 +0,0 @@
1
- export declare class AdkitClient {
2
- private apiKey;
3
- private baseUrl;
4
- constructor({ apiKey, baseUrl }: {
5
- apiKey: string;
6
- baseUrl: string;
7
- });
8
- private request;
9
- get(path: string): Promise<unknown>;
10
- post(path: string, body?: unknown): Promise<unknown>;
11
- patch(path: string, body?: unknown): Promise<unknown>;
12
- delete(path: string): Promise<unknown>;
13
- }
package/dist/client.js DELETED
@@ -1,84 +0,0 @@
1
- import { CliError } from './errors.js';
2
- function isErrorResponse(value) {
3
- return value != null && typeof value === 'object';
4
- }
5
- export class AdkitClient {
6
- apiKey;
7
- baseUrl;
8
- constructor({ apiKey, baseUrl }) {
9
- const isLocalhost = baseUrl.startsWith('http://localhost') || baseUrl.startsWith('http://127.0.0.1');
10
- if (baseUrl.startsWith('http://') && !isLocalhost)
11
- throw new Error('HTTPS is required — insecure HTTP base URLs are not allowed');
12
- this.apiKey = apiKey;
13
- this.baseUrl = baseUrl;
14
- }
15
- async request(method, path, body) {
16
- const url = `${this.baseUrl}${path}`;
17
- const headers = {
18
- Authorization: `Bearer ${this.apiKey}`,
19
- 'Content-Type': 'application/json',
20
- };
21
- const init = { method, headers };
22
- if (body !== undefined)
23
- init.body = JSON.stringify(body);
24
- let response;
25
- try {
26
- response = await fetch(url, init);
27
- }
28
- catch (err) {
29
- if (err instanceof DOMException && err.name === 'AbortError')
30
- throw new CliError('NETWORK_ERROR', 'Request timed out', 'Retry the command');
31
- throw new CliError('NETWORK_ERROR', 'Network connection error — check your internet connection and try again. If using a custom base URL, verify `ADKIT_BASE_URL` is correct.', 'Check internet connection');
32
- }
33
- if (response.status === 204)
34
- return undefined;
35
- if (!response.ok) {
36
- let serverMessage = '';
37
- let dataMessage = '';
38
- let retryable;
39
- try {
40
- const json = await response.json();
41
- if (isErrorResponse(json)) {
42
- serverMessage = json.statusMessage ?? json.message ?? '';
43
- dataMessage = json.data?.message ?? '';
44
- retryable = json.data?.retryable;
45
- }
46
- }
47
- catch {
48
- // no parseable body
49
- }
50
- if (response.status === 401)
51
- throw new CliError('INVALID_API_KEY', `Invalid or expired API key${serverMessage ? ` — ${serverMessage}` : ''}`, 'Run: adkit setup');
52
- if (response.status === 429) {
53
- const retryAfter = response.headers.get('Retry-After') ?? '60';
54
- throw new CliError('RATE_LIMITED', serverMessage || 'Rate limit exceeded', `Wait ${retryAfter} seconds before retrying`);
55
- }
56
- if (response.status === 404) {
57
- const fallback = `Not found: ${method} ${path} — the resource may have been deleted or the ID is wrong`;
58
- throw new CliError('NOT_FOUND', serverMessage || fallback, 'Check the resource ID');
59
- }
60
- if (response.status >= 500) {
61
- // H3/Nuxt sanitizes statusMessage on 5xx — prefer data.message (always set by normalizeError)
62
- const errorMsg = dataMessage || serverMessage || `Server error (HTTP ${String(response.status)})`;
63
- let suggestion;
64
- if (retryable === true)
65
- suggestion = 'Retry in a few seconds';
66
- throw new CliError('SERVER_ERROR', errorMsg, suggestion);
67
- }
68
- throw new CliError('SERVER_ERROR', serverMessage || `Request failed (HTTP ${String(response.status)})`);
69
- }
70
- return response.json();
71
- }
72
- async get(path) {
73
- return this.request('GET', path);
74
- }
75
- async post(path, body) {
76
- return this.request('POST', path, body);
77
- }
78
- async patch(path, body) {
79
- return this.request('PATCH', path, body);
80
- }
81
- async delete(path) {
82
- return this.request('DELETE', path);
83
- }
84
- }
@@ -1,7 +0,0 @@
1
- interface LoginOptions {
2
- baseUrl: string;
3
- scope?: string[];
4
- }
5
- export declare function login({ baseUrl, scope }: LoginOptions): Promise<void>;
6
- export declare function logout(): void;
7
- export {};
@@ -1,184 +0,0 @@
1
- import open from 'open';
2
- import { unlinkSync, existsSync } from 'node:fs';
3
- import { hostname } from 'node:os';
4
- import { writeConfig, readConfig, CONFIG_PATH } from '../config.js';
5
- import { AdkitClient } from '../client.js';
6
- const MAX_POLL_ATTEMPTS = 450; // 450 × 2s = 15 min — setup flow can take a while
7
- const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
8
- function createSpinner() {
9
- let frame = 0;
10
- let timer = null;
11
- let currentText = '';
12
- return {
13
- start(text) {
14
- currentText = text;
15
- frame = 0;
16
- timer = setInterval(() => {
17
- process.stderr.write(`\r${SPINNER_FRAMES[frame++ % SPINNER_FRAMES.length]} ${currentText}`);
18
- }, 80);
19
- },
20
- update(text) {
21
- currentText = text;
22
- },
23
- stop(finalText) {
24
- if (timer)
25
- clearInterval(timer);
26
- process.stderr.write('\r\x1b[K'); // clear line
27
- if (finalText)
28
- console.log(finalText);
29
- },
30
- };
31
- }
32
- function printNextSteps(scope) {
33
- const lines = ['Getting started:'];
34
- if (scope?.includes('manage')) {
35
- lines.push(' adkit meta accounts list List your connected ad accounts');
36
- lines.push(' adkit meta campaigns list List campaigns');
37
- lines.push(' adkit meta campaigns create Create a campaign');
38
- lines.push(' adkit drafts list View pending drafts');
39
- }
40
- else
41
- lines.push(' adkit setup manage Connect Meta Ads');
42
- lines.push(' adkit --help See all commands');
43
- lines.push('');
44
- console.log(lines.join('\n'));
45
- }
46
- async function detectDefaultAccounts(baseUrl, apiKey) {
47
- try {
48
- const client = new AdkitClient({ apiKey, baseUrl });
49
- const data = (await client.get('/manage/status'));
50
- const config = readConfig();
51
- if (!config?.selectedProject || !config.projects)
52
- return;
53
- const project = config.projects[config.selectedProject];
54
- if (!project)
55
- return;
56
- let changed = false;
57
- const metaAccounts = data.platforms?.meta?.accounts;
58
- if (metaAccounts?.length === 1) {
59
- project.defaultMetaAccount = metaAccounts[0].id;
60
- changed = true;
61
- console.log(`Default Meta account: ${metaAccounts[0].name} (${metaAccounts[0].id})`);
62
- }
63
- const googleAccounts = data.platforms?.google?.accounts;
64
- if (googleAccounts?.length === 1) {
65
- project.defaultGoogleAccount = googleAccounts[0].id;
66
- changed = true;
67
- console.log(`Default Google account: ${googleAccounts[0].name} (${googleAccounts[0].id})`);
68
- }
69
- if (changed)
70
- writeConfig({ projects: config.projects });
71
- }
72
- catch {
73
- // Non-critical — skip silently if account detection fails
74
- }
75
- }
76
- export async function login({ baseUrl, scope }) {
77
- const spinner = createSpinner();
78
- // Step 1: Create CLI session
79
- spinner.start('Connecting to AdKit...');
80
- let createResponse;
81
- try {
82
- createResponse = await fetch(`${baseUrl}/auth/cli-session`, {
83
- method: 'POST',
84
- headers: { 'Content-Type': 'application/json' },
85
- body: JSON.stringify({ src: 'cli', hostname: hostname(), scope: scope && scope.length > 0 ? scope : undefined }),
86
- });
87
- }
88
- catch {
89
- spinner.stop();
90
- throw new Error('Network connection failed — check your internet connection');
91
- }
92
- if (!createResponse.ok) {
93
- spinner.stop();
94
- let msg = 'Failed to create session';
95
- try {
96
- const errData = (await createResponse.json());
97
- if (errData.message)
98
- msg = errData.message;
99
- }
100
- catch {
101
- // no parseable body
102
- }
103
- throw new Error(msg);
104
- }
105
- const createData = (await createResponse.json());
106
- const sessionId = createData.session.sessionId;
107
- const rawUrl = createData.session.url;
108
- // Step 2: Open browser
109
- const origin = new URL(baseUrl).origin;
110
- const sessionUrl = rawUrl.startsWith('http') ? rawUrl : `${origin}${rawUrl}`;
111
- await open(sessionUrl);
112
- spinner.stop(`✓ Browser opened — complete setup at ${sessionUrl}`);
113
- // Step 3: Poll until complete
114
- spinner.start('Waiting for setup to complete...');
115
- let projects;
116
- let legacyApiKey;
117
- for (let attempt = 0; attempt < MAX_POLL_ATTEMPTS; attempt++) {
118
- let pollResponse;
119
- try {
120
- pollResponse = await fetch(`${baseUrl}/auth/cli-session/${sessionId}`, {
121
- method: 'GET',
122
- });
123
- }
124
- catch {
125
- spinner.stop();
126
- throw new Error('Network connection failed during polling');
127
- }
128
- if (!pollResponse.ok) {
129
- spinner.stop();
130
- if (pollResponse.status === 404)
131
- throw new Error('Session not found or expired');
132
- throw new Error(`Poll failed with status ${pollResponse.status}`);
133
- }
134
- let pollData;
135
- try {
136
- pollData = (await pollResponse.json());
137
- }
138
- catch {
139
- continue;
140
- }
141
- const status = pollData.session?.status;
142
- if (status === 'complete') {
143
- projects = pollData.session.projects;
144
- legacyApiKey = pollData.session.apiKey;
145
- break;
146
- }
147
- if (status === 'expired') {
148
- spinner.stop();
149
- throw new Error('Session expired — timed out waiting for authentication');
150
- }
151
- await new Promise((r) => setTimeout(r, 2000));
152
- }
153
- spinner.stop();
154
- if (!projects && !legacyApiKey)
155
- throw new Error('Login timed out — max poll attempts exceeded');
156
- // Step 4: Write config
157
- if (projects && projects.length > 0) {
158
- const projectsMap = {};
159
- for (const p of projects)
160
- projectsMap[p.id] = { name: p.name, apiKey: p.apiKey };
161
- writeConfig({
162
- projects: projectsMap,
163
- selectedProject: projects[0].id,
164
- apiKey: projects[0].apiKey,
165
- });
166
- console.log('\n✅ AdKit is configured!\n');
167
- const names = projects.map((p) => ` • ${p.name}`).join('\n');
168
- console.log(`Projects:\n${names}\n`);
169
- // Auto-detect default ad accounts
170
- if (scope?.includes('manage'))
171
- await detectDefaultAccounts(baseUrl, projects[0].apiKey);
172
- printNextSteps(scope);
173
- }
174
- else {
175
- writeConfig({ apiKey: legacyApiKey });
176
- console.log('\n✅ AdKit is configured!\n');
177
- printNextSteps(scope);
178
- }
179
- }
180
- export function logout() {
181
- if (existsSync(CONFIG_PATH))
182
- unlinkSync(CONFIG_PATH);
183
- console.log('Logged out — API key removed.');
184
- }
@@ -1,6 +0,0 @@
1
- import type { AdkitClient } from '../client.js';
2
- import { type Flags } from '../cli-utils.js';
3
- export declare function listDrafts(client: AdkitClient, _args: string[], flags: Flags): Promise<unknown>;
4
- export declare function getDraft(client: AdkitClient, args: string[], _flags: Flags): Promise<unknown>;
5
- export declare function publishDraft(client: AdkitClient, args: string[], _flags: Flags): Promise<unknown>;
6
- export declare function deleteDraft(client: AdkitClient, args: string[], _flags: Flags): Promise<unknown>;
@@ -1,36 +0,0 @@
1
- import { validateFlags } from '../cli-utils.js';
2
- import { CliError } from '../errors.js';
3
- function requireArg(args, index, label, hint) {
4
- const val = args[index];
5
- if (!val) {
6
- throw new CliError('MISSING_ARGUMENT', `Missing required argument: \`<${label}>\``, hint);
7
- }
8
- return val;
9
- }
10
- function queryString(params) {
11
- const entries = Object.entries(params).filter((e) => e[1] !== undefined);
12
- if (entries.length === 0)
13
- return '';
14
- return '?' + entries.map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&');
15
- }
16
- const DRAFT_LIST_FLAGS = ['platform', 'limit', 'offset'];
17
- export async function listDrafts(client, _args, flags) {
18
- validateFlags(flags, DRAFT_LIST_FLAGS, 'manage drafts list');
19
- const platform = typeof flags.platform === 'string' ? flags.platform : undefined;
20
- const limit = typeof flags.limit === 'string' ? flags.limit : undefined;
21
- const offset = typeof flags.offset === 'string' ? flags.offset : undefined;
22
- const qs = queryString({ platform, limit, offset });
23
- return client.get(`/manage/drafts${qs}`);
24
- }
25
- export async function getDraft(client, args, _flags) {
26
- const id = requireArg(args, 0, 'draft-id', 'Run: adkit drafts get <draft-id>');
27
- return client.get(`/manage/drafts/${id}`);
28
- }
29
- export async function publishDraft(client, args, _flags) {
30
- const id = requireArg(args, 0, 'draft-id', 'Run: adkit drafts publish <draft-id>');
31
- return client.post(`/manage/drafts/${id}/publish`);
32
- }
33
- export async function deleteDraft(client, args, _flags) {
34
- const id = requireArg(args, 0, 'draft-id', 'Run: adkit drafts delete <draft-id>');
35
- return client.delete(`/manage/drafts/${id}`);
36
- }
@@ -1,28 +0,0 @@
1
- import type { AdkitClient } from '../client.js';
2
- import { type Flags } from '../cli-utils.js';
3
- export declare function listAccounts(client: AdkitClient, _args: string[], _flags: Flags): Promise<unknown>;
4
- export declare function connectAccount(client: AdkitClient, args: string[], _flags: Flags): Promise<unknown>;
5
- export declare function disconnectAccount(client: AdkitClient, args: string[], _flags: Flags): Promise<unknown>;
6
- export declare function listPages(client: AdkitClient, args: string[], _flags: Flags): Promise<unknown>;
7
- export declare function listPixels(client: AdkitClient, args: string[], _flags: Flags): Promise<unknown>;
8
- export declare function listCampaigns(client: AdkitClient, _args: string[], flags: Flags): Promise<unknown>;
9
- export declare function createCampaign(client: AdkitClient, _args: string[], flags: Flags): Promise<unknown>;
10
- export declare function updateCampaign(client: AdkitClient, args: string[], flags: Flags): Promise<unknown>;
11
- export declare function deleteCampaign(client: AdkitClient, args: string[], _flags: Flags): Promise<unknown>;
12
- export declare function listAdSets(client: AdkitClient, _args: string[], flags: Flags): Promise<unknown>;
13
- export declare function createAdSet(client: AdkitClient, _args: string[], flags: Flags): Promise<unknown>;
14
- export declare function updateAdSet(client: AdkitClient, args: string[], flags: Flags): Promise<unknown>;
15
- export declare function deleteAdSet(client: AdkitClient, args: string[], _flags: Flags): Promise<unknown>;
16
- export declare function listAds(client: AdkitClient, _args: string[], flags: Flags): Promise<unknown>;
17
- export declare function createAd(client: AdkitClient, _args: string[], flags: Flags): Promise<unknown>;
18
- export declare function updateAd(client: AdkitClient, args: string[], flags: Flags): Promise<unknown>;
19
- export declare function deleteAd(client: AdkitClient, args: string[], _flags: Flags): Promise<unknown>;
20
- export declare function createCreative(client: AdkitClient, _args: string[], flags: Flags): Promise<unknown>;
21
- export declare function updateCreative(client: AdkitClient, args: string[], flags: Flags): Promise<unknown>;
22
- export declare function deleteCreative(client: AdkitClient, args: string[], _flags: Flags): Promise<unknown>;
23
- export declare function searchInterests(client: AdkitClient, args: string[], flags: Flags): Promise<{
24
- results: unknown[];
25
- }>;
26
- export declare function uploadMedia(client: AdkitClient, _args: string[], flags: Flags): Promise<unknown>;
27
- export declare function listMedia(client: AdkitClient, _args: string[], flags: Flags): Promise<unknown>;
28
- export declare function deleteMedia(client: AdkitClient, args: string[], flags: Flags): Promise<unknown>;