@koda-sl/baker-cli 0.144.0 → 0.146.1
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-PEBP6G74.js → chunk-FBUVCOH6.js} +2 -2
- package/dist/{chunk-SCI57ZZ6.js → chunk-LVCBCJWF.js} +9 -3
- package/dist/chunk-LVCBCJWF.js.map +1 -0
- package/dist/{chunk-BFZELBTE.js → chunk-UFBKUMN2.js} +3 -3
- package/dist/cli.js +30 -7
- package/dist/cli.js.map +1 -1
- package/dist/{client-N7XWYCHT.js → client-R5ZSVIK3.js} +2 -2
- package/dist/{output-7M5VQPTZ.js → output-R534QTMO.js} +3 -3
- package/dist/{shared-6SZHAUM2.js → shared-MUWU7BK5.js} +4 -4
- package/package.json +1 -1
- package/dist/chunk-SCI57ZZ6.js.map +0 -1
- /package/dist/{chunk-PEBP6G74.js.map → chunk-FBUVCOH6.js.map} +0 -0
- /package/dist/{chunk-BFZELBTE.js.map → chunk-UFBKUMN2.js.map} +0 -0
- /package/dist/{client-N7XWYCHT.js.map → client-R5ZSVIK3.js.map} +0 -0
- /package/dist/{output-7M5VQPTZ.js.map → output-R534QTMO.js.map} +0 -0
- /package/dist/{shared-6SZHAUM2.js.map → shared-MUWU7BK5.js.map} +0 -0
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ export BAKER_CHAT_ID="<chat-id>"
|
|
|
42
42
|
- `BAKER_GA4_PROPERTY_ID` — default GA4 property ID. Used when `--property-id` is not passed. If neither is set and exactly one property is connected, it is auto-selected.
|
|
43
43
|
- `BAKER_GSC_SITE_URL` — default GSC site URL. Used when `--site-url` is not passed. If neither is set and exactly one site is verified, it is auto-selected.
|
|
44
44
|
- `BAKER_X_ADS_ACCOUNT_ID` — default X Ads account ID (base36). Used when `--account-id` is not passed. If neither is set and exactly one X Ads account is connected, it is auto-selected.
|
|
45
|
-
- `BAKER_CHAT_ID` — chat context for staged Work Action commands and staged Scheduled Action create/update/delete. `scheduled-actions trigger` does not require it.
|
|
45
|
+
- `BAKER_CHAT_ID` — chat context for staged Work Action commands and staged Scheduled Action create/update/delete. `scheduled-actions trigger` does not require it. When set, it is also sent as an `x-baker-chat-id` header on every request, so library additions that apply immediately (images, videos, followed brands) are listed in that chat's changes as already applied.
|
|
46
46
|
|
|
47
47
|
## Debug logging
|
|
48
48
|
|
|
@@ -486,7 +486,7 @@ baker ads google draft remove g_temp_ab12 # cascades to dependents
|
|
|
486
486
|
baker ads google draft clear
|
|
487
487
|
```
|
|
488
488
|
|
|
489
|
-
Command groups: `budgets`, `campaigns`, `ad-groups`, `keywords` (add/update/remove), `negative-keywords`, `keyword-lists`, `ads`, `assets` (create/update/attach/detach), `asset-groups` (create/update — Performance Max), `audiences`, `conversions`, `bidding-strategies`, `labels`, `campaign-criteria`, and `draft`. Amounts are in major currency units (converted to micros). Money/bids: `--amount`, `--cpc-bid`, `--target-cpa` take major units; `--target-roas` a ratio. Less-common ops accept a `--file <payload.json>` (flags override file keys). Updates target a resource name or bare id as the positional argument; a target that names an op staged earlier **amends it in place**.
|
|
489
|
+
Command groups: `budgets`, `campaigns`, `ad-groups`, `keywords` (add/update/remove), `negative-keywords`, `keyword-lists`, `ads`, `assets` (create/update/attach/detach), `asset-groups` (create/update — Performance Max), `audiences`, `conversions`, `bidding-strategies`, `labels`, `campaign-criteria`, and `draft`. Amounts are in major currency units (converted to micros). Money/bids: `--amount`, `--cpc-bid`, `--target-cpa`, `--max-cpc` take major units; `--target-roas` a ratio. `--max-cpc` sets the max CPC bid ceiling for `TARGET_IMPRESSION_SHARE` / `TARGET_SPEND` / `PERCENT_CPC` and must be paired with `--bidding-strategy`. Less-common ops accept a `--file <payload.json>` (flags override file keys). Updates target a resource name or bare id as the positional argument; a target that names an op staged earlier **amends it in place**.
|
|
490
490
|
|
|
491
491
|
**Reviewing the draft** — `baker ads google draft list` renders everything you've staged as a grouped campaign ▸ ad group ▸ ad tree (with the simulated/live mode banner and non-blocking completeness advisories), the CLI counterpart to the dashboard's Google Ads tab. Pass `--json` for the raw envelope. Aim for a fully built campaign — 2–4 ad groups, ≥5 keywords each, 2–4 RSAs with 8–12 headlines, ≥4 sitelinks / ≥3 callouts / ≥1 structured snippet, and ≥1 shared negative list; the advisories flag what's still thin.
|
|
492
492
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
apiGet
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-LVCBCJWF.js";
|
|
4
4
|
import {
|
|
5
5
|
getEnv
|
|
6
6
|
} from "./chunk-RK67WL4O.js";
|
|
@@ -261,4 +261,4 @@ export {
|
|
|
261
261
|
writeAdsOutput,
|
|
262
262
|
resolveCustomerId
|
|
263
263
|
};
|
|
264
|
-
//# sourceMappingURL=chunk-
|
|
264
|
+
//# sourceMappingURL=chunk-FBUVCOH6.js.map
|
|
@@ -62,6 +62,10 @@ function sanitizeParams(params) {
|
|
|
62
62
|
}
|
|
63
63
|
return sanitized;
|
|
64
64
|
}
|
|
65
|
+
function chatHeader() {
|
|
66
|
+
const chatId = getEnv().BAKER_CHAT_ID;
|
|
67
|
+
return chatId ? { "x-baker-chat-id": chatId } : {};
|
|
68
|
+
}
|
|
65
69
|
function mapHttpError(status) {
|
|
66
70
|
if (status === 401 || status === 403) {
|
|
67
71
|
return "UNAUTHORIZED";
|
|
@@ -117,7 +121,8 @@ async function apiGet(path, params) {
|
|
|
117
121
|
method: "GET",
|
|
118
122
|
headers: {
|
|
119
123
|
Authorization: `Bearer ${env.BAKER_API_KEY}`,
|
|
120
|
-
Accept: "application/json"
|
|
124
|
+
Accept: "application/json",
|
|
125
|
+
...chatHeader()
|
|
121
126
|
},
|
|
122
127
|
signal: AbortSignal.timeout(6e4)
|
|
123
128
|
});
|
|
@@ -151,7 +156,8 @@ async function apiPost(path, body, opts) {
|
|
|
151
156
|
headers: {
|
|
152
157
|
Authorization: `Bearer ${env.BAKER_API_KEY}`,
|
|
153
158
|
"Content-Type": "application/json",
|
|
154
|
-
Accept: "application/json"
|
|
159
|
+
Accept: "application/json",
|
|
160
|
+
...chatHeader()
|
|
155
161
|
},
|
|
156
162
|
body: JSON.stringify(body),
|
|
157
163
|
signal: AbortSignal.timeout(timeoutMs)
|
|
@@ -189,4 +195,4 @@ export {
|
|
|
189
195
|
apiGet,
|
|
190
196
|
apiPost
|
|
191
197
|
};
|
|
192
|
-
//# sourceMappingURL=chunk-
|
|
198
|
+
//# sourceMappingURL=chunk-LVCBCJWF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import { debugLogHttp, readBodyForLog } from \"./debugLog.ts\";\nimport { getEnv } from \"./env.ts\";\n\nconst MAX_RATE_LIMIT_RETRIES = 3;\nconst MAX_TOTAL_WAIT_MS = 2 * 60 * 1000;\n\nasync function fetchWithRateLimitRetry(url: string, init: RequestInit): Promise<Response> {\n let totalWaited = 0;\n\n for (let attempt = 0; attempt <= MAX_RATE_LIMIT_RETRIES; attempt++) {\n const response = await fetch(url, init);\n\n if (response.status !== 429 || attempt >= MAX_RATE_LIMIT_RETRIES) {\n return response;\n }\n\n const retryAfterHeader = response.headers.get(\"Retry-After\");\n const waitMs = retryAfterHeader ? Number(retryAfterHeader) * 1000 : 2000 * 2 ** attempt;\n\n if (totalWaited + waitMs > MAX_TOTAL_WAIT_MS) {\n return response;\n }\n\n totalWaited += waitMs;\n await new Promise((resolve) => setTimeout(resolve, waitMs));\n }\n\n return fetch(url, init);\n}\n\ntype ErrorCode =\n | \"UNAUTHORIZED\"\n | \"NOT_FOUND\"\n | \"VALIDATION_ERROR\"\n | \"RATE_LIMITED\"\n | \"INTERNAL_ERROR\"\n | \"NETWORK_ERROR\"\n | \"TIMEOUT\"\n | \"IMAGE_PROCESSING_ERROR\";\n\nexport class ApiError extends Error {\n code: ErrorCode;\n\n constructor(code: ErrorCode, message: string) {\n super(message);\n this.name = \"ApiError\";\n this.code = code;\n }\n}\n\nconst CONVEX_ID_RE = /^[a-zA-Z0-9_]+$/;\n\nfunction hasControlCharacters(value: string): boolean {\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n // Allow tab (9), newline (10), carriage return (13)\n if (code < 32 && code !== 9 && code !== 10 && code !== 13) {\n return true;\n }\n }\n return false;\n}\n\nfunction validateStringValue(value: string): void {\n if (hasControlCharacters(value)) {\n throw new ApiError(\"VALIDATION_ERROR\", \"String value contains invalid control characters\");\n }\n}\n\nexport function validateConvexId(id: string): void {\n if (!CONVEX_ID_RE.test(id)) {\n throw new ApiError(\"VALIDATION_ERROR\", `Invalid ID format: \"${id}\". Expected alphanumeric string.`);\n }\n}\n\nfunction sanitizeParams(params: Record<string, string>): Record<string, string> {\n const sanitized: Record<string, string> = {};\n for (const [key, value] of Object.entries(params)) {\n validateStringValue(value);\n sanitized[key] = value;\n }\n return sanitized;\n}\n\n/**\n * Sent on every call so the backend can attribute immediately-applied writes\n * (library images and videos, followed advertisers) to the Session they were\n * made from. Absent outside a chat-attached environment.\n */\nfunction chatHeader(): Record<string, string> {\n const chatId = getEnv().BAKER_CHAT_ID;\n return chatId ? { \"x-baker-chat-id\": chatId } : {};\n}\n\nfunction mapHttpError(status: number): ErrorCode {\n if (status === 401 || status === 403) {\n return \"UNAUTHORIZED\";\n }\n if (status === 404) {\n return \"NOT_FOUND\";\n }\n if (status === 422 || status === 400) {\n return \"VALIDATION_ERROR\";\n }\n if (status === 429) {\n return \"RATE_LIMITED\";\n }\n return \"INTERNAL_ERROR\";\n}\n\nasync function handleResponse<T>(response: Response): Promise<T> {\n const body = await response.text();\n\n if (!response.ok) {\n let message = `HTTP ${response.status}: ${response.statusText}`;\n try {\n const parsed = JSON.parse(body) as { error?: string | { message?: string }; message?: string };\n if (typeof parsed.error === \"string\") {\n message = parsed.error;\n } else if (parsed.error?.message) {\n message = parsed.error.message;\n } else if (parsed.message) {\n message = parsed.message;\n }\n } catch {\n // Use default message\n }\n throw new ApiError(mapHttpError(response.status), message);\n }\n\n try {\n return JSON.parse(body) as T;\n } catch {\n throw new ApiError(\"INTERNAL_ERROR\", \"Failed to parse API response as JSON\");\n }\n}\n\nexport async function apiGet<T>(path: string, params?: Record<string, string>): Promise<T> {\n const env = getEnv();\n const url = new URL(path, env.BAKER_API_URL);\n if (params) {\n const clean = sanitizeParams(params);\n for (const [key, value] of Object.entries(clean)) {\n url.searchParams.set(key, value);\n }\n }\n\n const urlStr = url.toString();\n const startedAt = Date.now();\n let response: Response;\n try {\n response = await fetchWithRateLimitRetry(urlStr, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${env.BAKER_API_KEY}`,\n Accept: \"application/json\",\n ...chatHeader(),\n },\n signal: AbortSignal.timeout(60_000),\n });\n } catch (err) {\n debugLogHttp({ source: \"cli\", method: \"GET\", url: urlStr, durationMs: Date.now() - startedAt, error: err });\n if (err instanceof Error && (err.name === \"TimeoutError\" || err.name === \"AbortError\")) {\n throw new ApiError(\"TIMEOUT\", \"Request timed out after 60 seconds\");\n }\n throw new ApiError(\"NETWORK_ERROR\", `Request failed: ${err instanceof Error ? err.message : \"Unknown error\"}`);\n }\n\n debugLogHttp({\n source: \"cli\",\n method: \"GET\",\n url: urlStr,\n status: response.status,\n ok: response.ok,\n responseBody: await readBodyForLog(response),\n durationMs: Date.now() - startedAt,\n });\n return handleResponse<T>(response);\n}\n\nexport async function apiPost<T>(path: string, body: unknown, opts?: { timeoutMs?: number }): Promise<T> {\n const env = getEnv();\n const timeoutMs = opts?.timeoutMs ?? 60_000;\n const urlStr = new URL(path, env.BAKER_API_URL).toString();\n const startedAt = Date.now();\n let response: Response;\n try {\n response = await fetchWithRateLimitRetry(urlStr, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${env.BAKER_API_KEY}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n ...chatHeader(),\n },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(timeoutMs),\n });\n } catch (err) {\n debugLogHttp({\n source: \"cli\",\n method: \"POST\",\n url: urlStr,\n requestBody: body,\n durationMs: Date.now() - startedAt,\n error: err,\n });\n if (err instanceof Error && (err.name === \"TimeoutError\" || err.name === \"AbortError\")) {\n throw new ApiError(\"TIMEOUT\", `Request timed out after ${Math.round(timeoutMs / 1000)} seconds`);\n }\n throw new ApiError(\"NETWORK_ERROR\", `Request failed: ${err instanceof Error ? err.message : \"Unknown error\"}`);\n }\n\n debugLogHttp({\n source: \"cli\",\n method: \"POST\",\n url: urlStr,\n requestBody: body,\n status: response.status,\n ok: response.ok,\n responseBody: await readBodyForLog(response),\n durationMs: Date.now() - startedAt,\n });\n return handleResponse<T>(response);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
handleConnectionError,
|
|
3
3
|
writeAdsJson
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-FBUVCOH6.js";
|
|
5
5
|
import {
|
|
6
6
|
ApiError
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-LVCBCJWF.js";
|
|
8
8
|
import {
|
|
9
9
|
getEnv
|
|
10
10
|
} from "./chunk-RK67WL4O.js";
|
|
@@ -94,4 +94,4 @@ export {
|
|
|
94
94
|
csvOrJson,
|
|
95
95
|
resolveEffectiveStatus
|
|
96
96
|
};
|
|
97
|
-
//# sourceMappingURL=chunk-
|
|
97
|
+
//# sourceMappingURL=chunk-UFBKUMN2.js.map
|
package/dist/cli.js
CHANGED
|
@@ -43,7 +43,7 @@ import {
|
|
|
43
43
|
resolveAccountIdArg,
|
|
44
44
|
resolveEffectiveStatus,
|
|
45
45
|
todayIso
|
|
46
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-UFBKUMN2.js";
|
|
47
47
|
import {
|
|
48
48
|
buildQueryCacheKey,
|
|
49
49
|
cacheGet,
|
|
@@ -56,13 +56,13 @@ import {
|
|
|
56
56
|
writeAdsJson,
|
|
57
57
|
writeAdsOutput,
|
|
58
58
|
writeJsonEnvelope
|
|
59
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-FBUVCOH6.js";
|
|
60
60
|
import {
|
|
61
61
|
ApiError,
|
|
62
62
|
apiGet,
|
|
63
63
|
apiPost,
|
|
64
64
|
validateConvexId
|
|
65
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-LVCBCJWF.js";
|
|
66
66
|
import {
|
|
67
67
|
installStreamTaps,
|
|
68
68
|
logInvocation
|
|
@@ -2131,6 +2131,10 @@ var chatChangeTypeSchema = z5.enum([
|
|
|
2131
2131
|
"linkedin-ads",
|
|
2132
2132
|
"google-ads",
|
|
2133
2133
|
"meta-ads",
|
|
2134
|
+
// Immediate (already-applied) library effects — see lib/chatChanges.ts.
|
|
2135
|
+
"image",
|
|
2136
|
+
"video",
|
|
2137
|
+
"followed-advertiser",
|
|
2134
2138
|
"briefs"
|
|
2135
2139
|
]);
|
|
2136
2140
|
var chatChangeActionSchema = z5.enum(["created", "updated", "deleted"]);
|
|
@@ -7095,17 +7099,34 @@ var budgetsCommand = defineCommand29({
|
|
|
7095
7099
|
})
|
|
7096
7100
|
}
|
|
7097
7101
|
});
|
|
7102
|
+
var MAX_CPC_STRATEGIES = ["TARGET_IMPRESSION_SHARE", "TARGET_SPEND", "PERCENT_CPC"];
|
|
7098
7103
|
function biddingFromFlags(args) {
|
|
7099
7104
|
const type = args["bidding-strategy"];
|
|
7105
|
+
const maxCpcMicros = microsFlag(args["max-cpc"], "--max-cpc");
|
|
7100
7106
|
if (!type) {
|
|
7107
|
+
if (maxCpcMicros !== void 0) {
|
|
7108
|
+
failWriteValidation(
|
|
7109
|
+
"--max-cpc needs --bidding-strategy too (the ceiling belongs to a strategy) \u2014 e.g. --bidding-strategy TARGET_IMPRESSION_SHARE --max-cpc 12"
|
|
7110
|
+
);
|
|
7111
|
+
}
|
|
7101
7112
|
return void 0;
|
|
7102
7113
|
}
|
|
7114
|
+
if (maxCpcMicros !== void 0 && !MAX_CPC_STRATEGIES.includes(type.toUpperCase())) {
|
|
7115
|
+
failWriteValidation(`${type} does not take --max-cpc \u2014 only ${MAX_CPC_STRATEGIES.join(", ")} carry a bid ceiling`);
|
|
7116
|
+
}
|
|
7103
7117
|
return {
|
|
7104
7118
|
type,
|
|
7105
7119
|
targetCpaMicros: microsFlag(args["target-cpa"], "--target-cpa"),
|
|
7106
|
-
targetRoas: args["target-roas"] !== void 0 ? Number(args["target-roas"]) : void 0
|
|
7120
|
+
targetRoas: args["target-roas"] !== void 0 ? Number(args["target-roas"]) : void 0,
|
|
7121
|
+
cpcBidCeilingMicros: maxCpcMicros
|
|
7107
7122
|
};
|
|
7108
7123
|
}
|
|
7124
|
+
var maxCpcArg = {
|
|
7125
|
+
"max-cpc": {
|
|
7126
|
+
type: "string",
|
|
7127
|
+
description: "Max CPC bid ceiling (major units) for TARGET_IMPRESSION_SHARE, TARGET_SPEND or PERCENT_CPC"
|
|
7128
|
+
}
|
|
7129
|
+
};
|
|
7109
7130
|
var campaignsCommand = defineCommand29({
|
|
7110
7131
|
meta: { name: "campaigns", description: "Stage campaign create/update/pause/resume/remove" },
|
|
7111
7132
|
subCommands: {
|
|
@@ -7127,6 +7148,7 @@ var campaignsCommand = defineCommand29({
|
|
|
7127
7148
|
},
|
|
7128
7149
|
"target-cpa": { type: "string", description: "Target CPA (major units) for TARGET_CPA" },
|
|
7129
7150
|
"target-roas": { type: "string", description: "Target ROAS (e.g. 4.0) for TARGET_ROAS" },
|
|
7151
|
+
...maxCpcArg,
|
|
7130
7152
|
objective: { type: "string", description: "Advisory UI objective (SALES, LEADS, \u2026)" },
|
|
7131
7153
|
"start-date": { type: "string", description: "YYYY-MM-DD" },
|
|
7132
7154
|
"end-date": { type: "string", description: "YYYY-MM-DD" },
|
|
@@ -7158,6 +7180,7 @@ var campaignsCommand = defineCommand29({
|
|
|
7158
7180
|
"bidding-strategy": { type: "string" },
|
|
7159
7181
|
"target-cpa": { type: "string" },
|
|
7160
7182
|
"target-roas": { type: "string" },
|
|
7183
|
+
...maxCpcArg,
|
|
7161
7184
|
status: { type: "string" }
|
|
7162
7185
|
},
|
|
7163
7186
|
run: async ({ args }) => {
|
|
@@ -12835,10 +12858,10 @@ function duplicateCommand2(entity, label) {
|
|
|
12835
12858
|
replace: { type: "boolean", description: "Pause the original once the copy publishes" }
|
|
12836
12859
|
},
|
|
12837
12860
|
run: async ({ args }) => {
|
|
12838
|
-
const { apiPost: apiPost2 } = await import("./client-
|
|
12861
|
+
const { apiPost: apiPost2 } = await import("./client-R5ZSVIK3.js");
|
|
12839
12862
|
const { requireChatId: requireChatId2 } = await import("./env-3JMYIH25.js");
|
|
12840
|
-
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-
|
|
12841
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
12863
|
+
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-R534QTMO.js");
|
|
12864
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-MUWU7BK5.js");
|
|
12842
12865
|
try {
|
|
12843
12866
|
const accountId = bareAccountId2(args);
|
|
12844
12867
|
const chatId = requireChatId2();
|