@koda-sl/baker-cli 0.333.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 +94 -4
- 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(),
|
|
@@ -4918,7 +4989,15 @@ var scheduledEffectSchema = z13.object({
|
|
|
4918
4989
|
op: effectOpSchema,
|
|
4919
4990
|
staged: z13.boolean(),
|
|
4920
4991
|
name: z13.string(),
|
|
4921
|
-
summary: z13.string().nullable()
|
|
4992
|
+
summary: z13.string().nullable(),
|
|
4993
|
+
/**
|
|
4994
|
+
* What the publish did with this op, or null while it is still staged. `op`
|
|
4995
|
+
* is what was asked for; this is whether it happened — a task whose schedule
|
|
4996
|
+
* could not be saved still reads `op: "created"`.
|
|
4997
|
+
*/
|
|
4998
|
+
outcome: z13.enum(["applied", "failed", "skipped"]).nullable(),
|
|
4999
|
+
/** Why it failed or was skipped, or how it was applied differently (e.g. switched off). */
|
|
5000
|
+
reason: z13.string().nullable()
|
|
4922
5001
|
});
|
|
4923
5002
|
var tagEffectSchema = z13.object({
|
|
4924
5003
|
op: effectOpSchema,
|
|
@@ -19929,7 +20008,11 @@ registerSchema({
|
|
|
19929
20008
|
name: { type: "string", description: "Audience name (\u2264100 chars)", required: true },
|
|
19930
20009
|
type: { type: "string", description: "company-list|user-list|retargeting|engagement", required: true },
|
|
19931
20010
|
"list-file": { type: "string", description: "CSV file with the list rows", required: false },
|
|
19932
|
-
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
|
+
}
|
|
19933
20016
|
}
|
|
19934
20017
|
});
|
|
19935
20018
|
registerSchema({
|
|
@@ -20681,7 +20764,10 @@ Example: baker ads linkedin audiences create --name "ABM Tier-1" --type company-
|
|
|
20681
20764
|
name: { type: "string", description: "Audience name (\u2264100 chars)" },
|
|
20682
20765
|
type: { type: "string", description: AUDIENCE_TYPES2.join("|") },
|
|
20683
20766
|
"list-file": { type: "string", description: "CSV file with the list rows (header row required)" },
|
|
20684
|
-
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
|
+
}
|
|
20685
20771
|
},
|
|
20686
20772
|
run: async ({ args: args5 }) => {
|
|
20687
20773
|
const accountId = bareAccountId(args5);
|
|
@@ -22365,6 +22451,10 @@ function renderOutcome2(data, lines) {
|
|
|
22365
22451
|
lines.push(`LinkedIn Ads \u2014 published \xB7 ${summary || `${data.count} op(s)`} \xB7 ${data.mode}`);
|
|
22366
22452
|
for (const op of data.ops ?? []) {
|
|
22367
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
|
+
}
|
|
22368
22458
|
if (status !== "failed" && status !== "skipped") {
|
|
22369
22459
|
continue;
|
|
22370
22460
|
}
|