@koda-sl/baker-cli 0.344.0-dev.1f4f1c4b7 → 0.344.0-dev.9890d9fcc
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 +7 -7
- package/canvas/end-card-composition/meta.json +5 -1
- package/canvas/feature-reveal-composition/meta.json +12 -2
- package/canvas/lower-third-composition/meta.json +7 -1
- package/canvas/video-call-composition/meta.json +27 -5
- package/dist/cli.js +136 -64
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -118,14 +118,12 @@ Use `--output` to change format:
|
|
|
118
118
|
|
|
119
119
|
| Format | Description | Best for | Available on |
|
|
120
120
|
|---------|------------------------------------|--------------------|--------------|
|
|
121
|
-
| `json` | Structured JSON envelope (default) | AI agents | every command
|
|
122
|
-
| `files` | Tab-separated, one row per result | Piping / shell |
|
|
123
|
-
| `md` | Markdown table | Human reading |
|
|
121
|
+
| `json` | Structured JSON envelope (default) | AI agents | every command |
|
|
122
|
+
| `files` | Tab-separated, one row per result | Piping / shell | every command |
|
|
123
|
+
| `md` | Markdown table | Human reading | every command |
|
|
124
124
|
| `csv` | RFC 4180 comma-separated values | Analysis tools | `baker research …` only |
|
|
125
125
|
| `jsonl` | One JSON object per line | Streaming/appending | `baker research …` only |
|
|
126
126
|
|
|
127
|
-
`--output json` is accepted even by a command that declares no `--output`: the envelope is already what it prints, and on a command whose default is a readable view (`baker tags list`, the `draft` commands) it becomes that command's `--json`. The few commands that print only text — `baker analytics sending-events`, `baker canvas run` and `rerun` — refuse it, as a command without its own `--output` refuses `md` and `files`.
|
|
128
|
-
|
|
129
127
|
`csv` and `jsonl` are implemented by the research family alone. Asking any other command for them — or for a format that does not exist — falls back to the JSON envelope and says so on stderr, rather than printing nothing and exiting 0.
|
|
130
128
|
|
|
131
129
|
`files` and `md` print rows and nothing else, so any `hints` or data-quality note the envelope carries is written to **stderr** instead. Reading stdout alone still gives you clean, parseable rows.
|
|
@@ -341,9 +339,9 @@ The same lines also go to stderr. A read with nothing to report prints none of i
|
|
|
341
339
|
|-----------------|--------------------------------------------------------------|
|
|
342
340
|
| `--customer-id` | Google Ads customer ID (10 digits, no dashes). Falls back to `BAKER_GOOGLE_ADS_CUSTOMER_ID` env var. |
|
|
343
341
|
| `--preset` | Named query template (see presets below) |
|
|
344
|
-
| `--date-range` | Override preset date range (LAST_7_DAYS, LAST_30_DAYS, etc.) |
|
|
342
|
+
| `--date-range` | Override preset date range: a Google literal (LAST_7_DAYS, LAST_30_DAYS, LAST_MONTH, etc.) or `BETWEEN 'YYYY-MM-DD' AND 'YYYY-MM-DD'` — there is no LAST_90_DAYS |
|
|
345
343
|
| `--include-paused` | Include paused entities in preset results. Off by default: presets return only actually-serving entities (enabled campaign **and** ad group **and** ad). Google Ads has no single serving flag, so the whole chain must be `ENABLED` for an entity to serve. |
|
|
346
|
-
| `--limit` | Max rows per page (default 200)
|
|
344
|
+
| `--limit` | Max rows per page (default 200, at most 10,000) |
|
|
347
345
|
| `--cursor` | Pagination cursor from previous response |
|
|
348
346
|
| `--all` | Auto-paginate all results. Exhausts the pages, not the statement's `LIMIT` — pair it with a `--limit` above the expected row count, and a read that still fills its cap is flagged `TRUNCATED_RESULTS` either way |
|
|
349
347
|
| `--out` | Write data to file (format from extension: .csv, .jsonl, .json) |
|
|
@@ -389,6 +387,8 @@ The CLI rejects or automatically corrects common GAQL mistakes before hitting th
|
|
|
389
387
|
| `shopping_performance_view.product_*` | Rewrites to `segments.product_*` | Field renamed |
|
|
390
388
|
| `campaign.status = 'ACTIVE'` | Rewrites to `= 'ENABLED'` | Enum corrected |
|
|
391
389
|
| `segments.conversion_action_name` with `metrics.cost_micros` | Rejects; split into separate conversion-action and spend queries | `INCOMPATIBLE_FIELDS` with `fix.action: "split_query"` |
|
|
390
|
+
| `DURING` with a literal Google does not accept (`LAST_90_DAYS`, `LAST_12_MONTHS`, `THIS_YEAR` …) | Rejects before any request; `DURING` takes only `TODAY`, `YESTERDAY`, `LAST_7_DAYS`, `LAST_14_DAYS`, `LAST_30_DAYS`, `LAST_BUSINESS_WEEK`, `THIS_MONTH`, `LAST_MONTH`, `THIS_WEEK_SUN_TODAY`, `THIS_WEEK_MON_TODAY`, `LAST_WEEK_SUN_SAT`, `LAST_WEEK_MON_SUN` | `INVALID_DATE_RANGE`, with `fix.correctedCommand` spelling the same window as `BETWEEN 'YYYY-MM-DD' AND 'YYYY-MM-DD'` |
|
|
391
|
+
| `--limit` outside 1–10,000 | Rejects before any request | `VALIDATION_ERROR` naming the cap and `--all --out` for bigger reads |
|
|
392
392
|
| `FROM ad_group_criterion` without `negative` field | Warns | `"ad_group_criterion returns BOTH positive and negative keywords. Use --preset positive-keywords or negative-keywords."` |
|
|
393
393
|
|
|
394
394
|
Auto-fixed queries proceed normally. Warnings appear in the response:
|
|
@@ -8,7 +8,11 @@
|
|
|
8
8
|
"default_duration": 3,
|
|
9
9
|
"inputs": {},
|
|
10
10
|
"params": {
|
|
11
|
-
"logo_svg": {
|
|
11
|
+
"logo_svg": {
|
|
12
|
+
"kind": "string",
|
|
13
|
+
"default": "",
|
|
14
|
+
"description": "Raw inline <svg>…</svg> wordmark with fill set to text_color (optional)."
|
|
15
|
+
},
|
|
12
16
|
"headline": { "kind": "string", "required": true, "description": "Closing line." },
|
|
13
17
|
"cta_text": { "kind": "string", "default": "", "description": "Call-to-action pill label (optional)." },
|
|
14
18
|
"bg_color": { "kind": "color", "default": "#0b1020" },
|
|
@@ -9,10 +9,20 @@
|
|
|
9
9
|
"inputs": {},
|
|
10
10
|
"params": {
|
|
11
11
|
"title": { "kind": "string", "default": "", "description": "Optional heading above the list." },
|
|
12
|
-
"features": {
|
|
12
|
+
"features": {
|
|
13
|
+
"kind": "json",
|
|
14
|
+
"required": true,
|
|
15
|
+
"description": "Array of 1–6 short labels, e.g. [\"No setup fees\", \"Cancel anytime\"]."
|
|
16
|
+
},
|
|
13
17
|
"text_color": { "kind": "color", "default": "#0b1020" },
|
|
14
18
|
"accent_color": { "kind": "color", "default": "#1f9d57", "description": "Check-circle fill." },
|
|
15
19
|
"check_color": { "kind": "color", "default": "#ffffff", "description": "The check mark inside the circle." },
|
|
16
|
-
"stagger_s": {
|
|
20
|
+
"stagger_s": {
|
|
21
|
+
"kind": "number",
|
|
22
|
+
"default": 0.18,
|
|
23
|
+
"min": 0.02,
|
|
24
|
+
"max": 1,
|
|
25
|
+
"description": "Seconds between each item."
|
|
26
|
+
}
|
|
17
27
|
}
|
|
18
28
|
}
|
|
@@ -13,6 +13,12 @@
|
|
|
13
13
|
"bar_color": { "kind": "color", "default": "#0b1020" },
|
|
14
14
|
"text_color": { "kind": "color", "default": "#ffffff" },
|
|
15
15
|
"accent_color": { "kind": "color", "default": "#5b8cff", "description": "The leading accent block." },
|
|
16
|
-
"from_bottom_px": {
|
|
16
|
+
"from_bottom_px": {
|
|
17
|
+
"kind": "integer",
|
|
18
|
+
"default": 220,
|
|
19
|
+
"min": 0,
|
|
20
|
+
"max": 1600,
|
|
21
|
+
"description": "Distance of the bar from the bottom edge."
|
|
22
|
+
}
|
|
17
23
|
}
|
|
18
24
|
}
|
|
@@ -15,12 +15,34 @@
|
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
"params": {
|
|
18
|
-
"headline": {
|
|
19
|
-
|
|
18
|
+
"headline": {
|
|
19
|
+
"kind": "string",
|
|
20
|
+
"default": "",
|
|
21
|
+
"description": "Big line on the content stage (what the presenter is showing)."
|
|
22
|
+
},
|
|
23
|
+
"claim": {
|
|
24
|
+
"kind": "string",
|
|
25
|
+
"default": "",
|
|
26
|
+
"description": "Short proof/claim on the floating glass card (optional)."
|
|
27
|
+
},
|
|
20
28
|
"caption": { "kind": "string", "default": "", "description": "A caption line in the lower band (optional)." },
|
|
21
|
-
"pip_at_s": {
|
|
22
|
-
|
|
29
|
+
"pip_at_s": {
|
|
30
|
+
"kind": "number",
|
|
31
|
+
"default": 2,
|
|
32
|
+
"min": 0,
|
|
33
|
+
"max": 30,
|
|
34
|
+
"description": "When the presenter shrinks to the corner pill."
|
|
35
|
+
},
|
|
36
|
+
"bg_color": {
|
|
37
|
+
"kind": "color",
|
|
38
|
+
"default": "#0b1020",
|
|
39
|
+
"description": "Content-stage background (behind the presenter)."
|
|
40
|
+
},
|
|
23
41
|
"text_color": { "kind": "color", "default": "#ffffff" },
|
|
24
|
-
"accent_color": {
|
|
42
|
+
"accent_color": {
|
|
43
|
+
"kind": "color",
|
|
44
|
+
"default": "#5b8cff",
|
|
45
|
+
"description": "Headline accent + caption underline + pill ring tint."
|
|
46
|
+
}
|
|
25
47
|
}
|
|
26
48
|
}
|
package/dist/cli.js
CHANGED
|
@@ -2362,6 +2362,7 @@ var GOOGLE_ADS_LIMITS = {
|
|
|
2362
2362
|
businessNameMax: 25
|
|
2363
2363
|
}
|
|
2364
2364
|
};
|
|
2365
|
+
var GOOGLE_ADS_QUERY_MAX_PAGE_SIZE = 1e4;
|
|
2365
2366
|
var KEYWORD_MATCH_TYPES = ["EXACT", "PHRASE", "BROAD"];
|
|
2366
2367
|
var ADVERTISING_CHANNEL_TYPES = [
|
|
2367
2368
|
"SEARCH",
|
|
@@ -10079,7 +10080,72 @@ function urlOptionsHints(report) {
|
|
|
10079
10080
|
return hints2;
|
|
10080
10081
|
}
|
|
10081
10082
|
|
|
10083
|
+
// src/commands/ads/google/during-literals.ts
|
|
10084
|
+
var GAQL_DURING_LITERALS = [
|
|
10085
|
+
"TODAY",
|
|
10086
|
+
"YESTERDAY",
|
|
10087
|
+
"LAST_7_DAYS",
|
|
10088
|
+
"LAST_14_DAYS",
|
|
10089
|
+
"LAST_30_DAYS",
|
|
10090
|
+
"LAST_BUSINESS_WEEK",
|
|
10091
|
+
"THIS_MONTH",
|
|
10092
|
+
"LAST_MONTH",
|
|
10093
|
+
"THIS_WEEK_SUN_TODAY",
|
|
10094
|
+
"THIS_WEEK_MON_TODAY",
|
|
10095
|
+
"LAST_WEEK_SUN_SAT",
|
|
10096
|
+
"LAST_WEEK_MON_SUN"
|
|
10097
|
+
];
|
|
10098
|
+
function isDuringLiteral(value) {
|
|
10099
|
+
return GAQL_DURING_LITERALS.includes(value.toUpperCase());
|
|
10100
|
+
}
|
|
10101
|
+
function isoDay(date) {
|
|
10102
|
+
return date.toISOString().slice(0, 10);
|
|
10103
|
+
}
|
|
10104
|
+
function utcDate(year, month, day) {
|
|
10105
|
+
return new Date(Date.UTC(year, month, day));
|
|
10106
|
+
}
|
|
10107
|
+
function equivalentBetween(literal, now) {
|
|
10108
|
+
const upper2 = literal.toUpperCase();
|
|
10109
|
+
const today = utcDate(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate());
|
|
10110
|
+
const yesterday = utcDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate() - 1);
|
|
10111
|
+
const range = (from, to) => `BETWEEN '${isoDay(from)}' AND '${isoDay(to)}'`;
|
|
10112
|
+
const year = today.getUTCFullYear();
|
|
10113
|
+
const quarterStart = Math.floor(today.getUTCMonth() / 3) * 3;
|
|
10114
|
+
const rolling = upper2.match(/^LAST_(\d+)_(DAYS|WEEKS|MONTHS|YEARS)$/);
|
|
10115
|
+
if (rolling) {
|
|
10116
|
+
const n = Number(rolling[1]);
|
|
10117
|
+
const unit = rolling[2];
|
|
10118
|
+
if (n < 1) return null;
|
|
10119
|
+
if (unit === "DAYS" || unit === "WEEKS") {
|
|
10120
|
+
const days = unit === "DAYS" ? n : n * 7;
|
|
10121
|
+
return range(utcDate(year, today.getUTCMonth(), today.getUTCDate() - days), yesterday);
|
|
10122
|
+
}
|
|
10123
|
+
const months = unit === "MONTHS" ? n : n * 12;
|
|
10124
|
+
return range(utcDate(year, today.getUTCMonth() - months, today.getUTCDate()), yesterday);
|
|
10125
|
+
}
|
|
10126
|
+
switch (upper2) {
|
|
10127
|
+
case "THIS_YEAR":
|
|
10128
|
+
return range(utcDate(year, 0, 1), today);
|
|
10129
|
+
case "LAST_YEAR":
|
|
10130
|
+
return range(utcDate(year - 1, 0, 1), utcDate(year - 1, 11, 31));
|
|
10131
|
+
case "THIS_QUARTER":
|
|
10132
|
+
return range(utcDate(year, quarterStart, 1), today);
|
|
10133
|
+
case "LAST_QUARTER":
|
|
10134
|
+
return range(utcDate(year, quarterStart - 3, 1), utcDate(year, quarterStart, 0));
|
|
10135
|
+
default:
|
|
10136
|
+
return null;
|
|
10137
|
+
}
|
|
10138
|
+
}
|
|
10139
|
+
function duringLiteralExplanation(literal, between) {
|
|
10140
|
+
const accepted = GAQL_DURING_LITERALS.join(", ");
|
|
10141
|
+
const lead = between ? `Google does not accept ${literal} after DURING. The same window as explicit dates is ${between}.` : `Google does not accept ${literal} after DURING, and it names no fixed window \u2014 use BETWEEN 'YYYY-MM-DD' AND 'YYYY-MM-DD', or drop the date filter.`;
|
|
10142
|
+
return `${lead} DURING accepts only: ${accepted}. Any other window needs BETWEEN.`;
|
|
10143
|
+
}
|
|
10144
|
+
|
|
10082
10145
|
// src/commands/ads/google/changes-window.ts
|
|
10146
|
+
function monthlySpendTrendQuery(now = /* @__PURE__ */ new Date()) {
|
|
10147
|
+
return `SELECT campaign.name, segments.month, metrics.cost_micros, metrics.conversions FROM campaign WHERE segments.date ${equivalentBetween("LAST_12_MONTHS", now)}`;
|
|
10148
|
+
}
|
|
10083
10149
|
function isChangeScope(value) {
|
|
10084
10150
|
return CHANGE_SCOPES.includes(value);
|
|
10085
10151
|
}
|
|
@@ -10133,7 +10199,7 @@ function lookbackTooLong(scope, days, max) {
|
|
|
10133
10199
|
message: `Google's account history API reaches back ${CHANGE_SCOPE_MAX_DAYS.summary} days at most; ${days} days is outside that window.`,
|
|
10134
10200
|
fix: {
|
|
10135
10201
|
action: "use_different_resource",
|
|
10136
|
-
explanation:
|
|
10202
|
+
explanation: `Do not abort \u2014 infer the change from performance instead. Query monthly metrics per campaign (${monthlySpendTrendQuery()}) to see which campaigns stopped or started spending. That shows what changed and when, though not who changed it. Older history exists only in the Google Ads web UI, which has no API \u2014 ask the user to check it if the 'who' matters.`
|
|
10137
10203
|
}
|
|
10138
10204
|
};
|
|
10139
10205
|
}
|
|
@@ -10492,7 +10558,7 @@ var CORRECTION_RULES = [
|
|
|
10492
10558
|
matchApiError: /changeStatusError\W{0,4}START_DATE_TOO_OLD/i,
|
|
10493
10559
|
fix: () => ({
|
|
10494
10560
|
action: "use_different_resource",
|
|
10495
|
-
explanation:
|
|
10561
|
+
explanation: `Google's account history reaches back 90 days at most, and this query asks for more. Do not abort \u2014 infer the change from performance: ${monthlySpendTrendQuery()} shows which campaigns started or stopped spending and when, though not who changed them. Anything older with attribution exists only in the Google Ads web UI, which has no API.`
|
|
10496
10562
|
})
|
|
10497
10563
|
},
|
|
10498
10564
|
// 18c. change_status rejects a date range it cannot bound. Google raises this both for
|
|
@@ -12319,9 +12385,16 @@ import { resolve } from "path";
|
|
|
12319
12385
|
import { defineCommand as defineCommand28 } from "citty";
|
|
12320
12386
|
|
|
12321
12387
|
// src/commands/ads/google/presets.ts
|
|
12322
|
-
var
|
|
12388
|
+
var BETWEEN_RE = /^BETWEEN\s+'[0-9]{4}-[0-9]{2}-[0-9]{2}'\s+AND\s+'[0-9]{4}-[0-9]{2}-[0-9]{2}'$/i;
|
|
12323
12389
|
function isValidDateRange(value) {
|
|
12324
|
-
|
|
12390
|
+
const trimmed = value.trim();
|
|
12391
|
+
return isDuringLiteral(trimmed) || BETWEEN_RE.test(trimmed);
|
|
12392
|
+
}
|
|
12393
|
+
function dateRangeError(dateRange, now) {
|
|
12394
|
+
if (/^[A-Za-z0-9_]+$/.test(dateRange.trim())) {
|
|
12395
|
+
return `Invalid date range: "${dateRange}". ${duringLiteralExplanation(dateRange, equivalentBetween(dateRange, now))} Pass it as --date-range "BETWEEN 'YYYY-MM-DD' AND 'YYYY-MM-DD'".`;
|
|
12396
|
+
}
|
|
12397
|
+
return `Invalid date range: "${dateRange}". Use a GAQL date literal (e.g. LAST_30_DAYS, TODAY) or BETWEEN 'YYYY-MM-DD' AND 'YYYY-MM-DD'.`;
|
|
12325
12398
|
}
|
|
12326
12399
|
var SERVING_CHAINS = {
|
|
12327
12400
|
keyword_view: ["campaign.status", "ad_group.status", "ad_group_criterion.status"],
|
|
@@ -12457,17 +12530,15 @@ function buildStatusScope(statusFields, includePaused) {
|
|
|
12457
12530
|
const predicate = includePaused ? "!= 'REMOVED'" : "= 'ENABLED'";
|
|
12458
12531
|
return statusFields.map((field) => ` AND ${field} ${predicate}`).join("");
|
|
12459
12532
|
}
|
|
12460
|
-
function expandPreset(preset, params) {
|
|
12533
|
+
function expandPreset(preset, params, now = /* @__PURE__ */ new Date()) {
|
|
12461
12534
|
const dateRange = params.dateRange ?? preset.defaultDateRange;
|
|
12462
12535
|
const limit = params.limit ?? preset.defaultLimit;
|
|
12463
|
-
if (!isValidDateRange(dateRange)) {
|
|
12464
|
-
return {
|
|
12465
|
-
query: "",
|
|
12466
|
-
dateRangeError: `Invalid date range: "${dateRange}". Use a GAQL date literal (e.g. LAST_30_DAYS, TODAY) or BETWEEN 'YYYY-MM-DD' AND 'YYYY-MM-DD'.`
|
|
12467
|
-
};
|
|
12536
|
+
if (preset.gaqlTemplate.includes("{dateRange}") && !isValidDateRange(dateRange)) {
|
|
12537
|
+
return { query: "", dateRangeError: dateRangeError(dateRange, now) };
|
|
12468
12538
|
}
|
|
12469
12539
|
const statusScope = buildStatusScope(preset.statusFields, params.includePaused ?? false);
|
|
12470
|
-
const
|
|
12540
|
+
const range = dateRange.trim();
|
|
12541
|
+
const query = preset.gaqlTemplate.replace(/DURING\s+\{dateRange\}/g, BETWEEN_RE.test(range) ? range : `DURING ${range}`).replace(/\{dateRange\}/g, range).replace(/\{limit\}/g, String(limit)).replace(/\{statusScope\}/g, statusScope);
|
|
12471
12542
|
return { query };
|
|
12472
12543
|
}
|
|
12473
12544
|
|
|
@@ -12626,6 +12697,28 @@ function applyAutoFixes(query, limit) {
|
|
|
12626
12697
|
}
|
|
12627
12698
|
return { query: corrected, warnings };
|
|
12628
12699
|
}
|
|
12700
|
+
function rejectUnsupportedDuring(query, customerId) {
|
|
12701
|
+
for (const match of query.matchAll(/(?<=[a-z_]\.[a-z_.]+\s+)DURING\s+([A-Za-z0-9_]+)/gi)) {
|
|
12702
|
+
const literal = match[1] ?? "";
|
|
12703
|
+
if (isDuringLiteral(literal)) continue;
|
|
12704
|
+
const between = equivalentBetween(literal, /* @__PURE__ */ new Date());
|
|
12705
|
+
const fixed = between ? query.replace(match[0], between) : void 0;
|
|
12706
|
+
return {
|
|
12707
|
+
ok: false,
|
|
12708
|
+
error: {
|
|
12709
|
+
code: "INVALID_DATE_RANGE",
|
|
12710
|
+
message: `DURING ${literal} is not a Google Ads date range, so Google would refuse this query.`,
|
|
12711
|
+
fix: {
|
|
12712
|
+
action: "narrow_date_range",
|
|
12713
|
+
...fixed ? { correctedCommand: buildCommand2(fixed, customerId) } : {},
|
|
12714
|
+
explanation: duringLiteralExplanation(literal, between)
|
|
12715
|
+
},
|
|
12716
|
+
retryable: false
|
|
12717
|
+
}
|
|
12718
|
+
};
|
|
12719
|
+
}
|
|
12720
|
+
return null;
|
|
12721
|
+
}
|
|
12629
12722
|
function validatePreflight(query, customerId, limit) {
|
|
12630
12723
|
const warnings = [];
|
|
12631
12724
|
const corrected = query;
|
|
@@ -12697,6 +12790,8 @@ function validatePreflight(query, customerId, limit) {
|
|
|
12697
12790
|
}
|
|
12698
12791
|
};
|
|
12699
12792
|
}
|
|
12793
|
+
const duringRejection = rejectUnsupportedDuring(corrected, customerId);
|
|
12794
|
+
if (duringRejection) return { valid: false, warnings: [], error: duringRejection };
|
|
12700
12795
|
if (/\bsegments\.conversion_action_name\b/i.test(corrected) && /\bmetrics\.cost_micros\b/i.test(corrected)) {
|
|
12701
12796
|
return {
|
|
12702
12797
|
valid: false,
|
|
@@ -12905,7 +13000,7 @@ registerSchema({
|
|
|
12905
13000
|
},
|
|
12906
13001
|
"date-range": {
|
|
12907
13002
|
type: "string",
|
|
12908
|
-
description: "Date range for presets (LAST_7_DAYS, LAST_30_DAYS,
|
|
13003
|
+
description: "Date range for presets: a Google date literal (TODAY, YESTERDAY, LAST_7_DAYS, LAST_14_DAYS, LAST_30_DAYS, THIS_MONTH, LAST_MONTH \u2026) or BETWEEN 'YYYY-MM-DD' AND 'YYYY-MM-DD'. Google has no LAST_90_DAYS \u2014 use BETWEEN for any other window.",
|
|
12909
13004
|
required: false
|
|
12910
13005
|
},
|
|
12911
13006
|
"include-paused": {
|
|
@@ -13344,9 +13439,35 @@ async function executeQuery(finalQuery, args5, customerId, limit, warnings, useC
|
|
|
13344
13439
|
function shouldReadCache(args5) {
|
|
13345
13440
|
return !args5["no-cache"] && !args5.out;
|
|
13346
13441
|
}
|
|
13442
|
+
var DEFAULT_QUERY_LIMIT = 200;
|
|
13443
|
+
function parseQueryLimit(raw) {
|
|
13444
|
+
if (raw === void 0 || raw === null || raw === "") return { ok: true, limit: DEFAULT_QUERY_LIMIT };
|
|
13445
|
+
const limit = Number(raw);
|
|
13446
|
+
if (Number.isInteger(limit) && limit >= 1 && limit <= GOOGLE_ADS_QUERY_MAX_PAGE_SIZE) return { ok: true, limit };
|
|
13447
|
+
return {
|
|
13448
|
+
ok: false,
|
|
13449
|
+
error: {
|
|
13450
|
+
ok: false,
|
|
13451
|
+
error: {
|
|
13452
|
+
code: "VALIDATION_ERROR",
|
|
13453
|
+
message: `--limit must be a whole number from 1 to ${GOOGLE_ADS_QUERY_MAX_PAGE_SIZE}, got '${String(raw)}'.`,
|
|
13454
|
+
fix: {
|
|
13455
|
+
action: "retry_with_flag",
|
|
13456
|
+
explanation: `--limit is the size of one page, capped at ${GOOGLE_ADS_QUERY_MAX_PAGE_SIZE}. To read more rows, pass --limit ${GOOGLE_ADS_QUERY_MAX_PAGE_SIZE} with --all --out <file> and put your own LIMIT in the statement above the row count you expect.`
|
|
13457
|
+
},
|
|
13458
|
+
retryable: false
|
|
13459
|
+
}
|
|
13460
|
+
}
|
|
13461
|
+
};
|
|
13462
|
+
}
|
|
13347
13463
|
async function validateArgs(args5) {
|
|
13464
|
+
const parsedLimit = parseQueryLimit(args5.limit);
|
|
13465
|
+
if (!parsedLimit.ok) {
|
|
13466
|
+
writeAdsJson(parsedLimit.error);
|
|
13467
|
+
process.exit(1);
|
|
13468
|
+
}
|
|
13469
|
+
const { limit } = parsedLimit;
|
|
13348
13470
|
const customerId = await resolveCustomerId(args5);
|
|
13349
|
-
const limit = args5.limit ? Number(args5.limit) : 200;
|
|
13350
13471
|
const gaql = resolveGaql(args5, limit);
|
|
13351
13472
|
if (!gaql) {
|
|
13352
13473
|
process.exit(1);
|
|
@@ -67693,7 +67814,6 @@ function commandFor(root, argv) {
|
|
|
67693
67814
|
const { command, resolved } = resolveCommand2(root, argv);
|
|
67694
67815
|
return resolved ? command : null;
|
|
67695
67816
|
}
|
|
67696
|
-
var OUTPUT_EXPLANATION = "This command has no --output option: `--output json` is accepted by every command that prints the JSON envelope, and md or files only where `baker schema` lists `output`. Drop the option and read the default output. ";
|
|
67697
67817
|
function unknownFlagEnvelope(unknown, commandPath, suggestion, hasSchema) {
|
|
67698
67818
|
const list = unknown.join(", ");
|
|
67699
67819
|
return {
|
|
@@ -67703,7 +67823,7 @@ function unknownFlagEnvelope(unknown, commandPath, suggestion, hasSchema) {
|
|
|
67703
67823
|
message: `${list} ${unknown.length > 1 ? "are not options" : "is not an option"} of \`baker ${commandPath}\`.`,
|
|
67704
67824
|
fix: {
|
|
67705
67825
|
action: hasSchema ? "check_schema" : "check_help",
|
|
67706
|
-
explanation: (
|
|
67826
|
+
explanation: (suggestion ? `Did you mean ${suggestion}? ` : "") + `Run \`${hasSchema ? `baker schema ${commandPath}` : `baker ${commandPath} --help`}\` to see every option this command takes. Do not re-run the same call: until this version an unrecognised option was accepted and ignored, so a command that looked like it had filtered or narrowed the result was in fact answering the unfiltered question.`
|
|
67707
67827
|
},
|
|
67708
67828
|
retryable: false
|
|
67709
67829
|
}
|
|
@@ -67742,53 +67862,6 @@ function refuseUnknownFlags(root, argv) {
|
|
|
67742
67862
|
process.exit(1);
|
|
67743
67863
|
}
|
|
67744
67864
|
|
|
67745
|
-
// src/output-flag.ts
|
|
67746
|
-
var FLAG = "--output";
|
|
67747
|
-
var ENVELOPE = "json";
|
|
67748
|
-
var PRINTS_NO_ENVELOPE = /* @__PURE__ */ new Set(["analytics sending-events", "canvas run", "canvas rerun", "canvas sync-definition"]);
|
|
67749
|
-
function declaredArg(command, name) {
|
|
67750
|
-
const args5 = command.args;
|
|
67751
|
-
if (!args5 || typeof args5 !== "object" || !(name in args5)) {
|
|
67752
|
-
return null;
|
|
67753
|
-
}
|
|
67754
|
-
const def = args5[name];
|
|
67755
|
-
return def && typeof def === "object" ? def : {};
|
|
67756
|
-
}
|
|
67757
|
-
function envelopeRequests(argv) {
|
|
67758
|
-
const end = argv.indexOf("--");
|
|
67759
|
-
const limit = end === -1 ? argv.length : end;
|
|
67760
|
-
const found = [];
|
|
67761
|
-
for (let index = 0; index < limit; index++) {
|
|
67762
|
-
const token = argv[index];
|
|
67763
|
-
if (token === `${FLAG}=${ENVELOPE}`) {
|
|
67764
|
-
found.push({ index, length: 1 });
|
|
67765
|
-
} else if (token === FLAG && argv[index + 1] === ENVELOPE && index + 1 < limit) {
|
|
67766
|
-
found.push({ index, length: 2 });
|
|
67767
|
-
index++;
|
|
67768
|
-
}
|
|
67769
|
-
}
|
|
67770
|
-
return found;
|
|
67771
|
-
}
|
|
67772
|
-
function outputFlagForCommand(root, argv) {
|
|
67773
|
-
const requests = envelopeRequests(argv);
|
|
67774
|
-
if (requests.length === 0) {
|
|
67775
|
-
return argv;
|
|
67776
|
-
}
|
|
67777
|
-
const command = commandFor(root, argv);
|
|
67778
|
-
if (!command || declaredArg(command, "output") || PRINTS_NO_ENVELOPE.has(commandPathOf(root, argv))) {
|
|
67779
|
-
return argv;
|
|
67780
|
-
}
|
|
67781
|
-
const jsonSwitch = declaredArg(command, "json")?.type === "boolean";
|
|
67782
|
-
const dropped = new Set(requests.flatMap(({ index, length }) => length === 2 ? [index, index + 1] : [index]));
|
|
67783
|
-
const first = requests[0]?.index;
|
|
67784
|
-
return argv.flatMap((token, index) => {
|
|
67785
|
-
if (!dropped.has(index)) {
|
|
67786
|
-
return [token];
|
|
67787
|
-
}
|
|
67788
|
-
return jsonSwitch && index === first ? ["--json"] : [];
|
|
67789
|
-
});
|
|
67790
|
-
}
|
|
67791
|
-
|
|
67792
67865
|
// src/version.ts
|
|
67793
67866
|
import { readFileSync as readFileSync21 } from "fs";
|
|
67794
67867
|
function packageJsonUrl() {
|
|
@@ -67815,7 +67888,7 @@ var main = defineCommand245({
|
|
|
67815
67888
|
Auth: Set BAKER_API_KEY (starts with bk_) and BAKER_API_URL environment variables.
|
|
67816
67889
|
Chat: Set BAKER_CHAT_ID for action and scheduled-action commands that stage changes against a chat.
|
|
67817
67890
|
Output: All commands return JSON envelopes: { ok: true, data: ... } or { ok: false, error: { code, message } }.
|
|
67818
|
-
Formats: --output json
|
|
67891
|
+
Formats: Use --output json|files|md to control output format. Default: json. (The research commands additionally accept csv and jsonl.)
|
|
67819
67892
|
Introspection: Run 'baker schema <command>' to inspect argument schemas.`
|
|
67820
67893
|
},
|
|
67821
67894
|
subCommands: {
|
|
@@ -67853,7 +67926,6 @@ process.argv = [...process.argv.slice(0, 2), ...normalizeCacheFlag(process.argv.
|
|
|
67853
67926
|
installStreamTaps();
|
|
67854
67927
|
logInvocation(process.argv.slice(2));
|
|
67855
67928
|
installExitRecord();
|
|
67856
|
-
process.argv = [...process.argv.slice(0, 2), ...outputFlagForCommand(main, process.argv.slice(2))];
|
|
67857
67929
|
refuseUnknownFlags(main, process.argv.slice(2));
|
|
67858
67930
|
process.argv = [...process.argv.slice(0, 2), ...cacheFlagForParser(process.argv.slice(2))];
|
|
67859
67931
|
runMain(main);
|