@koda-sl/baker-cli 0.107.0-dev.aaab11a02 → 0.109.0-dev.2acd65459
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 +8 -0
- package/dist/cli.js +146 -59
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1006,6 +1006,14 @@ baker ads linkedin conversions create --name "Demo booked" --type LEAD --method
|
|
|
1006
1006
|
# Safe duplication — stage-time read of the source → staged DRAFT create ("Duplicate ad", never "Link to original")
|
|
1007
1007
|
baker ads linkedin campaigns duplicate 123456 --name "New variant"
|
|
1008
1008
|
|
|
1009
|
+
# Change copy/media/URL on a LIVE ad — direct-content ads (text/spotlight/follower/jobs) update IN PLACE;
|
|
1010
|
+
# pass only the changed fields, the rest of the ad's current content carries over
|
|
1011
|
+
baker ads linkedin creatives update 1458423674 --headline "New headline" --description "New copy."
|
|
1012
|
+
|
|
1013
|
+
# Post-based ads (image/video/carousel/…) sponsor a post whose content can't be edited — replace in ONE command:
|
|
1014
|
+
# duplicate with overrides (unchanged fields + status carry over) + --replace pauses the original once the copy publishes
|
|
1015
|
+
baker ads linkedin creatives duplicate 1458413484 --headline "New headline" --replace
|
|
1016
|
+
|
|
1009
1017
|
# Amend staged ops in place — `update <li_temp_ref>` merges into the staged create and re-validates
|
|
1010
1018
|
baker ads linkedin creatives update li_temp_x3 --headline "Sharper headline" --image-id <bakerImageId>
|
|
1011
1019
|
baker ads linkedin campaigns update li_temp_x2 --daily-budget 100 --currency EUR
|
package/dist/cli.js
CHANGED
|
@@ -1056,7 +1056,8 @@ var parentRefSchema = z3.union([
|
|
|
1056
1056
|
]);
|
|
1057
1057
|
var moneySchema = z3.object({
|
|
1058
1058
|
amount: z3.string().regex(/^\d+(\.\d{1,2})?$/, "expected a decimal amount like 50 or 50.00").refine((val) => Number(val) > 0, "amount must be greater than zero"),
|
|
1059
|
-
|
|
1059
|
+
/** LinkedIn ad accounts are single-currency — when omitted, staging fills it from the account. */
|
|
1060
|
+
currencyCode: z3.string().length(3).optional()
|
|
1060
1061
|
});
|
|
1061
1062
|
var runScheduleSchema = z3.object({
|
|
1062
1063
|
start: z3.number().int().positive(),
|
|
@@ -1125,7 +1126,7 @@ function validateCampaignBudgets(p, ctx, { requireBudget }) {
|
|
|
1125
1126
|
message: "totalBudget-only campaigns need runSchedule.end"
|
|
1126
1127
|
});
|
|
1127
1128
|
}
|
|
1128
|
-
if (p.dailyBudget) {
|
|
1129
|
+
if (p.dailyBudget?.currencyCode) {
|
|
1129
1130
|
const min = currencyMinimums(p.dailyBudget.currencyCode).dailyBudgetMin;
|
|
1130
1131
|
if (Number(p.dailyBudget.amount) < min) {
|
|
1131
1132
|
ctx.addIssue({
|
|
@@ -1135,7 +1136,7 @@ function validateCampaignBudgets(p, ctx, { requireBudget }) {
|
|
|
1135
1136
|
});
|
|
1136
1137
|
}
|
|
1137
1138
|
}
|
|
1138
|
-
if (p.unitCost) {
|
|
1139
|
+
if (p.unitCost?.currencyCode) {
|
|
1139
1140
|
const min = currencyMinimums(p.unitCost.currencyCode).unitCostMin;
|
|
1140
1141
|
if (Number(p.unitCost.amount) < min) {
|
|
1141
1142
|
ctx.addIssue({
|
|
@@ -1225,14 +1226,17 @@ var spotlightCreativeSchema = z3.object({
|
|
|
1225
1226
|
ctaLabel: z3.string().min(1).max(LINKEDIN_LIMITS.creative.spotlightCtaMax),
|
|
1226
1227
|
logoImageId: bakerMediaIdSchema.optional(),
|
|
1227
1228
|
logoUrn: z3.string().regex(IMAGE_URN_REGEX).optional(),
|
|
1228
|
-
showMemberProfilePhoto: z3.boolean().default(true)
|
|
1229
|
+
showMemberProfilePhoto: z3.boolean().default(true),
|
|
1230
|
+
/** Carried from the live snapshot on updates so LinkedIn's whole-content $set preserves it. */
|
|
1231
|
+
organizationName: z3.string().min(1).max(200).optional()
|
|
1229
1232
|
});
|
|
1230
1233
|
var followerCreativeSchema = z3.object({
|
|
1231
1234
|
format: z3.literal("follower"),
|
|
1232
1235
|
headline: z3.string().max(LINKEDIN_LIMITS.creative.spotlightHeadlineMax).optional(),
|
|
1233
1236
|
description: z3.string().max(LINKEDIN_LIMITS.creative.spotlightDescriptionMax).optional(),
|
|
1234
1237
|
logoImageId: bakerMediaIdSchema.optional(),
|
|
1235
|
-
logoUrn: z3.string().regex(IMAGE_URN_REGEX).optional()
|
|
1238
|
+
logoUrn: z3.string().regex(IMAGE_URN_REGEX).optional(),
|
|
1239
|
+
organizationName: z3.string().min(1).max(200).optional()
|
|
1236
1240
|
});
|
|
1237
1241
|
var documentCreativeSchema = z3.object({
|
|
1238
1242
|
format: z3.literal("document"),
|
|
@@ -5413,7 +5417,11 @@ registerSchema({
|
|
|
5413
5417
|
start: { type: "string", description: "Run schedule start (ISO date or epoch ms)", required: true },
|
|
5414
5418
|
end: { type: "string", description: "Run schedule end", required: false },
|
|
5415
5419
|
"total-budget": { type: "string", description: "Lifetime budget amount", required: false },
|
|
5416
|
-
currency: {
|
|
5420
|
+
currency: {
|
|
5421
|
+
type: "string",
|
|
5422
|
+
description: "3-letter currency code (defaults to the ad account currency)",
|
|
5423
|
+
required: false
|
|
5424
|
+
},
|
|
5417
5425
|
status: { type: "string", description: "DRAFT|ACTIVE|PAUSED (default DRAFT)", required: false },
|
|
5418
5426
|
file: { type: "string", description: "JSON payload file; flags override file keys", required: false }
|
|
5419
5427
|
}
|
|
@@ -5432,7 +5440,11 @@ registerSchema({
|
|
|
5432
5440
|
start: { type: "string", description: "New schedule start", required: false },
|
|
5433
5441
|
end: { type: "string", description: "New schedule end", required: false },
|
|
5434
5442
|
"total-budget": { type: "string", description: "New lifetime budget", required: false },
|
|
5435
|
-
currency: {
|
|
5443
|
+
currency: {
|
|
5444
|
+
type: "string",
|
|
5445
|
+
description: "3-letter currency code (defaults to the ad account currency)",
|
|
5446
|
+
required: false
|
|
5447
|
+
},
|
|
5436
5448
|
status: { type: "string", description: "ACTIVE|PAUSED|ARCHIVED", required: false },
|
|
5437
5449
|
file: { type: "string", description: "JSON file with fields to change", required: false }
|
|
5438
5450
|
}
|
|
@@ -5450,7 +5462,11 @@ registerSchema({
|
|
|
5450
5462
|
bid: { type: "string", description: "Manual bid amount (unitCost)", required: false },
|
|
5451
5463
|
"daily-budget": { type: "string", description: "Daily budget amount", required: false },
|
|
5452
5464
|
"total-budget": { type: "string", description: "Lifetime budget amount", required: false },
|
|
5453
|
-
currency: {
|
|
5465
|
+
currency: {
|
|
5466
|
+
type: "string",
|
|
5467
|
+
description: "3-letter currency code (defaults to the ad account currency)",
|
|
5468
|
+
required: false
|
|
5469
|
+
},
|
|
5454
5470
|
start: { type: "string", description: "Run schedule start", required: false },
|
|
5455
5471
|
end: { type: "string", description: "Run schedule end", required: false },
|
|
5456
5472
|
locale: { type: "string", description: "Profile locale like en_US (default en_US)", required: false },
|
|
@@ -5479,7 +5495,11 @@ registerSchema({
|
|
|
5479
5495
|
bid: { type: "string", description: "New manual bid", required: false },
|
|
5480
5496
|
"daily-budget": { type: "string", description: "New daily budget", required: false },
|
|
5481
5497
|
"total-budget": { type: "string", description: "New lifetime budget", required: false },
|
|
5482
|
-
currency: {
|
|
5498
|
+
currency: {
|
|
5499
|
+
type: "string",
|
|
5500
|
+
description: "3-letter currency code (defaults to the ad account currency)",
|
|
5501
|
+
required: false
|
|
5502
|
+
},
|
|
5483
5503
|
start: { type: "string", description: "New schedule start", required: false },
|
|
5484
5504
|
end: { type: "string", description: "New schedule end", required: false },
|
|
5485
5505
|
"targeting-file": { type: "string", description: "JSON file with replacement targetingCriteria", required: false },
|
|
@@ -5548,8 +5568,27 @@ registerSchema({
|
|
|
5548
5568
|
});
|
|
5549
5569
|
registerSchema({
|
|
5550
5570
|
command: "ads.linkedin.creatives.duplicate",
|
|
5551
|
-
description: "Stage a copy of an existing
|
|
5552
|
-
args:
|
|
5571
|
+
description: "Stage a copy of an existing ad, optionally with new content. Direct-content ads (text/spotlight/follower/jobs) copy field-by-field; post-based ads re-sponsor the same post \u2014 and since post content can't be edited, duplicate --replace is how post-based ads change copy (direct-content ads update in place via creatives.update instead). --replace stages pausing the original, gated on the new ad publishing successfully, and the copy inherits the source's status.",
|
|
5572
|
+
args: {
|
|
5573
|
+
id: { type: "positional", description: "Source creative id or URN", required: true },
|
|
5574
|
+
...writeAccountArgs,
|
|
5575
|
+
campaign: { type: "string", description: "Stage the copy under a different ad set", required: false },
|
|
5576
|
+
"intended-status": { type: "string", description: "Status for the copy (default DRAFT)", required: false },
|
|
5577
|
+
replace: { type: "boolean", description: "Also pause the original once the new ad publishes", required: false },
|
|
5578
|
+
headline: { type: "string", description: "New headline", required: false },
|
|
5579
|
+
description: { type: "string", description: "New description (text/spotlight)", required: false },
|
|
5580
|
+
intro: { type: "string", description: "New commentary / intro text", required: false },
|
|
5581
|
+
"landing-url": { type: "string", description: "New https destination URL", required: false },
|
|
5582
|
+
cta: { type: "string", description: "New CTA", required: false },
|
|
5583
|
+
"cta-label": { type: "string", description: "Spotlight custom CTA label", required: false },
|
|
5584
|
+
"image-id": { type: "string", description: "Baker image library id", required: false },
|
|
5585
|
+
"image-urn": { type: "string", description: "Existing urn:li:image:*", required: false },
|
|
5586
|
+
"video-id": { type: "string", description: "Baker video library id", required: false },
|
|
5587
|
+
"video-urn": { type: "string", description: "Existing urn:li:video:*", required: false },
|
|
5588
|
+
"logo-image-id": { type: "string", description: "Baker image id for the logo", required: false },
|
|
5589
|
+
title: { type: "string", description: "Media title", required: false },
|
|
5590
|
+
file: { type: "string", description: "JSON file with field overrides for the copy", required: false }
|
|
5591
|
+
}
|
|
5553
5592
|
});
|
|
5554
5593
|
registerSchema({
|
|
5555
5594
|
command: "ads.linkedin.creatives.create",
|
|
@@ -5581,27 +5620,27 @@ registerSchema({
|
|
|
5581
5620
|
});
|
|
5582
5621
|
registerSchema({
|
|
5583
5622
|
command: "ads.linkedin.creatives.update",
|
|
5584
|
-
description: "Stage changes to an existing creative
|
|
5623
|
+
description: "Stage changes to an existing creative. Direct-content ads (text/spotlight/follower/jobs) update copy/media/URL IN PLACE \u2014 pass only the changed fields (headline, description, landing-url, image-id, \u2026); the ad's current content carries over. Post-based ads (image/video/carousel/\u2026) can't edit content \u2014 use creatives.duplicate with --replace for those. Passing a li_temp_* ref AMENDS the creative staged in this chat instead. Applies on chat publish.",
|
|
5585
5624
|
args: {
|
|
5586
5625
|
id: { type: "positional", description: "Creative id/URN, or li_temp_* ref staged in this chat", required: true },
|
|
5587
5626
|
...writeAccountArgs,
|
|
5588
5627
|
"intended-status": { type: "string", description: "ACTIVE|PAUSED|ARCHIVED|DRAFT", required: false },
|
|
5589
5628
|
name: { type: "string", description: "New creative name", required: false },
|
|
5590
5629
|
headline: { type: "string", description: "New headline", required: false },
|
|
5591
|
-
intro: { type: "string", description: "
|
|
5592
|
-
description: { type: "string", description: "
|
|
5630
|
+
intro: { type: "string", description: "Commentary / intro text", required: false },
|
|
5631
|
+
description: { type: "string", description: "Description (text/spotlight)", required: false },
|
|
5593
5632
|
"landing-url": { type: "string", description: "New https destination URL", required: false },
|
|
5594
5633
|
cta: { type: "string", description: "New CTA", required: false },
|
|
5595
|
-
"image-id": { type: "string", description: "
|
|
5596
|
-
"image-urn": { type: "string", description: "
|
|
5597
|
-
"video-id": { type: "string", description: "
|
|
5598
|
-
"logo-image-id": { type: "string", description: "
|
|
5634
|
+
"image-id": { type: "string", description: "Baker image library id", required: false },
|
|
5635
|
+
"image-urn": { type: "string", description: "Existing urn:li:image:*", required: false },
|
|
5636
|
+
"video-id": { type: "string", description: "Baker video library id", required: false },
|
|
5637
|
+
"logo-image-id": { type: "string", description: "Baker image id for the logo", required: false },
|
|
5599
5638
|
"thumbnail-image-id": {
|
|
5600
5639
|
type: "string",
|
|
5601
|
-
description: "
|
|
5640
|
+
description: "Baker image id for the article thumbnail",
|
|
5602
5641
|
required: false
|
|
5603
5642
|
},
|
|
5604
|
-
title: { type: "string", description: "
|
|
5643
|
+
title: { type: "string", description: "Media or article title", required: false },
|
|
5605
5644
|
file: { type: "string", description: "JSON file with fields to change; flags override file keys", required: false }
|
|
5606
5645
|
}
|
|
5607
5646
|
});
|
|
@@ -6606,8 +6645,11 @@ function parseMoneyFlag(amount, currency, flag) {
|
|
|
6606
6645
|
if (amount === void 0 || amount === null || amount === "") {
|
|
6607
6646
|
return void 0;
|
|
6608
6647
|
}
|
|
6648
|
+
if (currency === void 0 || currency === null || currency === "") {
|
|
6649
|
+
return { amount: String(amount) };
|
|
6650
|
+
}
|
|
6609
6651
|
if (typeof currency !== "string" || currency.length !== 3) {
|
|
6610
|
-
failWriteValidation(`${flag}
|
|
6652
|
+
failWriteValidation(`${flag} got an invalid --currency (expected a 3-letter code like EUR)`);
|
|
6611
6653
|
}
|
|
6612
6654
|
return { amount: String(amount), currencyCode: currency.toUpperCase() };
|
|
6613
6655
|
}
|
|
@@ -6787,7 +6829,7 @@ Example: baker ads linkedin campaign-groups create --name "Q3 ABM" --start 2026-
|
|
|
6787
6829
|
start: { type: "string", description: "Run schedule start (ISO date or epoch ms)" },
|
|
6788
6830
|
end: { type: "string", description: "Run schedule end" },
|
|
6789
6831
|
"total-budget": { type: "string", description: "Lifetime budget amount" },
|
|
6790
|
-
currency: { type: "string", description: "3-letter currency code (
|
|
6832
|
+
currency: { type: "string", description: "3-letter currency code (defaults to the ad account currency)" },
|
|
6791
6833
|
status: { type: "string", description: "DRAFT|ACTIVE|PAUSED (default DRAFT)" },
|
|
6792
6834
|
file: { type: "string", description: "JSON file with the full payload; flags override file keys" }
|
|
6793
6835
|
},
|
|
@@ -6816,7 +6858,7 @@ Example: baker ads linkedin campaign-groups update 635137195 --total-budget 8000
|
|
|
6816
6858
|
start: { type: "string", description: "New run schedule start" },
|
|
6817
6859
|
end: { type: "string", description: "New run schedule end" },
|
|
6818
6860
|
"total-budget": { type: "string", description: "New lifetime budget" },
|
|
6819
|
-
currency: { type: "string", description: "3-letter currency code" },
|
|
6861
|
+
currency: { type: "string", description: "3-letter currency code (defaults to the ad account currency)" },
|
|
6820
6862
|
status: { type: "string", description: "ACTIVE|PAUSED|ARCHIVED|\u2026" },
|
|
6821
6863
|
file: { type: "string", description: "JSON file with fields to change" }
|
|
6822
6864
|
},
|
|
@@ -6867,7 +6909,7 @@ var campaignFlagArgs = {
|
|
|
6867
6909
|
bid: { type: "string", description: "Manual bid (unitCost) \u2014 playbook mandates manual bidding" },
|
|
6868
6910
|
"daily-budget": { type: "string", description: "Daily budget amount" },
|
|
6869
6911
|
"total-budget": { type: "string", description: "Lifetime budget amount" },
|
|
6870
|
-
currency: { type: "string", description: "3-letter currency code (
|
|
6912
|
+
currency: { type: "string", description: "3-letter currency code (defaults to the ad account currency)" },
|
|
6871
6913
|
start: { type: "string", description: "Run schedule start (ISO date or epoch ms)" },
|
|
6872
6914
|
end: { type: "string", description: "Run schedule end" },
|
|
6873
6915
|
locale: { type: "string", description: "Profile locale like en_US" },
|
|
@@ -6989,7 +7031,69 @@ Example: baker ads linkedin ${cliGroup} duplicate 123456 --name "New variant"`
|
|
|
6989
7031
|
}
|
|
6990
7032
|
var campaignsDuplicateCommand = duplicateCommand("campaign", "campaigns");
|
|
6991
7033
|
var campaignGroupsDuplicateCommand = duplicateCommand("campaignGroup", "campaign-groups");
|
|
6992
|
-
var creativesDuplicateCommand =
|
|
7034
|
+
var creativesDuplicateCommand = defineCommand36({
|
|
7035
|
+
meta: {
|
|
7036
|
+
name: "duplicate",
|
|
7037
|
+
description: `Stage a copy of an existing ad, optionally with new content \u2014 the ONLY way to change copy/media/URL on a live ad (LinkedIn makes ad content immutable). ${STAGED_NOTE}
|
|
7038
|
+
--replace also pauses the original once the new ad publishes (skipped if the new ad fails).
|
|
7039
|
+
Examples:
|
|
7040
|
+
baker ads linkedin creatives duplicate 1458413484 --headline "10x Demos, Same Team" --description "AI handles every demo request." --replace
|
|
7041
|
+
baker ads linkedin creatives duplicate urn:li:sponsoredCreative:789 --campaign 799305464`
|
|
7042
|
+
},
|
|
7043
|
+
args: {
|
|
7044
|
+
id: { type: "positional", description: "Source creative id or URN", required: true },
|
|
7045
|
+
...accountArgs,
|
|
7046
|
+
campaign: { type: "string", description: "Stage the copy under a different ad set (id/URN or li_temp_*)" },
|
|
7047
|
+
"intended-status": {
|
|
7048
|
+
type: "string",
|
|
7049
|
+
description: "Status for the copy (default DRAFT; with --replace, the source's status)"
|
|
7050
|
+
},
|
|
7051
|
+
replace: {
|
|
7052
|
+
type: "boolean",
|
|
7053
|
+
description: "Also pause the original once the new ad publishes; the copy inherits the source's status"
|
|
7054
|
+
},
|
|
7055
|
+
intro: { type: "string", description: "New commentary / intro text" },
|
|
7056
|
+
headline: { type: "string", description: "New headline" },
|
|
7057
|
+
description: { type: "string", description: "New description (text/spotlight ads)" },
|
|
7058
|
+
"landing-url": { type: "string", description: "New https destination URL" },
|
|
7059
|
+
cta: { type: "string", description: "New CTA (LEARN_MORE|REQUEST_DEMO|\u2026)" },
|
|
7060
|
+
"cta-label": { type: "string", description: "Spotlight custom CTA label" },
|
|
7061
|
+
"image-id": { type: "string", description: "Baker image library id" },
|
|
7062
|
+
"image-urn": { type: "string", description: "Existing urn:li:image:*" },
|
|
7063
|
+
"video-id": { type: "string", description: "Baker video library id" },
|
|
7064
|
+
"video-urn": { type: "string", description: "Existing urn:li:video:*" },
|
|
7065
|
+
"logo-image-id": { type: "string", description: "Baker image id for the logo" },
|
|
7066
|
+
title: { type: "string", description: "Media title" },
|
|
7067
|
+
file: { type: "string", description: "JSON file with field overrides for the copy" }
|
|
7068
|
+
},
|
|
7069
|
+
run: async ({ args }) => {
|
|
7070
|
+
try {
|
|
7071
|
+
const chatId = requireChatId();
|
|
7072
|
+
const file = loadJsonFileArg(args.file);
|
|
7073
|
+
const fileContent = file.content !== null && typeof file.content === "object" && !Array.isArray(file.content) ? file.content : {};
|
|
7074
|
+
const content = { ...fileContent, ...creativeContentPatch(args) };
|
|
7075
|
+
const overrides = mergePayload(file, {
|
|
7076
|
+
campaign: args.campaign,
|
|
7077
|
+
intendedStatus: args["intended-status"] ? String(args["intended-status"]).toUpperCase() : void 0,
|
|
7078
|
+
content: Object.keys(content).length > 0 ? content : void 0
|
|
7079
|
+
});
|
|
7080
|
+
const response = await apiPost(
|
|
7081
|
+
"/api/ads/linkedin/draft/duplicate",
|
|
7082
|
+
{
|
|
7083
|
+
chatId,
|
|
7084
|
+
accountId: bareAccountId(args),
|
|
7085
|
+
entity: "creative",
|
|
7086
|
+
sourceId: requireTarget(args, "creative"),
|
|
7087
|
+
...Object.keys(overrides).length > 0 ? { overrides } : {},
|
|
7088
|
+
...args.replace ? { replace: true } : {}
|
|
7089
|
+
}
|
|
7090
|
+
);
|
|
7091
|
+
writeJsonEnvelope(response);
|
|
7092
|
+
} catch (err) {
|
|
7093
|
+
handleLinkedinError(err);
|
|
7094
|
+
}
|
|
7095
|
+
}
|
|
7096
|
+
});
|
|
6993
7097
|
var CREATIVE_FORMATS = [
|
|
6994
7098
|
"image",
|
|
6995
7099
|
"video",
|
|
@@ -7093,7 +7197,6 @@ var CREATIVE_AMEND_CONTENT_FLAGS = [
|
|
|
7093
7197
|
["thumbnail-urn", "thumbnailUrn"],
|
|
7094
7198
|
["title", "title"]
|
|
7095
7199
|
];
|
|
7096
|
-
var CREATIVE_LIVE_UPDATE_KEYS = /* @__PURE__ */ new Set(["headline", "landingUrl", "cta"]);
|
|
7097
7200
|
function creativeContentPatch(args) {
|
|
7098
7201
|
const patch = {};
|
|
7099
7202
|
for (const [flag, key] of CREATIVE_AMEND_CONTENT_FLAGS) {
|
|
@@ -7110,30 +7213,30 @@ var creativesUpdateCommand = defineCommand36({
|
|
|
7110
7213
|
meta: {
|
|
7111
7214
|
name: "update",
|
|
7112
7215
|
description: `Stage changes to an existing creative, or amend a creative staged in this chat by passing its li_temp_* ref. ${STAGED_NOTE}
|
|
7113
|
-
|
|
7216
|
+
Direct-content ads (text/spotlight/follower/jobs) update copy/media/URL IN PLACE \u2014 changed fields merge into the ad's current content. Post-based ads (image/video/carousel/\u2026) can't edit content; use \`creatives duplicate <id> --headline "\u2026" --replace\` for those. Staged creatives (li_temp_*) accept all content flags and re-validate.
|
|
7114
7217
|
Examples:
|
|
7115
|
-
baker ads linkedin creatives update
|
|
7116
|
-
baker ads linkedin creatives update
|
|
7218
|
+
baker ads linkedin creatives update 1458423674 --headline "Sharper headline" --description "New copy."
|
|
7219
|
+
baker ads linkedin creatives update urn:li:sponsoredCreative:789 --intended-status PAUSED`
|
|
7117
7220
|
},
|
|
7118
7221
|
args: {
|
|
7119
7222
|
id: { type: "positional", description: "Creative id/URN, or li_temp_* ref staged in this chat", required: true },
|
|
7120
7223
|
...accountArgs,
|
|
7121
7224
|
"intended-status": { type: "string", description: "ACTIVE|PAUSED|ARCHIVED|DRAFT" },
|
|
7122
7225
|
name: { type: "string", description: "New creative name" },
|
|
7123
|
-
intro: { type: "string", description: "
|
|
7226
|
+
intro: { type: "string", description: "Commentary / intro text" },
|
|
7124
7227
|
headline: { type: "string", description: "New headline" },
|
|
7125
|
-
description: { type: "string", description: "
|
|
7228
|
+
description: { type: "string", description: "Description (text/spotlight ads)" },
|
|
7126
7229
|
"landing-url": { type: "string", description: "New https destination URL" },
|
|
7127
7230
|
cta: { type: "string", description: "New CTA (LEARN_MORE|REQUEST_DEMO|\u2026)" },
|
|
7128
|
-
"cta-label": { type: "string", description: "
|
|
7129
|
-
"image-id": { type: "string", description: "
|
|
7130
|
-
"image-urn": { type: "string", description: "
|
|
7131
|
-
"video-id": { type: "string", description: "
|
|
7132
|
-
"video-urn": { type: "string", description: "
|
|
7133
|
-
"logo-image-id": { type: "string", description: "
|
|
7134
|
-
"thumbnail-image-id": { type: "string", description: "
|
|
7135
|
-
"thumbnail-urn": { type: "string", description: "
|
|
7136
|
-
title: { type: "string", description: "
|
|
7231
|
+
"cta-label": { type: "string", description: "Spotlight custom CTA label" },
|
|
7232
|
+
"image-id": { type: "string", description: "Baker image library id" },
|
|
7233
|
+
"image-urn": { type: "string", description: "Existing urn:li:image:*" },
|
|
7234
|
+
"video-id": { type: "string", description: "Baker video library id" },
|
|
7235
|
+
"video-urn": { type: "string", description: "Existing urn:li:video:*" },
|
|
7236
|
+
"logo-image-id": { type: "string", description: "Baker image id for the logo" },
|
|
7237
|
+
"thumbnail-image-id": { type: "string", description: "Baker image id for the article thumbnail" },
|
|
7238
|
+
"thumbnail-urn": { type: "string", description: "Existing urn:li:image:* thumbnail" },
|
|
7239
|
+
title: { type: "string", description: "Media or article title" },
|
|
7137
7240
|
file: { type: "string", description: "JSON file with fields to change; flags override file keys" }
|
|
7138
7241
|
},
|
|
7139
7242
|
run: async ({ args }) => {
|
|
@@ -7142,28 +7245,12 @@ Examples:
|
|
|
7142
7245
|
const file = loadJsonFileArg(args.file);
|
|
7143
7246
|
const contentPatch = creativeContentPatch(args);
|
|
7144
7247
|
const intendedStatus = args["intended-status"] ? String(args["intended-status"]).toUpperCase() : void 0;
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
const content = { ...fileContent, ...contentPatch };
|
|
7148
|
-
const payload2 = mergePayload(file, {
|
|
7149
|
-
intendedStatus,
|
|
7150
|
-
content: Object.keys(content).length > 0 ? content : void 0
|
|
7151
|
-
});
|
|
7152
|
-
await stageOp({ kind: "creative.update", accountId, target, payload: payload2 });
|
|
7153
|
-
return;
|
|
7154
|
-
}
|
|
7155
|
-
const immutable = Object.keys(contentPatch).filter((key) => !CREATIVE_LIVE_UPDATE_KEYS.has(key));
|
|
7156
|
-
if (immutable.length > 0) {
|
|
7157
|
-
failWriteValidation(
|
|
7158
|
-
`creative content is immutable on LinkedIn (${immutable.join(", ")}) \u2014 pass a li_temp_* ref to amend a creative staged in this chat, or use \`creatives duplicate\``
|
|
7159
|
-
);
|
|
7160
|
-
}
|
|
7248
|
+
const fileContent = file.content !== null && typeof file.content === "object" && !Array.isArray(file.content) ? file.content : {};
|
|
7249
|
+
const content = { ...fileContent, ...contentPatch };
|
|
7161
7250
|
const payload = mergePayload(file, {
|
|
7162
7251
|
intendedStatus,
|
|
7163
7252
|
name: args.name,
|
|
7164
|
-
|
|
7165
|
-
landingUrl: contentPatch.landingUrl,
|
|
7166
|
-
cta: contentPatch.cta
|
|
7253
|
+
content: Object.keys(content).length > 0 ? content : void 0
|
|
7167
7254
|
});
|
|
7168
7255
|
await stageOp({ kind: "creative.update", accountId, target, payload });
|
|
7169
7256
|
}
|