@koda-sl/baker-cli 0.238.0-dev.7fb8e0c69 → 0.238.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 +4 -0
- package/dist/{chunk-CMPAHYLB.js → chunk-EKLAHWSF.js} +4 -4
- package/dist/chunk-EKLAHWSF.js.map +1 -0
- package/dist/cli.js +145 -44
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-CMPAHYLB.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
ulid,
|
|
59
59
|
validateCanvasDeep,
|
|
60
60
|
ytDlpBlockSignal
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-EKLAHWSF.js";
|
|
62
62
|
import {
|
|
63
63
|
csvOrJson,
|
|
64
64
|
daysAgoIso,
|
|
@@ -4461,24 +4461,6 @@ var FLOW_SIDE_EFFECT_CATALOG = [
|
|
|
4461
4461
|
gotcha: "`eventTagId` comes from X Events Manager and is passed verbatim. `eventName` is an optional label only.",
|
|
4462
4462
|
reference: TAGS_REF
|
|
4463
4463
|
},
|
|
4464
|
-
{
|
|
4465
|
-
kind: "side-effect",
|
|
4466
|
-
type: "microsoftAds",
|
|
4467
|
-
summary: "Fires a Microsoft Ads (UET) conversion event.",
|
|
4468
|
-
skeleton: {
|
|
4469
|
-
...SIDE_EFFECT_ENVELOPE,
|
|
4470
|
-
type: "microsoftAds",
|
|
4471
|
-
tagIds: TAG_REF_SLOT,
|
|
4472
|
-
eventName: "<UET event action, e.g. lead_submitted>",
|
|
4473
|
-
userMatching: matchingSlots("em", "ph"),
|
|
4474
|
-
value: null,
|
|
4475
|
-
currency: null,
|
|
4476
|
-
transactionId: null
|
|
4477
|
-
},
|
|
4478
|
-
owners: { tagIds: "tags" },
|
|
4479
|
-
gotcha: "`eventName` is the UET *event action*, and it only counts as a conversion once someone creates a matching custom-event conversion goal in Microsoft Advertising \u2014 the tag alone records nothing. `page_view` is refused outright (UET reserves it for SPA navigation), so pick any other action. `eventCategory` and `eventLabel` are optional plain strings (not mapped slots) \u2014 add them only when the goal filters on them. `userMatching` needs Enhanced conversions turned on for that goal, and `ph` must carry a country code (`+34\u2026`/`0034\u2026`) \u2014 map it from a phone field with the country picker, not a plain text field, or it is dropped rather than guessed at.",
|
|
4480
|
-
reference: TAGS_REF
|
|
4481
|
-
},
|
|
4482
4464
|
eventSideEffect("posthog", "Captures a PostHog event.", { eventParams: [] }),
|
|
4483
4465
|
{
|
|
4484
4466
|
kind: "side-effect",
|
|
@@ -5920,8 +5902,7 @@ var TAG_TYPES = [
|
|
|
5920
5902
|
"posthog",
|
|
5921
5903
|
"datafast",
|
|
5922
5904
|
"recaptcha",
|
|
5923
|
-
"twitterAds"
|
|
5924
|
-
"microsoftAds"
|
|
5905
|
+
"twitterAds"
|
|
5925
5906
|
];
|
|
5926
5907
|
var tagTypeSchema = z19.enum(TAG_TYPES);
|
|
5927
5908
|
var TAG_IDENTIFYING_FIELD = {
|
|
@@ -5942,8 +5923,7 @@ var TAG_IDENTIFYING_FIELD = {
|
|
|
5942
5923
|
posthog: "projectToken",
|
|
5943
5924
|
datafast: "websiteId",
|
|
5944
5925
|
recaptcha: "siteKey",
|
|
5945
|
-
twitterAds: "pixelId"
|
|
5946
|
-
microsoftAds: "tagId"
|
|
5926
|
+
twitterAds: "pixelId"
|
|
5947
5927
|
};
|
|
5948
5928
|
var tagDraftOpKindSchema = z19.enum(["create", "update", "delete"]);
|
|
5949
5929
|
var tagDraftOpViewSchema = z19.object({
|
|
@@ -11922,19 +11902,22 @@ var analyticsBeaconPayloadSchema = z23.object({
|
|
|
11922
11902
|
});
|
|
11923
11903
|
|
|
11924
11904
|
// ../api/src/analytics/trackingTemplate.ts
|
|
11925
|
-
|
|
11926
|
-
|
|
11927
|
-
|
|
11928
|
-
|
|
11929
|
-
|
|
11930
|
-
|
|
11931
|
-
|
|
11932
|
-
|
|
11933
|
-
device: "device",
|
|
11934
|
-
product_id: "product_id",
|
|
11935
|
-
merchant_id: "product_id",
|
|
11936
|
-
product_partition_id: "product_id"
|
|
11905
|
+
function placeholderKey(raw) {
|
|
11906
|
+
return raw.replace(/[{}]/g, "").replace(/^_+|_+$/g, "").trim().toLowerCase();
|
|
11907
|
+
}
|
|
11908
|
+
var EXTRA_PLACEHOLDER_ROLES = {
|
|
11909
|
+
google: {
|
|
11910
|
+
merchant_id: "product_id",
|
|
11911
|
+
product_partition_id: "product_id"
|
|
11912
|
+
}
|
|
11937
11913
|
};
|
|
11914
|
+
function placeholderRoles(platform) {
|
|
11915
|
+
const roles = {};
|
|
11916
|
+
for (const dimension of AD_PLATFORM_DEFINITIONS[platform].dimensions) {
|
|
11917
|
+
roles[placeholderKey(dimension.macro)] = dimension.role;
|
|
11918
|
+
}
|
|
11919
|
+
return { ...roles, ...EXTRA_PLACEHOLDER_ROLES[platform] ?? {} };
|
|
11920
|
+
}
|
|
11938
11921
|
function paramsFromTemplate(template) {
|
|
11939
11922
|
const start = template.indexOf("?");
|
|
11940
11923
|
const query = start === -1 ? template : template.slice(start + 1);
|
|
@@ -11950,13 +11933,13 @@ function paramsFromTemplate(template) {
|
|
|
11950
11933
|
}
|
|
11951
11934
|
function proposeMappingFromTemplate(template, platform) {
|
|
11952
11935
|
const builtIn = builtinAdParamMapping(platform);
|
|
11936
|
+
const vocabulary = placeholderRoles(platform);
|
|
11953
11937
|
const proposed = {};
|
|
11954
11938
|
const unexplained = [];
|
|
11955
11939
|
for (const param of paramsFromTemplate(template)) {
|
|
11956
11940
|
if (RESERVED_PARAM_NAMES.includes(param.name)) continue;
|
|
11957
11941
|
if (param.name in builtIn) continue;
|
|
11958
|
-
const
|
|
11959
|
-
const role = VALUETRACK_ROLES[placeholder];
|
|
11942
|
+
const role = vocabulary[placeholderKey(param.value)];
|
|
11960
11943
|
if (role) {
|
|
11961
11944
|
proposed[param.name] = role;
|
|
11962
11945
|
continue;
|
|
@@ -13171,10 +13154,74 @@ var analyticsMappingResponseSchema = z24.object({
|
|
|
13171
13154
|
* turn configuring `keyword` to mean keyword.
|
|
13172
13155
|
*/
|
|
13173
13156
|
builtIn: z24.array(z24.string()),
|
|
13157
|
+
/**
|
|
13158
|
+
* What the client's own ad account says about each parameter just staged.
|
|
13159
|
+
*
|
|
13160
|
+
* Present only when a Session staged a `set` on a platform whose tracking
|
|
13161
|
+
* configuration Baker can read. `contradicted` is the entry worth stopping
|
|
13162
|
+
* for: the account fills that name with a placeholder meaning something
|
|
13163
|
+
* else, so the answer just given would produce a report that is wrong and
|
|
13164
|
+
* looks entirely plausible.
|
|
13165
|
+
*/
|
|
13166
|
+
evidence: z24.record(
|
|
13167
|
+
z24.string(),
|
|
13168
|
+
z24.object({
|
|
13169
|
+
status: z24.enum(["confirmed", "contradicted", "unseen", "not_read"]),
|
|
13170
|
+
macro: z24.string().optional(),
|
|
13171
|
+
suggestedRole: adParamRoleSchema.optional(),
|
|
13172
|
+
source: z24.string().optional(),
|
|
13173
|
+
reason: z24.string().optional()
|
|
13174
|
+
})
|
|
13175
|
+
).optional(),
|
|
13174
13176
|
updatedAt: z24.number().nullable()
|
|
13175
13177
|
}),
|
|
13176
13178
|
hints: z24.array(z24.string()).optional()
|
|
13177
13179
|
});
|
|
13180
|
+
var analyticsTrackingRequestSchema = z24.object({
|
|
13181
|
+
platform: z24.enum(AD_PLATFORMS).optional(),
|
|
13182
|
+
days: z24.number().int().min(1).max(365).optional()
|
|
13183
|
+
});
|
|
13184
|
+
var trackingDimensionSchema = z24.object({
|
|
13185
|
+
role: adParamRoleSchema,
|
|
13186
|
+
/** The platform's own macro for it — what goes in the URL. */
|
|
13187
|
+
macro: z24.string(),
|
|
13188
|
+
/** The account's own spelling where it has one, else the canonical name. */
|
|
13189
|
+
name: z24.string(),
|
|
13190
|
+
/**
|
|
13191
|
+
* What has to happen for this dimension to reach a report.
|
|
13192
|
+
*
|
|
13193
|
+
* Four states rather than a boolean, because two of them need opposite fixes
|
|
13194
|
+
* and one of them is not a finding at all. `unmapped` is one
|
|
13195
|
+
* `baker analytics map` call and repairs the history with it; `missing` is a
|
|
13196
|
+
* change to the ad account and everything before it stays unattributable;
|
|
13197
|
+
* `unknown` means no visit arrived and the account could not be read, which
|
|
13198
|
+
* must never be reported as untagged.
|
|
13199
|
+
*/
|
|
13200
|
+
state: z24.enum(["covered", "unmapped", "missing", "unknown"]),
|
|
13201
|
+
evidence: z24.string().optional(),
|
|
13202
|
+
note: z24.string().optional()
|
|
13203
|
+
});
|
|
13204
|
+
var analyticsTrackingPlatformSchema = z24.object({
|
|
13205
|
+
platform: z24.enum(AD_PLATFORMS),
|
|
13206
|
+
label: z24.string(),
|
|
13207
|
+
sessions: z24.number(),
|
|
13208
|
+
/** Whether the ad account itself could be read, and why not when it could not. */
|
|
13209
|
+
account: z24.object({ read: z24.boolean(), templates: z24.number(), reason: z24.string().optional() }),
|
|
13210
|
+
dimensions: z24.array(trackingDimensionSchema),
|
|
13211
|
+
/** Names the URLs already carry that Baker does not read yet. */
|
|
13212
|
+
unmapped: z24.record(z24.string(), adParamRoleSchema),
|
|
13213
|
+
mapCommand: z24.string(),
|
|
13214
|
+
unexplained: z24.array(z24.object({ name: z24.string(), value: z24.string() })),
|
|
13215
|
+
/** The pairs to append to the account's tagging, or `""`. */
|
|
13216
|
+
suffix: z24.string(),
|
|
13217
|
+
whereItGoes: z24.string(),
|
|
13218
|
+
fix: z24.string().optional()
|
|
13219
|
+
});
|
|
13220
|
+
var analyticsTrackingResponseSchema = z24.object({
|
|
13221
|
+
ok: z24.literal(true),
|
|
13222
|
+
data: z24.object({ days: z24.number(), platforms: z24.array(analyticsTrackingPlatformSchema) }),
|
|
13223
|
+
hints: z24.array(z24.string()).optional()
|
|
13224
|
+
});
|
|
13178
13225
|
var submissionRecordRequestSchema = z24.object({
|
|
13179
13226
|
/** Injected by the Worker from the host or the site key. Never from the page. */
|
|
13180
13227
|
companyId: z24.string().min(1),
|
|
@@ -23883,13 +23930,13 @@ var mapCommand = (() => {
|
|
|
23883
23930
|
};
|
|
23884
23931
|
registerSchema({
|
|
23885
23932
|
command: "analytics.map",
|
|
23886
|
-
description: "
|
|
23933
|
+
description: "Stage how this company's campaign URLs spell each ad dimension, applied on publish",
|
|
23887
23934
|
args
|
|
23888
23935
|
});
|
|
23889
23936
|
return defineCommand88({
|
|
23890
23937
|
meta: {
|
|
23891
23938
|
name: "map",
|
|
23892
|
-
description: "Teach Baker how this company's campaign URLs spell each ad dimension on one platform \u2014 `--platform google --set kw=keyword`. Run it with no flags to see the whole mapping. Mappings are always per platform, because the platforms do not describe the same world: `builtIn` in the response is what that platform is already understood to send, so you do not spend a turn mapping `keyword` to keyword.
|
|
23939
|
+
description: "Teach Baker how this company's campaign URLs spell each ad dimension on one platform \u2014 `--platform google --set kw=keyword`. Run it with no flags to see the whole mapping, including what this chat has already staged. STAGED, not applied: the answers are reviewed in the chat and take effect when it is published, so nothing you map here changes a report or what the edge stores until then; discarding the chat takes them all back. Mappings are always per platform, because the platforms do not describe the same world: `builtIn` in the response is what that platform is already understood to send, so you do not spend a turn mapping `keyword` to keyword. Each --set is checked against the client's OWN ad account \u2014 `evidence` in the response says whether their tracking template really fills that name with what you claimed. Read it: `contradicted` means the account disagrees, and mapping it your way would produce a report that is wrong and looks plausible. Renaming a parameter Baker already captured fixes the history too, because roles are applied when a report is read; naming one it never read only starts collecting it from the publish onward, since no value was stored. You do NOT need to have seen a parameter to map it: a name nobody has sent yet is a valid --set, which is how a tracking template gets configured before the campaign that uses it runs. To drop an answer, --remove takes it back to whatever Baker knows by itself, and --set <name>=ignore says it is not campaign information at all so it stops being listed."
|
|
23893
23940
|
},
|
|
23894
23941
|
args,
|
|
23895
23942
|
run: async ({ args: raw }) => {
|
|
@@ -23907,6 +23954,61 @@ var mapCommand = (() => {
|
|
|
23907
23954
|
}
|
|
23908
23955
|
});
|
|
23909
23956
|
})();
|
|
23957
|
+
var trackingCommand = (() => {
|
|
23958
|
+
const args = {
|
|
23959
|
+
platform: {
|
|
23960
|
+
type: "string",
|
|
23961
|
+
description: "One platform: google, meta, microsoft, linkedin, tiktok, reddit, pinterest, snapchat. Omit to check the ones worth checking \u2014 every platform sending visits, plus Google and Meta, whose accounts Baker can read directly",
|
|
23962
|
+
required: false
|
|
23963
|
+
},
|
|
23964
|
+
days: { type: "string", description: "Lookback window for the traffic half (default: 30)", required: false }
|
|
23965
|
+
};
|
|
23966
|
+
registerSchema({
|
|
23967
|
+
command: "analytics.tracking",
|
|
23968
|
+
description: "Check whether a platform's ad URLs carry the campaign, ad group and ad a report needs",
|
|
23969
|
+
args
|
|
23970
|
+
});
|
|
23971
|
+
return defineCommand88({
|
|
23972
|
+
meta: {
|
|
23973
|
+
name: "tracking",
|
|
23974
|
+
description: `Check whether this company's ad URLs carry the dimensions any budget decision needs \u2014 the campaign, the ad group, the ad, and the keyword where the platform has one.
|
|
23975
|
+
|
|
23976
|
+
Read this before auditing an ad account and before answering any "which ad performed best" question. Each dimension comes back in one of four states, and they need different things:
|
|
23977
|
+
covered \u2014 arriving and understood, nothing to do
|
|
23978
|
+
unmapped \u2014 the URLs carry it under a name Baker does not read yet. Free to fix, and it repairs the traffic already collected: run the \`mapCommand\` in the response
|
|
23979
|
+
missing \u2014 nothing carries it. Add \`suffix\` to the account's tagging (\`whereItGoes\` says where, \`fix\` says whether Baker can stage it). This one cannot be filled in later \u2014 a parameter's values are only stored once it starts arriving
|
|
23980
|
+
unknown \u2014 no visit arrived AND the account could not be read. Not a finding; do not report it as untagged
|
|
23981
|
+
|
|
23982
|
+
Baker reads the client's own Google tracking templates and Meta URL parameters, so a platform that has not run yet still gets a real answer.
|
|
23983
|
+
|
|
23984
|
+
Examples:
|
|
23985
|
+
baker analytics tracking
|
|
23986
|
+
baker analytics tracking --platform meta
|
|
23987
|
+
baker analytics tracking --platform google --days 90`
|
|
23988
|
+
},
|
|
23989
|
+
args,
|
|
23990
|
+
run: async ({ args: raw }) => {
|
|
23991
|
+
try {
|
|
23992
|
+
const platform = raw.platform === void 0 ? void 0 : String(raw.platform);
|
|
23993
|
+
if (platform !== void 0 && !isAdPlatform(platform)) {
|
|
23994
|
+
writeJsonEnvelope({
|
|
23995
|
+
ok: false,
|
|
23996
|
+
error: { code: "BAD_REQUEST", message: `Unknown platform "${platform}"` }
|
|
23997
|
+
});
|
|
23998
|
+
process.exit(1);
|
|
23999
|
+
}
|
|
24000
|
+
const days = raw.days === void 0 ? void 0 : Number(raw.days);
|
|
24001
|
+
const response = await apiPost("/api/analytics/tracking", {
|
|
24002
|
+
...platform ? { platform } : {},
|
|
24003
|
+
...days !== void 0 && Number.isFinite(days) ? { days } : {}
|
|
24004
|
+
});
|
|
24005
|
+
writeJsonEnvelope(response);
|
|
24006
|
+
} catch (err) {
|
|
24007
|
+
handleError(err);
|
|
24008
|
+
}
|
|
24009
|
+
}
|
|
24010
|
+
});
|
|
24011
|
+
})();
|
|
23910
24012
|
function parsePairs(raw) {
|
|
23911
24013
|
if (raw === void 0) return void 0;
|
|
23912
24014
|
const out = {};
|
|
@@ -23955,7 +24057,9 @@ Examples:
|
|
|
23955
24057
|
baker analytics ads --role keyword \u2014 keywords by conversions AND by how many bounced
|
|
23956
24058
|
baker analytics ads --platform google --role keyword \u2014 the same, in Google's vocabulary and from Google's traffic only
|
|
23957
24059
|
baker analytics overview --role keyword --value "solar panels" \u2014 the whole report for those visits only
|
|
23958
|
-
baker analytics
|
|
24060
|
+
baker analytics tracking \u2014 do the ad URLs carry the campaign, ad group and ad at all
|
|
24061
|
+
baker analytics tracking --platform meta \u2014 the same for one platform, read from their own ad account
|
|
24062
|
+
baker analytics map --platform google --set kw=keyword \u2014 stage a parameter name, seen or not yet
|
|
23959
24063
|
baker analytics map --platform google --remove kw \u2014 take that answer back
|
|
23960
24064
|
baker analytics delivery --page 2 --page-size 50 \u2014 the next page of a long list
|
|
23961
24065
|
baker analytics overview --compare \u2014 this window against the one before it
|
|
@@ -23980,6 +24084,7 @@ Full guide: __tooling__/docs/tools/baker/analytics.md`
|
|
|
23980
24084
|
devices: devicesCommand,
|
|
23981
24085
|
ads: adsCommand3,
|
|
23982
24086
|
map: mapCommand,
|
|
24087
|
+
tracking: trackingCommand,
|
|
23983
24088
|
presets: presetsCommand
|
|
23984
24089
|
}
|
|
23985
24090
|
});
|
|
@@ -33840,10 +33945,6 @@ var MAPPING_SLOTS = {
|
|
|
33840
33945
|
twitterAds: [
|
|
33841
33946
|
{ kind: "record", key: "userMatching", allowed: ["em", "ph"] },
|
|
33842
33947
|
{ kind: "scalar", keys: ["value", "currency"] }
|
|
33843
|
-
],
|
|
33844
|
-
microsoftAds: [
|
|
33845
|
-
{ kind: "record", key: "userMatching", allowed: ["em", "ph"] },
|
|
33846
|
-
{ kind: "scalar", keys: ["value", "currency", "transactionId"] }
|
|
33847
33948
|
]
|
|
33848
33949
|
};
|
|
33849
33950
|
var UNMAPPABLE = {
|