adport 0.4.0 → 0.5.0
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/{apple-ZLY4ZTQ3.js → apple-YVGL356A.js} +3 -4
- package/dist/{apple-ZLY4ZTQ3.js.map → apple-YVGL356A.js.map} +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/{reddit-LC3F2OLD.js → reddit-EVDTD2DI.js} +2 -2
- package/dist/{reddit-LC3F2OLD.js.map → reddit-EVDTD2DI.js.map} +1 -1
- package/package.json +9 -9
|
@@ -44,14 +44,13 @@ async function connectApple({ io }) {
|
|
|
44
44
|
data: { client_id: clientId, team_id: teamId, key_id: keyId, private_key: privateKeyPem }
|
|
45
45
|
});
|
|
46
46
|
io.out("");
|
|
47
|
-
io.out(`\u2713 Connected. ${accounts.length}
|
|
47
|
+
io.out(`\u2713 Connected. ${accounts.length} ad account(s):`);
|
|
48
48
|
for (const account of accounts) {
|
|
49
49
|
io.out(` ${account.id} ${account.name} ${account.currency ?? ""} ${account.status ?? ""}`);
|
|
50
50
|
}
|
|
51
51
|
printLocalConnectionSaved(io);
|
|
52
52
|
io.out("");
|
|
53
|
-
io.out("
|
|
54
|
-
io.out("to the new Ads Platform API when its docs go live \u2014 your credentials carry over.");
|
|
53
|
+
io.out("Using Apple Ads Platform API v1. The API-user credentials stay local.");
|
|
55
54
|
io.out("");
|
|
56
55
|
io.out("Try: adport accounts \xB7 adport report --provider apple \xB7 adport mcp");
|
|
57
56
|
} finally {
|
|
@@ -64,4 +63,4 @@ function expandHome(p) {
|
|
|
64
63
|
export {
|
|
65
64
|
connectApple
|
|
66
65
|
};
|
|
67
|
-
//# sourceMappingURL=apple-
|
|
66
|
+
//# sourceMappingURL=apple-YVGL356A.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/connect/apple.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport readline from 'node:readline/promises';\nimport { CredentialStore } from '@adport/core';\nimport { AppleAdsClient, AppleAdsProvider } from '@adport/provider-apple';\nimport type { ProgramIO } from '../program.js';\nimport { printLocalConnectionIntro, printLocalConnectionSaved } from './local.js';\n\n/**\n * Apple Ads is fully self-serve for your own org: create an API user, generate\n * an EC key pair locally, upload the public key — no Apple approval involved.\n */\nexport async function connectApple({ io }: { io: ProgramIO }): Promise<void> {\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const store = new CredentialStore();\n try {\n printLocalConnectionIntro(io, 'Apple Ads');\n io.out('Connecting Apple Ads (Apple Search Ads). One-time setup (~10 min, no approval):');\n io.out(' 1. In ads.apple.com: Account Settings → API → create an API user (API role).');\n io.out(' 2. Generate an EC key pair locally:');\n io.out(' openssl ecparam -genkey -name prime256v1 -noout -out private-key.pem');\n io.out(' openssl ec -in private-key.pem -pubout -out public-key.pem');\n io.out(' 3. Upload public-key.pem in Account Settings → API; Apple shows your');\n io.out(' clientId, teamId, and keyId (all needed below).');\n io.out(' Note: access tokens last 1h and are re-minted automatically; no rotation chores.');\n io.out(' Your private key stays on this machine; upload only the public key to Apple.');\n io.out('');\n\n const clientId = (await rl.question('clientId (SEARCHADS.xxxx): ')).trim();\n const teamId = (await rl.question(`teamId [${clientId}]: `)).trim() || clientId;\n const keyId = (await rl.question('keyId: ')).trim();\n const keyPath = (await rl.question('Path to private-key.pem: ')).trim();\n if (!clientId || !keyId || !keyPath) {\n io.err('Missing values — aborting.');\n process.exitCode = 1;\n return;\n }\n const privateKeyPem = await fs.readFile(expandHome(keyPath), 'utf8');\n\n io.out('Verifying access…');\n const provider = new AppleAdsProvider(new AppleAdsClient({ clientId, teamId, keyId, privateKeyPem }));\n const accounts = await provider.listAccounts();\n await store.set({\n provider: 'apple',\n source: 'byo',\n data: { client_id: clientId, team_id: teamId, key_id: keyId, private_key: privateKeyPem },\n });\n io.out('');\n io.out(`✓ Connected. ${accounts.length}
|
|
1
|
+
{"version":3,"sources":["../src/connect/apple.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport readline from 'node:readline/promises';\nimport { CredentialStore } from '@adport/core';\nimport { AppleAdsClient, AppleAdsProvider } from '@adport/provider-apple';\nimport type { ProgramIO } from '../program.js';\nimport { printLocalConnectionIntro, printLocalConnectionSaved } from './local.js';\n\n/**\n * Apple Ads is fully self-serve for your own org: create an API user, generate\n * an EC key pair locally, upload the public key — no Apple approval involved.\n */\nexport async function connectApple({ io }: { io: ProgramIO }): Promise<void> {\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const store = new CredentialStore();\n try {\n printLocalConnectionIntro(io, 'Apple Ads');\n io.out('Connecting Apple Ads (Apple Search Ads). One-time setup (~10 min, no approval):');\n io.out(' 1. In ads.apple.com: Account Settings → API → create an API user (API role).');\n io.out(' 2. Generate an EC key pair locally:');\n io.out(' openssl ecparam -genkey -name prime256v1 -noout -out private-key.pem');\n io.out(' openssl ec -in private-key.pem -pubout -out public-key.pem');\n io.out(' 3. Upload public-key.pem in Account Settings → API; Apple shows your');\n io.out(' clientId, teamId, and keyId (all needed below).');\n io.out(' Note: access tokens last 1h and are re-minted automatically; no rotation chores.');\n io.out(' Your private key stays on this machine; upload only the public key to Apple.');\n io.out('');\n\n const clientId = (await rl.question('clientId (SEARCHADS.xxxx): ')).trim();\n const teamId = (await rl.question(`teamId [${clientId}]: `)).trim() || clientId;\n const keyId = (await rl.question('keyId: ')).trim();\n const keyPath = (await rl.question('Path to private-key.pem: ')).trim();\n if (!clientId || !keyId || !keyPath) {\n io.err('Missing values — aborting.');\n process.exitCode = 1;\n return;\n }\n const privateKeyPem = await fs.readFile(expandHome(keyPath), 'utf8');\n\n io.out('Verifying access…');\n const provider = new AppleAdsProvider(new AppleAdsClient({ clientId, teamId, keyId, privateKeyPem }));\n const accounts = await provider.listAccounts();\n await store.set({\n provider: 'apple',\n source: 'byo',\n data: { client_id: clientId, team_id: teamId, key_id: keyId, private_key: privateKeyPem },\n });\n io.out('');\n io.out(`✓ Connected. ${accounts.length} ad account(s):`);\n for (const account of accounts) {\n io.out(` ${account.id} ${account.name} ${account.currency ?? ''} ${account.status ?? ''}`);\n }\n printLocalConnectionSaved(io);\n io.out('');\n io.out('Using Apple Ads Platform API v1. The API-user credentials stay local.');\n io.out('');\n io.out('Try: adport accounts · adport report --provider apple · adport mcp');\n } finally {\n rl.close();\n }\n}\n\nfunction expandHome(p: string): string {\n return p.startsWith('~/') ? path.join(os.homedir(), p.slice(2)) : p;\n}\n"],"mappings":";;;;;;AAAA,SAAS,YAAY,UAAU;AAC/B,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,cAAc;AACrB,SAAS,uBAAuB;AAChC,SAAS,gBAAgB,wBAAwB;AAQjD,eAAsB,aAAa,EAAE,GAAG,GAAqC;AAC3E,QAAM,KAAK,SAAS,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AACpF,QAAM,QAAQ,IAAI,gBAAgB;AAClC,MAAI;AACF,8BAA0B,IAAI,WAAW;AACzC,OAAG,IAAI,iFAAiF;AACxF,OAAG,IAAI,0FAAgF;AACvF,OAAG,IAAI,uCAAuC;AAC9C,OAAG,IAAI,6EAA6E;AACpF,OAAG,IAAI,mEAAmE;AAC1E,OAAG,IAAI,6EAAwE;AAC/E,OAAG,IAAI,sDAAsD;AAC7D,OAAG,IAAI,oFAAoF;AAC3F,OAAG,IAAI,gFAAgF;AACvF,OAAG,IAAI,EAAE;AAET,UAAM,YAAY,MAAM,GAAG,SAAS,6BAA6B,GAAG,KAAK;AACzE,UAAM,UAAU,MAAM,GAAG,SAAS,WAAW,QAAQ,KAAK,GAAG,KAAK,KAAK;AACvE,UAAM,SAAS,MAAM,GAAG,SAAS,SAAS,GAAG,KAAK;AAClD,UAAM,WAAW,MAAM,GAAG,SAAS,2BAA2B,GAAG,KAAK;AACtE,QAAI,CAAC,YAAY,CAAC,SAAS,CAAC,SAAS;AACnC,SAAG,IAAI,iCAA4B;AACnC,cAAQ,WAAW;AACnB;AAAA,IACF;AACA,UAAM,gBAAgB,MAAM,GAAG,SAAS,WAAW,OAAO,GAAG,MAAM;AAEnE,OAAG,IAAI,wBAAmB;AAC1B,UAAM,WAAW,IAAI,iBAAiB,IAAI,eAAe,EAAE,UAAU,QAAQ,OAAO,cAAc,CAAC,CAAC;AACpG,UAAM,WAAW,MAAM,SAAS,aAAa;AAC7C,UAAM,MAAM,IAAI;AAAA,MACd,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,MAAM,EAAE,WAAW,UAAU,SAAS,QAAQ,QAAQ,OAAO,aAAa,cAAc;AAAA,IAC1F,CAAC;AACD,OAAG,IAAI,EAAE;AACT,OAAG,IAAI,qBAAgB,SAAS,MAAM,iBAAiB;AACvD,eAAW,WAAW,UAAU;AAC9B,SAAG,IAAI,KAAK,QAAQ,EAAE,KAAK,QAAQ,IAAI,KAAK,QAAQ,YAAY,EAAE,KAAK,QAAQ,UAAU,EAAE,EAAE;AAAA,IAC/F;AACA,8BAA0B,EAAE;AAC5B,OAAG,IAAI,EAAE;AACT,OAAG,IAAI,uEAAuE;AAC9E,OAAG,IAAI,EAAE;AACT,OAAG,IAAI,mFAA6E;AAAA,EACtF,UAAE;AACA,OAAG,MAAM;AAAA,EACX;AACF;AAEA,SAAS,WAAW,GAAmB;AACrC,SAAO,EAAE,WAAW,IAAI,IAAI,KAAK,KAAK,GAAG,QAAQ,GAAG,EAAE,MAAM,CAAC,CAAC,IAAI;AACpE;","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { Command } from "commander";
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "adport",
|
|
9
|
-
version: "0.
|
|
9
|
+
version: "0.5.0",
|
|
10
10
|
description: "adport CLI \u2014 the open control plane for paid media",
|
|
11
11
|
license: "Apache-2.0",
|
|
12
12
|
type: "module",
|
|
@@ -203,7 +203,7 @@ function buildProgram(io = defaultIO) {
|
|
|
203
203
|
return;
|
|
204
204
|
}
|
|
205
205
|
if (provider === "apple") {
|
|
206
|
-
const { connectApple } = await import("./apple-
|
|
206
|
+
const { connectApple } = await import("./apple-YVGL356A.js");
|
|
207
207
|
await connectApple({ io });
|
|
208
208
|
return;
|
|
209
209
|
}
|
|
@@ -213,7 +213,7 @@ function buildProgram(io = defaultIO) {
|
|
|
213
213
|
return;
|
|
214
214
|
}
|
|
215
215
|
if (provider === "reddit") {
|
|
216
|
-
const { connectReddit } = await import("./reddit-
|
|
216
|
+
const { connectReddit } = await import("./reddit-EVDTD2DI.js");
|
|
217
217
|
await connectReddit({ openBrowser: opts.browser, io });
|
|
218
218
|
return;
|
|
219
219
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/program.ts","../package.json","../src/index.ts"],"sourcesContent":["import { Command } from 'commander';\nimport packageJson from '../package.json';\nimport {\n AdportError,\n AuditLog,\n CredentialStore,\n type AdportRuntime,\n type AnyToolDefinition,\n} from '@adport/core';\n\nexport interface ProgramIO {\n out: (line: string) => void;\n err: (line: string) => void;\n}\n\nconst defaultIO: ProgramIO = {\n out: (line) => console.log(line),\n err: (line) => console.error(line),\n};\n\nfunction json(value: unknown): string {\n return JSON.stringify(value, null, 2);\n}\n\nfunction table(rows: Array<Record<string, unknown>>): string {\n if (rows.length === 0) return '(empty)';\n const keys = Object.keys(rows[0]!);\n const widths = keys.map((k) => Math.max(k.length, ...rows.map((r) => String(r[k] ?? '').length)));\n const line = (values: string[]) => values.map((v, i) => v.padEnd(widths[i]!)).join(' ');\n return [line(keys), line(widths.map((w) => '-'.repeat(w))), ...rows.map((r) => line(keys.map((k) => String(r[k] ?? ''))))].join('\\n');\n}\n\nasync function runtime(includeMock?: boolean): Promise<AdportRuntime> {\n const { assembleRuntime } = await import('@adport/mcp');\n return assembleRuntime({ includeMock });\n}\n\nexport function buildProgram(io: ProgramIO = defaultIO): Command {\n const program = new Command('adport');\n program\n .description('The open control plane for paid media (MCP + CLI)')\n .option('--demo', 'Use synthetic mock accounts and tools (never real provider data)')\n .version(packageJson.version)\n .configureOutput({ writeOut: (s) => io.out(s.trimEnd()), writeErr: (s) => io.err(s.trimEnd()) });\n const commandRuntime = () => runtime(program.opts<{ demo?: boolean }>().demo === true ? true : undefined);\n\n const tools = program.command('tools').description('Inspect and invoke the shared tool registry');\n\n tools\n .command('list')\n .description('List available tools')\n .option('--json', 'JSON output')\n .action(async (opts: { json?: boolean }) => {\n const { registry } = await commandRuntime();\n const defs = registry.list();\n if (opts.json) {\n io.out(\n json(\n defs.map((t: AnyToolDefinition) => ({\n name: t.name,\n namespace: t.namespace,\n readOnly: t.annotations.readOnly ?? false,\n destructive: t.annotations.destructive ?? false,\n })),\n ),\n );\n return;\n }\n io.out(\n table(\n defs.map((t) => ({\n name: t.name,\n namespace: t.namespace,\n mode: t.annotations.readOnly ? 'read' : t.annotations.destructive ? 'DESTRUCTIVE' : 'write',\n })),\n ),\n );\n });\n\n tools\n .command('run <name>')\n .description('Invoke a tool with JSON input (the same tools the MCP server exposes)')\n .option('--input <json>', 'JSON object with the tool arguments', '{}')\n .action(async (name: string, opts: { input: string }) => {\n const rt = await commandRuntime();\n const result = await rt.registry.call(name, JSON.parse(opts.input), rt.ctx);\n io.out(json(result));\n });\n\n program\n .command('accounts')\n .description('List connected ad accounts across providers')\n .option('--provider <id>', 'Limit to one provider')\n .option('--json', 'JSON output')\n .action(async (opts: { provider?: string; json?: boolean }) => {\n const rt = await commandRuntime();\n const result = (await rt.registry.call('accounts_list', { provider: opts.provider }, rt.ctx)) as {\n accounts: Array<Record<string, unknown>>;\n };\n io.out(opts.json ? json(result.accounts) : table(result.accounts));\n });\n\n program\n .command('report')\n .description('Normalized cross-platform performance report')\n .option('--provider <id>', 'Limit to one provider')\n .option('--level <level>', 'account | campaign | ad_group | ad', 'campaign')\n .option('--metrics <list>', 'Comma-separated metrics', 'spend,impressions,clicks,conversions')\n .option('--range <range>', 'Preset (last_7_days, ...) or START..END', 'last_7_days')\n .option('--limit <n>', 'Max rows', '100')\n .option('--json', 'JSON output')\n .action(async (opts: { provider?: string; level: string; metrics: string; range: string; limit: string; json?: boolean }) => {\n const rt = await commandRuntime();\n const dateRange = opts.range.includes('..')\n ? { start: opts.range.split('..')[0]!, end: opts.range.split('..')[1]! }\n : opts.range;\n const result = (await rt.registry.call(\n 'report',\n {\n provider: opts.provider,\n level: opts.level,\n metrics: opts.metrics.split(',').map((m) => m.trim()),\n date_range: dateRange,\n limit: Number(opts.limit),\n },\n rt.ctx,\n )) as { rows: Array<{ provider: string; accountId: string; entity: { name: string; status?: string }; metrics: Record<string, number> }>; truncated: boolean };\n if (opts.json) {\n io.out(json(result));\n return;\n }\n io.out(\n table(\n result.rows.map((r) => ({\n provider: r.provider,\n account: r.accountId,\n entity: r.entity.name,\n status: r.entity.status ?? '',\n ...r.metrics,\n })),\n ),\n );\n if (result.truncated) io.err('(truncated — raise --limit for more rows)');\n });\n\n program\n .command('policy')\n .description('Show the active write policy and where it was loaded from')\n .action(async () => {\n const rt = await commandRuntime();\n io.out(json({ source: rt.policySource, policy: rt.ctx.engine.policy }));\n });\n\n const audit = program.command('audit').description('Inspect or extend the write-audit trail');\n\n audit\n .command('show', { isDefault: true })\n .description('Show recent write-audit entries')\n .option('--limit <n>', 'Max entries', '20')\n .action(async (opts: { limit: string }) => {\n const entries = await new AuditLog().read(Number(opts.limit));\n if (entries.length === 0) {\n io.out('No audit entries yet.');\n return;\n }\n io.out(entries.map((e) => JSON.stringify(e)).join('\\n'));\n });\n\n audit\n .command('export')\n .description('Export write-audit entries to stdout for archival or compliance ingestion')\n .option('--limit <n>', 'Max entries', '10000')\n .option('--format <format>', 'jsonl | json', 'jsonl')\n .action(async (opts: { limit: string; format: string }) => {\n const limit = Number(opts.limit);\n if (!Number.isInteger(limit) || limit < 1) {\n throw new AdportError('INVALID_INPUT', '--limit must be a positive integer');\n }\n if (opts.format !== 'jsonl' && opts.format !== 'json') {\n throw new AdportError('INVALID_INPUT', '--format must be jsonl or json');\n }\n const entries = await new AuditLog().read(limit);\n io.out(opts.format === 'json' ? json(entries) : entries.map((e) => JSON.stringify(e)).join('\\n'));\n });\n\n audit\n .command('run')\n .description('Run the audit rule packs over connected accounts and persist findings')\n .option('--provider <id>', 'Limit to one provider')\n .option('--range <range>', 'Preset or START..END', 'last_30_days')\n .action(async (opts: { provider?: string; range: string }) => {\n const rt = await commandRuntime();\n const dateRange = opts.range.includes('..')\n ? { start: opts.range.split('..')[0]!, end: opts.range.split('..')[1]! }\n : opts.range;\n const result = (await rt.registry.call(\n 'audit_run',\n { provider: opts.provider, date_range: dateRange },\n rt.ctx,\n )) as { findings: Array<{ id: string; severity: string; title: string }>; counts: Record<string, number>; evaluatedAccounts: number };\n io.out(`Evaluated ${result.evaluatedAccounts} account(s): ${result.counts.critical} critical, ${result.counts.warn} warn, ${result.counts.info} info`);\n for (const finding of result.findings) {\n io.out(` [${finding.severity.toUpperCase()}] ${finding.id}\\n ${finding.title}`);\n }\n if (result.findings.length > 0) io.out('Next: adport recommendations · adport recommendations apply <id>');\n });\n\n audit\n .command('note <text>')\n .description('Record an external/manual change in the audit trail (e.g. a change made in the platform UI)')\n .option('--provider <id>', 'Provider the change concerns', 'external')\n .option('--account <id>', 'Account id the change concerns', '-')\n .action(async (text: string, opts: { provider: string; account: string }) => {\n await new AuditLog().append({\n event: 'note',\n provider: opts.provider,\n tool: 'audit_note',\n accountId: opts.account,\n summary: text,\n });\n io.out('Noted.');\n });\n\n program\n .command('connect <provider>')\n .description('Connect an ad account (guided wizard)')\n .option('--no-browser', 'Print auth URLs instead of opening a browser')\n .action(async (provider: string, opts: { browser: boolean }) => {\n if (provider === 'google') {\n const { connectGoogle } = await import('./connect/google.js');\n await connectGoogle({ openBrowser: opts.browser, io });\n return;\n }\n if (provider === 'meta') {\n const { connectMeta } = await import('./connect/meta.js');\n await connectMeta({ io });\n return;\n }\n if (provider === 'tiktok') {\n const { connectTikTok } = await import('./connect/tiktok.js');\n await connectTikTok({ io });\n return;\n }\n if (provider === 'apple') {\n const { connectApple } = await import('./connect/apple.js');\n await connectApple({ io });\n return;\n }\n if (provider === 'microsoft') {\n const { connectMicrosoft } = await import('./connect/microsoft.js');\n await connectMicrosoft({ openBrowser: opts.browser, io });\n return;\n }\n if (provider === 'reddit') {\n const { connectReddit } = await import('./connect/reddit.js');\n await connectReddit({ openBrowser: opts.browser, io });\n return;\n }\n if (provider === 'mock') {\n io.out('The mock provider is explicit demo mode, not a connection. Try: adport --demo accounts');\n return;\n }\n io.err(`Provider \"${provider}\" is not supported. Available: google, meta, tiktok, apple, microsoft, reddit, mock.`);\n process.exitCode = 1;\n });\n\n program\n .command('disconnect <provider>')\n .description('Remove a provider connection from this machine')\n .action(async (provider: string) => {\n if (!['google', 'meta', 'tiktok', 'apple', 'microsoft', 'reddit'].includes(provider)) {\n io.err(`Provider \"${provider}\" is not supported. Available: google, meta, tiktok, apple, microsoft, reddit.`);\n process.exitCode = 1;\n return;\n }\n const removed = await new CredentialStore().delete(provider);\n if (!removed) {\n io.out(`No local ${provider} credentials were stored.`);\n return;\n }\n io.out(`Removed local ${provider} credentials.`);\n io.out('Provider-side access was not revoked. Revoke the token or key at the provider if needed.');\n });\n\n const recommendations = program.command('recommendations').description('Review and act on audit findings');\n\n recommendations\n .command('list', { isDefault: true })\n .description('List findings (default: open), most severe first')\n .option('--status <status>', 'open | dismissed | applied', 'open')\n .option('--json', 'JSON output')\n .action(async (opts: { status: string; json?: boolean }) => {\n const rt = await commandRuntime();\n const result = (await rt.registry.call('recommendations_list', { status: opts.status }, rt.ctx)) as {\n findings: Array<{ id: string; severity: string; title: string; recommendation: string; proposedAction?: unknown }>;\n };\n if (opts.json) {\n io.out(json(result.findings));\n return;\n }\n if (result.findings.length === 0) {\n io.out(`No ${opts.status} findings. Run: adport audit run`);\n return;\n }\n for (const f of result.findings) {\n io.out(`[${f.severity.toUpperCase()}] ${f.id}`);\n io.out(` ${f.title}`);\n io.out(` → ${f.recommendation}${f.proposedAction ? ' (has ready-to-apply action)' : ''}`);\n }\n });\n\n recommendations\n .command('apply <findingId>')\n .description('Run a finding\\'s proposed action through the two-step validate→apply flow')\n .option('--pending <id>', 'pending_operation_id from the validation step')\n .action(async (findingId: string, opts: { pending?: string }) => {\n const rt = await commandRuntime();\n const result = await rt.registry.call(\n 'recommendation_apply',\n { finding_id: findingId, pending_operation_id: opts.pending },\n rt.ctx,\n );\n io.out(json(result));\n });\n\n recommendations\n .command('dismiss <findingId>')\n .description('Dismiss a finding (never reopened by future runs)')\n .action(async (findingId: string) => {\n const rt = await commandRuntime();\n const result = await rt.registry.call('recommendation_dismiss', { finding_id: findingId }, rt.ctx);\n io.out(json(result));\n });\n\n program\n .command('doctor')\n .description('Check credential and connection health for every provider')\n .action(async () => {\n const store = new CredentialStore();\n const records = await store.list();\n const rt = await commandRuntime();\n io.out(`policy: ${rt.policySource}`);\n io.out(`providers loaded: ${rt.ctx.providers.list().map((p) => p.id).join(', ') || '(none)'}`);\n for (const record of records) {\n io.out(`${record.provider}: credentials stored (source: ${record.source}, updated ${record.updatedAt})`);\n }\n for (const id of ['google', 'meta', 'tiktok', 'apple', 'microsoft', 'reddit'] as const) {\n const provider = rt.ctx.providers.list().find((p) => p.id === id);\n if (!provider) {\n io.out(`${id}: not connected (run \\`adport connect ${id}\\`)`);\n continue;\n }\n try {\n const accounts = await provider.listAccounts();\n io.out(`${id}: OK — ${accounts.length} accessible account(s)`);\n } catch (err) {\n io.err(`${id}: FAILED — ${err instanceof Error ? err.message : String(err)}`);\n process.exitCode = 1;\n }\n }\n });\n\n program\n .command('mcp')\n .description('Start the adport MCP server on stdio')\n .action(async () => {\n const { runStdioServer } = await import('@adport/mcp');\n await runStdioServer(await commandRuntime());\n // Keep the process alive for the stdio transport.\n await new Promise(() => {});\n });\n\n return program;\n}\n\nexport async function main(argv: string[]): Promise<void> {\n const program = buildProgram();\n try {\n await program.parseAsync(argv);\n } catch (err) {\n if (err instanceof AdportError) {\n console.error(JSON.stringify(err.toJSON(), null, 2));\n process.exitCode = 1;\n return;\n }\n throw err;\n }\n}\n","{\n \"name\": \"adport\",\n \"version\": \"0.4.0\",\n \"description\": \"adport CLI — the open control plane for paid media\",\n \"license\": \"Apache-2.0\",\n \"type\": \"module\",\n \"bin\": {\n \"adport\": \"./dist/index.js\"\n },\n \"files\": [\"dist\"],\n \"scripts\": {\n \"build\": \"tsup src/index.ts --format esm --sourcemap --clean\",\n \"test\": \"vitest run\",\n \"typecheck\": \"tsc --noEmit\",\n \"clean\": \"rm -rf dist\"\n },\n \"dependencies\": {\n \"@adport/core\": \"workspace:*\",\n \"@adport/mcp\": \"workspace:*\",\n \"@adport/provider-apple\": \"workspace:*\",\n \"@adport/provider-google\": \"workspace:*\",\n \"@adport/provider-meta\": \"workspace:*\",\n \"@adport/provider-microsoft\": \"workspace:*\",\n \"@adport/provider-reddit\": \"workspace:*\",\n \"@adport/provider-tiktok\": \"workspace:*\",\n \"commander\": \"^13.0.0\",\n \"yaml\": \"^2.6.0\",\n \"zod\": \"^4.4.3\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^26.1.2\",\n \"tsup\": \"^8.3.0\",\n \"typescript\": \"^5.8.0\",\n \"vitest\": \"^4.1.10\"\n }\n}\n","#!/usr/bin/env node\nimport { main } from './program.js';\n\nawait main(process.argv);\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/program.ts","../package.json","../src/index.ts"],"sourcesContent":["import { Command } from 'commander';\nimport packageJson from '../package.json';\nimport {\n AdportError,\n AuditLog,\n CredentialStore,\n type AdportRuntime,\n type AnyToolDefinition,\n} from '@adport/core';\n\nexport interface ProgramIO {\n out: (line: string) => void;\n err: (line: string) => void;\n}\n\nconst defaultIO: ProgramIO = {\n out: (line) => console.log(line),\n err: (line) => console.error(line),\n};\n\nfunction json(value: unknown): string {\n return JSON.stringify(value, null, 2);\n}\n\nfunction table(rows: Array<Record<string, unknown>>): string {\n if (rows.length === 0) return '(empty)';\n const keys = Object.keys(rows[0]!);\n const widths = keys.map((k) => Math.max(k.length, ...rows.map((r) => String(r[k] ?? '').length)));\n const line = (values: string[]) => values.map((v, i) => v.padEnd(widths[i]!)).join(' ');\n return [line(keys), line(widths.map((w) => '-'.repeat(w))), ...rows.map((r) => line(keys.map((k) => String(r[k] ?? ''))))].join('\\n');\n}\n\nasync function runtime(includeMock?: boolean): Promise<AdportRuntime> {\n const { assembleRuntime } = await import('@adport/mcp');\n return assembleRuntime({ includeMock });\n}\n\nexport function buildProgram(io: ProgramIO = defaultIO): Command {\n const program = new Command('adport');\n program\n .description('The open control plane for paid media (MCP + CLI)')\n .option('--demo', 'Use synthetic mock accounts and tools (never real provider data)')\n .version(packageJson.version)\n .configureOutput({ writeOut: (s) => io.out(s.trimEnd()), writeErr: (s) => io.err(s.trimEnd()) });\n const commandRuntime = () => runtime(program.opts<{ demo?: boolean }>().demo === true ? true : undefined);\n\n const tools = program.command('tools').description('Inspect and invoke the shared tool registry');\n\n tools\n .command('list')\n .description('List available tools')\n .option('--json', 'JSON output')\n .action(async (opts: { json?: boolean }) => {\n const { registry } = await commandRuntime();\n const defs = registry.list();\n if (opts.json) {\n io.out(\n json(\n defs.map((t: AnyToolDefinition) => ({\n name: t.name,\n namespace: t.namespace,\n readOnly: t.annotations.readOnly ?? false,\n destructive: t.annotations.destructive ?? false,\n })),\n ),\n );\n return;\n }\n io.out(\n table(\n defs.map((t) => ({\n name: t.name,\n namespace: t.namespace,\n mode: t.annotations.readOnly ? 'read' : t.annotations.destructive ? 'DESTRUCTIVE' : 'write',\n })),\n ),\n );\n });\n\n tools\n .command('run <name>')\n .description('Invoke a tool with JSON input (the same tools the MCP server exposes)')\n .option('--input <json>', 'JSON object with the tool arguments', '{}')\n .action(async (name: string, opts: { input: string }) => {\n const rt = await commandRuntime();\n const result = await rt.registry.call(name, JSON.parse(opts.input), rt.ctx);\n io.out(json(result));\n });\n\n program\n .command('accounts')\n .description('List connected ad accounts across providers')\n .option('--provider <id>', 'Limit to one provider')\n .option('--json', 'JSON output')\n .action(async (opts: { provider?: string; json?: boolean }) => {\n const rt = await commandRuntime();\n const result = (await rt.registry.call('accounts_list', { provider: opts.provider }, rt.ctx)) as {\n accounts: Array<Record<string, unknown>>;\n };\n io.out(opts.json ? json(result.accounts) : table(result.accounts));\n });\n\n program\n .command('report')\n .description('Normalized cross-platform performance report')\n .option('--provider <id>', 'Limit to one provider')\n .option('--level <level>', 'account | campaign | ad_group | ad', 'campaign')\n .option('--metrics <list>', 'Comma-separated metrics', 'spend,impressions,clicks,conversions')\n .option('--range <range>', 'Preset (last_7_days, ...) or START..END', 'last_7_days')\n .option('--limit <n>', 'Max rows', '100')\n .option('--json', 'JSON output')\n .action(async (opts: { provider?: string; level: string; metrics: string; range: string; limit: string; json?: boolean }) => {\n const rt = await commandRuntime();\n const dateRange = opts.range.includes('..')\n ? { start: opts.range.split('..')[0]!, end: opts.range.split('..')[1]! }\n : opts.range;\n const result = (await rt.registry.call(\n 'report',\n {\n provider: opts.provider,\n level: opts.level,\n metrics: opts.metrics.split(',').map((m) => m.trim()),\n date_range: dateRange,\n limit: Number(opts.limit),\n },\n rt.ctx,\n )) as { rows: Array<{ provider: string; accountId: string; entity: { name: string; status?: string }; metrics: Record<string, number> }>; truncated: boolean };\n if (opts.json) {\n io.out(json(result));\n return;\n }\n io.out(\n table(\n result.rows.map((r) => ({\n provider: r.provider,\n account: r.accountId,\n entity: r.entity.name,\n status: r.entity.status ?? '',\n ...r.metrics,\n })),\n ),\n );\n if (result.truncated) io.err('(truncated — raise --limit for more rows)');\n });\n\n program\n .command('policy')\n .description('Show the active write policy and where it was loaded from')\n .action(async () => {\n const rt = await commandRuntime();\n io.out(json({ source: rt.policySource, policy: rt.ctx.engine.policy }));\n });\n\n const audit = program.command('audit').description('Inspect or extend the write-audit trail');\n\n audit\n .command('show', { isDefault: true })\n .description('Show recent write-audit entries')\n .option('--limit <n>', 'Max entries', '20')\n .action(async (opts: { limit: string }) => {\n const entries = await new AuditLog().read(Number(opts.limit));\n if (entries.length === 0) {\n io.out('No audit entries yet.');\n return;\n }\n io.out(entries.map((e) => JSON.stringify(e)).join('\\n'));\n });\n\n audit\n .command('export')\n .description('Export write-audit entries to stdout for archival or compliance ingestion')\n .option('--limit <n>', 'Max entries', '10000')\n .option('--format <format>', 'jsonl | json', 'jsonl')\n .action(async (opts: { limit: string; format: string }) => {\n const limit = Number(opts.limit);\n if (!Number.isInteger(limit) || limit < 1) {\n throw new AdportError('INVALID_INPUT', '--limit must be a positive integer');\n }\n if (opts.format !== 'jsonl' && opts.format !== 'json') {\n throw new AdportError('INVALID_INPUT', '--format must be jsonl or json');\n }\n const entries = await new AuditLog().read(limit);\n io.out(opts.format === 'json' ? json(entries) : entries.map((e) => JSON.stringify(e)).join('\\n'));\n });\n\n audit\n .command('run')\n .description('Run the audit rule packs over connected accounts and persist findings')\n .option('--provider <id>', 'Limit to one provider')\n .option('--range <range>', 'Preset or START..END', 'last_30_days')\n .action(async (opts: { provider?: string; range: string }) => {\n const rt = await commandRuntime();\n const dateRange = opts.range.includes('..')\n ? { start: opts.range.split('..')[0]!, end: opts.range.split('..')[1]! }\n : opts.range;\n const result = (await rt.registry.call(\n 'audit_run',\n { provider: opts.provider, date_range: dateRange },\n rt.ctx,\n )) as { findings: Array<{ id: string; severity: string; title: string }>; counts: Record<string, number>; evaluatedAccounts: number };\n io.out(`Evaluated ${result.evaluatedAccounts} account(s): ${result.counts.critical} critical, ${result.counts.warn} warn, ${result.counts.info} info`);\n for (const finding of result.findings) {\n io.out(` [${finding.severity.toUpperCase()}] ${finding.id}\\n ${finding.title}`);\n }\n if (result.findings.length > 0) io.out('Next: adport recommendations · adport recommendations apply <id>');\n });\n\n audit\n .command('note <text>')\n .description('Record an external/manual change in the audit trail (e.g. a change made in the platform UI)')\n .option('--provider <id>', 'Provider the change concerns', 'external')\n .option('--account <id>', 'Account id the change concerns', '-')\n .action(async (text: string, opts: { provider: string; account: string }) => {\n await new AuditLog().append({\n event: 'note',\n provider: opts.provider,\n tool: 'audit_note',\n accountId: opts.account,\n summary: text,\n });\n io.out('Noted.');\n });\n\n program\n .command('connect <provider>')\n .description('Connect an ad account (guided wizard)')\n .option('--no-browser', 'Print auth URLs instead of opening a browser')\n .action(async (provider: string, opts: { browser: boolean }) => {\n if (provider === 'google') {\n const { connectGoogle } = await import('./connect/google.js');\n await connectGoogle({ openBrowser: opts.browser, io });\n return;\n }\n if (provider === 'meta') {\n const { connectMeta } = await import('./connect/meta.js');\n await connectMeta({ io });\n return;\n }\n if (provider === 'tiktok') {\n const { connectTikTok } = await import('./connect/tiktok.js');\n await connectTikTok({ io });\n return;\n }\n if (provider === 'apple') {\n const { connectApple } = await import('./connect/apple.js');\n await connectApple({ io });\n return;\n }\n if (provider === 'microsoft') {\n const { connectMicrosoft } = await import('./connect/microsoft.js');\n await connectMicrosoft({ openBrowser: opts.browser, io });\n return;\n }\n if (provider === 'reddit') {\n const { connectReddit } = await import('./connect/reddit.js');\n await connectReddit({ openBrowser: opts.browser, io });\n return;\n }\n if (provider === 'mock') {\n io.out('The mock provider is explicit demo mode, not a connection. Try: adport --demo accounts');\n return;\n }\n io.err(`Provider \"${provider}\" is not supported. Available: google, meta, tiktok, apple, microsoft, reddit, mock.`);\n process.exitCode = 1;\n });\n\n program\n .command('disconnect <provider>')\n .description('Remove a provider connection from this machine')\n .action(async (provider: string) => {\n if (!['google', 'meta', 'tiktok', 'apple', 'microsoft', 'reddit'].includes(provider)) {\n io.err(`Provider \"${provider}\" is not supported. Available: google, meta, tiktok, apple, microsoft, reddit.`);\n process.exitCode = 1;\n return;\n }\n const removed = await new CredentialStore().delete(provider);\n if (!removed) {\n io.out(`No local ${provider} credentials were stored.`);\n return;\n }\n io.out(`Removed local ${provider} credentials.`);\n io.out('Provider-side access was not revoked. Revoke the token or key at the provider if needed.');\n });\n\n const recommendations = program.command('recommendations').description('Review and act on audit findings');\n\n recommendations\n .command('list', { isDefault: true })\n .description('List findings (default: open), most severe first')\n .option('--status <status>', 'open | dismissed | applied', 'open')\n .option('--json', 'JSON output')\n .action(async (opts: { status: string; json?: boolean }) => {\n const rt = await commandRuntime();\n const result = (await rt.registry.call('recommendations_list', { status: opts.status }, rt.ctx)) as {\n findings: Array<{ id: string; severity: string; title: string; recommendation: string; proposedAction?: unknown }>;\n };\n if (opts.json) {\n io.out(json(result.findings));\n return;\n }\n if (result.findings.length === 0) {\n io.out(`No ${opts.status} findings. Run: adport audit run`);\n return;\n }\n for (const f of result.findings) {\n io.out(`[${f.severity.toUpperCase()}] ${f.id}`);\n io.out(` ${f.title}`);\n io.out(` → ${f.recommendation}${f.proposedAction ? ' (has ready-to-apply action)' : ''}`);\n }\n });\n\n recommendations\n .command('apply <findingId>')\n .description('Run a finding\\'s proposed action through the two-step validate→apply flow')\n .option('--pending <id>', 'pending_operation_id from the validation step')\n .action(async (findingId: string, opts: { pending?: string }) => {\n const rt = await commandRuntime();\n const result = await rt.registry.call(\n 'recommendation_apply',\n { finding_id: findingId, pending_operation_id: opts.pending },\n rt.ctx,\n );\n io.out(json(result));\n });\n\n recommendations\n .command('dismiss <findingId>')\n .description('Dismiss a finding (never reopened by future runs)')\n .action(async (findingId: string) => {\n const rt = await commandRuntime();\n const result = await rt.registry.call('recommendation_dismiss', { finding_id: findingId }, rt.ctx);\n io.out(json(result));\n });\n\n program\n .command('doctor')\n .description('Check credential and connection health for every provider')\n .action(async () => {\n const store = new CredentialStore();\n const records = await store.list();\n const rt = await commandRuntime();\n io.out(`policy: ${rt.policySource}`);\n io.out(`providers loaded: ${rt.ctx.providers.list().map((p) => p.id).join(', ') || '(none)'}`);\n for (const record of records) {\n io.out(`${record.provider}: credentials stored (source: ${record.source}, updated ${record.updatedAt})`);\n }\n for (const id of ['google', 'meta', 'tiktok', 'apple', 'microsoft', 'reddit'] as const) {\n const provider = rt.ctx.providers.list().find((p) => p.id === id);\n if (!provider) {\n io.out(`${id}: not connected (run \\`adport connect ${id}\\`)`);\n continue;\n }\n try {\n const accounts = await provider.listAccounts();\n io.out(`${id}: OK — ${accounts.length} accessible account(s)`);\n } catch (err) {\n io.err(`${id}: FAILED — ${err instanceof Error ? err.message : String(err)}`);\n process.exitCode = 1;\n }\n }\n });\n\n program\n .command('mcp')\n .description('Start the adport MCP server on stdio')\n .action(async () => {\n const { runStdioServer } = await import('@adport/mcp');\n await runStdioServer(await commandRuntime());\n // Keep the process alive for the stdio transport.\n await new Promise(() => {});\n });\n\n return program;\n}\n\nexport async function main(argv: string[]): Promise<void> {\n const program = buildProgram();\n try {\n await program.parseAsync(argv);\n } catch (err) {\n if (err instanceof AdportError) {\n console.error(JSON.stringify(err.toJSON(), null, 2));\n process.exitCode = 1;\n return;\n }\n throw err;\n }\n}\n","{\n \"name\": \"adport\",\n \"version\": \"0.5.0\",\n \"description\": \"adport CLI — the open control plane for paid media\",\n \"license\": \"Apache-2.0\",\n \"type\": \"module\",\n \"bin\": {\n \"adport\": \"./dist/index.js\"\n },\n \"files\": [\"dist\"],\n \"scripts\": {\n \"build\": \"tsup src/index.ts --format esm --sourcemap --clean\",\n \"test\": \"vitest run\",\n \"typecheck\": \"tsc --noEmit\",\n \"clean\": \"rm -rf dist\"\n },\n \"dependencies\": {\n \"@adport/core\": \"workspace:*\",\n \"@adport/mcp\": \"workspace:*\",\n \"@adport/provider-apple\": \"workspace:*\",\n \"@adport/provider-google\": \"workspace:*\",\n \"@adport/provider-meta\": \"workspace:*\",\n \"@adport/provider-microsoft\": \"workspace:*\",\n \"@adport/provider-reddit\": \"workspace:*\",\n \"@adport/provider-tiktok\": \"workspace:*\",\n \"commander\": \"^13.0.0\",\n \"yaml\": \"^2.6.0\",\n \"zod\": \"^4.4.3\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^26.1.2\",\n \"tsup\": \"^8.3.0\",\n \"typescript\": \"^5.8.0\",\n \"vitest\": \"^4.1.10\"\n }\n}\n","#!/usr/bin/env node\nimport { main } from './program.js';\n\nawait main(process.argv);\n"],"mappings":"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","names":[]}
|
|
@@ -28,7 +28,7 @@ async function connectReddit(input) {
|
|
|
28
28
|
const clientSecret = (await rl.question(`App secret${existing?.data.client_secret ? " (Enter to reuse stored)" : ""}: `)).trim() || existing?.data.client_secret || "";
|
|
29
29
|
const redirectUri = (await rl.question("Exact redirect URI [http://localhost:53682]: ")).trim() || "http://localhost:53682";
|
|
30
30
|
const userAgent = (await rl.question(
|
|
31
|
-
`Honest User-Agent${existing?.data.user_agent ? " (Enter to reuse stored)" : " (e.g. desktop:dev.adport.local:v0.
|
|
31
|
+
`Honest User-Agent${existing?.data.user_agent ? " (Enter to reuse stored)" : " (e.g. desktop:dev.adport.local:v0.5.0 (by /u/yourname))"}: `
|
|
32
32
|
)).trim() || existing?.data.user_agent || "";
|
|
33
33
|
if (!clientId || !clientSecret || !userAgent) {
|
|
34
34
|
input.io.err("Missing app id, app secret, or User-Agent \u2014 aborting.");
|
|
@@ -86,4 +86,4 @@ function validateLocalRedirect(value) {
|
|
|
86
86
|
export {
|
|
87
87
|
connectReddit
|
|
88
88
|
};
|
|
89
|
-
//# sourceMappingURL=reddit-
|
|
89
|
+
//# sourceMappingURL=reddit-EVDTD2DI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/connect/reddit.ts"],"sourcesContent":["import readline from 'node:readline/promises';\nimport { CredentialStore } from '@adport/core';\nimport { RedditAdsClient, RedditAdsProvider, type RedditCredentials } from '@adport/provider-reddit';\nimport type { ProgramIO } from '../program.js';\nimport { printLocalConnectionIntro, printLocalConnectionSaved } from './local.js';\nimport {\n buildRedditAuthUrl,\n exchangeRedditCode,\n generateOAuthState,\n openInBrowser,\n startLoopbackServer,\n} from './oauth.js';\n\nexport async function connectReddit(input: { openBrowser: boolean; io: ProgramIO }): Promise<void> {\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const store = new CredentialStore();\n try {\n printLocalConnectionIntro(input.io, 'Reddit Ads');\n input.io.out('Create a Reddit developer app at https://www.reddit.com/prefs/apps (type: web app).');\n input.io.out('Reddit requires the redirect URI to match exactly. For local use, register');\n input.io.out('http://localhost:53682 and keep this terminal running during authorization.');\n input.io.out('');\n\n const existing = await store.get('reddit');\n const clientId = (await rl.question(`App/client ID${existing?.data.client_id ? ' (Enter to reuse stored)' : ''}: `)).trim()\n || existing?.data.client_id || '';\n const clientSecret = (await rl.question(`App secret${existing?.data.client_secret ? ' (Enter to reuse stored)' : ''}: `)).trim()\n || existing?.data.client_secret || '';\n const redirectUri = (await rl.question('Exact redirect URI [http://localhost:53682]: ')).trim()\n || 'http://localhost:53682';\n const userAgent = (await rl.question(\n `Honest User-Agent${existing?.data.user_agent ? ' (Enter to reuse stored)' : ' (e.g. desktop:dev.adport.local:v0.
|
|
1
|
+
{"version":3,"sources":["../src/connect/reddit.ts"],"sourcesContent":["import readline from 'node:readline/promises';\nimport { CredentialStore } from '@adport/core';\nimport { RedditAdsClient, RedditAdsProvider, type RedditCredentials } from '@adport/provider-reddit';\nimport type { ProgramIO } from '../program.js';\nimport { printLocalConnectionIntro, printLocalConnectionSaved } from './local.js';\nimport {\n buildRedditAuthUrl,\n exchangeRedditCode,\n generateOAuthState,\n openInBrowser,\n startLoopbackServer,\n} from './oauth.js';\n\nexport async function connectReddit(input: { openBrowser: boolean; io: ProgramIO }): Promise<void> {\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const store = new CredentialStore();\n try {\n printLocalConnectionIntro(input.io, 'Reddit Ads');\n input.io.out('Create a Reddit developer app at https://www.reddit.com/prefs/apps (type: web app).');\n input.io.out('Reddit requires the redirect URI to match exactly. For local use, register');\n input.io.out('http://localhost:53682 and keep this terminal running during authorization.');\n input.io.out('');\n\n const existing = await store.get('reddit');\n const clientId = (await rl.question(`App/client ID${existing?.data.client_id ? ' (Enter to reuse stored)' : ''}: `)).trim()\n || existing?.data.client_id || '';\n const clientSecret = (await rl.question(`App secret${existing?.data.client_secret ? ' (Enter to reuse stored)' : ''}: `)).trim()\n || existing?.data.client_secret || '';\n const redirectUri = (await rl.question('Exact redirect URI [http://localhost:53682]: ')).trim()\n || 'http://localhost:53682';\n const userAgent = (await rl.question(\n `Honest User-Agent${existing?.data.user_agent ? ' (Enter to reuse stored)' : ' (e.g. desktop:dev.adport.local:v0.5.0 (by /u/yourname))'}: `,\n )).trim() || existing?.data.user_agent || '';\n if (!clientId || !clientSecret || !userAgent) {\n input.io.err('Missing app id, app secret, or User-Agent — aborting.');\n process.exitCode = 1;\n return;\n }\n\n const redirect = validateLocalRedirect(redirectUri);\n const state = generateOAuthState();\n const loopback = await startLoopbackServer(\n redirect.hostname as '127.0.0.1' | 'localhost',\n state,\n Number(redirect.port),\n redirect.pathname === '/' ? '' : redirect.pathname,\n );\n const authUrl = buildRedditAuthUrl(clientId, redirectUri, state);\n input.io.out('Authorizing scopes: adsread, adsedit, adsdatadeletion (permanent refresh token).');\n if (input.openBrowser) {\n openInBrowser(authUrl);\n input.io.out(`If the browser did not open, visit:\\n ${authUrl}`);\n } else {\n input.io.out(`Open this URL in a browser on this machine:\\n ${authUrl}`);\n }\n\n let refreshToken: string;\n try {\n const code = await loopback.waitForCode;\n ({ refreshToken } = await exchangeRedditCode({ clientId, clientSecret, code, redirectUri, userAgent }));\n } finally {\n loopback.close();\n }\n const credentials: RedditCredentials = { clientId, clientSecret, refreshToken, userAgent };\n input.io.out('Verifying business and ad-account access…');\n const accounts = await new RedditAdsProvider(new RedditAdsClient(credentials)).listAccounts();\n await store.set({\n provider: 'reddit', source: 'byo',\n data: { client_id: clientId, client_secret: clientSecret, refresh_token: refreshToken, user_agent: userAgent },\n });\n input.io.out(`✓ Connected. ${accounts.length} accessible Reddit ad account(s).`);\n for (const account of accounts) input.io.out(` ${account.id} ${account.name}${account.currency ? ` ${account.currency}` : ''}`);\n printLocalConnectionSaved(input.io);\n input.io.out('Try: adport accounts --provider reddit · adport report --provider reddit · adport mcp');\n } finally {\n rl.close();\n }\n}\n\nfunction validateLocalRedirect(value: string): URL {\n const url = new URL(value);\n if (url.protocol !== 'http:' || !['localhost', '127.0.0.1'].includes(url.hostname) || !url.port || url.search || url.hash) {\n throw new Error('Reddit local redirect URI must be http://localhost:<port> or http://127.0.0.1:<port>, optionally with a path.');\n }\n return url;\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adport",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "adport CLI — the open control plane for paid media",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
"commander": "^13.0.0",
|
|
15
15
|
"yaml": "^2.6.0",
|
|
16
16
|
"zod": "^4.4.3",
|
|
17
|
-
"@adport/core": "0.
|
|
18
|
-
"@adport/
|
|
19
|
-
"@adport/
|
|
20
|
-
"@adport/provider-
|
|
21
|
-
"@adport/provider-
|
|
22
|
-
"@adport/provider-microsoft": "0.
|
|
23
|
-
"@adport/provider-reddit": "0.
|
|
24
|
-
"@adport/provider-tiktok": "0.
|
|
17
|
+
"@adport/core": "0.5.0",
|
|
18
|
+
"@adport/mcp": "0.5.0",
|
|
19
|
+
"@adport/provider-apple": "0.5.0",
|
|
20
|
+
"@adport/provider-meta": "0.5.0",
|
|
21
|
+
"@adport/provider-google": "0.5.0",
|
|
22
|
+
"@adport/provider-microsoft": "0.5.0",
|
|
23
|
+
"@adport/provider-reddit": "0.5.0",
|
|
24
|
+
"@adport/provider-tiktok": "0.5.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^26.1.2",
|