@koda-sl/baker-cli 0.294.0-dev.ae1dcf96d → 0.294.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/dist/cli.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  ulid,
59
59
  validateCanvasDeep,
60
60
  ytDlpBlockSignal
61
- } from "./chunk-2IHIUOJX.js";
61
+ } from "./chunk-NNQDWCFG.js";
62
62
  import {
63
63
  csvOrJson,
64
64
  daysAgoIso,
@@ -13327,53 +13327,12 @@ function mappingCommandFor(platform, proposed) {
13327
13327
 
13328
13328
  // ../api/src/analytics/websiteTag.ts
13329
13329
  import { z as z27 } from "zod";
13330
- var websiteTagRequestSchema = z27.object({
13331
- measure: z27.enum(["campaigns", "outcomes", "all"]).optional()
13332
- });
13333
- var analyticsSitesRequestSchema = z27.object({
13334
- add: z27.array(z27.string()).optional(),
13335
- remove: z27.array(z27.string()).optional()
13336
- });
13337
- var analyticsSitesResponseSchema = z27.object({
13338
- /** Every declared website after the change, which is the answer to a bare read. */
13339
- origins: z27.array(z27.string()),
13340
- /** Normalized and actually new — an entry already present is reported in neither list. */
13341
- added: z27.array(z27.string()),
13342
- removed: z27.array(z27.string()),
13343
- /** Still-undeclared domains this company owns. See {@link suggestedPixelOrigins}. */
13344
- suggestedOrigins: z27.array(z27.string())
13345
- });
13346
13330
  var websiteTagResponseSchema = z27.object({
13347
13331
  host: z27.string(),
13348
13332
  siteKey: z27.string(),
13349
13333
  origins: z27.array(z27.string()),
13350
- /** Echoed back, so a caller that asked for nothing can see what it got. */
13351
- measure: z27.enum(["campaigns", "outcomes", "all"]),
13352
- /**
13353
- * Whether `campaigns` scope can recognise anybody here — see
13354
- * {@link campaignsScopeCanMatch}. `false` means the default measures nobody
13355
- * on this company's install, however correctly the tag is pasted.
13356
- */
13357
- campaignsCanMatch: z27.boolean(),
13358
- /**
13359
- * Whether `host` is one of the company's own domains rather than Baker's.
13360
- *
13361
- * Worth answering because it is the difference between an install a content
13362
- * blocker removes and one it has no list entry for — the pixel takes its
13363
- * collect endpoint from its own `src`, so this decides the fate of the event
13364
- * stream and not just the script load. See {@link pixelHost}.
13365
- */
13366
- firstParty: z27.boolean(),
13367
- /**
13368
- * Websites this company plainly owns and has not declared — the registrable
13369
- * domains of its own landing domains. See {@link suggestedPixelOrigins}.
13370
- *
13371
- * A suggestion for somebody to accept, never a scope already granted: nothing
13372
- * in Baker reads this list, and `baker analytics sites --add` is what acts on
13373
- * it.
13374
- */
13375
- suggestedOrigins: z27.array(z27.string()),
13376
13334
  tag: z27.string(),
13335
+ tagManagerTag: z27.string(),
13377
13336
  brief: z27.string()
13378
13337
  });
13379
13338
 
@@ -27997,7 +27956,7 @@ one marked "Already counted", so a retry is visible without being counted.
27997
27956
 
27998
27957
  The same holds **across connections**, which is the reason to use it. If the page also
27999
27958
  reports this outcome with Baker's website tag, pass one string as \`event_id\` here and as
28000
- \`eventId\` in \`window.baker.track(name, { eventId })\`: the browser event and the
27959
+ \`eventId\` in \`window.baker.conversion(name, { eventId })\`: the browser event and the
28001
27960
  server event are then one event and count once, whichever arrives first and whether or not
28002
27961
  the other ever does. Report an important outcome from both \u2014 a browser can be blocked, a
28003
27962
  server cannot \u2014 and always pair them with an id. Send no id and the two are two conversions,
@@ -29086,73 +29045,6 @@ function formatHint(data, format) {
29086
29045
  ];
29087
29046
  }
29088
29047
 
29089
- // src/commands/analytics/websiteTagHints.ts
29090
- function asTyped(origin) {
29091
- return origin.replace(/^https?:\/\//, "");
29092
- }
29093
- function suggestionHint(suggested) {
29094
- if (suggested.length === 0) return [];
29095
- const commands = suggested.map((origin) => `baker analytics sites --add ${asTyped(origin)}`).join(" \xB7 ");
29096
- return [
29097
- `Baker publishes landing pages on ${suggested.map(asTyped).join(", ")} for this company, and no declared website covers ${suggested.length === 1 ? "it" : "them"}. Declaring the domain covers every subdomain of it \u2014 the marketing site, the shop, the booking page, and the ones that do not exist yet: ${commands}`
29098
- ];
29099
- }
29100
- function websiteTagHints(response) {
29101
- const hints2 = [];
29102
- if (response.origins.length === 0) {
29103
- hints2.push(
29104
- "NO WEBSITE DECLARED \u2014 this tag will be ignored everywhere it is installed, silently, with no failing request to find. Declare the site before installing anything: baker analytics sites --add <the client's domain>. It takes effect at once and needs no republish."
29105
- );
29106
- }
29107
- hints2.push(...suggestionHint(response.suggestedOrigins));
29108
- if (response.firstParty) {
29109
- hints2.push(
29110
- `This tag loads from ${response.host} \u2014 the client's own domain, not Baker's \u2014 so the script and every event it sends travel first-party, which a content blocker has no list entry for. The trade is a dependency: if that domain is ever removed from Baker, this tag 404s and measurement stops. Re-run this command after any domain change.`
29111
- );
29112
- }
29113
- if (response.measure === "all") {
29114
- hints2.push(
29115
- "This tag measures the client's WHOLE WEBSITE \u2014 every visitor and every page view, not only the people your campaigns brought. Their reports will describe their business rather than their campaigns, and outcomes their site produces from organic, email and direct traffic will land in their conversion numbers. Only correct if somebody asked for that; otherwise re-run without --measure."
29116
- );
29117
- }
29118
- if (response.measure === "campaigns" && !response.campaignsCanMatch) {
29119
- hints2.push(
29120
- "THIS TAG WILL MEASURE NOBODY \u2014 and will look installed. `campaigns` scope recognises a visitor by a first-party cookie, and a browser does not carry one between two different registrable domains. This company's landings are not on a subdomain of the site this tag goes on, so no visitor can ever match. Two fixes: put the landings on a subdomain of the client's own domain (a custom domain in Baker), or install with --measure outcomes, which measures no browsing and reports the outcomes the site tells Baker about."
29121
- );
29122
- } else if (response.measure === "campaigns") {
29123
- hints2.push(
29124
- "This tag measures only visitors who have been on one of this company's Baker landing pages \u2014 their whole journey through the site, to the outcome. Anybody else is not measured at all. Use --measure all only if the client asked for their whole website measured."
29125
- );
29126
- }
29127
- hints2.push(
29128
- 'Reporting an outcome is not the same as counting it. After a `window.baker.track("name")` call is live, name it with: baker analytics conversions --event page:<name> --name "<what to call it>". That applies immediately and counts everything already collected.'
29129
- );
29130
- return hints2;
29131
- }
29132
- function analyticsSitesHints(response) {
29133
- const hints2 = [];
29134
- if (response.origins.length === 0) {
29135
- hints2.push(
29136
- "No website is declared, so this company's measurement tag is ignored wherever it is installed \u2014 silently, with no failing request to find. Add one with: baker analytics sites --add <the client's domain>"
29137
- );
29138
- }
29139
- hints2.push(...suggestionHint(response.suggestedOrigins));
29140
- if (response.added.length > 0) {
29141
- hints2.push(
29142
- `Live now. A tag already installed on ${response.added.map(asTyped).join(", ")} starts being accepted immediately \u2014 there is no new tag to paste and nothing to publish. Only events sent from here on are kept; the ones refused before this were never stored and cannot be recovered.`
29143
- );
29144
- }
29145
- if (response.removed.length > 0) {
29146
- hints2.push(
29147
- `Measurement from ${response.removed.map(asTyped).join(", ")} will stop at once, with no error on that site \u2014 a tag still installed there goes quiet. Everything already collected from it is kept.`
29148
- );
29149
- }
29150
- hints2.push(
29151
- "One entry covers everything under it: example.com answers for www., go. and shop.eu. It never widens upward, so declaring go.example.com leaves example.com uncovered \u2014 declare the domain, not the subdomain you are installing on today."
29152
- );
29153
- return hints2;
29154
- }
29155
-
29156
29048
  // src/commands/analytics/index.ts
29157
29049
  var SHARED_ARGS = {
29158
29050
  days: { type: "string", description: "Lookback window in days (default: 30)", required: false },
@@ -29881,13 +29773,7 @@ var websiteTagCommand = (() => {
29881
29773
  registerSchema({
29882
29774
  command: "analytics.website-tag",
29883
29775
  description: "The measurement tag for a website Baker does not publish, with this company's key in it",
29884
- args: {
29885
- measure: {
29886
- type: "string",
29887
- required: false,
29888
- description: 'Whose activity to measure: "campaigns" (default), "outcomes" or "all"'
29889
- }
29890
- }
29776
+ args: {}
29891
29777
  });
29892
29778
  return defineCommand95({
29893
29779
  meta: {
@@ -29899,80 +29785,16 @@ Reach for it whenever measurement has to reach a page Baker did not build. What
29899
29785
  Three things worth knowing before you install it:
29900
29786
  the origins list \u2014 the key is IGNORED from any origin not on it, silently. An empty list means the tag will measure nothing.
29901
29787
  Tag Manager is usually the way in \u2014 a Custom HTML tag on All Pages. If the client has a container connected, you can stage that yourself (baker tag-manager).
29902
- --measure decides the BILL \u2014 the tag goes on every page whatever you do; this decides whose activity is measured. Leave it alone unless the client asked for their whole website.
29903
-
29904
- --measure campaigns (default) people your Baker campaigns brought to the site. Their whole journey, through to the outcome. Nobody else is measured at all.
29905
- --measure outcomes nobody's browsing. Only what the site reports with window.baker.track(...), and forms it wired to Baker.
29906
- --measure all every visitor and every page view of the whole website. Their reports then describe their business, not their campaigns, and outcomes from organic, email and direct land in their conversion numbers. A decision, never a default.
29788
+ in a container, use tagManagerTag \u2014 the response carries two tags. \`tag\` is for a page somebody can edit; \`tagManagerTag\` is the one to stage, because a container rebuilds a Custom HTML tag's script element from its src alone and drops the key, so \`tag\` measures nothing there, published and silent. Check it on the page afterwards: window.baker in the browser console.
29907
29789
 
29908
29790
  Examples:
29909
29791
  baker analytics website-tag \u2014 the tag, the origins and the install brief
29910
- baker analytics website-tag --measure all \u2014 measure their whole website, because they asked for that
29911
29792
  baker analytics events --origin site \u2014 after it is live, what that website is reporting`
29912
29793
  },
29913
- args: {
29914
- measure: {
29915
- type: "string",
29916
- description: 'Whose activity to measure: "campaigns" (default), "outcomes" or "all". Widening is a decision \u2014 see above.'
29917
- }
29918
- },
29919
- run: async (ctx) => {
29920
- try {
29921
- const measure = typeof ctx.args.measure === "string" ? ctx.args.measure : void 0;
29922
- const envelope = await apiPost(
29923
- "/api/analytics/website-tag",
29924
- measure ? { measure } : {}
29925
- );
29926
- writeJsonEnvelope({ ...envelope, hints: websiteTagHints(envelope.data) });
29927
- } catch (err) {
29928
- handleError(err);
29929
- }
29930
- }
29931
- });
29932
- })();
29933
- var sitesCommand = (() => {
29934
- registerSchema({
29935
- command: "analytics.sites",
29936
- description: "The websites this company's measurement tag is accepted from, and adding or removing one",
29937
- args: {
29938
- add: { type: "string", required: false, description: "Website address to accept measurement from" },
29939
- remove: { type: "string", required: false, description: "Website address to stop accepting measurement from" }
29940
- }
29941
- });
29942
- return defineCommand95({
29943
- meta: {
29944
- name: "sites",
29945
- description: `Which websites this company's measurement tag is accepted from \u2014 and the command that changes it.
29946
-
29947
- The site key ships in the source of every page it is pasted on, so this list is the whole of what stops a stranger who read it appending forged conversions to these numbers. A tag on a website that is NOT on this list is ignored, silently, with no failing request anywhere. That is the single most common reason an install measures nothing.
29948
-
29949
- One entry covers the estate under it: example.com answers for www.example.com, go.example.com and shop.eu.example.com. It never widens upward \u2014 declaring go.example.com does NOT cover example.com \u2014 so declare the DOMAIN, not the subdomain you happen to be installing on today.
29950
-
29951
- Start here:
29952
- baker analytics sites \u2014 what is declared now, and what is worth adding
29953
- baker analytics sites --add example.com \u2014 accept measurement from that site and everything under it
29954
- baker analytics sites --remove old-site.com
29955
-
29956
- Examples:
29957
- baker analytics website-tag \u2014 get the tag; if its origins are empty, come here first
29958
- baker analytics sites --add foodforjoe.es \u2014 one entry covering www., go. and shop.`
29959
- },
29960
- args: {
29961
- add: {
29962
- type: "string",
29963
- description: "Website address to accept measurement from, e.g. example.com \u2014 covers every subdomain of it. Repeat for several"
29964
- },
29965
- remove: { type: "string", description: "Website address to stop accepting measurement from" }
29966
- },
29967
- run: async (ctx) => {
29794
+ args: {},
29795
+ run: async () => {
29968
29796
  try {
29969
- const raw = ctx.rawArgs;
29970
- const body = {
29971
- add: repeatedValues(raw, "add", ctx.args.add),
29972
- remove: repeatedValues(raw, "remove", ctx.args.remove)
29973
- };
29974
- const envelope = await apiPost("/api/analytics/sites", body);
29975
- writeJsonEnvelope({ ...envelope, hints: analyticsSitesHints(envelope.data) });
29797
+ writeJsonEnvelope(await apiPost("/api/analytics/website-tag", {}));
29976
29798
  } catch (err) {
29977
29799
  handleError(err);
29978
29800
  }
@@ -30049,7 +29871,6 @@ Full guide: __tooling__/docs/tools/baker/analytics.md`
30049
29871
  arrivals: arrivalsCommand,
30050
29872
  "sending-events": sendingEventsCommand,
30051
29873
  "website-tag": websiteTagCommand,
30052
- sites: sitesCommand,
30053
29874
  presets: presetsCommand
30054
29875
  }
30055
29876
  });
@@ -44345,7 +44166,7 @@ function siteHints(sites) {
44345
44166
  resources: sites.map((site) => ({ id: site.siteUrl, label: site.permissionLevel }))
44346
44167
  });
44347
44168
  }
44348
- var sitesCommand2 = defineCommand134({
44169
+ var sitesCommand = defineCommand134({
44349
44170
  meta: {
44350
44171
  name: "sites",
44351
44172
  description: `List verified Search Console sites.
@@ -44410,7 +44231,7 @@ Examples:
44410
44231
  Full guide: __tooling__/docs/tools/baker/gsc.md`
44411
44232
  },
44412
44233
  subCommands: {
44413
- sites: sitesCommand2,
44234
+ sites: sitesCommand,
44414
44235
  query: queryCommand3,
44415
44236
  sitemaps: sitemapsCommand
44416
44237
  }