@koda-sl/baker-cli 0.334.0 → 0.335.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 +85 -3
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1887,7 +1887,78 @@ var audienceCreateSchema = z3.object({
|
|
|
1887
1887
|
message: `${p.audienceType} audiences need a raw source config (use --file)`
|
|
1888
1888
|
});
|
|
1889
1889
|
}
|
|
1890
|
-
|
|
1890
|
+
if (!isList && p.raw) {
|
|
1891
|
+
for (const message of retargetingConfigProblems(p.raw)) {
|
|
1892
|
+
ctx.addIssue({ code: "custom", path: ["raw"], message: `${p.audienceType} source config: ${message}` });
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
});
|
|
1896
|
+
var ENGAGEMENT_LOOKBACK_DAYS = [7, 14, 28, 30, 60, 90, 180, 365];
|
|
1897
|
+
var WEBSITE_LOOKBACK_DAYS = ENGAGEMENT_LOOKBACK_DAYS.filter((days) => days >= 14 && days <= 180);
|
|
1898
|
+
var EVENT_LOOKBACK_DAYS = [730];
|
|
1899
|
+
var WEBSITE_SOURCE_PLATFORM = "LINKEDIN_WEBSITE_RETARGETING";
|
|
1900
|
+
var TRIGGER_SOURCE_TYPE_BY_PLATFORM = { [WEBSITE_SOURCE_PLATFORM]: "WEBSITE" };
|
|
1901
|
+
function lookbackDaysFor(sourcePlatform) {
|
|
1902
|
+
if (sourcePlatform === WEBSITE_SOURCE_PLATFORM) {
|
|
1903
|
+
return WEBSITE_LOOKBACK_DAYS;
|
|
1904
|
+
}
|
|
1905
|
+
return sourcePlatform === "EVENT_PAGES" ? EVENT_LOOKBACK_DAYS : ENGAGEMENT_LOOKBACK_DAYS;
|
|
1906
|
+
}
|
|
1907
|
+
var ENGAGEMENT_TRIGGER_URN = /^urn:li:dmpEngagementTrigger:\(urn:li:dmpEngagementSourceType:([A-Z_]+),([A-Z_]+)\)$/;
|
|
1908
|
+
var RETARGETING_EXAMPLE = '{"sourcePlatform":"VIDEO_ADS","type":"USER","engagementRules":[{"engagementSource":"urn:li:sponsoredCampaign:123","engagementTrigger":"urn:li:dmpEngagementTrigger:(urn:li:dmpEngagementSourceType:VIDEO_ADS,FIRST_QUARTILE)","timeFrame":{"timeSpan":{"duration":90,"unit":"DAY"}}}]}';
|
|
1909
|
+
var engagementRuleSchema = z3.object({
|
|
1910
|
+
engagementSource: z3.string().regex(/^urn:li:[A-Za-z]+:\S+$/, "engagementSource must be a URN (urn:li:\u2026)"),
|
|
1911
|
+
engagementTrigger: z3.string().regex(
|
|
1912
|
+
ENGAGEMENT_TRIGGER_URN,
|
|
1913
|
+
"engagementTrigger must be urn:li:dmpEngagementTrigger:(urn:li:dmpEngagementSourceType:<SOURCE>,<TRIGGER>)"
|
|
1914
|
+
),
|
|
1915
|
+
timeFrame: z3.object({
|
|
1916
|
+
timeSpan: z3.object({ duration: z3.number().int().positive(), unit: z3.literal("DAY") })
|
|
1917
|
+
})
|
|
1918
|
+
}).passthrough();
|
|
1919
|
+
var engagementRulesSchema = z3.array(engagementRuleSchema).min(1);
|
|
1920
|
+
function retargetingConfigProblems(raw) {
|
|
1921
|
+
const problems = [];
|
|
1922
|
+
const sourcePlatform = typeof raw.sourcePlatform === "string" ? raw.sourcePlatform.trim() : "";
|
|
1923
|
+
if (!sourcePlatform) {
|
|
1924
|
+
problems.push("missing sourcePlatform");
|
|
1925
|
+
}
|
|
1926
|
+
if (raw.type !== "USER") {
|
|
1927
|
+
problems.push('type must be "USER" \u2014 LinkedIn only attaches engagement rules to USER segments');
|
|
1928
|
+
}
|
|
1929
|
+
const rules = engagementRulesSchema.safeParse(raw.engagementRules);
|
|
1930
|
+
if (!rules.success) {
|
|
1931
|
+
const detail = rules.error.issues.map((issue) => issue.message).join("; ");
|
|
1932
|
+
problems.push(
|
|
1933
|
+
`engagementRules needs at least one source rule (engagementSource, engagementTrigger, timeFrame) \u2014 ${detail}. e.g. ${RETARGETING_EXAMPLE}`
|
|
1934
|
+
);
|
|
1935
|
+
return problems;
|
|
1936
|
+
}
|
|
1937
|
+
const allowed = lookbackDaysFor(sourcePlatform);
|
|
1938
|
+
const expectedTriggerSource = TRIGGER_SOURCE_TYPE_BY_PLATFORM[sourcePlatform] ?? sourcePlatform;
|
|
1939
|
+
for (const rule of rules.data) {
|
|
1940
|
+
const triggerSource = ENGAGEMENT_TRIGGER_URN.exec(rule.engagementTrigger)?.[1];
|
|
1941
|
+
if (sourcePlatform && triggerSource !== expectedTriggerSource) {
|
|
1942
|
+
problems.push(
|
|
1943
|
+
`engagementTrigger ${rule.engagementTrigger} is a ${triggerSource} trigger, not ${expectedTriggerSource}`
|
|
1944
|
+
);
|
|
1945
|
+
}
|
|
1946
|
+
const days = rule.timeFrame.timeSpan.duration;
|
|
1947
|
+
if (!allowed.includes(days)) {
|
|
1948
|
+
problems.push(`lookback ${days} days is not offered for ${sourcePlatform} \u2014 use ${allowed.join(", ")}`);
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
const shapes = new Set(rules.data.map((rule) => `${rule.engagementTrigger}|${rule.timeFrame.timeSpan.duration}`));
|
|
1952
|
+
if (shapes.size > 1) {
|
|
1953
|
+
problems.push("every engagement rule on one audience must use the same trigger and lookback");
|
|
1954
|
+
}
|
|
1955
|
+
const sources = rules.data.map((rule) => rule.engagementSource);
|
|
1956
|
+
const repeated = [...new Set(sources.filter((source, index) => sources.indexOf(source) !== index))];
|
|
1957
|
+
if (repeated.length > 0) {
|
|
1958
|
+
problems.push(`each engagementSource can appear in only one rule: ${repeated.join(", ")}`);
|
|
1959
|
+
}
|
|
1960
|
+
return problems;
|
|
1961
|
+
}
|
|
1891
1962
|
var audienceUploadListSchema = z3.object({
|
|
1892
1963
|
segment: parentRefSchema,
|
|
1893
1964
|
listColumns: z3.array(z3.string().min(1)).optional(),
|
|
@@ -19937,7 +20008,11 @@ registerSchema({
|
|
|
19937
20008
|
name: { type: "string", description: "Audience name (\u2264100 chars)", required: true },
|
|
19938
20009
|
type: { type: "string", description: "company-list|user-list|retargeting|engagement", required: true },
|
|
19939
20010
|
"list-file": { type: "string", description: "CSV file with the list rows", required: false },
|
|
19940
|
-
file: {
|
|
20011
|
+
file: {
|
|
20012
|
+
type: "string",
|
|
20013
|
+
description: "JSON raw source config for retargeting/engagement \u2014 sourcePlatform, type USER, and engagementRules (engagementSource, engagementTrigger, timeFrame)",
|
|
20014
|
+
required: false
|
|
20015
|
+
}
|
|
19941
20016
|
}
|
|
19942
20017
|
});
|
|
19943
20018
|
registerSchema({
|
|
@@ -20689,7 +20764,10 @@ Example: baker ads linkedin audiences create --name "ABM Tier-1" --type company-
|
|
|
20689
20764
|
name: { type: "string", description: "Audience name (\u2264100 chars)" },
|
|
20690
20765
|
type: { type: "string", description: AUDIENCE_TYPES2.join("|") },
|
|
20691
20766
|
"list-file": { type: "string", description: "CSV file with the list rows (header row required)" },
|
|
20692
|
-
file: {
|
|
20767
|
+
file: {
|
|
20768
|
+
type: "string",
|
|
20769
|
+
description: 'JSON file with a raw source config (retargeting/engagement) \u2014 sourcePlatform, type USER and at least one engagementRules entry, e.g. {"sourcePlatform":"VIDEO_ADS","type":"USER","engagementRules":[{"engagementSource":"urn:li:sponsoredCampaign:123","engagementTrigger":"urn:li:dmpEngagementTrigger:(urn:li:dmpEngagementSourceType:VIDEO_ADS,FIRST_QUARTILE)","timeFrame":{"timeSpan":{"duration":90,"unit":"DAY"}}}]}'
|
|
20770
|
+
}
|
|
20693
20771
|
},
|
|
20694
20772
|
run: async ({ args: args5 }) => {
|
|
20695
20773
|
const accountId = bareAccountId(args5);
|
|
@@ -22373,6 +22451,10 @@ function renderOutcome2(data, lines) {
|
|
|
22373
22451
|
lines.push(`LinkedIn Ads \u2014 published \xB7 ${summary || `${data.count} op(s)`} \xB7 ${data.mode}`);
|
|
22374
22452
|
for (const op of data.ops ?? []) {
|
|
22375
22453
|
const status = op.result?.status;
|
|
22454
|
+
if (status === "applied" && op.result?.error) {
|
|
22455
|
+
lines.push(` \u26A0 ${op.summary} \u2014 applied in part: ${op.result.error}`);
|
|
22456
|
+
continue;
|
|
22457
|
+
}
|
|
22376
22458
|
if (status !== "failed" && status !== "skipped") {
|
|
22377
22459
|
continue;
|
|
22378
22460
|
}
|