@koda-sl/baker-cli 0.344.0-dev.9890d9fcc → 0.344.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/README.md +2 -4
- package/dist/{chunk-D5P4COPD.js → chunk-FFOURYP5.js} +4 -4
- package/dist/chunk-FFOURYP5.js.map +1 -0
- package/dist/cli.js +14 -135
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-D5P4COPD.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -67,7 +67,7 @@ import {
|
|
|
67
67
|
validateCanvasDeep,
|
|
68
68
|
withoutCastName,
|
|
69
69
|
ytDlpBlockSignal
|
|
70
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-FFOURYP5.js";
|
|
71
71
|
import {
|
|
72
72
|
csvOrJson,
|
|
73
73
|
daysAgoIso,
|
|
@@ -2362,7 +2362,6 @@ var GOOGLE_ADS_LIMITS = {
|
|
|
2362
2362
|
businessNameMax: 25
|
|
2363
2363
|
}
|
|
2364
2364
|
};
|
|
2365
|
-
var GOOGLE_ADS_QUERY_MAX_PAGE_SIZE = 1e4;
|
|
2366
2365
|
var KEYWORD_MATCH_TYPES = ["EXACT", "PHRASE", "BROAD"];
|
|
2367
2366
|
var ADVERTISING_CHANNEL_TYPES = [
|
|
2368
2367
|
"SEARCH",
|
|
@@ -10080,72 +10079,7 @@ function urlOptionsHints(report) {
|
|
|
10080
10079
|
return hints2;
|
|
10081
10080
|
}
|
|
10082
10081
|
|
|
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
|
-
|
|
10145
10082
|
// 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
|
-
}
|
|
10149
10083
|
function isChangeScope(value) {
|
|
10150
10084
|
return CHANGE_SCOPES.includes(value);
|
|
10151
10085
|
}
|
|
@@ -10199,7 +10133,7 @@ function lookbackTooLong(scope, days, max) {
|
|
|
10199
10133
|
message: `Google's account history API reaches back ${CHANGE_SCOPE_MAX_DAYS.summary} days at most; ${days} days is outside that window.`,
|
|
10200
10134
|
fix: {
|
|
10201
10135
|
action: "use_different_resource",
|
|
10202
|
-
explanation:
|
|
10136
|
+
explanation: "Do not abort \u2014 infer the change from performance instead. Query monthly metrics per campaign (SELECT campaign.name, segments.month, metrics.cost_micros, metrics.conversions FROM campaign WHERE segments.date DURING LAST_12_MONTHS) 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."
|
|
10203
10137
|
}
|
|
10204
10138
|
};
|
|
10205
10139
|
}
|
|
@@ -10558,7 +10492,7 @@ var CORRECTION_RULES = [
|
|
|
10558
10492
|
matchApiError: /changeStatusError\W{0,4}START_DATE_TOO_OLD/i,
|
|
10559
10493
|
fix: () => ({
|
|
10560
10494
|
action: "use_different_resource",
|
|
10561
|
-
explanation:
|
|
10495
|
+
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: SELECT campaign.name, segments.month, metrics.cost_micros, metrics.conversions FROM campaign WHERE segments.date DURING LAST_12_MONTHS 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."
|
|
10562
10496
|
})
|
|
10563
10497
|
},
|
|
10564
10498
|
// 18c. change_status rejects a date range it cannot bound. Google raises this both for
|
|
@@ -12385,16 +12319,9 @@ import { resolve } from "path";
|
|
|
12385
12319
|
import { defineCommand as defineCommand28 } from "citty";
|
|
12386
12320
|
|
|
12387
12321
|
// src/commands/ads/google/presets.ts
|
|
12388
|
-
var
|
|
12322
|
+
var GAQL_DATE_RANGE_RE = /^(?:TODAY|YESTERDAY|LAST_7_DAYS|LAST_14_DAYS|LAST_30_DAYS|LAST_90_DAYS|THIS_MONTH|LAST_MONTH|THIS_QUARTER|LAST_QUARTER|THIS_YEAR|LAST_YEAR|ALL_TIME|BETWEEN\s+'[0-9]{4}-[0-9]{2}-[0-9]{2}'\s+AND\s+'[0-9]{4}-[0-9]{2}-[0-9]{2}')$/i;
|
|
12389
12323
|
function isValidDateRange(value) {
|
|
12390
|
-
|
|
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'.`;
|
|
12324
|
+
return GAQL_DATE_RANGE_RE.test(value.trim());
|
|
12398
12325
|
}
|
|
12399
12326
|
var SERVING_CHAINS = {
|
|
12400
12327
|
keyword_view: ["campaign.status", "ad_group.status", "ad_group_criterion.status"],
|
|
@@ -12530,15 +12457,17 @@ function buildStatusScope(statusFields, includePaused) {
|
|
|
12530
12457
|
const predicate = includePaused ? "!= 'REMOVED'" : "= 'ENABLED'";
|
|
12531
12458
|
return statusFields.map((field) => ` AND ${field} ${predicate}`).join("");
|
|
12532
12459
|
}
|
|
12533
|
-
function expandPreset(preset, params
|
|
12460
|
+
function expandPreset(preset, params) {
|
|
12534
12461
|
const dateRange = params.dateRange ?? preset.defaultDateRange;
|
|
12535
12462
|
const limit = params.limit ?? preset.defaultLimit;
|
|
12536
|
-
if (
|
|
12537
|
-
return {
|
|
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
|
+
};
|
|
12538
12468
|
}
|
|
12539
12469
|
const statusScope = buildStatusScope(preset.statusFields, params.includePaused ?? false);
|
|
12540
|
-
const
|
|
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);
|
|
12470
|
+
const query = preset.gaqlTemplate.replace(/\{dateRange\}/g, dateRange).replace(/\{limit\}/g, String(limit)).replace(/\{statusScope\}/g, statusScope);
|
|
12542
12471
|
return { query };
|
|
12543
12472
|
}
|
|
12544
12473
|
|
|
@@ -12697,28 +12626,6 @@ function applyAutoFixes(query, limit) {
|
|
|
12697
12626
|
}
|
|
12698
12627
|
return { query: corrected, warnings };
|
|
12699
12628
|
}
|
|
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
|
-
}
|
|
12722
12629
|
function validatePreflight(query, customerId, limit) {
|
|
12723
12630
|
const warnings = [];
|
|
12724
12631
|
const corrected = query;
|
|
@@ -12790,8 +12697,6 @@ function validatePreflight(query, customerId, limit) {
|
|
|
12790
12697
|
}
|
|
12791
12698
|
};
|
|
12792
12699
|
}
|
|
12793
|
-
const duringRejection = rejectUnsupportedDuring(corrected, customerId);
|
|
12794
|
-
if (duringRejection) return { valid: false, warnings: [], error: duringRejection };
|
|
12795
12700
|
if (/\bsegments\.conversion_action_name\b/i.test(corrected) && /\bmetrics\.cost_micros\b/i.test(corrected)) {
|
|
12796
12701
|
return {
|
|
12797
12702
|
valid: false,
|
|
@@ -13000,7 +12905,7 @@ registerSchema({
|
|
|
13000
12905
|
},
|
|
13001
12906
|
"date-range": {
|
|
13002
12907
|
type: "string",
|
|
13003
|
-
description: "Date range for presets
|
|
12908
|
+
description: "Date range for presets (LAST_7_DAYS, LAST_30_DAYS, LAST_90_DAYS, or BETWEEN 'X' AND 'Y')",
|
|
13004
12909
|
required: false
|
|
13005
12910
|
},
|
|
13006
12911
|
"include-paused": {
|
|
@@ -13439,35 +13344,9 @@ async function executeQuery(finalQuery, args5, customerId, limit, warnings, useC
|
|
|
13439
13344
|
function shouldReadCache(args5) {
|
|
13440
13345
|
return !args5["no-cache"] && !args5.out;
|
|
13441
13346
|
}
|
|
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
|
-
}
|
|
13463
13347
|
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;
|
|
13470
13348
|
const customerId = await resolveCustomerId(args5);
|
|
13349
|
+
const limit = args5.limit ? Number(args5.limit) : 200;
|
|
13471
13350
|
const gaql = resolveGaql(args5, limit);
|
|
13472
13351
|
if (!gaql) {
|
|
13473
13352
|
process.exit(1);
|