@koda-sl/baker-cli 0.187.0 → 0.188.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 CHANGED
@@ -594,7 +594,9 @@ baker tag-manager draft show --chat <chat-id> gtm_temp_ab12
594
594
  baker actions draft --chat <chat-id>
595
595
  ```
596
596
 
597
- Command groups: `budgets`, `campaigns`, `ad-groups`, `keywords` (add/update/remove), `negative-keywords`, `keyword-lists`, `ads`, `assets` (create/update/attach/detach), `asset-groups` (create/update/attach/detach — Performance Max), `audiences`, `conversions` (create/update/goal), `bidding-strategies`, `labels`, `campaign-criteria`, and `draft`. Amounts are in major currency units (converted to micros). Money/bids: `--amount`, `--cpc-bid`, `--target-cpa`, `--max-cpc` take major units; `--target-roas` a ratio. `--max-cpc` sets the max CPC bid ceiling for `TARGET_IMPRESSION_SHARE` / `TARGET_SPEND` / `PERCENT_CPC` and must be paired with `--bidding-strategy`. Less-common ops accept a `--file <payload.json>` (flags override file keys). Updates target a resource name or bare id as the positional argument; a target that names an op staged earlier **amends it in place**.
597
+ Command groups: `budgets`, `campaigns`, `ad-groups`, `keywords` (add/update/remove), `negative-keywords`, `keyword-lists`, `ads`, `assets` (create/update/attach/detach), `asset-groups` (create/update/attach/detach — Performance Max), `audiences`, `conversions` (create/update/goal), `bidding-strategies`, `labels`, `campaign-criteria` (add/update/remove), and `draft`. Amounts are in major currency units (converted to micros). Money/bids: `--amount`, `--cpc-bid`, `--target-cpa`, `--max-cpc` take major units; `--target-roas` a ratio. `--max-cpc` sets the max CPC bid ceiling for `TARGET_IMPRESSION_SHARE` / `TARGET_SPEND` / `PERCENT_CPC` and must be paired with `--bidding-strategy`. Less-common ops accept a `--file <payload.json>` (flags override file keys). Updates target a resource name or bare id as the positional argument; a target that names an op staged earlier **amends it in place**.
598
+
599
+ **A device criterion can be added, but never removed** — `campaign-criteria add` with a device criterion works, but Google then rejects `campaign-criteria remove` on it forever, including on a criterion you added yourself (and Baker refuses the removal before publish). Adjust it instead with `campaign-criteria update customers/<cid>/campaignCriteria/<campaignId>~<criterionId> --bid-modifier <n>`: `1` for no adjustment, `1.25` to bid 25% more, `0.9` to bid 10% less, `0` to stop serving on that device. Locations, languages and ad schedules remove normally.
598
600
 
599
601
  **Primary vs secondary conversion actions** — `conversions update <id> --primary` makes an action a primary action (automated bidding optimizes toward it); `--no-primary` (or `--primary=false`) demotes it to secondary (reported only) — the spaced form `--primary false` is rejected, since a boolean flag written with a space is set to true and the word dropped. `conversions create` stages a new action as **secondary** unless its `--file` payload sets `"primaryForGoal": true`, so a new action never silently joins the bidding target of a Maximize Conversions or Target CPA campaign. The staged card shows an "Action optimization" row with the before/after role.
600
602
 
package/dist/cli.js CHANGED
@@ -6700,14 +6700,13 @@ var adScheduleCriterionSchema = z17.object({
6700
6700
  endHour: z17.number().int().min(0).max(24),
6701
6701
  endMinute: z17.enum(["ZERO", "FIFTEEN", "THIRTY", "FORTY_FIVE"]).default("ZERO")
6702
6702
  });
6703
+ var bidModifierSchema = z17.number().min(0).max(10).refine((v) => v === 0 || v >= 0.1, {
6704
+ message: "bid modifier must be 0 (exclude the device) or between 0.1 and 10.0"
6705
+ });
6703
6706
  var deviceCriterionSchema = z17.object({
6704
6707
  criterionType: z17.literal("device"),
6705
6708
  device: z17.enum(DEVICE_TYPES),
6706
- // Google's `CampaignCriterion.bid_modifier`: "The modifier must be in the range 0.1 - 10.0. Use 0
6707
- // to opt out of a Device type." So 0 (exclude the device) and 0.1–10.0 are valid; the (0, 0.1) gap is not.
6708
- bidModifier: z17.number().min(0).max(10).optional().refine((v) => v === void 0 || v === 0 || v >= 0.1, {
6709
- message: "bid modifier must be 0 (exclude the device) or between 0.1 and 10.0"
6710
- })
6709
+ bidModifier: bidModifierSchema.optional()
6711
6710
  });
6712
6711
  var campaignCriterionAddSchema = z17.object({
6713
6712
  campaign: refSchema,
@@ -6728,6 +6727,9 @@ var campaignCriterionAddSchema = z17.object({
6728
6727
  });
6729
6728
  }
6730
6729
  });
6730
+ var campaignCriterionUpdateSchema = z17.object({
6731
+ bidModifier: bidModifierSchema
6732
+ });
6731
6733
  var GOOGLE_DRAFT_OP_KINDS = [
6732
6734
  "google.budget.create",
6733
6735
  "google.budget.update",
@@ -6775,6 +6777,7 @@ var GOOGLE_DRAFT_OP_KINDS = [
6775
6777
  "google.label.create",
6776
6778
  "google.label.attach",
6777
6779
  "google.campaignCriterion.add",
6780
+ "google.campaignCriterion.update",
6778
6781
  "google.campaignCriterion.remove"
6779
6782
  ];
6780
6783
  var googleDraftOpKindSchema = z17.enum(GOOGLE_DRAFT_OP_KINDS);
@@ -6834,6 +6837,7 @@ var googleDraftOpInputSchema = z17.discriminatedUnion("kind", [
6834
6837
  createOp2("google.label.create", labelCreateSchema),
6835
6838
  createOp2("google.label.attach", labelAttachSchema),
6836
6839
  createOp2("google.campaignCriterion.add", campaignCriterionAddSchema),
6840
+ updateOp2("google.campaignCriterion.update", campaignCriterionUpdateSchema),
6837
6841
  targetOp("google.campaignCriterion.remove")
6838
6842
  ]);
6839
6843
 
@@ -7021,6 +7025,9 @@ var googleDraftStatusCollectionSchema = z19.object({
7021
7025
  label: z19.string(),
7022
7026
  added: z19.number(),
7023
7027
  removed: z19.number(),
7028
+ /** Members that stay in the set with a changed value — a device's bid adjustment. Optional: a
7029
+ * status tree built by an older backend carries no such count. */
7030
+ updated: z19.number().optional(),
7024
7031
  existing: z19.number()
7025
7032
  });
7026
7033
  var googleDraftChangeOperationSchema = z19.enum(["create", "update", "pause", "resume", "remove"]);
@@ -8348,6 +8355,9 @@ function collectionLine(collection) {
8348
8355
  if (collection.removed > 0) {
8349
8356
  parts.push(`-${collection.removed}`);
8350
8357
  }
8358
+ if ((collection.updated ?? 0) > 0) {
8359
+ parts.push(`~${collection.updated}`);
8360
+ }
8351
8361
  return parts.length > 0 ? `${collection.label}: ${parts.join(", ")}` : void 0;
8352
8362
  }
8353
8363
  function renderNode(node, depth, lines) {
@@ -11142,14 +11152,64 @@ var labelsCommand = defineCommand30({
11142
11152
  attach: fileCreateCommand("attach", "google.label.attach", "Attach a label to a campaign/adGroup/ad")
11143
11153
  }
11144
11154
  });
11155
+ function bidModifierFlag(value) {
11156
+ if (value === void 0 || value === null || value === "") {
11157
+ failWriteValidation(
11158
+ "--bid-modifier is required: 1 for no adjustment, 1.25 to bid 25% more, 0.9 to bid 10% less, 0 to stop serving on it"
11159
+ );
11160
+ }
11161
+ const num3 = Number(value);
11162
+ if (Number.isNaN(num3) || num3 < 0 || num3 > 10 || num3 > 0 && num3 < 0.1) {
11163
+ failWriteValidation("--bid-modifier must be 0 (stop serving on it) or between 0.1 and 10.0");
11164
+ }
11165
+ return num3;
11166
+ }
11145
11167
  var campaignCriteriaCommand = defineCommand30({
11146
11168
  meta: {
11147
11169
  name: "campaign-criteria",
11148
- description: "Stage campaign criteria (location/language/adSchedule/device) add/remove (via --file)"
11170
+ description: "Stage campaign criteria (location/language/adSchedule/device): add/remove a targeting criterion, or update a device bid adjustment"
11149
11171
  },
11150
11172
  subCommands: {
11151
11173
  add: fileCreateCommand("add", "google.campaignCriterion.add", "Add a campaign criterion"),
11152
- remove: statusCommand2("google.campaignCriterion.remove", "campaign criterion")
11174
+ update: defineCommand30({
11175
+ meta: {
11176
+ name: "update",
11177
+ description: "Change a criterion's bid adjustment \u2014 the only way to change a device setting the campaign already has, since Google never lets one be removed. Start here: `campaign-criteria update customers/<cid>/campaignCriteria/<campaignId>~<criterionId> --bid-modifier 1` resets a boost to neutral; --bid-modifier 0 stops ads serving on that device. Use `campaign-criteria add` instead when the campaign has no criterion for that device yet. Read the current ones with: baker ads google query \"SELECT campaign_criterion.resource_name, campaign_criterion.device.type, campaign_criterion.bid_modifier FROM campaign_criterion WHERE campaign_criterion.type = 'DEVICE'\""
11178
+ },
11179
+ args: {
11180
+ ...customerIdArg,
11181
+ id: {
11182
+ type: "positional",
11183
+ description: "Criterion resource name (customers/\u2026/campaignCriteria/{campaignId}~{criterionId})",
11184
+ required: false
11185
+ },
11186
+ "bid-modifier": {
11187
+ type: "string",
11188
+ description: "1 = no adjustment, 1.25 = bid 25% more, 0.9 = bid 10% less, 0 = don't serve on it"
11189
+ }
11190
+ },
11191
+ run: async ({ args }) => {
11192
+ const customerId = requireCustomerId(args);
11193
+ const target = requireTarget(args, "campaign criterion");
11194
+ await stageUpdate("google.campaignCriterion.update", customerId, target, {
11195
+ bidModifier: bidModifierFlag(args["bid-modifier"])
11196
+ });
11197
+ }
11198
+ }),
11199
+ remove: defineCommand30({
11200
+ meta: {
11201
+ name: "remove",
11202
+ description: "Stage a campaign criterion remove. Works for what you added \u2014 locations, languages, ad schedules. A device setting CANNOT be removed once the campaign has one: use `campaign-criteria update --bid-modifier` to change or neutralise it instead."
11203
+ },
11204
+ args: {
11205
+ ...customerIdArg,
11206
+ id: { type: "positional", description: "Criterion resource name or id", required: false }
11207
+ },
11208
+ run: async ({ args }) => {
11209
+ const customerId = requireCustomerId(args);
11210
+ await stageTarget("google.campaignCriterion.remove", customerId, requireTarget(args, "campaign criterion"));
11211
+ }
11212
+ })
11153
11213
  }
11154
11214
  });
11155
11215
  var googleWriteCommands = {