@koda-sl/baker-cli 0.259.0 → 0.260.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
@@ -19735,33 +19735,224 @@ var ATTRIBUTION_EVENT_TYPES = ["CLICK_THROUGH", "VIEW_THROUGH", "ENGAGED_VIDEO_V
19735
19735
  var ADVANTAGE_AUDIENCE_OPEN_AGE_MAX = 65;
19736
19736
  var ADVANTAGE_AUDIENCE_MAX_HARD_AGE_MIN = 25;
19737
19737
  var CTA_TYPES2 = [
19738
+ "BOOK_TRAVEL",
19739
+ "CONTACT_US",
19740
+ "DONATE",
19741
+ "DONATE_NOW",
19742
+ "DOWNLOAD",
19743
+ "GET_DIRECTIONS",
19744
+ "GO_LIVE",
19745
+ "INTERESTED",
19738
19746
  "LEARN_MORE",
19747
+ "SEE_DETAILS",
19748
+ "LIKE_PAGE",
19749
+ "MESSAGE_PAGE",
19750
+ "RAISE_MONEY",
19751
+ "SAVE",
19752
+ "SEND_TIP",
19739
19753
  "SHOP_NOW",
19740
19754
  "SIGN_UP",
19741
- "SUBSCRIBE",
19742
- "DOWNLOAD",
19743
- "GET_QUOTE",
19744
- "CONTACT_US",
19745
- "BOOK_TRAVEL",
19746
- "APPLY_NOW",
19747
- "GET_OFFER",
19755
+ "VIEW_INSTAGRAM_PROFILE",
19756
+ "INSTAGRAM_MESSAGE",
19757
+ "LOYALTY_LEARN_MORE",
19758
+ "PURCHASE_GIFT_CARDS",
19759
+ "PAY_TO_ACCESS",
19760
+ "SEE_MORE",
19761
+ "TRY_IN_CAMERA",
19762
+ "WHATSAPP_LINK",
19763
+ "GET_IN_TOUCH",
19764
+ "TRY_NOW",
19765
+ "ASK_A_QUESTION",
19766
+ "START_A_CHAT",
19767
+ "CHAT_NOW",
19768
+ "ASK_US",
19769
+ "CHAT_WITH_US",
19770
+ "BOOK_NOW",
19771
+ "CHECK_AVAILABILITY",
19748
19772
  "ORDER_NOW",
19749
- "DONATE_NOW",
19750
- "REQUEST_TIME",
19751
- "SEE_MENU",
19752
- "MESSAGE_PAGE",
19753
19773
  "WHATSAPP_MESSAGE",
19754
- "CALL_NOW",
19755
- "GET_DIRECTIONS",
19774
+ "GET_MOBILE_APP",
19775
+ "INSTALL_MOBILE_APP",
19776
+ "USE_MOBILE_APP",
19777
+ "INSTALL_APP",
19778
+ "USE_APP",
19756
19779
  "PLAY_GAME",
19757
- "LISTEN_NOW",
19780
+ "TRY_DEMO",
19781
+ "WATCH_VIDEO",
19758
19782
  "WATCH_MORE",
19759
19783
  "OPEN_LINK",
19784
+ "NO_BUTTON",
19785
+ "LISTEN_MUSIC",
19786
+ "MOBILE_DOWNLOAD",
19787
+ "GET_OFFER",
19788
+ "GET_OFFER_VIEW",
19789
+ "BUY_NOW",
19790
+ "BUY_TICKETS",
19791
+ "UPDATE_APP",
19792
+ "BET_NOW",
19793
+ "ADD_TO_CART",
19794
+ "SELL_NOW",
19795
+ "GET_SHOWTIMES",
19796
+ "LISTEN_NOW",
19797
+ "GET_EVENT_TICKETS",
19798
+ "REMIND_ME",
19799
+ "SEARCH_MORE",
19800
+ "PRE_REGISTER",
19801
+ "SWIPE_UP_PRODUCT",
19802
+ "SWIPE_UP_SHOP",
19803
+ "PLAY_GAME_ON_FACEBOOK",
19804
+ "VISIT_WORLD",
19805
+ "OPEN_INSTANT_APP",
19806
+ "JOIN_GROUP",
19807
+ "GET_PROMOTIONS",
19808
+ "SEND_UPDATES",
19809
+ "INQUIRE_NOW",
19810
+ "VISIT_PROFILE",
19811
+ "CHAT_ON_WHATSAPP",
19812
+ "EXPLORE_MORE",
19813
+ "CONFIRM",
19814
+ "JOIN_CHANNEL",
19815
+ "MAKE_AN_APPOINTMENT",
19816
+ "ASK_ABOUT_SERVICES",
19817
+ "BOOK_A_CONSULTATION",
19818
+ "GET_A_QUOTE",
19819
+ "BUY_VIA_MESSAGE",
19820
+ "ASK_FOR_MORE_INFO",
19821
+ "VIEW_PRODUCT",
19822
+ "VIEW_CHANNEL",
19823
+ "WATCH_LIVE_VIDEO",
19824
+ "JOIN_LIVE_VIDEO",
19825
+ "IMAGINE",
19826
+ "CALL",
19827
+ "MISSED_CALL",
19828
+ "CALL_NOW",
19829
+ "CALL_ME",
19830
+ "APPLY_NOW",
19831
+ "BUY",
19832
+ "GET_QUOTE",
19833
+ "SUBSCRIBE",
19834
+ "RECORD_NOW",
19835
+ "VOTE_NOW",
19836
+ "GIVE_FREE_RIDES",
19837
+ "REGISTER_NOW",
19838
+ "OPEN_MESSENGER_EXT",
19839
+ "EVENT_RSVP",
19840
+ "CIVIC_ACTION",
19841
+ "SEND_INVITES",
19842
+ "REFER_FRIENDS",
19843
+ "REQUEST_TIME",
19844
+ "SEE_MENU",
19845
+ "SEARCH",
19846
+ "TRY_IT",
19847
+ "TRY_ON",
19848
+ "LINK_CARD",
19849
+ "DIAL_CODE",
19850
+ "FIND_YOUR_GROUPS",
19851
+ "START_ORDER"
19852
+ ];
19853
+ var ASSET_FEED_CTA_TYPES = [
19854
+ "OPEN_LINK",
19855
+ "LIKE_PAGE",
19856
+ "SHOP_NOW",
19857
+ "PLAY_GAME",
19858
+ "INSTALL_APP",
19859
+ "USE_APP",
19860
+ "CALL",
19861
+ "CALL_ME",
19862
+ "VIDEO_CALL",
19760
19863
  "INSTALL_MOBILE_APP",
19761
19864
  "USE_MOBILE_APP",
19762
- "GET_SHOWTIMES",
19865
+ "MOBILE_DOWNLOAD",
19866
+ "BOOK_TRAVEL",
19867
+ "LISTEN_MUSIC",
19868
+ "WATCH_VIDEO",
19869
+ "LEARN_MORE",
19870
+ "SIGN_UP",
19871
+ "DOWNLOAD",
19872
+ "WATCH_MORE",
19873
+ "NO_BUTTON",
19874
+ "VISIT_PAGES_FEED",
19875
+ "CALL_NOW",
19876
+ "APPLY_NOW",
19877
+ "CONTACT",
19878
+ "BUY_NOW",
19879
+ "GET_OFFER",
19880
+ "GET_OFFER_VIEW",
19763
19881
  "BUY_TICKETS",
19764
- "NO_BUTTON"
19882
+ "UPDATE_APP",
19883
+ "GET_DIRECTIONS",
19884
+ "BUY",
19885
+ "SEND_UPDATES",
19886
+ "MESSAGE_PAGE",
19887
+ "DONATE",
19888
+ "SUBSCRIBE",
19889
+ "SAY_THANKS",
19890
+ "SELL_NOW",
19891
+ "SHARE",
19892
+ "DONATE_NOW",
19893
+ "GET_QUOTE",
19894
+ "CONTACT_US",
19895
+ "ORDER_NOW",
19896
+ "START_ORDER",
19897
+ "ADD_TO_CART",
19898
+ "VIEW_CART",
19899
+ "VIEW_IN_CART",
19900
+ "VIDEO_ANNOTATION",
19901
+ "RECORD_NOW",
19902
+ "INQUIRE_NOW",
19903
+ "CONFIRM",
19904
+ "REFER_FRIENDS",
19905
+ "REQUEST_TIME",
19906
+ "GET_SHOWTIMES",
19907
+ "LISTEN_NOW",
19908
+ "TRY_DEMO",
19909
+ "WOODHENGE_SUPPORT",
19910
+ "SOTTO_SUBSCRIBE",
19911
+ "FOLLOW_USER",
19912
+ "RAISE_MONEY",
19913
+ "SEE_SHOP",
19914
+ "GET_DETAILS",
19915
+ "FIND_OUT_MORE",
19916
+ "VISIT_WEBSITE",
19917
+ "BROWSE_SHOP",
19918
+ "EVENT_RSVP",
19919
+ "WHATSAPP_MESSAGE",
19920
+ "FOLLOW_NEWS_STORYLINE",
19921
+ "SEE_MORE",
19922
+ "BOOK_NOW",
19923
+ "FIND_A_GROUP",
19924
+ "FIND_YOUR_GROUPS",
19925
+ "PAY_TO_ACCESS",
19926
+ "PURCHASE_GIFT_CARDS",
19927
+ "FOLLOW_PAGE",
19928
+ "SEND_A_GIFT",
19929
+ "SWIPE_UP_SHOP",
19930
+ "SWIPE_UP_PRODUCT",
19931
+ "SEND_GIFT_MONEY",
19932
+ "PLAY_GAME_ON_FACEBOOK",
19933
+ "GET_STARTED",
19934
+ "OPEN_INSTANT_APP",
19935
+ "AUDIO_CALL",
19936
+ "GET_PROMOTIONS",
19937
+ "JOIN_CHANNEL",
19938
+ "MAKE_AN_APPOINTMENT",
19939
+ "ASK_ABOUT_SERVICES",
19940
+ "BOOK_A_CONSULTATION",
19941
+ "GET_A_QUOTE",
19942
+ "BUY_VIA_MESSAGE",
19943
+ "ASK_FOR_MORE_INFO",
19944
+ "CHAT_WITH_US",
19945
+ "VIEW_PRODUCT",
19946
+ "VIEW_CHANNEL",
19947
+ "GET_IN_TOUCH",
19948
+ "ASK_A_QUESTION",
19949
+ "START_A_CHAT",
19950
+ "CHAT_NOW",
19951
+ "ASK_US",
19952
+ "WATCH_LIVE_VIDEO",
19953
+ "JOIN_LIVE_VIDEO",
19954
+ "SHOP_WITH_AI",
19955
+ "TRY_ON_WITH_AI"
19765
19956
  ];
19766
19957
  var LEAD_FORM_CTA_TYPES = [
19767
19958
  "APPLY_NOW",
@@ -20336,9 +20527,28 @@ var dynamicCreativeSchema = z25.object({
20336
20527
  descriptions: z25.array(z25.object({ text: descriptionSchema })).max(DYN.dynamicTextsMax).optional(),
20337
20528
  images: z25.array(dynamicImageSchema).optional(),
20338
20529
  videos: z25.array(dynamicVideoSchema).optional(),
20339
- ad_formats: z25.array(z25.enum(AD_FORMATS2)).min(1),
20340
- call_to_action_types: z25.array(z25.enum(CTA_TYPES2)).optional(),
20530
+ /**
20531
+ * Optional: Meta infers the format from the assets when it is omitted, and
20532
+ * every flexible creative read back off a live account omits it.
20533
+ */
20534
+ ad_formats: z25.array(z25.enum(AD_FORMATS2)).min(1).optional(),
20535
+ call_to_action_types: z25.array(z25.string()).optional(),
20536
+ /**
20537
+ * The button on the creative's own `link_data` — a flexible ad carries both
20538
+ * envelopes, and this is the one that takes `SEE_DETAILS`. Kept separate
20539
+ * from `call_to_action_types` because Meta validates the two against
20540
+ * different enums.
20541
+ */
20542
+ call_to_action: callToActionSchema.optional(),
20341
20543
  link_urls: z25.array(z25.object({ website_url: httpsUrlSchema3, display_url: z25.string().optional() })).min(1),
20544
+ /**
20545
+ * `asset_feed_spec.optimization_type` — passed through as a free string on
20546
+ * purpose. Meta's own 400 enumerates ten values and then accepts
20547
+ * `DEGREES_OF_FREEDOM`, which is not among them and is what every
20548
+ * Advantage+ flexible creative on a live account reports. An enum here
20549
+ * would refuse the value Meta itself hands back.
20550
+ */
20551
+ optimization_type: z25.string().optional(),
20342
20552
  /** Multi-language / placement customization — structural passthrough for v1. */
20343
20553
  asset_customization_rules: z25.array(z25.record(z25.string(), z25.unknown())).optional()
20344
20554
  }).superRefine((p, ctx) => {
@@ -20349,6 +20559,17 @@ var dynamicCreativeSchema = z25.object({
20349
20559
  message: "a dynamic creative needs at least one image or video"
20350
20560
  });
20351
20561
  }
20562
+ p.call_to_action_types?.forEach((type, index) => {
20563
+ if (ASSET_FEED_CTA_TYPES.some((allowed) => allowed === type)) {
20564
+ return;
20565
+ }
20566
+ const isLinkButton = CTA_TYPES2.some((allowed) => allowed === type);
20567
+ ctx.addIssue({
20568
+ code: "custom",
20569
+ path: ["call_to_action_types", index],
20570
+ message: isLinkButton ? `${type} is not one of the buttons Meta accepts in asset_feed_spec.call_to_action_types \u2014 it is a link_data button. Pass it as call_to_action: { type: "${type}" } instead.` : `${type} is not a Meta call-to-action button.`
20571
+ });
20572
+ });
20352
20573
  });
20353
20574
  var existingPostCreativeSchema = z25.object({
20354
20575
  creativeType: z25.literal("existing_post"),
@@ -20359,11 +20580,33 @@ var existingPostCreativeSchema = z25.object({
20359
20580
  url_tags: creativeSharedFields.url_tags,
20360
20581
  enhancements: creativeSharedFields.enhancements
20361
20582
  });
20583
+ var specCreativeSchema = z25.object({
20584
+ creativeType: z25.literal("spec"),
20585
+ name: creativeSharedFields.name,
20586
+ url_tags: creativeSharedFields.url_tags,
20587
+ /** Promote the existing post — keeps the ad's likes, comments and shares. */
20588
+ object_story_id: z25.string().regex(/^\d+_\d+$/, 'expected "<page_id>_<post_id>"').optional(),
20589
+ object_story_spec: z25.record(z25.string(), z25.unknown()).optional(),
20590
+ asset_feed_spec: z25.record(z25.string(), z25.unknown()).optional(),
20591
+ degrees_of_freedom_spec: z25.record(z25.string(), z25.unknown()).optional(),
20592
+ instagram_user_id: creativeSharedFields.instagram_user_id,
20593
+ /** The creative this spec was cloned from, for the review diff. */
20594
+ clonedFrom: z25.string().regex(NUMERIC_ID_REGEX3).optional()
20595
+ }).superRefine((p, ctx) => {
20596
+ if (!(p.object_story_id || p.object_story_spec || p.asset_feed_spec)) {
20597
+ ctx.addIssue({
20598
+ code: "custom",
20599
+ path: ["object_story_spec"],
20600
+ message: "a spec creative needs object_story_id, object_story_spec or asset_feed_spec"
20601
+ });
20602
+ }
20603
+ });
20362
20604
  var creativeContentSchema2 = z25.discriminatedUnion("creativeType", [
20363
20605
  singleCreativeSchema,
20364
20606
  carouselCreativeSchema2,
20365
20607
  dynamicCreativeSchema,
20366
- existingPostCreativeSchema
20608
+ existingPostCreativeSchema,
20609
+ specCreativeSchema
20367
20610
  ]);
20368
20611
  var adCreativeCreateSchema = creativeContentSchema2;
20369
20612
  var adCreativeUpdateSchema = z25.object({
@@ -20507,6 +20750,16 @@ var metaDraftDuplicateRequestSchema = z26.object({
20507
20750
  /** Pause the original after the copy publishes. */
20508
20751
  replace: z26.boolean().optional()
20509
20752
  });
20753
+ var metaDraftRetagRequestSchema = z26.object({
20754
+ chatId: z26.string(),
20755
+ accountId: z26.string(),
20756
+ adId: z26.string(),
20757
+ urlTags: z26.string().max(1e3).optional(),
20758
+ set: z26.record(z26.string(), z26.string()).optional()
20759
+ }).refine(
20760
+ (p) => p.urlTags === void 0 !== (p.set === void 0),
20761
+ "pass either the whole tracking string or the key=value pairs to change, not both"
20762
+ );
20510
20763
  var metaDraftOpViewSchema = z26.object({
20511
20764
  ref: z26.string(),
20512
20765
  kind: metaDraftOpKindSchema,
@@ -21075,6 +21328,64 @@ Example: baker ads meta ads update 6123 --creative meta_temp_cr02`
21075
21328
  });
21076
21329
  }
21077
21330
  });
21331
+ var adsRetagCommand = defineCommand56({
21332
+ meta: {
21333
+ name: "retag",
21334
+ description: `Stage new URL tracking parameters on a LIVE ad \u2014 the fix for a wrong utm_medium, a missing ad id, or any tag already running. ${STAGED_NOTE2}
21335
+ Start here when a report attributes paid traffic to the wrong channel: --set rewrites only the keys you name and leaves the rest of the string alone.
21336
+ Baker clones the ad's own creative behind the scenes, so every button, text variant and enhancement is carried across exactly as Meta holds them \u2014 nothing is retyped.
21337
+ Example: baker ads meta ads retag 120252158038400247 --set "utm_medium=paid-social&utm_placement={{placement}}"
21338
+ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{site_source_name}}&utm_medium=paid-social&ad_id={{ad.id}}"`
21339
+ },
21340
+ args: {
21341
+ id: { type: "positional", description: "Ad id (a live ad \u2014 not a meta_temp_* ref)", required: true },
21342
+ ...accountArgs2,
21343
+ "url-tags": { type: "string", description: "Replace the WHOLE tracking string" },
21344
+ set: {
21345
+ type: "string",
21346
+ description: 'Rewrite only these keys, keeping the rest: "utm_medium=paid-social&ad_id={{ad.id}}"'
21347
+ }
21348
+ },
21349
+ run: async ({ args }) => {
21350
+ const { apiPost: apiPost2 } = await import("./client-VDCCDEHE.js");
21351
+ const { requireChatId: requireChatId2 } = await import("./env-FWMZXMQK.js");
21352
+ const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-JBYI5IVX.js");
21353
+ const { handleMetaError: handleMetaError2 } = await import("./shared-GWFXJXKJ.js");
21354
+ try {
21355
+ const accountId = bareAccountId2(args);
21356
+ const urlTags = typeof args["url-tags"] === "string" ? args["url-tags"] : void 0;
21357
+ const setRaw = typeof args.set === "string" ? args.set : void 0;
21358
+ if (urlTags === void 0 === (setRaw === void 0)) {
21359
+ failWriteValidation3("pass either --url-tags (the whole string) or --set (the keys to change), not both");
21360
+ }
21361
+ const response = await apiPost2("/api/ads/meta/draft/retag", {
21362
+ chatId: requireChatId2(),
21363
+ accountId,
21364
+ adId: requireTarget3(args, "ad"),
21365
+ urlTags,
21366
+ set: setRaw === void 0 ? void 0 : parseSetPairs(setRaw)
21367
+ });
21368
+ writeJsonEnvelope2(response);
21369
+ } catch (err) {
21370
+ handleMetaError2(err);
21371
+ }
21372
+ }
21373
+ });
21374
+ function parseSetPairs(raw) {
21375
+ const pairs = {};
21376
+ for (const part of raw.replace(/^[?&]+/, "").split("&")) {
21377
+ if (part.length === 0) continue;
21378
+ const eq = part.indexOf("=");
21379
+ if (eq <= 0) {
21380
+ failWriteValidation3(`--set expects key=value pairs joined by & \u2014 could not read "${part}"`);
21381
+ }
21382
+ pairs[part.slice(0, eq)] = part.slice(eq + 1);
21383
+ }
21384
+ if (Object.keys(pairs).length === 0) {
21385
+ failWriteValidation3("--set needs at least one key=value pair");
21386
+ }
21387
+ return pairs;
21388
+ }
21078
21389
  var audiencesCreateCommand2 = defineCommand56({
21079
21390
  meta: {
21080
21391
  name: "create",
@@ -21257,7 +21568,7 @@ var listCommand4 = defineCommand57({
21257
21568
  var adsListCommand = defineCommand57({
21258
21569
  meta: {
21259
21570
  name: "ads",
21260
- description: `List ads in a Meta ad account, or stage writes (create/update/pause/resume/archive/duplicate).
21571
+ description: `List ads in a Meta ad account, or stage writes (create/update/pause/resume/archive/duplicate/retag).
21261
21572
  Defaults to ACTIVE only \u2014 pass --all-statuses to widen. Write subcommands stage ops on this chat's draft.
21262
21573
 
21263
21574
  The dashboard shows effective_status (e.g. WITH_ISSUES, PENDING_REVIEW, DISAPPROVED, ADSET_PAUSED), not status.
@@ -21266,7 +21577,8 @@ Examples:
21266
21577
  baker ads meta ads --account-id act_123
21267
21578
  baker ads meta ads --adset-id 6123
21268
21579
  baker ads meta ads create --name "Ad 1" --adset meta_temp_as01 --creative meta_temp_cr01
21269
- baker ads meta ads pause 6123 --account-id act_123`
21580
+ baker ads meta ads pause 6123 --account-id act_123
21581
+ baker ads meta ads retag 6123 --set "utm_medium=paid-social" \u2014 fix tracking on a LIVE ad, keeping everything else`
21270
21582
  },
21271
21583
  subCommands: {
21272
21584
  list: listCommand4,
@@ -21275,7 +21587,8 @@ Examples:
21275
21587
  pause: adsPauseCommand,
21276
21588
  resume: adsResumeCommand,
21277
21589
  archive: adsArchiveCommand,
21278
- duplicate: adsDuplicateCommand
21590
+ duplicate: adsDuplicateCommand,
21591
+ retag: adsRetagCommand
21279
21592
  },
21280
21593
  // `args` stays even though the parent has no `run`: citty scans rawArgs for the
21281
21594
  // subcommand name using THIS command's arg defs, so without them `--account-id act_1`