@koda-sl/baker-cli 0.379.0-dev.0114084a3 → 0.379.0-dev.600795410
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/README.md +2 -2
- package/dist/{chunk-VLUGGVJL.js → chunk-MK4AIHRF.js} +69 -15
- package/dist/chunk-MK4AIHRF.js.map +1 -0
- package/dist/cli.js +475 -917
- package/dist/cli.js.map +1 -1
- package/dist/{shared-J7DQZ2ED.js → shared-DDBXEUL4.js} +4 -2
- package/package.json +1 -1
- package/dist/chunk-VLUGGVJL.js.map +0 -1
- /package/dist/{shared-J7DQZ2ED.js.map → shared-DDBXEUL4.js.map} +0 -0
package/README.md
CHANGED
|
@@ -865,7 +865,7 @@ baker ads x targeting-constants --constant tv_shows --locale en-US
|
|
|
865
865
|
|
|
866
866
|
### Meta Ads (`baker ads meta`)
|
|
867
867
|
|
|
868
|
-
Meta Marketing API (Facebook + Instagram). Connect via OAuth in the dashboard, pick which ad accounts to scope to, then call from the CLI. Account ID via `--account-id act_123` or `BAKER_META_AD_ACCOUNT_ID` env var.
|
|
868
|
+
Meta Marketing API (Facebook + Instagram). Connect via OAuth in the dashboard, pick which ad accounts to scope to, then call from the CLI. Account ID via `--account-id act_123` or `BAKER_META_AD_ACCOUNT_ID` env var; with a single connected account it is used automatically.
|
|
869
869
|
|
|
870
870
|
The command surface is **curated for AI agents**, not 1:1 with the Marketing API. Smart defaults so an agent doesn't need to remember every flag.
|
|
871
871
|
|
|
@@ -969,7 +969,7 @@ baker ads meta draft remove meta_temp_cr # removing a create cascades to depen
|
|
|
969
969
|
baker ads meta draft clear
|
|
970
970
|
```
|
|
971
971
|
|
|
972
|
-
Status changes are `pause|resume|archive
|
|
972
|
+
Status changes are `pause|resume|archive` subcommands on `campaigns`/`adsets`/`ads`. `duplicate` reconstructs a paused copy from the live snapshot (`--replace` also pauses the original once the copy publishes — write it attached, `--replace=false` or `--no-replace`, since the spaced form `--replace false` is rejected: a boolean flag written with a space is set to true and the word dropped). Carousel/dynamic creatives and complex targeting go via `--file` (creativeType `carousel`/`dynamic`; full Meta targeting spec). Advantage+ Creative enhancements: `--standard-enhancements on|off`, or per-feature toggles via a `--file` `enhancements.features` map.
|
|
973
973
|
|
|
974
974
|
#### Smart defaults (so agents don't enumerate the API)
|
|
975
975
|
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
+
cacheGet,
|
|
3
|
+
cacheSet,
|
|
2
4
|
handleConnectionError,
|
|
3
5
|
needsConnectionFix,
|
|
4
6
|
writeAdsJson
|
|
5
7
|
} from "./chunk-XHC4LMK4.js";
|
|
6
8
|
import {
|
|
7
|
-
ApiError
|
|
9
|
+
ApiError,
|
|
10
|
+
apiGet
|
|
8
11
|
} from "./chunk-MF7YA62W.js";
|
|
9
12
|
import {
|
|
10
13
|
getEnv
|
|
@@ -46,30 +49,80 @@ function handleMetaError(err) {
|
|
|
46
49
|
process.exit(1);
|
|
47
50
|
}
|
|
48
51
|
var ACCOUNT_ID_RE = /^(act_)?[0-9]+$/;
|
|
49
|
-
|
|
52
|
+
var META_ACCOUNTS_CACHE = { category: "meta-accounts", key: "accounts:scoped", ttlMs: 60 * 60 * 1e3 };
|
|
53
|
+
function withActPrefix(id) {
|
|
54
|
+
return id.startsWith("act_") ? id : `act_${id}`;
|
|
55
|
+
}
|
|
56
|
+
async function fetchConnectedAccounts(useCache) {
|
|
57
|
+
if (useCache) {
|
|
58
|
+
const cached = cacheGet(META_ACCOUNTS_CACHE.category, META_ACCOUNTS_CACHE.key);
|
|
59
|
+
if (cached) return cached.data;
|
|
60
|
+
}
|
|
61
|
+
const data = await apiGet("/api/ads/meta/accounts", useCache ? {} : { "skip-cache": "true" });
|
|
62
|
+
if (useCache) {
|
|
63
|
+
cacheSet(META_ACCOUNTS_CACHE.category, META_ACCOUNTS_CACHE.key, data, META_ACCOUNTS_CACHE.ttlMs);
|
|
64
|
+
}
|
|
65
|
+
return data;
|
|
66
|
+
}
|
|
67
|
+
function connectedAccountId(account) {
|
|
68
|
+
const id = account.externalId ?? account.id ?? account.account_id;
|
|
69
|
+
return id && ACCOUNT_ID_RE.test(id) ? withActPrefix(id) : void 0;
|
|
70
|
+
}
|
|
71
|
+
async function resolveAccountIdArg(args) {
|
|
50
72
|
const fromArgs = args["account-id"];
|
|
51
73
|
const id = fromArgs || getEnv().BAKER_META_AD_ACCOUNT_ID;
|
|
52
|
-
if (
|
|
74
|
+
if (id) {
|
|
75
|
+
if (!ACCOUNT_ID_RE.test(id)) {
|
|
76
|
+
writeAdsJson({
|
|
77
|
+
ok: false,
|
|
78
|
+
error: {
|
|
79
|
+
code: "INVALID_ACCOUNT_ID",
|
|
80
|
+
message: `Invalid account ID "${id}". Expected numeric ID, optionally prefixed with "act_".`
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
return withActPrefix(id);
|
|
86
|
+
}
|
|
87
|
+
let accounts;
|
|
88
|
+
try {
|
|
89
|
+
accounts = await fetchConnectedAccounts(!args["no-cache"]);
|
|
90
|
+
} catch (err) {
|
|
91
|
+
if (err instanceof ApiError && needsConnectionFix(err.code, err.message)) {
|
|
92
|
+
handleConnectionError("meta_ads", err.message);
|
|
93
|
+
}
|
|
53
94
|
writeAdsJson({
|
|
54
95
|
ok: false,
|
|
55
96
|
error: {
|
|
56
97
|
code: "MISSING_ACCOUNT_ID",
|
|
57
|
-
message: "Pass --account-id or set BAKER_META_AD_ACCOUNT_ID. Run `baker ads meta accounts` to find IDs."
|
|
98
|
+
message: "Could not look up this company's Meta ad accounts. Pass --account-id or set BAKER_META_AD_ACCOUNT_ID. Run `baker ads meta accounts` to find IDs."
|
|
58
99
|
}
|
|
59
100
|
});
|
|
60
101
|
process.exit(1);
|
|
61
102
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
103
|
+
const connected = accounts.flatMap((account) => {
|
|
104
|
+
const accountId = connectedAccountId(account);
|
|
105
|
+
return accountId ? [{ id: accountId, name: account.name }] : [];
|
|
106
|
+
});
|
|
107
|
+
const [single] = connected;
|
|
108
|
+
if (connected.length === 1 && single) {
|
|
109
|
+
process.stderr.write(`Using Meta ad account ${single.name ? `"${single.name}" ` : ""}(${single.id})
|
|
110
|
+
`);
|
|
111
|
+
return single.id;
|
|
71
112
|
}
|
|
72
|
-
|
|
113
|
+
if (connected.length === 0) {
|
|
114
|
+
handleConnectionError("meta_ads");
|
|
115
|
+
}
|
|
116
|
+
const list = connected.map((account) => ` ${account.id}${account.name ? ` ${account.name}` : ""}`).join("\n");
|
|
117
|
+
writeAdsJson({
|
|
118
|
+
ok: false,
|
|
119
|
+
error: {
|
|
120
|
+
code: "MULTIPLE_ACCOUNTS",
|
|
121
|
+
message: `This company connected ${connected.length} Meta ad accounts. Pass --account-id or set BAKER_META_AD_ACCOUNT_ID:
|
|
122
|
+
${list}`
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
process.exit(1);
|
|
73
126
|
}
|
|
74
127
|
function getDateRange(args) {
|
|
75
128
|
const datePreset = args["date-preset"];
|
|
@@ -116,6 +169,7 @@ function statusFilterHints(rows, effectiveStatus, noun) {
|
|
|
116
169
|
export {
|
|
117
170
|
metaForbiddenFix,
|
|
118
171
|
handleMetaError,
|
|
172
|
+
META_ACCOUNTS_CACHE,
|
|
119
173
|
resolveAccountIdArg,
|
|
120
174
|
getDateRange,
|
|
121
175
|
todayIso,
|
|
@@ -125,4 +179,4 @@ export {
|
|
|
125
179
|
resolveEffectiveStatus,
|
|
126
180
|
statusFilterHints
|
|
127
181
|
};
|
|
128
|
-
//# sourceMappingURL=chunk-
|
|
182
|
+
//# sourceMappingURL=chunk-MK4AIHRF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/ads/meta/shared.ts"],"sourcesContent":["import { ApiError, apiGet } from \"../../../client.ts\";\nimport { getEnv } from \"../../../env.ts\";\nimport { handleConnectionError, needsConnectionFix } from \"../../../error-handler.ts\";\nimport { cacheGet, cacheSet } from \"../cache.ts\";\nimport { writeAdsJson } from \"../output.ts\";\nimport type { AdsErrorEnvelope, QueryFix } from \"../types.ts\";\n\nconst DAY_MS = 86_400_000;\n\n/**\n * Meta answers a permission refusal (Graph codes 200/10/294) with a bare\n * \"Permissions error\" that covers two causes needing opposite remedies: a\n * consent grant the connection never got — nothing validates Meta's granted\n * scopes after connect, unlike HubSpot's `requireCapability` — or a role the\n * user lacks on one asset, since a Pixel/Dataset, Page or catalog lives in a\n * Business and is assigned separately from the ad account. Only the blast radius\n * separates them, so hand the agent that test rather than a verdict: guessing\n * \"reconnect\" wastes the user's time on an unassigned asset, and ruling it out\n * strands a connection that really is short a scope.\n */\nexport function metaForbiddenFix(message: string): QueryFix {\n return {\n action: \"reject\",\n explanation: [\n message,\n \"This is a permission refusal, not a dead connection, and Meta returns the same code for two causes with opposite remedies. Tell them apart by how much else works before you answer.\",\n \"If other reads on this account are ALSO refused (campaigns, ad sets, insights), the connection is short a permission it was never granted. Only the user can widen it, by reconnecting Meta from the dashboard.\",\n \"If those reads work and only this object is refused, the asset (pixel/dataset, Page, or catalog) belongs to a Business the connected user holds no role in. Ad-account access does not carry asset access and reconnecting cannot grant it — the client assigns that asset to the connected user or partner in Meta Business settings, under the asset's own section (Data sources → Datasets for a pixel).\",\n \"Either way do not retry the same call, and do not abort the wider job. Continue with what you can read, and state in your answer that this specific check could not run and why — never present the task as verified when this step was skipped.\",\n ].join(\"\\n\\n\"),\n };\n}\n\nexport function handleMetaError(err: unknown): never {\n if (err instanceof ApiError) {\n if (needsConnectionFix(err.code, err.message)) {\n handleConnectionError(\"meta_ads\", err.message);\n }\n const envelope: AdsErrorEnvelope = {\n ok: false,\n error: {\n code: err.code,\n message: err.message,\n fix: err.code === \"FORBIDDEN\" ? metaForbiddenFix(err.message) : { action: \"reject\", explanation: err.message },\n retryable: err.code === \"RATE_LIMITED\" || err.code === \"UNAVAILABLE\" || err.code === \"INTERNAL_ERROR\",\n },\n };\n writeAdsJson(envelope);\n process.exit(1);\n }\n const message = err instanceof Error ? err.message : \"Unexpected error\";\n writeAdsJson({ ok: false, error: { code: \"NETWORK_ERROR\", message } });\n process.exit(1);\n}\n\nconst ACCOUNT_ID_RE = /^(act_)?[0-9]+$/;\n\n/** A row of `/api/ads/meta/accounts` — the company's picked accounts, as `baker ads meta accounts` prints them. */\ninterface ConnectedMetaAccount {\n externalId?: string;\n id?: string;\n account_id?: string;\n name?: string;\n}\n\n/** Shared with `baker ads meta accounts`, so one listing serves both. */\nexport const META_ACCOUNTS_CACHE = { category: \"meta-accounts\", key: \"accounts:scoped\", ttlMs: 60 * 60 * 1000 };\n\nfunction withActPrefix(id: string): string {\n return id.startsWith(\"act_\") ? id : `act_${id}`;\n}\n\nasync function fetchConnectedAccounts(useCache: boolean): Promise<ConnectedMetaAccount[]> {\n if (useCache) {\n const cached = cacheGet<ConnectedMetaAccount[]>(META_ACCOUNTS_CACHE.category, META_ACCOUNTS_CACHE.key);\n if (cached) return cached.data;\n }\n const data = await apiGet<ConnectedMetaAccount[]>(\"/api/ads/meta/accounts\", useCache ? {} : { \"skip-cache\": \"true\" });\n if (useCache) {\n cacheSet(META_ACCOUNTS_CACHE.category, META_ACCOUNTS_CACHE.key, data, META_ACCOUNTS_CACHE.ttlMs);\n }\n return data;\n}\n\nfunction connectedAccountId(account: ConnectedMetaAccount): string | undefined {\n const id = account.externalId ?? account.id ?? account.account_id;\n return id && ACCOUNT_ID_RE.test(id) ? withActPrefix(id) : undefined;\n}\n\n/**\n * The Meta ad account a command works on: `--account-id`, else\n * `BAKER_META_AD_ACCOUNT_ID`, else the company's only connected account — the\n * default `baker ads meta accounts` promises. With several connected, nothing\n * is picked for the agent: the refusal lists them so the next call can name one.\n */\nexport async function resolveAccountIdArg(args: Record<string, unknown>): Promise<string> {\n const fromArgs = args[\"account-id\"] as string | undefined;\n const id = fromArgs || getEnv().BAKER_META_AD_ACCOUNT_ID;\n if (id) {\n if (!ACCOUNT_ID_RE.test(id)) {\n writeAdsJson({\n ok: false,\n error: {\n code: \"INVALID_ACCOUNT_ID\",\n message: `Invalid account ID \"${id}\". Expected numeric ID, optionally prefixed with \"act_\".`,\n },\n });\n process.exit(1);\n }\n return withActPrefix(id);\n }\n\n let accounts: ConnectedMetaAccount[];\n try {\n accounts = await fetchConnectedAccounts(!args[\"no-cache\"]);\n } catch (err) {\n if (err instanceof ApiError && needsConnectionFix(err.code, err.message)) {\n handleConnectionError(\"meta_ads\", err.message);\n }\n writeAdsJson({\n ok: false,\n error: {\n code: \"MISSING_ACCOUNT_ID\",\n message:\n \"Could not look up this company's Meta ad accounts. Pass --account-id or set BAKER_META_AD_ACCOUNT_ID. Run `baker ads meta accounts` to find IDs.\",\n },\n });\n process.exit(1);\n }\n\n const connected = accounts.flatMap((account) => {\n const accountId = connectedAccountId(account);\n return accountId ? [{ id: accountId, name: account.name }] : [];\n });\n const [single] = connected;\n if (connected.length === 1 && single) {\n process.stderr.write(`Using Meta ad account ${single.name ? `\"${single.name}\" ` : \"\"}(${single.id})\\n`);\n return single.id;\n }\n if (connected.length === 0) {\n handleConnectionError(\"meta_ads\");\n }\n const list = connected.map((account) => ` ${account.id}${account.name ? ` ${account.name}` : \"\"}`).join(\"\\n\");\n writeAdsJson({\n ok: false,\n error: {\n code: \"MULTIPLE_ACCOUNTS\",\n message: `This company connected ${connected.length} Meta ad accounts. Pass --account-id or set BAKER_META_AD_ACCOUNT_ID:\\n${list}`,\n },\n });\n process.exit(1);\n}\n\nexport function getDateRange(args: Record<string, unknown>): { datePreset?: string; since?: string; until?: string } {\n const datePreset = args[\"date-preset\"] as string | undefined;\n const since = args.since as string | undefined;\n const until = args.until as string | undefined;\n if (since && until) return { since, until };\n return { datePreset: datePreset ?? \"last_7d\" };\n}\n\nexport function todayIso(): string {\n return new Date().toISOString().slice(0, 10);\n}\n\nexport function daysAgoIso(days: number): string {\n return new Date(Date.now() - days * DAY_MS).toISOString().slice(0, 10);\n}\n\nexport function csvOrJson(args: Record<string, unknown>): string {\n return (args.output as string | undefined) ?? \"json\";\n}\n\n/**\n * Matched by Meta itself, so finding one entity by name reads only the rows that\n * match instead of the whole account.\n */\nexport const NAME_CONTAINS_ARG = {\n type: \"string\",\n description:\n \"Only rows whose name contains this text, matched by Meta before anything is returned. Start here to find one entity by name: --name-contains octubre --all-statuses\",\n} as const;\n\n/**\n * Default to ACTIVE-only on listings — that's almost always what an AI agent or\n * a human glance wants. Pass `--effective-status ACTIVE,PAUSED` to override, or\n * `--all-statuses` to drop the filter entirely.\n */\nexport function resolveEffectiveStatus(args: Record<string, unknown>): string | undefined {\n if (args[\"all-statuses\"]) {\n return undefined;\n }\n const explicit = args[\"effective-status\"] as string | undefined;\n if (explicit) {\n return explicit;\n }\n return \"ACTIVE\";\n}\n\n/**\n * An empty listing under a status filter reads exactly like \"nothing exists\":\n * a paused campaign's ad sets are CAMPAIGN_PAUSED, so the ACTIVE default hides\n * every one of them. Say which filter produced the empty list and how to widen it.\n */\nexport function statusFilterHints(\n rows: ReadonlyArray<unknown>,\n effectiveStatus: string | undefined,\n noun: string,\n): string[] {\n if (rows.length > 0 || effectiveStatus === undefined) return [];\n if (effectiveStatus === \"ACTIVE\") {\n return [\n `No ACTIVE ${noun}. The ACTIVE filter hides paused, archived and in-review ones (under a paused campaign or ad set that is all of them), so this does NOT mean none exist. Re-run with --all-statuses before concluding there are none.`,\n ];\n }\n return [\n `No ${noun} with effective_status ${effectiveStatus}. Re-run with --all-statuses to see every status before concluding there are none.`,\n ];\n}\n"],"mappings":"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","names":[]}
|