@koda-sl/baker-cli 0.156.0 → 0.158.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 +62 -4
- package/dist/{chunk-7Z6C5OVO.js → chunk-CG6OTNUU.js} +7 -2
- package/dist/chunk-CG6OTNUU.js.map +1 -0
- package/dist/cli.js +1808 -1159
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-7Z6C5OVO.js.map +0 -1
package/README.md
CHANGED
|
@@ -160,6 +160,34 @@ baker ads google currency --customer-id 5904042878
|
|
|
160
160
|
|
|
161
161
|
---
|
|
162
162
|
|
|
163
|
+
### `baker ads google url-options`
|
|
164
|
+
|
|
165
|
+
The UTM / tracking parameters in force on the account: the account-level Final URL Suffix and tracking template, plus every campaign that overrides them. Start here for any "add `utm_agency=…`" or agency-tag question.
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
baker ads google url-options --customer-id 1234567890 # overriding campaigns only
|
|
169
|
+
baker ads google url-options --customer-id 1234567890 --full # every campaign read
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Every value is a tagged union, never a bare string, so an unread level can never be reported as an unset one:
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"ok": true,
|
|
177
|
+
"data": {
|
|
178
|
+
"account": { "final_url_suffix": { "state": "set", "value": "utm_source=google" } },
|
|
179
|
+
"campaigns": { "overriding": [], "omitted": 12 },
|
|
180
|
+
"levels_not_read": ["ad_group", "ad"]
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
`set` holds a value · `not_set` means Google carries none at that level · `not_read` means it was never observed. **Only `not_set` is a finding.**
|
|
186
|
+
|
|
187
|
+
Writing it: `baker ads google campaigns update <id> --final-url-suffix "utm_source=google&utm_agency=baker"` stages a campaign-level override (it *replaces* the account value for that campaign, it does not merge). The **account** level is deliberately not stageable — Google writes it through `CustomerService`, outside the atomic publish batch, so it could not be published atomically nor reversed by discarding the chat. `--level account` stages nothing and returns a structured `error.fix` naming where to set it.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
163
191
|
### `baker ads google query`
|
|
164
192
|
|
|
165
193
|
Run arbitrary GAQL queries. The most powerful command.
|
|
@@ -191,22 +219,46 @@ baker ads google query --list-presets
|
|
|
191
219
|
"ok": true,
|
|
192
220
|
"data": [
|
|
193
221
|
{ "campaign.name": "Brand US", "metrics.clicks": 4521, "metrics.cost_micros": 2850000000 }
|
|
194
|
-
]
|
|
222
|
+
]
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
`--full` adds a `fields` dictionary describing each selected column. It is off by default — the rows already carry the data, and the glossary is a per-call cost.
|
|
227
|
+
|
|
228
|
+
```json
|
|
229
|
+
{
|
|
230
|
+
"ok": true,
|
|
231
|
+
"data": [...],
|
|
195
232
|
"fields": {
|
|
196
233
|
"campaign.name": "Campaign display name",
|
|
197
|
-
"metrics.clicks": "Total clicks (integer)"
|
|
198
|
-
"metrics.cost_micros": "Total cost in micros (÷ 1,000,000 for actual currency)"
|
|
234
|
+
"metrics.clicks": "Total clicks (integer)"
|
|
199
235
|
}
|
|
200
236
|
}
|
|
201
237
|
```
|
|
202
238
|
|
|
239
|
+
**Absent is not empty.** Google omits a field entirely from a row when it holds no value, so a missing key means *this read did not observe it*, never *the setting is unset*. When one or more selected fields come back on **no** row, the response carries a `MISSING_FIELDS` warning naming them:
|
|
240
|
+
|
|
241
|
+
```json
|
|
242
|
+
{
|
|
243
|
+
"ok": true,
|
|
244
|
+
"data": [...],
|
|
245
|
+
"warnings": [
|
|
246
|
+
{
|
|
247
|
+
"code": "MISSING_FIELDS",
|
|
248
|
+
"message": "These SELECTed fields came back on no row: ad_group_ad.ad.final_url_suffix. ..."
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Read it before interpreting any null. It does not fire on the `--out` path (rows stream to disk), and `.resource_name` is never reported (the server strips it from every row).
|
|
255
|
+
|
|
203
256
|
**Response (with pagination):**
|
|
204
257
|
|
|
205
258
|
```json
|
|
206
259
|
{
|
|
207
260
|
"ok": true,
|
|
208
261
|
"data": [...],
|
|
209
|
-
"fields": { ... },
|
|
210
262
|
"pagination": { "hasMore": true, "cursor": "eyJwYWdl..." }
|
|
211
263
|
}
|
|
212
264
|
```
|
|
@@ -823,6 +875,12 @@ baker ads linkedin bid-pricing --account-id 503001492 \
|
|
|
823
875
|
|
|
824
876
|
**Listings** (`campaign-groups`/`campaigns`/`creatives`) default to `ACTIVE` only — pass `--all-statuses` to widen, or `--statuses ACTIVE,PAUSED` for a custom set.
|
|
825
877
|
|
|
878
|
+
**`creatives` is compact by default** — `id`, `urn`, `campaign`, `intendedStatus`, `isServing`, `reviewStatus`, `format`, and the resolved destination. The destination is read out of the format-specific `content` block for you: direct-content ads (text, spotlight) report a `landingUrl`; post-based ads (image, video, carousel, document, article, event, TLA) report a `postUrn`, because their destination lives in the sponsored post and is not reachable through the ads API. Pass `--fields id,content.textAd.landingPage` for specific dotted paths, or `--full` for the complete raw records.
|
|
879
|
+
|
|
880
|
+
**Many ids, one call.** `creatives update` and every `pause`/`resume`/`archive` accept a list — `creatives pause 111,222,333`, or `--ids-file ads.txt` (one id per line or comma-separated, `#` comments skipped). The whole set stages in a single all-or-nothing request: if any id fails validation the draft is left untouched and the error names the offending index, so there is never a half-applied batch to reason about. A single id takes the exact same path as before, including `li_temp_*` amends (amends stay single-id — pass those on their own).
|
|
881
|
+
|
|
882
|
+
**Post-based ads are not editable.** Image, video, carousel, document, article, event and TLA creatives sponsor a LinkedIn post; the copy, media and destination belong to the post, not the ad. Both `creatives update` and `creatives duplicate` reject content flags on these rather than accepting them and silently dropping them. To change the copy, stage a new `creatives create` and pause the old ad. Direct-content formats (text, spotlight, follower, jobs) do update in place.
|
|
883
|
+
|
|
826
884
|
**Pagination** is auto-drained (start/count loop hidden).
|
|
827
885
|
|
|
828
886
|
**Demographic pivots** (`MEMBER_*`) come back delayed 12-24h with a ≥3-event privacy floor — small buckets are dropped. The CLI surfaces `DELAYED_DEMOGRAPHIC` and (when results are unexpectedly empty) `BELOW_PRIVACY_FLOOR` warnings.
|
|
@@ -741,7 +741,12 @@ async function parseErrorBody(res) {
|
|
|
741
741
|
} catch {
|
|
742
742
|
}
|
|
743
743
|
const errObj = body.error ?? {};
|
|
744
|
-
|
|
744
|
+
const bodyless = body.error === void 0 && res.status >= 500;
|
|
745
|
+
const message2 = bodyless ? `HTTP ${res.status} with no response body \u2014 the request was dropped before the server answered` : errObj.message ?? `HTTP ${res.status}`;
|
|
746
|
+
if (bodyless && res.status === 502) {
|
|
747
|
+
return { kind: "server", status: res.status, message: message2 };
|
|
748
|
+
}
|
|
749
|
+
return classifyHttpError(res.status, errObj, message2);
|
|
745
750
|
}
|
|
746
751
|
function classifyHttpError(status, errObj, message2) {
|
|
747
752
|
if (errObj.code === CONTENT_POLICY_CODE) {
|
|
@@ -8023,4 +8028,4 @@ export {
|
|
|
8023
8028
|
defaultRegistry,
|
|
8024
8029
|
createEngineFromEnv
|
|
8025
8030
|
};
|
|
8026
|
-
//# sourceMappingURL=chunk-
|
|
8031
|
+
//# sourceMappingURL=chunk-CG6OTNUU.js.map
|