@koda-sl/baker-cli 0.504.0 → 0.506.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.
Files changed (42) hide show
  1. package/README.md +3 -0
  2. package/dist/{ads-MAPZYX6F.js → ads-T5RPISTB.js} +3 -3
  3. package/dist/{analytics-4CCQYY7Z.js → analytics-P5UFA6I4.js} +315 -18
  4. package/dist/analytics-P5UFA6I4.js.map +1 -0
  5. package/dist/{chunk-DI44SZVP.js → chunk-7J3NZBPV.js} +31 -1
  6. package/dist/chunk-7J3NZBPV.js.map +1 -0
  7. package/dist/{chunk-VU5Z2V4S.js → chunk-D3KLDIPQ.js} +2 -2
  8. package/dist/{chunk-GJCB46L6.js → chunk-HWDRW36T.js} +2 -2
  9. package/dist/{chunk-S3FFLLYF.js → chunk-LIRX2Q66.js} +2 -2
  10. package/dist/{chunk-DX46OE4U.js → chunk-OJGYYH6K.js} +2 -2
  11. package/dist/{chunk-ZEGNIP3Y.js → chunk-TVTSA4EN.js} +3 -3
  12. package/dist/cli.js +3 -3
  13. package/dist/{funnel-727XATM5.js → funnel-S6JTLUK6.js} +3 -3
  14. package/dist/{google-VPL4KZDP.js → google-3GSINSOV.js} +2 -2
  15. package/dist/{lookup-LWJMDEEL.js → lookup-ZJIP2M4X.js} +4 -4
  16. package/dist/{performance-CIUVIFD7.js → performance-WPFGEJTE.js} +13 -3
  17. package/dist/performance-WPFGEJTE.js.map +1 -0
  18. package/dist/{plan-O2TTEUIW.js → plan-TVQSEKYL.js} +6 -6
  19. package/dist/{questionnaire-VE42SW77.js → questionnaire-LEZJLMAV.js} +3 -3
  20. package/dist/{sends-OLVQGOAE.js → sends-6FI7WELX.js} +3 -3
  21. package/dist/{sources-PSM2A5QD.js → sources-L3KNVLIB.js} +4 -4
  22. package/dist/{unstage-QFVL7AZ4.js → unstage-MDSSPUKV.js} +3 -3
  23. package/dist/{url-options-LA6BL3GS.js → url-options-IHL4OU4C.js} +2 -2
  24. package/package.json +1 -1
  25. package/dist/analytics-4CCQYY7Z.js.map +0 -1
  26. package/dist/chunk-DI44SZVP.js.map +0 -1
  27. package/dist/performance-CIUVIFD7.js.map +0 -1
  28. /package/dist/{ads-MAPZYX6F.js.map → ads-T5RPISTB.js.map} +0 -0
  29. /package/dist/{chunk-VU5Z2V4S.js.map → chunk-D3KLDIPQ.js.map} +0 -0
  30. /package/dist/{chunk-GJCB46L6.js.map → chunk-HWDRW36T.js.map} +0 -0
  31. /package/dist/{chunk-S3FFLLYF.js.map → chunk-LIRX2Q66.js.map} +0 -0
  32. /package/dist/{chunk-DX46OE4U.js.map → chunk-OJGYYH6K.js.map} +0 -0
  33. /package/dist/{chunk-ZEGNIP3Y.js.map → chunk-TVTSA4EN.js.map} +0 -0
  34. /package/dist/{funnel-727XATM5.js.map → funnel-S6JTLUK6.js.map} +0 -0
  35. /package/dist/{google-VPL4KZDP.js.map → google-3GSINSOV.js.map} +0 -0
  36. /package/dist/{lookup-LWJMDEEL.js.map → lookup-ZJIP2M4X.js.map} +0 -0
  37. /package/dist/{plan-O2TTEUIW.js.map → plan-TVQSEKYL.js.map} +0 -0
  38. /package/dist/{questionnaire-VE42SW77.js.map → questionnaire-LEZJLMAV.js.map} +0 -0
  39. /package/dist/{sends-OLVQGOAE.js.map → sends-6FI7WELX.js.map} +0 -0
  40. /package/dist/{sources-PSM2A5QD.js.map → sources-L3KNVLIB.js.map} +0 -0
  41. /package/dist/{unstage-QFVL7AZ4.js.map → unstage-MDSSPUKV.js.map} +0 -0
  42. /package/dist/{url-options-LA6BL3GS.js.map → url-options-IHL4OU4C.js.map} +0 -0
package/README.md CHANGED
@@ -1818,6 +1818,9 @@ baker analytics delivery --page 2 # the next page of a long list
1818
1818
  baker analytics submissions --flow contact # every attempt at a Form, delivered or not
1819
1819
  baker analytics feed --source Zapier # the raw event feed, newest first, narrowed to what one source sent
1820
1820
  baker analytics feed --sends failed # only the uploads a conversion's sends made and the platform refused
1821
+ baker analytics feed --bots # only the events taken for machine traffic (a headless browser such as agent-browser), hidden everywhere else
1822
+ baker analytics website-tag --check # every event the website's Tag Manager sends Baker, and which no real visit has brought
1823
+ baker analytics debug --start --url https://client.com/ # a link that records what the person's own browser heard; read it with `baker analytics debug <code>`
1821
1824
  baker analytics feed --person 'ana@empresa.com, +34600111222, deal:40001234567' --days 90 # everything these people did; emails and phones are hashed by Baker
1822
1825
  baker analytics lookup --person 'ana@empresa.com, 90001234567' # what Baker saw of each person in a list, all time — found or not, pages, CRM stages, uploads
1823
1826
  baker analytics lookup --people-file leads.txt # one per line: emails, phones, HubSpot contact or deal:<id>, gclid/fbclid, browser ids
@@ -33,16 +33,16 @@ Examples:
33
33
  Full guides: __tooling__/docs/tools/baker/ads-<platform>.md (google|meta|linkedin|x|chatgpt|performance|terms)`
34
34
  },
35
35
  subCommands: {
36
- google: () => import("./google-VPL4KZDP.js").then((m) => m.googleCommand),
36
+ google: () => import("./google-3GSINSOV.js").then((m) => m.googleCommand),
37
37
  meta: () => import("./meta-KS3SQSYZ.js").then((m) => m.metaCommand),
38
38
  linkedin: () => import("./linkedin-4MGRSWXZ.js").then((m) => m.linkedinCommand),
39
39
  x: () => import("./x-7VY6K7JS.js").then((m) => m.xCommand),
40
40
  chatgpt: () => import("./chatgpt-SVGWMEQD.js").then((m) => m.chatgptCommand),
41
- performance: () => import("./performance-CIUVIFD7.js").then((m) => m.performanceCommand),
41
+ performance: () => import("./performance-WPFGEJTE.js").then((m) => m.performanceCommand),
42
42
  terms: () => import("./terms-O6ODXEOK.js").then((m) => m.termsCommand)
43
43
  }
44
44
  });
45
45
  export {
46
46
  adsCommand
47
47
  };
48
- //# sourceMappingURL=ads-MAPZYX6F.js.map
48
+ //# sourceMappingURL=ads-T5RPISTB.js.map
@@ -5,7 +5,7 @@ import "./chunk-MGYC2IRC.js";
5
5
  import {
6
6
  flowEventKeys,
7
7
  flowNodes
8
- } from "./chunk-S3FFLLYF.js";
8
+ } from "./chunk-LIRX2Q66.js";
9
9
  import {
10
10
  flowDataPath,
11
11
  flowExists,
@@ -16,20 +16,23 @@ import {
16
16
  INGEST_ARRIVALS_MAX,
17
17
  eventIngestUrl,
18
18
  ingestBrief
19
- } from "./chunk-GJCB46L6.js";
19
+ } from "./chunk-HWDRW36T.js";
20
20
  import "./chunk-GRQ2AXDX.js";
21
+ import {
22
+ TAG_MANAGER_TIMEOUT_MS
23
+ } from "./chunk-3GAR4AZK.js";
21
24
  import {
22
25
  peopleArgs,
23
26
  peopleLimitError
24
- } from "./chunk-ZEGNIP3Y.js";
27
+ } from "./chunk-TVTSA4EN.js";
25
28
  import {
26
29
  ConversionArgsError,
27
30
  conversionsWrite,
28
31
  parseConversionsArgs
29
- } from "./chunk-DX46OE4U.js";
32
+ } from "./chunk-OJGYYH6K.js";
30
33
  import {
31
34
  analyticsErrorEnvelope
32
- } from "./chunk-VU5Z2V4S.js";
35
+ } from "./chunk-D3KLDIPQ.js";
33
36
  import {
34
37
  AD_PARAM_ROLE_SPECS,
35
38
  ANALYTICS_EVENT_DOORS,
@@ -42,11 +45,12 @@ import {
42
45
  isBookkeepingRow,
43
46
  parseEventKey,
44
47
  rowMatchKeys
45
- } from "./chunk-DI44SZVP.js";
48
+ } from "./chunk-7J3NZBPV.js";
46
49
  import "./chunk-EDLZGTGN.js";
47
50
  import {
48
51
  repeatedValues
49
52
  } from "./chunk-ERSX3MKH.js";
53
+ import "./chunk-D5FY4FAK.js";
50
54
  import {
51
55
  writeJsonEnvelope
52
56
  } from "./chunk-ZRP7Y2DM.js";
@@ -507,6 +511,84 @@ function withFormatHint(envelope, format) {
507
511
  return { ...envelope, ...hints.length > 0 ? { hints } : {} };
508
512
  }
509
513
 
514
+ // src/commands/analytics/debugLink.ts
515
+ function debugStartHints(started) {
516
+ if (started.link === null) {
517
+ return [
518
+ `Code ${started.code} records for two hours. Run it again with --url <the page to test> for a link to send, or add ?baker_debug=${started.code} to that page's address yourself.`
519
+ ];
520
+ }
521
+ return [
522
+ `Send the person this link: ${started.link} \u2014 they open it in the browser they normally use, accept the cookie banner, do exactly what did not work (open the widget, start the call, submit the form), then tell you they are done. Then run \`baker analytics debug ${started.code}\`. It records for two hours, nothing it records is counted anywhere, and emails and phone numbers are masked.`
523
+ ];
524
+ }
525
+ function inner(row) {
526
+ if (!row.data) return "";
527
+ try {
528
+ const parsed = JSON.parse(row.data);
529
+ const name = parsed.event ?? parsed.action ?? parsed.name;
530
+ return typeof name === "string" ? name : "";
531
+ } catch {
532
+ return "";
533
+ }
534
+ }
535
+ function isTagManagerNoise(label) {
536
+ return label.startsWith("gtm.") || label.startsWith("cookie_consent") || label === "consent" || label === "set";
537
+ }
538
+ var FOLLOWS_WITHIN_MS = 2e3;
539
+ function debugReadHints(read) {
540
+ if (read.records.length === 0) {
541
+ return [
542
+ `Nothing recorded under ${read.code}: the Baker tag never loaded on a visit with this link. Either the link was not opened yet, the cookie banner was not accepted (on a site that loads Tag Manager only after consent, the tag never starts), or the site dropped ?baker_debug from the address before the tag ran. ${read.active ? "The link still records \u2014 ask them to try again." : "The link has expired; start a new one."}`
543
+ ];
544
+ }
545
+ const hints = [];
546
+ const boot = read.records.find((row) => row.kind === "pixel" && row.label === "boot");
547
+ if (boot?.data?.includes('"measuring":false')) {
548
+ hints.push(
549
+ "The tag did not measure this visit (its scope or the visitor's consent ruled it out), so its `track` calls sent nothing to Baker. The records below are still what the page heard."
550
+ );
551
+ }
552
+ const messages = read.records.filter((row) => row.kind === "message" && row.from && row.from !== "null");
553
+ const byOrigin = /* @__PURE__ */ new Map();
554
+ for (const row of messages) {
555
+ const said = byOrigin.get(row.from ?? "") ?? /* @__PURE__ */ new Map();
556
+ const what = inner(row) ? `${row.label} (${inner(row)})` : row.label;
557
+ said.set(what, (said.get(what) ?? 0) + 1);
558
+ byOrigin.set(row.from ?? "", said);
559
+ }
560
+ for (const [origin, said] of byOrigin) {
561
+ hints.push(
562
+ `${origin} sent: ${[...said].map(([what, count]) => count > 1 ? `${what} \xD7${count}` : what).join(", ")}. An event that is not on this list was never sent by that frame on this visit \u2014 the tag manager could not have passed it on.`
563
+ );
564
+ }
565
+ const unanswered = messages.filter(
566
+ (message) => !read.records.some(
567
+ (row) => row.kind === "dataLayer" && !isTagManagerNoise(row.label) && // Either side of it: a listener the site registered before the tag
568
+ // ran first, so its push is stamped before the message is.
569
+ Math.abs(row.t - message.t) <= FOLLOWS_WITHIN_MS
570
+ )
571
+ );
572
+ if (unanswered.length > 0) {
573
+ hints.push(
574
+ `${[...new Set(unanswered.map((row) => row.label))].join(", ")}: arrived as a message and no dataLayer event followed, so no tag listening for one could fire. Compare the message (--full) with the listener in the container (\`baker tag-manager read --entities tag --full\`) \u2014 a different \`type\` or event name is the usual cause.`
575
+ );
576
+ }
577
+ const tracked = read.records.filter((row) => row.kind === "track").map((row) => row.label);
578
+ if (tracked.length > 0) {
579
+ hints.push(
580
+ `The tag was asked to send: ${[...new Set(tracked)].join(", ")}. These reach Baker's feed within a minute or two (\`baker analytics feed --origin website --days 1\`).`
581
+ );
582
+ }
583
+ if (read.dropped > 0)
584
+ hints.push(`${read.dropped} records arrived after this link had kept its maximum and were not kept.`);
585
+ return hints;
586
+ }
587
+ function compactDebugRead(read, full) {
588
+ if (full) return read;
589
+ return { ...read, records: read.records.map(({ data: _data, ...row }) => row) };
590
+ }
591
+
510
592
  // src/commands/analytics/feedRows.ts
511
593
  function isStreamRow(value) {
512
594
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -540,6 +622,14 @@ function feedHints(shape) {
540
622
  }
541
623
  return hints;
542
624
  }
625
+ function hiddenMachinesHints(hidden) {
626
+ if (hidden === void 0 || hidden.events === 0) return [];
627
+ const headless = hidden.reasons.some((share) => share.reason === "ua");
628
+ const why = headless ? "a headless browser, which is what agent-browser is, so a check you ran on the site lands here" : "a datacenter or crawler network, or headers no real browser sends";
629
+ return [
630
+ `${hidden.events} events in this window came from machines and are not listed \u2014 stored, but left out of the feed and every report (${why}). They arrived; this is not lost data. \`baker analytics feed --bots\` lists them, each with its \`botReason\`. Never present them to the client as visits.`
631
+ ];
632
+ }
543
633
  function peopleSearchHints(search, rows) {
544
634
  const found = new Set(rows.flatMap((row) => Array.isArray(row.personTerms) ? row.personTerms : []));
545
635
  return search.filter((term) => !found.has(term.term)).map(
@@ -938,6 +1028,61 @@ function refineCompaniesReport(data, companies, targets) {
938
1028
  return [...visitorCompanyHints(matched.companies.length > 0 ? matched.companies : companies), ...skipped, ...cut];
939
1029
  }
940
1030
 
1031
+ // src/commands/analytics/websiteTagCheck.ts
1032
+ var BAKER_CALL = /baker\s*\.\s*(?:track|conversion)\s*\(\s*(["'])([^"'\n]{1,120})\1/g;
1033
+ function tagHtml(raw) {
1034
+ if (typeof raw !== "object" || raw === null) return "";
1035
+ const parameters = raw.parameter;
1036
+ if (!Array.isArray(parameters)) return "";
1037
+ const html = parameters.find(
1038
+ (parameter) => typeof parameter === "object" && parameter !== null && parameter.key === "html" && typeof parameter.value === "string"
1039
+ );
1040
+ return html?.value ?? "";
1041
+ }
1042
+ function checkWebsiteEvents(tags, catalog) {
1043
+ const expected = /* @__PURE__ */ new Map();
1044
+ for (const tag of tags) {
1045
+ for (const match of tagHtml(tag.raw).matchAll(BAKER_CALL)) {
1046
+ const name = match[2];
1047
+ if (name === void 0) continue;
1048
+ const entry = expected.get(name) ?? { tags: [], paused: true };
1049
+ entry.tags.push(tag.name);
1050
+ entry.paused = entry.paused && tag.paused === true;
1051
+ expected.set(name, entry);
1052
+ }
1053
+ }
1054
+ const seen = new Map((catalog ?? []).map((row) => [row.eventKey, row]));
1055
+ const events = [...expected].map(([name, { tags: sentBy, paused }]) => {
1056
+ const arrived = seen.get(`page:${name}`);
1057
+ const events2 = arrived?.events ?? 0;
1058
+ const status = paused ? "paused" : catalog === null ? "not_checked" : events2 > 0 ? "arriving" : "never_seen";
1059
+ return { name, tags: sentBy, paused, status, events: events2, lastSeen: arrived?.lastSeen ?? null };
1060
+ });
1061
+ return { events };
1062
+ }
1063
+ function websiteEventCheckHints(events, days) {
1064
+ const hints = [];
1065
+ const missing = events.filter((event) => event.status === "never_seen");
1066
+ if (missing.length > 0) {
1067
+ hints.push(
1068
+ `${missing.map((event) => `\`${event.name}\``).join(", ")}: a tag sends ${missing.length === 1 ? "it" : "them"} and no real visit brought one in ${days} days. Tag Manager only fires the tag when something on the page pushes its trigger \u2014 find out whether the page ever does: \`baker analytics debug --start\` gives the person a link that records what their browser hears, and the agent-browser recipe "what a live site tells its tag manager" reads a widget's code for when it sends each event.`
1069
+ );
1070
+ }
1071
+ const paused = events.filter((event) => event.status === "paused");
1072
+ if (paused.length > 0) {
1073
+ hints.push(
1074
+ `${paused.map((event) => `\`${event.name}\``).join(", ")}: every tag sending ${paused.length === 1 ? "it is" : "them is"} paused in Tag Manager, so nothing is sent. That is a setting in the container, not a fault on the site.`
1075
+ );
1076
+ }
1077
+ const doubled = events.filter((event) => event.tags.length > 1);
1078
+ if (doubled.length > 0) {
1079
+ hints.push(
1080
+ `${doubled.map((event) => `\`${event.name}\` (${event.tags.join(", ")})`).join("; ")}: sent by more than one tag, so one moment can arrive twice. Give each call the same \`eventId\` or keep one tag.`
1081
+ );
1082
+ }
1083
+ return hints;
1084
+ }
1085
+
941
1086
  // src/commands/analytics/websiteTagHints.ts
942
1087
  function asTyped(origin) {
943
1088
  return origin.replace(/^https?:\/\//, "");
@@ -1136,6 +1281,7 @@ function requestBody(args, options) {
1136
1281
  sentTo: options.sentTo,
1137
1282
  eventUid: options.eventUid,
1138
1283
  people: options.people,
1284
+ machines: options.machines,
1139
1285
  ...pageOf(args)
1140
1286
  };
1141
1287
  return Object.fromEntries(
@@ -1143,9 +1289,13 @@ function requestBody(args, options) {
1143
1289
  );
1144
1290
  }
1145
1291
  var EVENT_ORIGINS = ANALYTICS_EVENT_DOORS;
1146
- function feedReportHints(feed, peopleSearch) {
1292
+ function feedReportHints(feed, data) {
1147
1293
  if (feed === void 0) return [];
1148
- return [...feedHints(feed), ...peopleSearchHints(peopleSearch ?? [], feed.rows)];
1294
+ return [
1295
+ ...feedHints(feed),
1296
+ ...hiddenMachinesHints(data.hiddenMachines),
1297
+ ...peopleSearchHints(data.peopleSearch ?? [], feed.rows)
1298
+ ];
1149
1299
  }
1150
1300
  async function runPreset(args, options, refine) {
1151
1301
  const origin = args.origin === void 0 ? "" : String(args.origin);
@@ -1174,7 +1324,7 @@ async function runPreset(args, options, refine) {
1174
1324
  if (feed !== void 0) data.stream = feed.rows;
1175
1325
  const refinedHints = refine ? refine(data, response.data) : [];
1176
1326
  const hints = [
1177
- ...feedReportHints(feed, response.data.peopleSearch),
1327
+ ...feedReportHints(feed, response.data),
1178
1328
  // The platform the ad blocks were scoped to, so the tagging hint can
1179
1329
  // only speak about the inventory it was actually given. `adParams` is one
1180
1330
  // platform's list; a hint drawn from it without knowing which platform
@@ -1459,6 +1609,7 @@ function feedNarrowing(args) {
1459
1609
  ...args.send ? { sendId: String(args.send) } : {},
1460
1610
  ...args["sent-to"] ? { sentTo: String(args["sent-to"]) } : {},
1461
1611
  ...args.uid ? { eventUid: String(args.uid) } : {},
1612
+ ...args.bots === true ? { machines: true } : {},
1462
1613
  ...peopleArgs(args)
1463
1614
  };
1464
1615
  }
@@ -1512,6 +1663,11 @@ var feedCommand = presetCommand({
1512
1663
  description: "A file with one person per line, read like --person \u2014 a column pasted from a CRM export",
1513
1664
  required: false
1514
1665
  },
1666
+ bots: {
1667
+ type: "boolean",
1668
+ description: "List ONLY the events taken for machine traffic \u2014 a headless browser (agent-browser is one: every check you run on a site from it lands here), a datacenter network \u2014 each with its `botReason`. Stored, but left out of the feed and every report. Reach for it to confirm a test visit you just made arrived; never quote these rows to the client as visitors",
1669
+ required: false
1670
+ },
1515
1671
  everything: {
1516
1672
  type: "boolean",
1517
1673
  description: "Include the rows held back by default: the ones recorded so the reports can be worked out (identifications, step views, session starts, a destination's answer already folded onto its dispatch) and embedded forms and calendars announcing that they drew. Reach for it when debugging the collector rather than an integration \u2014 an embed that draws and never fires again is only visible here",
@@ -1946,7 +2102,13 @@ var websiteTagCommand = (() => {
1946
2102
  type: "string",
1947
2103
  required: false,
1948
2104
  description: 'Whose activity to measure: "campaigns" (default), "outcomes" or "all"'
1949
- }
2105
+ },
2106
+ check: {
2107
+ type: "boolean",
2108
+ required: false,
2109
+ description: "Every event the Tag Manager container sends Baker, and whether a real visit has brought it"
2110
+ },
2111
+ days: { type: "string", required: false, description: "With --check: how far back to look (default 30)" }
1950
2112
  }
1951
2113
  });
1952
2114
  return defineCommand({
@@ -1969,15 +2131,25 @@ Three things worth knowing before you install it:
1969
2131
  Examples:
1970
2132
  baker analytics website-tag \u2014 the tag, the origins and the install brief
1971
2133
  baker analytics website-tag --measure all \u2014 measure their whole website, because they asked for that
2134
+ baker analytics website-tag --check \u2014 every event Tag Manager sends Baker, and which never arrived
1972
2135
  baker analytics events --origin website \u2014 after it is live, what that website is reporting`
1973
2136
  },
1974
2137
  args: {
1975
2138
  measure: {
1976
2139
  type: "string",
1977
2140
  description: 'Whose activity to measure: "campaigns" (default), "outcomes" or "all". Widening is a decision \u2014 see above.'
1978
- }
2141
+ },
2142
+ check: {
2143
+ type: "boolean",
2144
+ description: 'Read the connected Tag Manager container for every window.baker.track call its tags make, and say which events a real visit has brought in the window and which never arrived. Start here when "an event is missing": an event the container sends and nobody has seen is invisible on every other report'
2145
+ },
2146
+ days: { type: "string", description: "With --check: how many days back to look for each event (default 30)" }
1979
2147
  },
1980
2148
  run: async (ctx) => {
2149
+ if (ctx.args.check === true) {
2150
+ await runWebsiteEventCheck(Number(ctx.args.days ?? 30) || 30);
2151
+ return;
2152
+ }
1981
2153
  try {
1982
2154
  const measure = typeof ctx.args.measure === "string" ? ctx.args.measure : void 0;
1983
2155
  const envelope = await apiPost(
@@ -1991,6 +2163,130 @@ Examples:
1991
2163
  }
1992
2164
  });
1993
2165
  })();
2166
+ async function runWebsiteEventCheck(days) {
2167
+ let tags;
2168
+ try {
2169
+ tags = (await apiPost(
2170
+ "/api/tag-manager/read",
2171
+ { entities: ["tag"], full: true },
2172
+ { timeoutMs: TAG_MANAGER_TIMEOUT_MS }
2173
+ )).tags;
2174
+ } catch (err) {
2175
+ writeJsonEnvelope({
2176
+ ok: false,
2177
+ error: {
2178
+ code: "TAG_MANAGER_UNAVAILABLE",
2179
+ message: `The check reads the website's Tag Manager container, and it could not: ${err instanceof Error ? err.message : String(err)}`,
2180
+ fix: {
2181
+ action: "continue_without",
2182
+ explanation: "Without a connected container there is no list of what the site is wired to send. Read what did arrive with `baker analytics feed --origin website`, and ask the person to connect Tag Manager if the site uses it."
2183
+ }
2184
+ }
2185
+ });
2186
+ process.exit(1);
2187
+ }
2188
+ try {
2189
+ let catalog;
2190
+ let unread = "";
2191
+ try {
2192
+ const response = await apiPost("/api/analytics/query", {
2193
+ preset: "conversions",
2194
+ eventOrigin: "website",
2195
+ days
2196
+ });
2197
+ catalog = response.data.eventCatalog ?? [];
2198
+ } catch (err) {
2199
+ catalog = null;
2200
+ unread = err instanceof Error ? err.message : String(err);
2201
+ }
2202
+ const { events } = checkWebsiteEvents(tags, catalog);
2203
+ const hints = websiteEventCheckHints(events, days);
2204
+ if (catalog === null) {
2205
+ hints.push(
2206
+ `What arrived could not be read (${unread}), so this lists what the container sends, unchecked. \`baker analytics feed --origin website\` is the other half once reading works.`
2207
+ );
2208
+ }
2209
+ if (events.length === 0) {
2210
+ hints.push(
2211
+ "No tag in the container calls window.baker.track, so the website sends Baker page views and nothing else. Outcomes come from tags you stage with `baker tag-manager`."
2212
+ );
2213
+ }
2214
+ writeJsonEnvelope({ ok: true, data: { days, events }, hints });
2215
+ } catch (err) {
2216
+ handleError(err);
2217
+ }
2218
+ }
2219
+ var DEBUG_ARGS = {
2220
+ code: {
2221
+ type: "positional",
2222
+ required: false,
2223
+ description: "The code `--start` returned: read what was recorded under it"
2224
+ },
2225
+ start: {
2226
+ type: "boolean",
2227
+ required: false,
2228
+ description: "Mint a debug link for the person to open in their own browser"
2229
+ },
2230
+ url: {
2231
+ type: "string",
2232
+ required: false,
2233
+ description: "With --start: the page the person should open (the link is built on it)"
2234
+ },
2235
+ full: { type: "boolean", required: false, description: "Every record's payload, masked, not just what it was" }
2236
+ };
2237
+ registerSchema({
2238
+ command: "analytics.debug",
2239
+ description: "A link that records what a person's own browser heard on their website, and the read of it",
2240
+ args: DEBUG_ARGS
2241
+ });
2242
+ var debugCommand = defineCommand({
2243
+ meta: {
2244
+ name: "debug",
2245
+ description: `Watch a real visit from the person's own browser: what the page heard \u2014 messages from its iframes, custom events, dataLayer pushes \u2014 and what Baker's website tag did with it.
2246
+
2247
+ Start here when an event from the client's own website never arrives and a test from your browser cannot settle it: a voice, video or chat widget your headless browser cannot run, a login that is theirs, a cookie banner only they answer. Your own browser is flagged as a bot and in no report, so their visit is the test that counts.
2248
+
2249
+ baker analytics debug --start --url https://client.com/ \u2014 a link to send them; it records for two hours
2250
+ baker analytics debug <code> \u2014 what their visit recorded, in order, with what to read first
2251
+ baker analytics debug <code> --full \u2014 every record's payload (emails and phones masked)
2252
+
2253
+ Nothing recorded is counted or shown in Baker; it is purged a day later.`
2254
+ },
2255
+ args: DEBUG_ARGS,
2256
+ run: async ({ args }) => {
2257
+ try {
2258
+ if (args.start === true) {
2259
+ const response2 = await apiPost("/api/analytics/debug", {
2260
+ start: true,
2261
+ ...typeof args.url === "string" && args.url !== "" ? { url: args.url } : {}
2262
+ });
2263
+ writeJsonEnvelope({ ok: true, data: response2.data, hints: debugStartHints(response2.data) });
2264
+ return;
2265
+ }
2266
+ if (typeof args.code !== "string" || args.code === "") {
2267
+ writeJsonEnvelope({
2268
+ ok: false,
2269
+ error: {
2270
+ code: "VALIDATION_ERROR",
2271
+ message: "Pass --start to mint a debug link, or the code it returned to read it."
2272
+ }
2273
+ });
2274
+ process.exit(1);
2275
+ }
2276
+ const response = await apiPost("/api/analytics/debug", {
2277
+ code: args.code,
2278
+ full: true
2279
+ });
2280
+ writeJsonEnvelope({
2281
+ ok: true,
2282
+ data: compactDebugRead(response.data, args.full === true),
2283
+ hints: debugReadHints(response.data)
2284
+ });
2285
+ } catch (err) {
2286
+ handleError(err);
2287
+ }
2288
+ }
2289
+ });
1994
2290
  var sitesCommand = (() => {
1995
2291
  registerSchema({
1996
2292
  command: "analytics.sites",
@@ -2108,21 +2404,22 @@ Full guide: __tooling__/docs/tools/baker/analytics.md`
2108
2404
  tags: tagsCommand,
2109
2405
  events: eventsCommand,
2110
2406
  feed: feedCommand,
2111
- lookup: () => import("./lookup-LWJMDEEL.js").then((m) => m.lookupCommand),
2407
+ lookup: () => import("./lookup-ZJIP2M4X.js").then((m) => m.lookupCommand),
2112
2408
  devices: devicesCommand,
2113
2409
  ads: adsCommand,
2114
2410
  conversions: conversionsCommand,
2115
- sends: () => import("./sends-OLVQGOAE.js").then((m) => m.sendsCommand),
2411
+ sends: () => import("./sends-6FI7WELX.js").then((m) => m.sendsCommand),
2116
2412
  map: mapCommand,
2117
- unstage: () => import("./unstage-QFVL7AZ4.js").then((m) => m.unstageCommand),
2413
+ unstage: () => import("./unstage-MDSSPUKV.js").then((m) => m.unstageCommand),
2118
2414
  tracking: trackingCommand,
2119
2415
  arrivals: arrivalsCommand,
2120
2416
  "sending-events": sendingEventsCommand,
2121
- sources: () => import("./sources-PSM2A5QD.js").then((m) => m.sourcesCommand),
2417
+ sources: () => import("./sources-L3KNVLIB.js").then((m) => m.sourcesCommand),
2122
2418
  "website-tag": websiteTagCommand,
2419
+ debug: debugCommand,
2123
2420
  sites: sitesCommand,
2124
- plan: () => import("./plan-O2TTEUIW.js").then((m) => m.planCommand),
2125
- questionnaire: () => import("./questionnaire-VE42SW77.js").then((m) => m.questionnaireCommand),
2421
+ plan: () => import("./plan-TVQSEKYL.js").then((m) => m.planCommand),
2422
+ questionnaire: () => import("./questionnaire-LEZJLMAV.js").then((m) => m.questionnaireCommand),
2126
2423
  presets: presetsCommand
2127
2424
  }
2128
2425
  });
@@ -2135,4 +2432,4 @@ export {
2135
2432
  requestBody,
2136
2433
  sendingEventsAddress
2137
2434
  };
2138
- //# sourceMappingURL=analytics-4CCQYY7Z.js.map
2435
+ //# sourceMappingURL=analytics-P5UFA6I4.js.map